From 36a996d70499a8bc4cf9c28853c2b5606d73f81d Mon Sep 17 00:00:00 2001 From: s-aga-r Date: Wed, 18 Oct 2023 12:01:22 +0530 Subject: [PATCH 01/25] chore: make `Reserve Stock` checkbox visible in SO --- erpnext/selling/doctype/sales_order/sales_order.json | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/erpnext/selling/doctype/sales_order/sales_order.json b/erpnext/selling/doctype/sales_order/sales_order.json index a74084d21fdd..01d047ceadba 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.json +++ b/erpnext/selling/doctype/sales_order/sales_order.json @@ -1631,10 +1631,9 @@ { "default": "0", "depends_on": "eval: (doc.docstatus == 0 || doc.reserve_stock)", - "description": "If checked, Stock Reservation Entries will be created on Submit", + "description": "If checked, Stock will be reserved on Submit", "fieldname": "reserve_stock", "fieldtype": "Check", - "hidden": 1, "label": "Reserve Stock", "no_copy": 1, "print_hide": 1, @@ -1645,7 +1644,7 @@ "idx": 105, "is_submittable": 1, "links": [], - "modified": "2023-07-24 08:59:11.599875", + "modified": "2023-10-18 12:41:54.813462", "modified_by": "Administrator", "module": "Selling", "name": "Sales Order", From 2b4fa98941817966b8a936e4076be84406ad035a Mon Sep 17 00:00:00 2001 From: s-aga-r Date: Wed, 18 Oct 2023 12:38:42 +0530 Subject: [PATCH 02/25] refactor: rename field `Auto Reserve Stock for Sales Order` --- .../doctype/sales_order/sales_order.js | 12 +++----- .../stock_settings/stock_settings.json | 29 +++++++++---------- 2 files changed, 18 insertions(+), 23 deletions(-) diff --git a/erpnext/selling/doctype/sales_order/sales_order.js b/erpnext/selling/doctype/sales_order/sales_order.js index ba8bc339f38f..3ad18daf1930 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.js +++ b/erpnext/selling/doctype/sales_order/sales_order.js @@ -87,17 +87,13 @@ frappe.ui.form.on("Sales Order", { frm.events.get_items_from_internal_purchase_order(frm); } - if (frm.is_new()) { + if (frm.doc.docstatus === 0) { frappe.db.get_single_value("Stock Settings", "enable_stock_reservation").then((value) => { - if (value) { - frappe.db.get_single_value("Stock Settings", "auto_reserve_stock_for_sales_order").then((value) => { - // If `Reserve Stock on Sales Order Submission` is enabled in Stock Settings, set Reserve Stock to 1 else 0. - frm.set_value("reserve_stock", value ? 1 : 0); - }) - } else { - // If `Stock Reservation` is disabled in Stock Settings, set Reserve Stock to 0 and read only. + if (!value) { + // If `Stock Reservation` is disabled in Stock Settings, set Reserve Stock to 0 and make the field read-only and hidden. frm.set_value("reserve_stock", 0); frm.set_df_property("reserve_stock", "read_only", 1); + frm.set_df_property("reserve_stock", "hidden", 1); } }) } diff --git a/erpnext/stock/doctype/stock_settings/stock_settings.json b/erpnext/stock/doctype/stock_settings/stock_settings.json index 2052daafedb3..122829032def 100644 --- a/erpnext/stock/doctype/stock_settings/stock_settings.json +++ b/erpnext/stock/doctype/stock_settings/stock_settings.json @@ -38,8 +38,8 @@ "stock_reservation_tab", "enable_stock_reservation", "column_break_rx3e", - "auto_reserve_stock_for_sales_order", "allow_partial_reservation", + "auto_reserve_stock_for_sales_order_on_purchase", "serial_and_batch_reservation_section", "auto_reserve_serial_and_batch", "serial_and_batch_item_settings_tab", @@ -65,8 +65,7 @@ "stock_frozen_upto_days", "column_break_26", "role_allowed_to_create_edit_back_dated_transactions", - "stock_auth_role", - "section_break_plhx" + "stock_auth_role" ], "fields": [ { @@ -356,7 +355,7 @@ { "default": "1", "depends_on": "eval: doc.enable_stock_reservation", - "description": "If enabled, Partial Stock Reservation Entries can be created. For example, If you have a Sales Order of 100 units and the Available Stock is 90 units then a Stock Reservation Entry will be created for 90 units. ", + "description": "Partial stock can be reserved. For example, If you have a Sales Order of 100 units and the Available Stock is 90 units then a Stock Reservation Entry will be created for 90 units. ", "fieldname": "allow_partial_reservation", "fieldtype": "Check", "label": "Allow Partial Reservation" @@ -383,7 +382,7 @@ { "default": "1", "depends_on": "eval: doc.enable_stock_reservation", - "description": "If enabled, Serial and Batch Nos will be auto-reserved based on Pick Serial / Batch Based On", + "description": "Serial and Batch Nos will be auto-reserved based on Pick Serial / Batch Based On", "fieldname": "auto_reserve_serial_and_batch", "fieldtype": "Check", "label": "Auto Reserve Serial and Batch Nos" @@ -393,14 +392,6 @@ "fieldtype": "Section Break", "label": "Serial and Batch Reservation" }, - { - "default": "0", - "depends_on": "eval: doc.enable_stock_reservation", - "description": "If enabled, Stock Reservation Entries will be created on submission of Sales Order", - "fieldname": "auto_reserve_stock_for_sales_order", - "fieldtype": "Check", - "label": "Auto Reserve Stock for Sales Order" - }, { "fieldname": "conversion_factor_section", "fieldtype": "Section Break", @@ -421,6 +412,14 @@ "fieldname": "allow_to_edit_stock_uom_qty_for_purchase", "fieldtype": "Check", "label": "Allow to Edit Stock UOM Qty for Purchase Documents" + }, + { + "default": "0", + "depends_on": "eval: doc.enable_stock_reservation", + "description": "Stock will be reserved on submission of Purchase Receipt created against Material Receipt for Sales Order.", + "fieldname": "auto_reserve_stock_for_sales_order_on_purchase", + "fieldtype": "Check", + "label": "Auto Reserve Stock for Sales Order on Purchase" } ], "icon": "icon-cog", @@ -428,7 +427,7 @@ "index_web_pages_for_search": 1, "issingle": 1, "links": [], - "modified": "2023-10-01 14:22:36.136111", + "modified": "2023-10-18 12:35:30.068799", "modified_by": "Administrator", "module": "Stock", "name": "Stock Settings", @@ -453,4 +452,4 @@ "sort_order": "ASC", "states": [], "track_changes": 1 -} +} \ No newline at end of file From 188175be84b5eaa0be73face69f4f2b58b80dd64 Mon Sep 17 00:00:00 2001 From: s-aga-r Date: Thu, 19 Oct 2023 14:43:29 +0530 Subject: [PATCH 03/25] feat: add fields to hold SO and SO Item ref in PR Item --- .../doctype/purchase_order/purchase_order.py | 2 ++ .../purchase_receipt_item.json | 28 +++++++++++++++++-- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.py b/erpnext/buying/doctype/purchase_order/purchase_order.py index 465fe96b58b5..7c40aafbe05a 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.py +++ b/erpnext/buying/doctype/purchase_order/purchase_order.py @@ -556,6 +556,8 @@ def update_item(obj, target, source_parent): "bom": "bom", "material_request": "material_request", "material_request_item": "material_request_item", + "sales_order": "sales_order", + "sales_order_item": "sales_order_item", }, "postprocess": update_item, "condition": lambda doc: abs(doc.received_qty) < abs(doc.qty) 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 d93d21c1f204..f5240a609419 100644 --- a/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json +++ b/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json @@ -125,7 +125,9 @@ "dimension_col_break", "cost_center", "section_break_80", - "page_break" + "page_break", + "sales_order", + "sales_order_item" ], "fields": [ { @@ -1062,12 +1064,32 @@ "fieldtype": "Link", "label": "WIP Composite Asset", "options": "Asset" + }, + { + "fieldname": "sales_order", + "fieldtype": "Link", + "label": "Sales Order", + "no_copy": 1, + "options": "Sales Order", + "print_hide": 1, + "read_only": 1, + "search_index": 1 + }, + { + "fieldname": "sales_order_item", + "fieldtype": "Data", + "hidden": 1, + "label": "Sales Order Item", + "no_copy": 1, + "print_hide": 1, + "read_only": 1, + "search_index": 1 } ], "idx": 1, "istable": 1, "links": [], - "modified": "2023-10-03 21:11:50.547261", + "modified": "2023-10-19 10:50:58.071735", "modified_by": "Administrator", "module": "Stock", "name": "Purchase Receipt Item", @@ -1078,4 +1100,4 @@ "sort_field": "modified", "sort_order": "DESC", "states": [] -} +} \ No newline at end of file From 64497c922892d19ca378b5da75cf6b528f5e52d9 Mon Sep 17 00:00:00 2001 From: s-aga-r Date: Thu, 19 Oct 2023 14:48:13 +0530 Subject: [PATCH 04/25] feat: reserve stock for SO on PR submission --- .../doctype/sales_order/sales_order.py | 2 +- erpnext/stock/doctype/pick_list/pick_list.py | 2 +- .../purchase_receipt/purchase_receipt.py | 26 +++++++ .../stock_reservation_entry.py | 67 ++++++++++--------- 4 files changed, 62 insertions(+), 35 deletions(-) diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py index b91002eb8667..d38216242e93 100755 --- a/erpnext/selling/doctype/sales_order/sales_order.py +++ b/erpnext/selling/doctype/sales_order/sales_order.py @@ -541,7 +541,7 @@ def create_stock_reservation_entries(self, items_details=None, notify=True) -> N create_stock_reservation_entries_for_so_items as create_stock_reservation_entries, ) - create_stock_reservation_entries(so=self, items_details=items_details, notify=notify) + create_stock_reservation_entries(sales_order=self, items_details=items_details, notify=notify) @frappe.whitelist() def cancel_stock_reservation_entries(self, sre_list=None, notify=True) -> None: diff --git a/erpnext/stock/doctype/pick_list/pick_list.py b/erpnext/stock/doctype/pick_list/pick_list.py index 2fcd1025a0e4..8c9d03c1bd5e 100644 --- a/erpnext/stock/doctype/pick_list/pick_list.py +++ b/erpnext/stock/doctype/pick_list/pick_list.py @@ -242,7 +242,7 @@ def create_stock_reservation_entries(self, notify=True) -> None: for so, locations in so_details.items(): so_doc = frappe.get_doc("Sales Order", so) create_stock_reservation_entries_for_so_items( - so=so_doc, items_details=locations, against_pick_list=True, notify=notify + sales_order=so_doc, items_details=locations, against_pick_list=True, notify=notify ) @frappe.whitelist() diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py index de0db1aa8fa3..fc88dd8d5fa1 100644 --- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py @@ -264,6 +264,7 @@ def on_submit(self): self.make_gl_entries() self.repost_future_sle_and_gle() self.set_consumed_qty_in_subcontract_order() + self.reserve_stock_for_sales_order() def check_next_docstatus(self): submit_rv = frappe.db.sql( @@ -829,6 +830,31 @@ def update_billing_status(self, update_modified=True): self.load_from_db() + def reserve_stock_for_sales_order(self): + if self.is_return or not cint( + frappe.db.get_single_value("Stock Settings", "auto_reserve_stock_for_sales_order_on_purchase") + ): + return + + self.reload() # reload to get the Serial and Batch Bundle Details + + so_items_details_map = {} + for item in self.items: + if item.sales_order and item.sales_order_item: + item_details = { + "name": item.sales_order_item, + "item_code": item.item_code, + "warehouse": item.warehouse, + "qty_to_reserve": item.stock_qty, + "serial_and_batch_bundle": item.get("serial_and_batch_bundle"), + } + so_items_details_map.setdefault(item.sales_order, []).append(item_details) + + if so_items_details_map: + for so, items_details in so_items_details_map.items(): + so_doc = frappe.get_doc("Sales Order", so) + so_doc.create_stock_reservation_entries(items_details) + def update_billed_amount_based_on_po(po_details, update_modified=True): po_billed_amt_details = get_billed_amount_against_po(po_details) diff --git a/erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.py b/erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.py index 936be3f73b4b..effad7df985e 100644 --- a/erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.py +++ b/erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.py @@ -761,7 +761,7 @@ def has_reserved_stock(voucher_type: str, voucher_no: str, voucher_detail_no: st def create_stock_reservation_entries_for_so_items( - so: object, + sales_order: object, items_details: list[dict] = None, against_pick_list: bool = False, notify=True, @@ -771,15 +771,17 @@ def create_stock_reservation_entries_for_so_items( from erpnext.selling.doctype.sales_order.sales_order import get_unreserved_qty if not against_pick_list and ( - so.get("_action") == "submit" - and so.set_warehouse - and cint(frappe.get_cached_value("Warehouse", so.set_warehouse, "is_group")) + sales_order.get("_action") == "submit" + and sales_order.set_warehouse + and cint(frappe.get_cached_value("Warehouse", sales_order.set_warehouse, "is_group")) ): return frappe.msgprint( - _("Stock cannot be reserved in the group warehouse {0}.").format(frappe.bold(so.set_warehouse)) + _("Stock cannot be reserved in the group warehouse {0}.").format( + frappe.bold(sales_order.set_warehouse) + ) ) - validate_stock_reservation_settings(so) + validate_stock_reservation_settings(sales_order) allow_partial_reservation = frappe.db.get_single_value( "Stock Settings", "allow_partial_reservation" @@ -787,29 +789,28 @@ def create_stock_reservation_entries_for_so_items( items = [] if items_details: + item_field = "sales_order_item" if against_pick_list else "name" + for item in items_details: - so_item = frappe.get_doc( - "Sales Order Item", item.get("sales_order_item") if against_pick_list else item.get("name") - ) - so_item.reserve_stock = 1 + so_item = frappe.get_doc("Sales Order Item", item.get(item_field)) so_item.warehouse = item.get("warehouse") so_item.qty_to_reserve = ( item.get("picked_qty") - item.get("stock_reserved_qty", 0) if against_pick_list else (flt(item.get("qty_to_reserve")) * flt(so_item.conversion_factor, 1)) ) + so_item.serial_and_batch_bundle = item.get("serial_and_batch_bundle") if against_pick_list: so_item.pick_list = item.get("parent") so_item.pick_list_item = item.get("name") - so_item.pick_list_sbb = item.get("serial_and_batch_bundle") items.append(so_item) sre_count = 0 - reserved_qty_details = get_sre_reserved_qty_details_for_voucher("Sales Order", so.name) + reserved_qty_details = get_sre_reserved_qty_details_for_voucher("Sales Order", sales_order.name) - for item in items if items_details else so.get("items"): + for item in items if items_details else sales_order.get("items"): # Skip if `Reserved Stock` is not checked for the item. if not item.get("reserve_stock"): continue @@ -817,9 +818,9 @@ def create_stock_reservation_entries_for_so_items( # Stock should be reserved from the Pick List if has Picked Qty. if not against_pick_list and flt(item.picked_qty) > 0: frappe.throw( - _( - "Row #{0}: Item {1} has been picked, please create a Stock Reservation from the Pick List." - ).format(item.idx, frappe.bold(item.item_code)) + _("Row #{0}: Item {1} has been picked, please reserve stock from the Pick List.").format( + item.idx, frappe.bold(item.item_code) + ) ) is_stock_item, has_serial_no, has_batch_no = frappe.get_cached_value( @@ -915,33 +916,33 @@ def create_stock_reservation_entries_for_so_items( sre.warehouse = item.warehouse sre.has_serial_no = has_serial_no sre.has_batch_no = has_batch_no - sre.voucher_type = so.doctype - sre.voucher_no = so.name + sre.voucher_type = sales_order.doctype + sre.voucher_no = sales_order.name sre.voucher_detail_no = item.name sre.available_qty = available_qty_to_reserve sre.voucher_qty = item.stock_qty sre.reserved_qty = qty_to_be_reserved - sre.company = so.company + sre.company = sales_order.company sre.stock_uom = item.stock_uom - sre.project = so.project + sre.project = sales_order.project if against_pick_list: sre.against_pick_list = item.pick_list sre.against_pick_list_item = item.pick_list_item - if item.pick_list_sbb: - sbb = frappe.get_doc("Serial and Batch Bundle", item.pick_list_sbb) - sre.reservation_based_on = "Serial and Batch" - for entry in sbb.entries: - sre.append( - "sb_entries", - { - "serial_no": entry.serial_no, - "batch_no": entry.batch_no, - "qty": 1 if has_serial_no else abs(entry.qty), - "warehouse": entry.warehouse, - }, - ) + if item.serial_and_batch_bundle: + sbb = frappe.get_doc("Serial and Batch Bundle", item.serial_and_batch_bundle) + sre.reservation_based_on = "Serial and Batch" + for entry in sbb.entries: + sre.append( + "sb_entries", + { + "serial_no": entry.serial_no, + "batch_no": entry.batch_no, + "qty": 1 if has_serial_no else abs(entry.qty), + "warehouse": entry.warehouse, + }, + ) sre.save() sre.submit() From 5ae9c2f62b741d64da4ce74b3b251339711e8256 Mon Sep 17 00:00:00 2001 From: s-aga-r Date: Thu, 19 Oct 2023 16:21:32 +0530 Subject: [PATCH 05/25] feat: add field `From Voucher Type` in SRE --- .../stock_reservation_entry.json | 21 ++++++++++++++----- .../stock_reservation_entry.py | 1 + 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.json b/erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.json index 5c3018f73423..f92bf49137b5 100644 --- a/erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.json +++ b/erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.json @@ -17,6 +17,7 @@ "voucher_no", "voucher_detail_no", "column_break_7dxj", + "from_voucher_type", "against_pick_list", "against_pick_list_item", "section_break_xt4m", @@ -272,10 +273,10 @@ }, { "fieldname": "against_pick_list", - "fieldtype": "Link", - "label": "Against Pick List", + "fieldtype": "Dynamic Link", + "label": "From Voucher No", "no_copy": 1, - "options": "Pick List", + "options": "from_voucher_type", "print_hide": 1, "read_only": 1, "report_hide": 1, @@ -284,7 +285,7 @@ { "fieldname": "against_pick_list_item", "fieldtype": "Data", - "label": "Against Pick List Item", + "label": "From Voucher Detail No", "no_copy": 1, "print_hide": 1, "read_only": 1, @@ -297,6 +298,16 @@ { "fieldname": "column_break_grdt", "fieldtype": "Column Break" + }, + { + "fieldname": "from_voucher_type", + "fieldtype": "Select", + "label": "From Voucher Type", + "no_copy": 1, + "options": "\nPick List\nPurchase Receipt", + "print_hide": 1, + "read_only": 1, + "report_hide": 1 } ], "hide_toolbar": 1, @@ -304,7 +315,7 @@ "index_web_pages_for_search": 1, "is_submittable": 1, "links": [], - "modified": "2023-08-08 17:15:13.317706", + "modified": "2023-10-19 16:09:08.418544", "modified_by": "Administrator", "module": "Stock", "name": "Stock Reservation Entry", diff --git a/erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.py b/erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.py index effad7df985e..80f4c1e50565 100644 --- a/erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.py +++ b/erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.py @@ -927,6 +927,7 @@ def create_stock_reservation_entries_for_so_items( sre.project = sales_order.project if against_pick_list: + sre.from_voucher_type = "Pick List" sre.against_pick_list = item.pick_list sre.against_pick_list_item = item.pick_list_item From 78fe56741931ad2c253bf9acca2896c2411f4ac6 Mon Sep 17 00:00:00 2001 From: s-aga-r Date: Thu, 19 Oct 2023 16:38:43 +0530 Subject: [PATCH 06/25] refactor: rename field `against_pick_list_item` --- .../stock_reservation_entry.json | 22 +++++++++---------- .../stock_reservation_entry.py | 13 ++++++----- .../test_stock_reservation_entry.py | 3 ++- 3 files changed, 21 insertions(+), 17 deletions(-) diff --git a/erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.json b/erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.json index f92bf49137b5..1a518fa38ae6 100644 --- a/erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.json +++ b/erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.json @@ -19,7 +19,7 @@ "column_break_7dxj", "from_voucher_type", "against_pick_list", - "against_pick_list_item", + "from_voucher_detail_no", "section_break_xt4m", "stock_uom", "column_break_grdt", @@ -282,15 +282,6 @@ "report_hide": 1, "search_index": 1 }, - { - "fieldname": "against_pick_list_item", - "fieldtype": "Data", - "label": "From Voucher Detail No", - "no_copy": 1, - "print_hide": 1, - "read_only": 1, - "report_hide": 1 - }, { "fieldname": "column_break_7dxj", "fieldtype": "Column Break" @@ -308,6 +299,15 @@ "print_hide": 1, "read_only": 1, "report_hide": 1 + }, + { + "fieldname": "from_voucher_detail_no", + "fieldtype": "Data", + "label": "From Voucher Detail No", + "no_copy": 1, + "print_hide": 1, + "read_only": 1, + "report_hide": 1 } ], "hide_toolbar": 1, @@ -315,7 +315,7 @@ "index_web_pages_for_search": 1, "is_submittable": 1, "links": [], - "modified": "2023-10-19 16:09:08.418544", + "modified": "2023-10-19 16:26:46.598043", "modified_by": "Administrator", "module": "Stock", "name": "Stock Reservation Entry", diff --git a/erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.py b/erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.py index 80f4c1e50565..66e246a86ab6 100644 --- a/erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.py +++ b/erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.py @@ -316,21 +316,24 @@ def update_reserved_qty_in_pick_list( ) -> None: """Updates total reserved qty in the Pick List.""" - if self.against_pick_list and self.against_pick_list_item: + if ( + self.from_voucher_type == "Pick List" and self.against_pick_list and self.from_voucher_detail_no + ): sre = frappe.qb.DocType("Stock Reservation Entry") reserved_qty = ( frappe.qb.from_(sre) .select(Sum(sre.reserved_qty)) .where( (sre.docstatus == 1) + & (sre.from_voucher_type == "Pick List") & (sre.against_pick_list == self.against_pick_list) - & (sre.against_pick_list_item == self.against_pick_list_item) + & (sre.from_voucher_detail_no == self.from_voucher_detail_no) ) ).run(as_list=True)[0][0] or 0 frappe.db.set_value( "Pick List Item", - self.against_pick_list_item, + self.from_voucher_detail_no, reserved_qty_field, reserved_qty, update_modified=update_modified, @@ -803,7 +806,7 @@ def create_stock_reservation_entries_for_so_items( if against_pick_list: so_item.pick_list = item.get("parent") - so_item.pick_list_item = item.get("name") + so_item.from_voucher_detail_no = item.get("name") items.append(so_item) @@ -929,7 +932,7 @@ def create_stock_reservation_entries_for_so_items( if against_pick_list: sre.from_voucher_type = "Pick List" sre.against_pick_list = item.pick_list - sre.against_pick_list_item = item.pick_list_item + sre.from_voucher_detail_no = item.from_voucher_detail_no if item.serial_and_batch_bundle: sbb = frappe.get_doc("Serial and Batch Bundle", item.serial_and_batch_bundle) diff --git a/erpnext/stock/doctype/stock_reservation_entry/test_stock_reservation_entry.py b/erpnext/stock/doctype/stock_reservation_entry/test_stock_reservation_entry.py index 1168a4e1c618..27f43bf66810 100644 --- a/erpnext/stock/doctype/stock_reservation_entry/test_stock_reservation_entry.py +++ b/erpnext/stock/doctype/stock_reservation_entry/test_stock_reservation_entry.py @@ -555,8 +555,9 @@ def test_stock_reservation_from_pick_list(self): (sre.voucher_type == "Sales Order") & (sre.voucher_no == location.sales_order) & (sre.voucher_detail_no == location.sales_order_item) + & (sre.from_voucher_type == "Pick List") & (sre.against_pick_list == pl.name) - & (sre.against_pick_list_item == location.name) + & (sre.from_voucher_detail_no == location.name) ) ).run(as_dict=True) reserved_sb_details: set[tuple] = { From 961d2d9926a1a9c0396c3292d431d3bad6865e62 Mon Sep 17 00:00:00 2001 From: s-aga-r Date: Thu, 19 Oct 2023 17:51:34 +0530 Subject: [PATCH 07/25] refactor: rename field `against_pick_list` --- erpnext/stock/doctype/pick_list/pick_list.js | 3 +- erpnext/stock/doctype/pick_list/pick_list.py | 6 +- .../doctype/pick_list/pick_list_dashboard.py | 2 +- .../stock_reservation_entry.js | 2 +- .../stock_reservation_entry.json | 30 ++++---- .../stock_reservation_entry.py | 70 +++++++++++-------- .../test_stock_reservation_entry.py | 2 +- .../report/reserved_stock/reserved_stock.js | 20 +++++- .../report/reserved_stock/reserved_stock.py | 23 +++--- 9 files changed, 96 insertions(+), 62 deletions(-) diff --git a/erpnext/stock/doctype/pick_list/pick_list.js b/erpnext/stock/doctype/pick_list/pick_list.js index ae05b80727f2..7cd171ea92ed 100644 --- a/erpnext/stock/doctype/pick_list/pick_list.js +++ b/erpnext/stock/doctype/pick_list/pick_list.js @@ -265,7 +265,8 @@ frappe.ui.form.on('Pick List', { from_date: moment(frm.doc.creation).format('YYYY-MM-DD'), to_date: to_date, voucher_type: "Sales Order", - against_pick_list: frm.doc.name, + from_voucher_type: "Pick List", + from_voucher_no: frm.doc.name, } frappe.set_route("query-report", "Reserved Stock"); } diff --git a/erpnext/stock/doctype/pick_list/pick_list.py b/erpnext/stock/doctype/pick_list/pick_list.py index 8c9d03c1bd5e..3503556f3ed0 100644 --- a/erpnext/stock/doctype/pick_list/pick_list.py +++ b/erpnext/stock/doctype/pick_list/pick_list.py @@ -242,7 +242,7 @@ def create_stock_reservation_entries(self, notify=True) -> None: for so, locations in so_details.items(): so_doc = frappe.get_doc("Sales Order", so) create_stock_reservation_entries_for_so_items( - sales_order=so_doc, items_details=locations, against_pick_list=True, notify=notify + sales_order=so_doc, items_details=locations, from_voucher_type="Pick List", notify=notify ) @frappe.whitelist() @@ -253,7 +253,9 @@ def cancel_stock_reservation_entries(self, notify=True) -> None: cancel_stock_reservation_entries, ) - cancel_stock_reservation_entries(against_pick_list=self.name, notify=notify) + cancel_stock_reservation_entries( + from_voucher_type="Pick List", from_voucher_no=self.name, notify=notify + ) def validate_picked_qty(self, data): over_delivery_receipt_allowance = 100 + flt( diff --git a/erpnext/stock/doctype/pick_list/pick_list_dashboard.py b/erpnext/stock/doctype/pick_list/pick_list_dashboard.py index 0830fa21430f..29571a54007f 100644 --- a/erpnext/stock/doctype/pick_list/pick_list_dashboard.py +++ b/erpnext/stock/doctype/pick_list/pick_list_dashboard.py @@ -2,7 +2,7 @@ def get_data(): return { "fieldname": "pick_list", "non_standard_fieldnames": { - "Stock Reservation Entry": "against_pick_list", + "Stock Reservation Entry": "from_voucher_no", }, "internal_links": { "Sales Order": ["locations", "sales_order"], diff --git a/erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.js b/erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.js index c5df319e224c..f60a0378b60e 100644 --- a/erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.js +++ b/erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.js @@ -92,7 +92,7 @@ frappe.ui.form.on('Stock Reservation Entry', { 'qty', 'read_only', frm.doc.has_serial_no ); - frm.set_df_property('sb_entries', 'allow_on_submit', frm.doc.against_pick_list ? 0 : 1); + frm.set_df_property('sb_entries', 'allow_on_submit', frm.doc.from_voucher_type == "Pick List" ? 0 : 1); }, hide_rate_related_fields(frm) { diff --git a/erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.json b/erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.json index 1a518fa38ae6..76cedd4b1e2c 100644 --- a/erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.json +++ b/erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.json @@ -18,7 +18,7 @@ "voucher_detail_no", "column_break_7dxj", "from_voucher_type", - "against_pick_list", + "from_voucher_no", "from_voucher_detail_no", "section_break_xt4m", "stock_uom", @@ -159,7 +159,7 @@ "oldfieldname": "actual_qty", "oldfieldtype": "Currency", "print_width": "150px", - "read_only_depends_on": "eval: ((doc.reservation_based_on == \"Serial and Batch\") || (doc.against_pick_list) || (doc.delivered_qty > 0))", + "read_only_depends_on": "eval: ((doc.reservation_based_on == \"Serial and Batch\") || (doc.from_voucher_type == \"Pick List\") || (doc.delivered_qty > 0))", "width": "150px" }, { @@ -269,18 +269,7 @@ "label": "Reservation Based On", "no_copy": 1, "options": "Qty\nSerial and Batch", - "read_only_depends_on": "eval: (doc.delivered_qty > 0 || doc.against_pick_list)" - }, - { - "fieldname": "against_pick_list", - "fieldtype": "Dynamic Link", - "label": "From Voucher No", - "no_copy": 1, - "options": "from_voucher_type", - "print_hide": 1, - "read_only": 1, - "report_hide": 1, - "search_index": 1 + "read_only_depends_on": "eval: (doc.delivered_qty > 0 || doc.from_voucher_type == \"Pick List\")" }, { "fieldname": "column_break_7dxj", @@ -308,6 +297,17 @@ "print_hide": 1, "read_only": 1, "report_hide": 1 + }, + { + "fieldname": "from_voucher_no", + "fieldtype": "Dynamic Link", + "label": "From Voucher No", + "no_copy": 1, + "options": "from_voucher_type", + "print_hide": 1, + "read_only": 1, + "report_hide": 1, + "search_index": 1 } ], "hide_toolbar": 1, @@ -315,7 +315,7 @@ "index_web_pages_for_search": 1, "is_submittable": 1, "links": [], - "modified": "2023-10-19 16:26:46.598043", + "modified": "2023-10-19 16:41:16.545416", "modified_by": "Administrator", "module": "Stock", "name": "Stock Reservation Entry", diff --git a/erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.py b/erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.py index 66e246a86ab6..9097e621e60e 100644 --- a/erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.py +++ b/erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.py @@ -1,6 +1,8 @@ # Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt +from typing import Literal + import frappe from frappe import _ from frappe.model.document import Document @@ -113,7 +115,7 @@ def auto_reserve_serial_and_batch(self, based_on: str = None) -> None: """Auto pick Serial and Batch Nos to reserve when `Reservation Based On` is `Serial and Batch`.""" if ( - not self.against_pick_list + not self.from_voucher_type and (self.get("_action") == "submit") and (self.has_serial_no or self.has_batch_no) and cint(frappe.db.get_single_value("Stock Settings", "auto_reserve_serial_and_batch")) @@ -317,7 +319,7 @@ def update_reserved_qty_in_pick_list( """Updates total reserved qty in the Pick List.""" if ( - self.from_voucher_type == "Pick List" and self.against_pick_list and self.from_voucher_detail_no + self.from_voucher_type == "Pick List" and self.from_voucher_no and self.from_voucher_detail_no ): sre = frappe.qb.DocType("Stock Reservation Entry") reserved_qty = ( @@ -326,7 +328,7 @@ def update_reserved_qty_in_pick_list( .where( (sre.docstatus == 1) & (sre.from_voucher_type == "Pick List") - & (sre.against_pick_list == self.against_pick_list) + & (sre.from_voucher_no == self.from_voucher_no) & (sre.from_voucher_detail_no == self.from_voucher_detail_no) ) ).run(as_list=True)[0][0] or 0 @@ -368,7 +370,7 @@ def can_be_updated(self) -> None: ).format(self.status, self.doctype) frappe.throw(msg) - if self.against_pick_list: + if self.from_voucher_type == "Pick List": msg = _( "Stock Reservation Entry created against a Pick List cannot be updated. If you need to make changes, we recommend canceling the existing entry and creating a new one." ) @@ -766,14 +768,14 @@ def has_reserved_stock(voucher_type: str, voucher_no: str, voucher_detail_no: st def create_stock_reservation_entries_for_so_items( sales_order: object, items_details: list[dict] = None, - against_pick_list: bool = False, + from_voucher_type: Literal["Pick List", "Purchase Receipt"] = None, notify=True, ) -> None: """Creates Stock Reservation Entries for Sales Order Items.""" from erpnext.selling.doctype.sales_order.sales_order import get_unreserved_qty - if not against_pick_list and ( + if not from_voucher_type and ( sales_order.get("_action") == "submit" and sales_order.set_warehouse and cint(frappe.get_cached_value("Warehouse", sales_order.set_warehouse, "is_group")) @@ -792,20 +794,20 @@ def create_stock_reservation_entries_for_so_items( items = [] if items_details: - item_field = "sales_order_item" if against_pick_list else "name" + item_field = "sales_order_item" if from_voucher_type == "Pick List" else "name" for item in items_details: so_item = frappe.get_doc("Sales Order Item", item.get(item_field)) so_item.warehouse = item.get("warehouse") so_item.qty_to_reserve = ( item.get("picked_qty") - item.get("stock_reserved_qty", 0) - if against_pick_list + if from_voucher_type == "Pick List" else (flt(item.get("qty_to_reserve")) * flt(so_item.conversion_factor, 1)) ) so_item.serial_and_batch_bundle = item.get("serial_and_batch_bundle") - if against_pick_list: - so_item.pick_list = item.get("parent") + if from_voucher_type == "Pick List": + so_item.from_voucher_no = item.get("parent") so_item.from_voucher_detail_no = item.get("name") items.append(so_item) @@ -819,7 +821,7 @@ def create_stock_reservation_entries_for_so_items( continue # Stock should be reserved from the Pick List if has Picked Qty. - if not against_pick_list and flt(item.picked_qty) > 0: + if not from_voucher_type == "Pick List" and flt(item.picked_qty) > 0: frappe.throw( _("Row #{0}: Item {1} has been picked, please reserve stock from the Pick List.").format( item.idx, frappe.bold(item.item_code) @@ -929,9 +931,9 @@ def create_stock_reservation_entries_for_so_items( sre.stock_uom = item.stock_uom sre.project = sales_order.project - if against_pick_list: - sre.from_voucher_type = "Pick List" - sre.against_pick_list = item.pick_list + if from_voucher_type: + sre.from_voucher_type = from_voucher_type + sre.from_voucher_no = item.from_voucher_no sre.from_voucher_detail_no = item.from_voucher_detail_no if item.serial_and_batch_bundle: @@ -961,29 +963,37 @@ def cancel_stock_reservation_entries( voucher_type: str = None, voucher_no: str = None, voucher_detail_no: str = None, - against_pick_list: str = None, + from_voucher_type: Literal["Pick List", "Purchase Receipt"] = None, + from_voucher_no: str = None, + from_voucher_detail_no: str = None, sre_list: list[dict] = None, notify: bool = True, ) -> None: """Cancel Stock Reservation Entries.""" - if not sre_list and against_pick_list: - sre = frappe.qb.DocType("Stock Reservation Entry") - sre_list = ( - frappe.qb.from_(sre) - .select(sre.name) - .where( - (sre.docstatus == 1) - & (sre.against_pick_list == against_pick_list) - & (sre.status.notin(["Delivered", "Cancelled"])) + if not sre_list: + if voucher_type and voucher_no: + sre_list = get_stock_reservation_entries_for_voucher( + voucher_type, voucher_no, voucher_detail_no, fields=["name"] + ) + elif from_voucher_type and from_voucher_no: + sre = frappe.qb.DocType("Stock Reservation Entry") + query = ( + frappe.qb.from_(sre) + .select(sre.name) + .where( + (sre.docstatus == 1) + & (sre.from_voucher_type == from_voucher_type) + & (sre.from_voucher_no == from_voucher_no) + & (sre.status.notin(["Delivered", "Cancelled"])) + ) + .orderby(sre.creation) ) - .orderby(sre.creation) - ).run(as_dict=True) - elif not sre_list and (voucher_type and voucher_no): - sre_list = get_stock_reservation_entries_for_voucher( - voucher_type, voucher_no, voucher_detail_no, fields=["name"] - ) + if from_voucher_detail_no: + query = query.where(sre.from_voucher_detail_no == from_voucher_detail_no) + + sre_list = query.run(as_dict=True) if sre_list: for sre in sre_list: diff --git a/erpnext/stock/doctype/stock_reservation_entry/test_stock_reservation_entry.py b/erpnext/stock/doctype/stock_reservation_entry/test_stock_reservation_entry.py index 27f43bf66810..9ea35ecacb1f 100644 --- a/erpnext/stock/doctype/stock_reservation_entry/test_stock_reservation_entry.py +++ b/erpnext/stock/doctype/stock_reservation_entry/test_stock_reservation_entry.py @@ -556,7 +556,7 @@ def test_stock_reservation_from_pick_list(self): & (sre.voucher_no == location.sales_order) & (sre.voucher_detail_no == location.sales_order_item) & (sre.from_voucher_type == "Pick List") - & (sre.against_pick_list == pl.name) + & (sre.from_voucher_no == pl.name) & (sre.from_voucher_detail_no == location.name) ) ).run(as_dict=True) diff --git a/erpnext/stock/report/reserved_stock/reserved_stock.js b/erpnext/stock/report/reserved_stock/reserved_stock.js index 2199f52df039..68727411d5a4 100644 --- a/erpnext/stock/report/reserved_stock/reserved_stock.js +++ b/erpnext/stock/report/reserved_stock/reserved_stock.js @@ -91,16 +91,30 @@ frappe.query_reports["Reserved Stock"] = { }, }, { - fieldname: "against_pick_list", - label: __("Against Pick List"), + fieldname: "from_voucher_type", + label: __("From Voucher Type"), fieldtype: "Link", - options: "Pick List", + options: "DocType", + get_query: () => ({ + filters: { + name: ["in", ["Pick List", "Purchase Receipt"]], + } + }), + }, + { + fieldname: "from_voucher_no", + label: __("From Voucher No"), + fieldtype: "Dynamic Link", + options: "from_voucher_type", get_query: () => ({ filters: { docstatus: 1, company: frappe.query_report.get_filter_value("company"), }, }), + get_options: function () { + return frappe.query_report.get_filter_value("from_voucher_type"); + }, }, { fieldname: "reservation_based_on", diff --git a/erpnext/stock/report/reserved_stock/reserved_stock.py b/erpnext/stock/report/reserved_stock/reserved_stock.py index d93ee1c88f8e..21ce203ad6d0 100644 --- a/erpnext/stock/report/reserved_stock/reserved_stock.py +++ b/erpnext/stock/report/reserved_stock/reserved_stock.py @@ -44,7 +44,8 @@ def get_data(filters): (sre.available_qty - sre.reserved_qty).as_("available_qty"), sre.voucher_type, sre.voucher_no, - sre.against_pick_list, + sre.from_voucher_type, + sre.from_voucher_no, sre.name.as_("stock_reservation_entry"), sre.status, sre.project, @@ -65,7 +66,8 @@ def get_data(filters): "warehouse", "voucher_type", "voucher_no", - "against_pick_list", + "from_voucher_type", + "from_voucher_no", "reservation_based_on", "status", "project", @@ -142,7 +144,6 @@ def get_columns(): "fieldname": "voucher_type", "label": _("Voucher Type"), "fieldtype": "Data", - "options": "Warehouse", "width": 110, }, { @@ -153,11 +154,17 @@ def get_columns(): "width": 120, }, { - "fieldname": "against_pick_list", - "label": _("Against Pick List"), - "fieldtype": "Link", - "options": "Pick List", - "width": 130, + "fieldname": "from_voucher_type", + "label": _("From Voucher Type"), + "fieldtype": "Data", + "width": 110, + }, + { + "fieldname": "from_voucher_no", + "label": _("From Voucher No"), + "fieldtype": "Dynamic Link", + "options": "from_voucher_type", + "width": 120, }, { "fieldname": "stock_reservation_entry", From 45395027d3b5c51ac3ccdbebb1f0d23d5ffd2ec1 Mon Sep 17 00:00:00 2001 From: s-aga-r Date: Thu, 19 Oct 2023 19:57:50 +0530 Subject: [PATCH 08/25] fix: incorrect serial and batch get reserved --- .../doctype/sales_order/sales_order.py | 15 +++++++++-- erpnext/stock/doctype/pick_list/pick_list.py | 27 ++++++++++++------- .../purchase_receipt/purchase_receipt.py | 10 +++++-- .../stock_reservation_entry.py | 19 +++++++------ 4 files changed, 47 insertions(+), 24 deletions(-) diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py index d38216242e93..94f9d6e37c4d 100755 --- a/erpnext/selling/doctype/sales_order/sales_order.py +++ b/erpnext/selling/doctype/sales_order/sales_order.py @@ -3,6 +3,7 @@ import json +from typing import Literal import frappe import frappe.utils @@ -534,14 +535,24 @@ def has_unreserved_stock(self) -> bool: return False @frappe.whitelist() - def create_stock_reservation_entries(self, items_details=None, notify=True) -> None: + def create_stock_reservation_entries( + self, + items_details: list[dict] = None, + from_voucher_type: Literal["Pick List", "Purchase Receipt"] = None, + notify=True, + ) -> None: """Creates Stock Reservation Entries for Sales Order Items.""" from erpnext.stock.doctype.stock_reservation_entry.stock_reservation_entry import ( create_stock_reservation_entries_for_so_items as create_stock_reservation_entries, ) - create_stock_reservation_entries(sales_order=self, items_details=items_details, notify=notify) + create_stock_reservation_entries( + sales_order=self, + items_details=items_details, + from_voucher_type=from_voucher_type, + notify=notify, + ) @frappe.whitelist() def cancel_stock_reservation_entries(self, sre_list=None, notify=True) -> None: diff --git a/erpnext/stock/doctype/pick_list/pick_list.py b/erpnext/stock/doctype/pick_list/pick_list.py index 3503556f3ed0..ed2020957749 100644 --- a/erpnext/stock/doctype/pick_list/pick_list.py +++ b/erpnext/stock/doctype/pick_list/pick_list.py @@ -229,20 +229,27 @@ def update_sales_order_picking_status(self) -> None: def create_stock_reservation_entries(self, notify=True) -> None: """Creates Stock Reservation Entries for Sales Order Items against Pick List.""" - from erpnext.stock.doctype.stock_reservation_entry.stock_reservation_entry import ( - create_stock_reservation_entries_for_so_items, - ) - - so_details = {} + so_items_details_map = {} for location in self.locations: if location.warehouse and location.sales_order and location.sales_order_item: - so_details.setdefault(location.sales_order, []).append(location) + item_details = { + "name": location.sales_order_item, + "item_code": location.item_code, + "warehouse": location.warehouse, + "qty_to_reserve": (flt(location.picked_qty) - flt(location.stock_reserved_qty)), + "from_voucher_no": location.parent, + "from_voucher_detail_no": location.name, + "serial_and_batch_bundle": location.serial_and_batch_bundle, + } + so_items_details_map.setdefault(location.sales_order, []).append(item_details) - if so_details: - for so, locations in so_details.items(): + if so_items_details_map: + for so, items_details in so_items_details_map.items(): so_doc = frappe.get_doc("Sales Order", so) - create_stock_reservation_entries_for_so_items( - sales_order=so_doc, items_details=locations, from_voucher_type="Pick List", notify=notify + so_doc.create_stock_reservation_entries( + items_details=items_details, + from_voucher_type="Pick List", + notify=notify, ) @frappe.whitelist() diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py index fc88dd8d5fa1..42d6b02deea2 100644 --- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py @@ -846,14 +846,20 @@ def reserve_stock_for_sales_order(self): "item_code": item.item_code, "warehouse": item.warehouse, "qty_to_reserve": item.stock_qty, - "serial_and_batch_bundle": item.get("serial_and_batch_bundle"), + "from_voucher_no": item.parent, + "from_voucher_detail_no": item.name, + "serial_and_batch_bundle": item.serial_and_batch_bundle, } so_items_details_map.setdefault(item.sales_order, []).append(item_details) if so_items_details_map: for so, items_details in so_items_details_map.items(): so_doc = frappe.get_doc("Sales Order", so) - so_doc.create_stock_reservation_entries(items_details) + so_doc.create_stock_reservation_entries( + items_details=items_details, + from_voucher_type="Purchase Receipt", + notify=True, + ) def update_billed_amount_based_on_po(po_details, update_modified=True): diff --git a/erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.py b/erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.py index 9097e621e60e..e589628c624e 100644 --- a/erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.py +++ b/erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.py @@ -794,22 +794,21 @@ def create_stock_reservation_entries_for_so_items( items = [] if items_details: - item_field = "sales_order_item" if from_voucher_type == "Pick List" else "name" - for item in items_details: - so_item = frappe.get_doc("Sales Order Item", item.get(item_field)) + so_item = frappe.get_doc("Sales Order Item", item.get("name")) so_item.warehouse = item.get("warehouse") so_item.qty_to_reserve = ( - item.get("picked_qty") - item.get("stock_reserved_qty", 0) - if from_voucher_type == "Pick List" - else (flt(item.get("qty_to_reserve")) * flt(so_item.conversion_factor, 1)) + flt(item.get("qty_to_reserve")) + if from_voucher_type in ["Pick List", "Purchase Receipt"] + else ( + flt(item.get("qty_to_reserve")) + * (flt(item.get("conversion_factor")) or flt(so_item.conversion_factor) or 1) + ) ) + so_item.from_voucher_no = item.get("from_voucher_no") + so_item.from_voucher_detail_no = item.get("from_voucher_detail_no") so_item.serial_and_batch_bundle = item.get("serial_and_batch_bundle") - if from_voucher_type == "Pick List": - so_item.from_voucher_no = item.get("parent") - so_item.from_voucher_detail_no = item.get("name") - items.append(so_item) sre_count = 0 From 4f363f5bf3da286999966f10d0cca22264f42199 Mon Sep 17 00:00:00 2001 From: s-aga-r Date: Fri, 20 Oct 2023 11:44:14 +0530 Subject: [PATCH 09/25] fix: partial reservation against SBB --- .../stock_reservation_entry.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.py b/erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.py index e589628c624e..c7a9e16d0ed0 100644 --- a/erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.py +++ b/erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.py @@ -935,20 +935,28 @@ def create_stock_reservation_entries_for_so_items( sre.from_voucher_no = item.from_voucher_no sre.from_voucher_detail_no = item.from_voucher_detail_no - if item.serial_and_batch_bundle: + if item.get("serial_and_batch_bundle"): sbb = frappe.get_doc("Serial and Batch Bundle", item.serial_and_batch_bundle) sre.reservation_based_on = "Serial and Batch" - for entry in sbb.entries: + + index, picked_qty = 0, 0 + while index < len(sbb.entries) and picked_qty < qty_to_be_reserved: + entry = sbb.entries[index] + qty = 1 if has_serial_no else min(abs(entry.qty), qty_to_be_reserved - picked_qty) + sre.append( "sb_entries", { "serial_no": entry.serial_no, "batch_no": entry.batch_no, - "qty": 1 if has_serial_no else abs(entry.qty), + "qty": qty, "warehouse": entry.warehouse, }, ) + index += 1 + picked_qty += qty + sre.save() sre.submit() From ec9434aae3d0ec0cfa6f6c58dcc9db21b677ac8a Mon Sep 17 00:00:00 2001 From: HENRY Florian Date: Mon, 23 Oct 2023 06:45:23 +0200 Subject: [PATCH 10/25] refactor: remove fr translation duplicate in frappe app (#37288) --- erpnext/translations/fr.csv | 412 +----------------------------------- 1 file changed, 4 insertions(+), 408 deletions(-) diff --git a/erpnext/translations/fr.csv b/erpnext/translations/fr.csv index 32fe9fffa03b..d3875c113244 100644 --- a/erpnext/translations/fr.csv +++ b/erpnext/translations/fr.csv @@ -21,9 +21,6 @@ A Lead requires either a person's name or an organization's name,Un responsable A customer with the same name already exists,Un client avec un nom identique existe déjà, A question must have more than one options,Une question doit avoir plus d'une option, A qustion must have at least one correct options,Une qustion doit avoir au moins une des options correctes, -A4,A4, -API Endpoint,API Endpoint, -API Key,Clé API, Abbr can not be blank or space,Abré. ne peut être vide ou contenir un espace, Abbreviation already used for another company,Abréviation déjà utilisée pour une autre société, Abbreviation cannot have more than 5 characters,L'abbréviation ne peut pas avoir plus de 5 caractères, @@ -36,9 +33,7 @@ Academic Term: ,Période scolaire:, Academic Year,Année académique, Academic Year: ,Année scolaire:, Accepted + Rejected Qty must be equal to Received quantity for Item {0},La Qté Acceptée + Rejetée doit être égale à la quantité Reçue pour l'Article {0}, -Access Token,Jeton d'Accès, Accessable Value,Valeur accessible, -Account,Compte, Account Number,Numéro de compte, Account Number {0} already used in account {1},Numéro de compte {0} déjà utilisé dans le compte {1}, Account Pay Only,Compte Bénéficiaire Seulement, @@ -75,12 +70,10 @@ Accounting Entry for {0}: {1} can only be made in currency: {2},Écriture Compta Accounting Ledger,Livre des Comptes, Accounting journal entries.,Les écritures comptables., Accounts,Comptes, -Accounts Manager,Responsable des Comptes, Accounts Payable,Comptes Créditeurs, Accounts Payable Summary,Résumé des Comptes Créditeurs, Accounts Receivable,Comptes débiteurs, Accounts Receivable Summary,Résumé des Comptes Débiteurs, -Accounts User,Comptable, Accounts table cannot be blank.,Le tableau de comptes ne peut être vide., Accumulated Depreciation,Amortissement Cumulé, Accumulated Depreciation Amount,Montant d'Amortissement Cumulé, @@ -89,10 +82,8 @@ Accumulated Monthly,Cumul mensuel, Accumulated Values,Valeurs accumulées, Accumulated Values in Group Company,Valeurs accumulées dans la société mère, Achieved ({}),Atteint ({}), -Action,Action, Action Initialised,Action initialisée, Actions,Actions, -Active,actif, Activity Cost exists for Employee {0} against Activity Type - {1},Des Coûts d'Activité existent pour l'Employé {0} pour le Type d'Activité - {1}, Activity Cost per Employee,Coût de l'Activité par Employé, Activity Type,Type d'activité, @@ -104,7 +95,6 @@ Actual Qty {0} / Waiting Qty {1},Qté Réelle {0} / Quantité en Attente {1}, Actual Qty: Quantity available in the warehouse.,Quantité réelle : Quantité disponible dans l'entrepôt ., Actual qty in stock,Qté réelle en stock, Actual type tax cannot be included in Item rate in row {0},Le type de taxe réel ne peut pas être inclus dans le prix de l'Article à la ligne {0}, -Add,Ajouter, Add / Edit Prices,Ajouter / Modifier Prix, Add Comment,Ajouter un Commentaire, Add Customers,Ajouter des clients, @@ -127,17 +117,11 @@ Add more items or open full form,Ajouter plus d'articles ou ouvrir le formulaire Add notes,Ajouter des notes, Add the rest of your organization as your users. You can also add invite Customers to your portal by adding them from Contacts,Ajouter le reste de votre organisation en tant qu'utilisateurs. Vous pouvez aussi inviter des Clients sur votre portail en les ajoutant depuis les Contacts, Add/Remove Recipients,Ajouter/Supprimer des Destinataires, -Added,Ajouté, Added {0} users,{0} utilisateurs ajoutés, Additional Salary Component Exists.,La composante salariale supplémentaire existe., -Address,Adresse, -Address Line 2,Adresse Ligne 2, Address Name,Nom de l'Adresse, -Address Title,Titre de l'Adresse, -Address Type,Type d'Adresse, Administrative Expenses,Charges Administratives, Administrative Officer,Agent administratif, -Administrator,Administrateur, Admission,Admission, Admission and Enrollment,Admission et inscription, Admissions for {0},Admissions pour {0}, @@ -171,7 +155,6 @@ All Assessment Groups,Tous les Groupes d'Évaluation, All BOMs,Toutes les nomenclatures, All Contacts.,Tous les contacts., All Customer Groups,Tous les Groupes Client, -All Day,Toute la Journée, All Departments,Tous les départements, All Healthcare Service Units,Tous les services de soins de santé, All Item Groups,Tous les Groupes d'Articles, @@ -193,8 +176,6 @@ Already record exists for the item {0},L'enregistrement existe déjà pour l'art "Already set default in pos profile {0} for user {1}, kindly disabled default","Déjà défini par défaut dans le profil pdv {0} pour l'utilisateur {1}, veuillez désactiver la valeur par défaut", Alternate Item,Article alternatif, Alternative item must not be same as item code,L'article alternatif ne doit pas être le même que le code article, -Amended From,Modifié Depuis, -Amount,Montant, Amount After Depreciation,Montant après amortissement, Amount of Integrated Tax,Montant de la taxe intégrée, Amount of TDS Deducted,Quantité de TDS déduite, @@ -216,7 +197,6 @@ Another Period Closing Entry {0} has been made after {1},Une autre Entrée de Cl Another Sales Person {0} exists with the same Employee id,Un autre Commercial {0} existe avec le même ID d'Employé, Antibiotic,Antibiotique, Apparel & Accessories,Vêtements & Accessoires, -Applicable For,Applicable Pour, "Applicable if the company is SpA, SApA or SRL","Applicable si la société est SpA, SApA ou SRL", Applicable if the company is a limited liability company,Applicable si la société est une société à responsabilité limitée, Applicable if the company is an Individual or a Proprietorship,Applicable si la société est un particulier ou une entreprise, @@ -264,15 +244,12 @@ Asset scrapped via Journal Entry {0},Actif mis au rebut via Écriture de Journal Asset {0} does not belong to company {1},L'actif {0} ne fait pas partie à la société {1}, Asset {0} must be submitted,L'actif {0} doit être soumis, Assets,Actifs - Immo., -Assign To,Attribuer À, Associate,Associé, At least one mode of payment is required for POS invoice.,Au moins un mode de paiement est nécessaire pour une facture de PDV, Atleast one item should be entered with negative quantity in return document,Au moins un article doit être saisi avec quantité négative dans le document de retour, Atleast one of the Selling or Buying must be selected,Au moins Vente ou Achat doit être sélectionné, Atleast one warehouse is mandatory,Au moins un entrepôt est obligatoire, Attach Logo,Attacher le logo, -Attachment,Pièce jointe, -Attachments,Pièces jointes, Attendance can not be marked for future dates,La présence ne peut pas être marquée pour les dates à venir, Attendance date can not be less than employee's joining date,Date de présence ne peut pas être antérieure à la date d'embauche de l'employé, Attendance for employee {0} is already marked,La présence de l'employé {0} est déjà marquée, @@ -282,7 +259,6 @@ Attribute table is mandatory,Table d'Attribut est obligatoire, Attribute {0} selected multiple times in Attributes Table,Attribut {0} sélectionné à plusieurs reprises dans le Tableau des Attributs, Authorized Signatory,Signataire Autorisé, Auto Material Requests Generated,Demandes de Matériel Générées Automatiquement, -Auto Repeat,Répétition automatique, Auto repeat document updated,Document de répétition automatique mis à jour, Automotive,Automobile, Available,Disponible, @@ -332,8 +308,6 @@ Banking,Banque, Banking and Payments,Banque et paiements, Barcode {0} already used in Item {1},Le Code Barre {0} est déjà utilisé dans l'article {1}, Barcode {0} is not a valid {1} code,Le code-barres {0} n'est pas un code {1} valide, -Base URL,URL de base, -Based On,Basé Sur, Based On Payment Terms,Basé sur les conditions de paiement, Batch,Lot, Batch Entries,Entrées de lot, @@ -406,7 +380,6 @@ Can only make payment against unbilled {0},Le paiement n'est possible qu'avec le Can refer row only if the charge type is 'On Previous Row Amount' or 'Previous Row Total',Peut se référer à ligne seulement si le type de charge est 'Montant de la ligne précedente' ou 'Total des lignes précedente', "Can't change valuation method, as there are transactions against some items which does not have it's own valuation method","Impossible de modifier la méthode de valorisation, car il existe des transactions sur certains articles ne possèdant pas leur propre méthode de valorisation", Can't create standard criteria. Please rename the criteria,Impossible de créer des critères standard. Veuillez renommer les critères, -Cancel,Annuler, Cancel Material Visit {0} before cancelling this Warranty Claim,Annuler la Visite Matérielle {0} avant d'annuler cette Réclamation de Garantie, Cancel Material Visits {0} before cancelling this Maintenance Visit,Annuler les Visites Matérielles {0} avant d'annuler cette Visite de Maintenance, Cancel Subscription,Annuler l'abonnement, @@ -459,8 +432,6 @@ Cash Flow from Operations,Flux de trésorerie provenant des opérations, Cash In Hand,Liquidités, Cash or Bank Account is mandatory for making payment entry,Espèces ou Compte Bancaire est obligatoire pour réaliser une écriture de paiement, Cashier Closing,Fermeture de la caisse, -Category,Catégorie, -Category Name,Nom de la Catégorie, Caution,Mise en garde, Central Tax,Taxe centrale, Certification,Certification, @@ -488,32 +459,22 @@ Child Task exists for this Task. You can not delete this Task.,Une tâche enfant Child nodes can be only created under 'Group' type nodes,Les noeuds enfants peuvent être créés uniquement dans les nœuds de type 'Groupe', Child warehouse exists for this warehouse. You can not delete this warehouse.,Un entrepôt enfant existe pour cet entrepôt. Vous ne pouvez pas supprimer cet entrepôt., Circular Reference Error,Erreur de référence circulaire, -City,Ville, -City/Town,Ville, Clay,Argile, -Clear filters,Effacer les filtres, Clear values,Des valeurs claires, Clearance Date,Date de Compensation, Clearance Date not mentioned,Date de Compensation non indiquée, Clearance Date updated,Date de Compensation mise à jour, -Client,Client, -Client ID,ID Client, -Client Secret,Secret Client, Clinical Procedure,Procédure clinique, Clinical Procedure Template,Modèle de procédure clinique, Close Balance Sheet and book Profit or Loss.,Clôturer Bilan et Compte de Résultats., Close Loan,Prêt proche, Close the POS,Clôturer le point de vente, -Closed,Fermé, Closed order cannot be cancelled. Unclose to cancel.,Les commandes fermées ne peuvent être annulées. Réouvrir pour annuler., Closing (Cr),Fermeture (Cr), Closing (Dr),Fermeture (Dr), Closing (Opening + Total),Fermeture (ouverture + total), Closing Account {0} must be of type Liability / Equity,Le Compte Clôturé {0} doit être de type Passif / Capitaux Propres, Closing Balance,Solde de clôture, -Code,Code, -Collapse All,Tout réduire, -Color,Couleur, Colour,Couleur, Combined invoice portion must equal 100%,La portion combinée de la facture doit être égale à 100%, Commercial,Commercial, @@ -525,7 +486,6 @@ Community Forum,Forum de la communauté, Company (not Customer or Supplier) master.,Données de base de la Société (ni les Clients ni les Fournisseurs), Company Abbreviation,Abréviation de la Société, Company Abbreviation cannot have more than 5 characters,L'abréviation de l'entreprise ne peut pas comporter plus de 5 caractères, -Company Name,Nom de la Société, Company Name cannot be Company,Nom de la Société ne peut pas être Company, Company currencies of both the companies should match for Inter Company Transactions.,Les devises des deux sociétés doivent correspondre pour les transactions inter-sociétés., Company is manadatory for company account,La société est le maître d'œuvre du compte d'entreprise, @@ -535,7 +495,6 @@ Compensatory leave request days not in valid holidays,Les jours de la demande de Complaint,Plainte, Completion Date,Date d'Achèvement, Computer,Ordinateur, -Condition,Conditions, Configure,Configurer, Configure {0},Configurer {0}, Confirmed orders from Customers.,Commandes confirmées des clients., @@ -552,11 +511,8 @@ Consumed,Consommé, Consumed Amount,Montant Consommé, Consumed Qty,Qté Consommée, Consumer Products,Produits de Consommation, -Contact,Contact, Contact Us,Contactez nous, -Content,Contenu, Content Masters,Masters de contenu, -Content Type,Type de Contenu, Continue Configuration,Continuer la configuration, Contract,Contrat, Contract End Date must be greater than Date of Joining,La Date de Fin de Contrat doit être supérieure à la Date d'Embauche, @@ -597,7 +553,6 @@ Course Enrollment {0} does not exists,L'inscription au cours {0} n'existe pas, Course Schedule,Horaire du cours, Course: ,Cours:, Cr,Cr, -Create,Créer, Create BOM,Créer une nomenclature, Create Delivery Trip,Créer un voyage de livraison, Create Employee,Créer un employé, @@ -673,8 +628,6 @@ Current BOM and New BOM can not be same,La nomenclature actuelle et la nouvelle Current Liabilities,Dettes Actuelles, Current Qty,Qté actuelle, Current invoice {0} is missing,La facture en cours {0} est manquante, -Custom HTML,HTML Personnalisé, -Custom?,Personnaliser ?, Customer,Client, Customer Addresses And Contacts,Adresses et Contacts des Clients, Customer Contact,Contact client, @@ -699,7 +652,6 @@ Daily Reminders,Rappels quotidiens, Data Import and Export,Importer et Exporter des Données, Data Import and Settings,Importation de données et paramètres, Database of potential customers.,Base de données de clients potentiels., -Date Format,Format de Date, Date Of Retirement must be greater than Date of Joining,La Date de Départ à la Retraite doit être supérieure à Date d'Embauche, Date of Birth,Date de naissance, Date of Birth cannot be greater than today.,Date de Naissance ne peut être après la Date du Jour., @@ -707,7 +659,6 @@ Date of Commencement should be greater than Date of Incorporation,La date de dé Date of Joining,Date d'Embauche, Date of Joining must be greater than Date of Birth,La Date d'Embauche doit être après à la Date de Naissance, Date of Transaction,Date de transaction, -Day,Jour, Debit,Débit, Debit ({0}),Débit ({0}), Debit Account,Compte de débit, @@ -723,14 +674,12 @@ Default Activity Cost exists for Activity Type - {0},Un Coût d’Activité par Default BOM ({0}) must be active for this item or its template,Nomenclature par défaut ({0}) doit être actif pour ce produit ou son modèle, Default BOM for {0} not found,Nomenclature par défaut {0} introuvable, Default BOM not found for Item {0} and Project {1},La nomenclature par défaut n'a pas été trouvée pour l'Article {0} et le Projet {1}, -Default Letter Head,En-Tête de Courrier par Défaut, Default Tax Template,Modèle de Taxes par Défaut, Default Unit of Measure for Item {0} cannot be changed directly because you have already made some transaction(s) with another UOM. You will need to create a new Item to use a different Default UOM.,L’Unité de Mesure par Défaut pour l’Article {0} ne peut pas être modifiée directement parce que vous avez déjà fait une (des) transaction (s) avec une autre unité de mesure. Vous devez créer un nouvel article pour utiliser une UdM par défaut différente., Default Unit of Measure for Variant '{0}' must be same as in Template '{1}',L’Unité de mesure par défaut pour la variante '{0}' doit être la même que dans le Modèle '{1}', Default settings for buying transactions.,Paramètres par défaut pour les transactions d'achat., Default settings for selling transactions.,Paramètres par défaut pour les transactions de vente., Default tax templates for sales and purchase are created.,Les modèles de taxe par défaut pour les ventes et les achats sont créés., -Defaults,Valeurs Par Défaut, Defense,Défense, Define Project type.,Définir le type de projet., Define budget for a financial year.,Définir le budget pour un exercice., @@ -750,10 +699,8 @@ Delivery Note {0} is not submitted,Bon de Livraison {0} n'est pas soumis, Delivery Note {0} must not be submitted,Bon de Livraison {0} ne doit pas être soumis, Delivery Notes {0} must be cancelled before cancelling this Sales Order,Bons de Livraison {0} doivent être annulés avant d’annuler cette Commande Client, Delivery Notes {0} updated,Notes de livraison {0} mises à jour, -Delivery Status,Statut de la Livraison, Delivery Trip,Service de Livraison, Delivery warehouse required for stock item {0},Entrepôt de Livraison requis pour article du stock {0}, -Department,Département, Department Stores,Grands magasins, Depreciation,Amortissement, Depreciation Amount,Montant d'Amortissement, @@ -768,7 +715,6 @@ Depreciation Row {0}: Next Depreciation Date cannot be before Available-for-use Depreciation Row {0}: Next Depreciation Date cannot be before Purchase Date,Ligne d'amortissement {0}: la date d'amortissement suivante ne peut pas être antérieure à la date d'achat, Designer,Designer, Detailed Reason,Raison détaillée, -Details,Détails, Details of Outward Supplies and inward supplies liable to reverse charge,Détails des livraisons sortantes et des livraisons entrantes susceptibles d'inverser la charge, Details of the operations carried out.,Détails des opérations effectuées., Diagnosis,Diagnostique, @@ -805,16 +751,11 @@ Doc Date,Date du document, Doc Name,Nom du document, Doc Type,Type de document, Docs Search,Recherche de documents, -Document Name,Nom du Document, -Document Type,Type de Document, -Domain,Domaine, -Domains,Domaines, Done,Terminé, Donor,Donneur, Donor Type information.,Informations sur le type de donneur., Donor information.,Informations sur le donneur, Download JSON,Télécharger JSON, -Draft,Brouillon, Drop Ship,Expédition Directe, Drug,Médicament, Due / Reference Date cannot be after {0},Date d’échéance / de référence ne peut pas être après le {0}, @@ -835,7 +776,6 @@ ERPNext Demo,Démo ERPNext, ERPNext Settings,Paramètres ERPNext, Earliest,Au plus tôt, Earnest Money,Arrhes, -Edit,modifier, Edit Publishing Details,Modifier les détails de publication, "Edit in full page for more options like assets, serial nos, batches etc.","Modifier en pleine page pour plus d'options comme les actifs, les numéros de série, les lots, etc.", Education,Éducation, @@ -846,13 +786,9 @@ Electrical,Électrique, Electronic Equipments,Équipements électroniques, Electronics,Électronique, Eligible ITC,CTI éligible, -Email Account,Compte Email, -Email Address,Adresse électronique, "Email Address must be unique, already exists for {0}","Adresse Email doit être unique, existe déjà pour {0}", Email Digest: ,Compte Rendu par Email :, Email Reminders will be sent to all parties with email contacts,Les rappels par emails seront envoyés à toutes les parties avec des contacts ayant une adresse email, -Email Sent,Email Envoyé, -Email Template,Modèle d'email, Email not found in default contact,Email non trouvé dans le contact par défaut, Email sent to {0},Email envoyé à {0}, Employee,Employé, @@ -866,9 +802,7 @@ Employee cannot report to himself.,L'employé ne peut pas rendre de compte à lu Employee {0} has already applied for {1} between {2} and {3} : ,L'employé {0} a déjà postulé pour {1} entre {2} et {3}:, Employee {0} of grade {1} have no default leave policy,L'employé {0} avec l'échelon {1} n'a pas de politique de congé par défaut, Enable / disable currencies.,Activer / Désactiver les devises, -Enabled,Activé, "Enabling 'Use for Shopping Cart', as Shopping Cart is enabled and there should be at least one Tax Rule for Shopping Cart","Activation de 'Utiliser pour Panier', comme le Panier est activé et qu'il devrait y avoir au moins une Règle de Taxes pour le Panier", -End Date,Date de Fin, End Date can not be less than Start Date,La date de fin ne peut être inférieure à la date de début, End Date cannot be before Start Date.,La date de fin ne peut pas être antérieure à la date de début., End Year,Année de Fin, @@ -889,7 +823,6 @@ Enter value betweeen {0} and {1},Entrez une valeur entre {0} et {1}, Entertainment & Leisure,Divertissement et Loisir, Entertainment Expenses,Charges de Représentation, Equity,Capitaux Propres, -Error Log,Journal des Erreurs, Error evaluating the criteria formula,Erreur lors de l'évaluation de la formule du critère, Error in formula or condition: {0},Erreur dans la formule ou dans la condition : {0}, Error: Not a valid id?,Erreur : Pas un identifiant valide ?, @@ -901,7 +834,6 @@ Exchange Rate must be same as {0} {1} ({2}),Taux de Change doit être le même q Excise Invoice,Facture d'Accise, Execution,Exécution, Executive Search,Recrutement de Cadres, -Expand All,Développer Tout, Expected Delivery Date,Date de livraison prévue, Expected Delivery Date should be after Sales Order Date,La Date de Livraison Prévue doit être après la Date indiquée sur la Commande Client, Expected End Date,Date de fin prévue, @@ -924,30 +856,22 @@ Explore,Explorer, Export E-Invoices,Exporter des factures électroniques, Extra Large,Extra large, Extra Small,Très Petit, -Fail,Échec, -Failed,Échoué, Failed to create website,Échec de la création du site Web, Failed to install presets,Échec de l'installation des préréglages, Failed to login,Échec de la connexion, Failed to setup company,Échec de la configuration de la société, Failed to setup defaults,Échec de la configuration par défaut, Failed to setup post company fixtures,Échec de la configuration des éléments liés la société, -Fax,Fax, Fee,Frais, Fee Created,Honoraires Créés, Fee Creation Failed,La création des honoraires a échoué, Fee Creation Pending,Création d'honoraires en attente, Fee Records Created - {0},Archive d'Honoraires Créée - {0}, -Feedback,Retour d’Expérience, Fees,Honoraires, -Female,Féminin, Fetch Data,Récupérer des données, Fetch Subscription Updates,Vérifier les mises à jour des abonnements, Fetch exploded BOM (including sub-assemblies),Récupérer la nomenclature éclatée (y compris les sous-ensembles), Fetching records......,Récupération des enregistrements ......, -Field Name,Nom du Champ, -Fieldname,Nom du Champ, -Fields,Champ, "Filter Fields Row #{0}: Fieldname {1} must be of type ""Link"" or ""Table MultiSelect""",Filtrer les champs Ligne # {0}: le nom de champ {1} doit être de type "Lien" ou "Table MultiSelect", Filter Total Zero Qty,Filtrer les totaux pour les qtés égales à zéro, Finance Book,Livre comptable, @@ -961,7 +885,6 @@ Finished Good Item Code,Code d'article fini, Finished Goods,Produits finis, Finished Item {0} must be entered for Manufacture type entry,Le Produit Fini {0} doit être saisi pour une écriture de type Production, Finished product quantity {0} and For Quantity {1} cannot be different,La quantité de produit fini {0} et Pour la quantité {1} ne peut pas être différente, -First Name,Prénom, "Fiscal Regime is mandatory, kindly set the fiscal regime in the company {0}","Le régime fiscal est obligatoire, veuillez définir le régime fiscal de l'entreprise {0}", Fiscal Year,Exercice fiscal, Fiscal Year End Date should be one year after Fiscal Year Start Date,La date de fin d'exercice doit être un an après la date de début d'exercice, @@ -994,9 +917,6 @@ For row {0}: Enter Planned Qty,Pour la ligne {0}: entrez la quantité planifiée Forum Activity,Activité du forum, Free item code is not selected,Le code d'article gratuit n'est pas sélectionné, Freight and Forwarding Charges,Frais de Fret et d'Expédition, -Frequency,Fréquence, -Friday,Vendredi, -From,À partir de, From Address 1,Ligne d'addresse 1 (Origine), From Address 2,Ligne d'addresse 2 (Origine), From Currency and To Currency cannot be same,La Devise de Base et la Devise de Cotation ne peuvent pas identiques, @@ -1021,18 +941,15 @@ From and To dates required,Les date Du et Au sont requises, From value must be less than to value in row {0},De la valeur doit être inférieure à la valeur de la ligne {0}, From {0} | {1} {2},Du {0} | {1} {2}, Fulfillment,Livraison, -Full Name,Nom Complet, Fully Depreciated,Complètement Déprécié, Furnitures and Fixtures,Meubles et Accessoires, "Further accounts can be made under Groups, but entries can be made against non-Groups","D'autres comptes individuels peuvent être créés dans les groupes, mais les écritures ne peuvent être faites que sur les comptes individuels", Further cost centers can be made under Groups but entries can be made against non-Groups,"D'autres centres de coûts peuvent être créés dans des Groupes, mais des écritures ne peuvent être faites que sur des centres de coûts individuels.", -Further nodes can be only created under 'Group' type nodes,D'autres nœuds peuvent être créés uniquement sous les nœuds de type 'Groupe', GSTIN,GSTIN, GSTR3B-Form,GSTR3B-Form, Gain/Loss on Asset Disposal,Gain/Perte sur Cessions des Immobilisations, Gantt Chart,Diagramme de Gantt, Gantt chart of all tasks.,Diagramme de Gantt de toutes les tâches., -Gender,Sexe, General,Général, General Ledger,Grand Livre, Generate Material Requests (MRP) and Work Orders.,Générer des demandes de matériel (MRP) et des ordres de travail., @@ -1050,7 +967,6 @@ Get Updates,Obtenir les mises à jour, Get customers from,Obtenir les clients de, Get from Patient Encounter,Obtenez de la rencontre du patient, Getting Started,Commencer, -GitHub Sync ID,GitHub Sync ID, Global settings for all manufacturing processes.,Paramètres globaux pour tous les processus de production., Go to the Desktop and start using ERPNext,Accédez au bureau et commencez à utiliser ERPNext, GoCardless SEPA Mandate,Mandat SEPA GoCardless, @@ -1090,8 +1006,6 @@ Guardian2 Name,Nom du Tuteur 2, HR Manager,Responsable RH, HSN,HSN, HSN/SAC,HSN / SAC, -Half Yearly,Semestriel, -Half-Yearly,Semestriel, Hardware,Matériel, Head of Marketing and Sales,Responsable du Marketing et des Ventes, Health Care,Soins de santé, @@ -1106,7 +1020,6 @@ Healthcare Service Unit Type,Type d'unité de service de soins de santé, Healthcare Services,Services de santé, Healthcare Settings,Paramètres de santé, Help Results for,Aide Résultats pour, -High,Haut, High Sensitivity,Haute sensibilité, Hold,Mettre en attente, Hold Invoice,Facture en attente, @@ -1114,15 +1027,12 @@ Holiday,Vacances, Holiday List,Liste de vacances, Hotel Rooms of type {0} are unavailable on {1},Les chambres d'hôtel de type {0} sont indisponibles le {1}, Hotels,Hôtels, -Hourly,Horaire, Hours,Heures, How Pricing Rule is applied?,Comment la Règle de Prix doit-elle être appliquée ?, Hub Category,Catégorie du Hub, -Hub Sync ID,Hub Sync ID, Human Resource,Ressource humaine, Human Resources,Ressources humaines, IGST Amount,IGST Montant, -IP Address,Adresse IP, ITC Available (whether in full op part),CIT Disponible (que ce soit en partie op), ITC Reversed,CTI inversé, Identifying Decision Makers,Identifier les décideurs, @@ -1133,11 +1043,7 @@ Identifying Decision Makers,Identifier les décideurs, "If unlimited expiry for the Loyalty Points, keep the Expiry Duration empty or 0.","Si vous souhaitez ne pas mettre de date d'expiration pour les points de fidélité, laissez la durée d'expiration vide ou mettez 0.", "If you have any questions, please get back to us.","Si vous avez des questions, veuillez revenir vers nous.", Ignore Existing Ordered Qty,Ignorer la quantité commandée existante, -Image,Image, -Image View,Voir l'Image, -Import Data,Importer des données, Import Day Book Data,Données du journal d'importation, -Import Log,Journal d'import, Import Master Data,Importer des données de base, Import in Bulk,Importer en Masse, Import of goods,Importation de marchandises, @@ -1151,7 +1057,6 @@ In Stock Qty,Qté En Stock, In Stock: ,En Stock :, In Value,En valeur, "In the case of multi-tier program, Customers will be auto assigned to the concerned tier as per their spent","Dans le cas d'un programme à plusieurs échelons, les clients seront automatiquement affectés au niveau approprié en fonction de leurs dépenses", -Inactive,Inactif, Incentives,Incitations, Include Default Book Entries,Inclure les entrées de livre par défaut, Include Exploded Items,Inclure les articles éclatés, @@ -1185,7 +1090,6 @@ Integrated Tax,Taxe intégrée, Inter-State Supplies,Fournitures inter-Etats, Internet Publishing,Publication Internet, Intra-State Supplies,Fournitures intra-étatiques, -Introduction,Introduction, Invalid Attribute,Attribut invalide, Invalid Blanket Order for the selected Customer and Item,Commande avec limites non valide pour le client et l'article sélectionnés, Invalid Company for Inter Company Transaction.,Société non valide pour une transaction inter-sociétés., @@ -1217,8 +1121,6 @@ Invoices,Factures, Invoices for Costumers.,Factures pour les clients., Inward supplies from ISD,Approvisionnement entrant de la DSI, Inward supplies liable to reverse charge (other than 1 & 2 above),Approvisionnements entrants susceptibles d’être dédouanés (autres que 1 et 2 ci-dessus), -Is Active,Est Active, -Is Default,Est Défaut, Is Existing Asset,Est Actif Existant, Is Frozen,Est gelé, Is Group,Est un Groupe, @@ -1288,7 +1190,6 @@ Join,Joindre, Journal Entries {0} are un-linked,Les Écritures de Journal {0} ne sont pas liées, Journal Entry,Écriture de Journal, Journal Entry {0} does not have account {1} or already matched against other voucher,L’Écriture de Journal {0} n'a pas le compte {1} ou est déjà réconciliée avec une autre pièce justificative, -Kanban Board,Tableau Kanban, Key Reports,Rapports clés, LMS Activity,Activité LMS, Lab Test,Test de laboratoire, @@ -1299,12 +1200,10 @@ Lab Test UOM,UdM de test de laboratoire, Lab Tests and Vital Signs,Tests de laboratoire et signes vitaux, Lab result datetime cannot be before testing datetime,La date et l'heure du résultat de laboratoire ne peuvent pas être avant la date et l'heure du test, Lab testing datetime cannot be before collection datetime,La date et l'heure du test de laboratoire ne peuvent pas être avant la date et l'heure de collecte, -Label,Étiquette, Laboratory,Laboratoire, Large,Grand, Last Communication,Dernière communication, Last Communication Date,Date de la Dernière Communication, -Last Name,Nom de Famille, Last Order Amount,Montant de la Dernière Commande, Last Order Date,Date de la dernière commande, Last Purchase Price,Dernier prix d'achat, @@ -1326,9 +1225,7 @@ Leaves must be allocated in multiples of 0.5,"Les Congés doivent être alloués Ledger,Livre, Legal,Juridique, Legal Expenses,Frais juridiques, -Letter Head,En-Tête, Letter Heads for print templates.,En-Têtes pour les modèles d'impression., -Level,Niveau, Liability,Passif, Limit Crossed,Limite Dépassée, Link to Material Request,Lien vers la demande de matériel, @@ -1343,7 +1240,6 @@ Local,Locale, Logs for maintaining sms delivery status,Journaux pour maintenir le statut de livraison des sms, Lost,Perdu, Lost Reasons,Raisons perdues, -Low,Bas, Low Sensitivity,Faible sensibilité, Lower Income,Revenu bas, Loyalty Amount,Montant de fidélité, @@ -1355,13 +1251,11 @@ Loyalty Program,Programme de fidélité, Main,Principal, Maintenance,Entretien, Maintenance Log,Journal de maintenance, -Maintenance Manager,Responsable de Maintenance, Maintenance Schedule,Échéancier d'Entretien, Maintenance Schedule is not generated for all the items. Please click on 'Generate Schedule',L'Échéancier d'Entretien n'est pas créé pour tous les articles. Veuillez clicker sur 'Créer un Échéancier', Maintenance Schedule {0} exists against {1},Un Calendrier de Maintenance {0} existe pour {1}, Maintenance Schedule {0} must be cancelled before cancelling this Sales Order,L'Échéancier d'Entretien {0} doit être annulé avant d'annuler cette Commande Client, Maintenance Status has to be Cancelled or Completed to Submit,Le statut de maintenance doit être annulé ou complété pour pouvoir être envoyé, -Maintenance User,Maintenance Utilisateur, Maintenance Visit,Visite d'Entretien, Maintenance Visit {0} must be cancelled before cancelling this Sales Order,La Visite d'Entretien {0} doit être annulée avant d'annuler cette Commande Client, Maintenance start date can not be before delivery date for Serial No {0},La date de début d'entretien ne peut pas être antérieure à la date de livraison pour le N° de Série {0}, @@ -1369,7 +1263,6 @@ Make,Faire, Make Payment,Faire un Paiement, Make project from a template.,Faire un projet à partir d'un modèle., Making Stock Entries,Faire des Écritures de Stock, -Male,Masculin, Manage Customer Group Tree.,Gérer l'Arborescence des Groupes de Clients., Manage Sales Partners.,Gérer les Partenaires Commerciaux., Manage Sales Person Tree.,Gérer l'Arborescence des Vendeurs., @@ -1379,7 +1272,6 @@ Management,Gestion, Manager,Directeur, Managing Projects,Gestion de Projets, Managing Subcontracting,Gestion de la Sous-traitance, -Mandatory,Obligatoire, Mandatory field - Academic Year,Champ Obligatoire - Année Académique, Mandatory field - Get Students From,Champ Obligatoire - Obtenir des étudiants de, Mandatory field - Program,Champ obligatoire - Programme, @@ -1388,8 +1280,6 @@ Manufacturer,Fabricant, Manufacturer Part Number,Numéro de Pièce du Fabricant, Manufacturing,Production, Manufacturing Quantity is mandatory,Quantité de production obligatoire, -Mapping,Mapping, -Mapping Type,Type de Mapping, Mark Absent,Marquer Absent, Mark Half Day,Marquer Demi-Journée, Mark Present,Marquer Présent, @@ -1424,7 +1314,6 @@ Medical Code,Code médical, Medical Code Standard,Standard du code médical, Medical Department,Département médical, Medical Record,Dossier médical, -Medium,Moyen, Member Activity,Activité des membres, Member ID,ID du membre, Member Name,Nom de membre, @@ -1439,12 +1328,8 @@ Merge,Fusionner, Merge Account,Fusionner le compte, Merge with Existing Account,Fusionner avec un compte existant, "Merging is only possible if following properties are same in both records. Is Group, Root Type, Company","La combinaison est possible seulement si les propriétés suivantes sont les mêmes dans les deux dossiers. Est Groupe, Type de Racine, Société", -Message Examples,Exemples de Messages, Message Sent,Message envoyé, -Method,Méthode, Middle Income,Revenu Intermédiaire, -Middle Name,Deuxième Nom, -Middle Name (Optional),Deuxième Prénom (Optionnel), Min Amt can not be greater than Max Amt,Min Amt ne peut pas être supérieur à Max Amt, Min Qty can not be greater than Max Qty,Qté Min ne peut pas être supérieure à Qté Max, Minimum Lead Age (Days),Âge Minimum du lead (Jours), @@ -1458,14 +1343,9 @@ Mode of Transport,Mode de transport, Mode of Transportation,Mode de transport, Model,Modèle, Moderate Sensitivity,Sensibilité modérée, -Monday,Lundi, -Monthly,Mensuel, Monthly Distribution,Répartition Mensuelle, -More,Plus, -More Information,Informations Complémentaires, More...,Plus..., Motion Picture & Video,Cinéma & Vidéo, -Move,mouvement, Move Item,Déplacer l'Article, Multi Currency,Multi-devise, Multiple Item prices.,Plusieurs Prix d'Articles., @@ -1497,7 +1377,6 @@ Net ITC Available(A) - (B),CTI net disponible (A) - (B), Net Profit,Bénéfice net, Net Total,Total net, New Account Name,Nouveau Nom de Compte, -New Address,Nouvelle adresse, New BOM,Nouvelle nomenclature, New Batch ID (Optional),Nouveau Numéro de Lot (Optionnel), New Batch Qty,Nouvelle Qté de Lot, @@ -1517,13 +1396,11 @@ New credit limit is less than current outstanding amount for the customer. Credi New task,Nouvelle tâche, New {0} pricing rules are created,De nouvelles règles de tarification {0} sont créées., Newspaper Publishers,Éditeurs de journaux, -Next,Suivant, Next Contact By cannot be same as the Lead Email Address,Prochain Contact Par ne peut être identique à l’Adresse Email du Lead, Next Contact Date cannot be in the past,La Date de Prochain Contact ne peut pas être dans le passé, Next Steps,Prochaines étapes, No Action,Pas d'action, No Customers yet!,Pas encore de clients!, -No Data,Aucune Donnée, No Delivery Note selected for Customer {},Aucun bon de livraison sélectionné pour le client {}, No Item with Barcode {0},Aucun Article avec le Code Barre {0}, No Item with Serial No {0},Aucun Article avec le N° de Série {0}, @@ -1565,15 +1442,12 @@ Non Profit,À But Non Lucratif, Non Profit (beta),Association (bêta), Non-GST outward supplies,Fournitures sortantes non liées à la TPS, Non-Group to Group,Non-Groupe à Groupe, -None,Aucun, None of the items have any change in quantity or value.,Aucun des Articles n’a de changement en quantité ou en valeur., Nos,N°, Not Available,Indisponible, Not Marked,Non marqué, Not Paid and Not Delivered,Non payé et non livré, -Not Permitted,Non Autorisé, Not Started,Non Commencé, -Not active,Non actif, Not allow to set alternative item for the item {0},Ne permet pas de définir un autre article pour l'article {0}, Not allowed to update stock transactions older than {0},Non autorisé à mettre à jour les transactions du stock antérieures à {0}, Not authorized to edit frozen Account {0},Vous n'êtes pas autorisé à modifier le compte gelé {0}, @@ -1592,7 +1466,6 @@ Notes,Remarques, Nothing is included in gross,Rien n'est inclus dans le brut, Nothing more to show.,Rien de plus à montrer., Notify Customers via Email,Avertir les clients par courrier électronique, -Number,Nombre, Number of Depreciations Booked cannot be greater than Total Number of Depreciations,Nombre d’Amortissements Comptabilisés ne peut pas être supérieur à Nombre Total d'Amortissements, Number of Interaction,Nombre d'Interactions, Number of Order,Nombre de Commandes, @@ -1634,7 +1507,6 @@ Opening Stock,Stock d'Ouverture, Opening Stock Balance,Solde d'Ouverture des Stocks, Opening Value,Valeur d'Ouverture, Opening {0} Invoice created,Ouverture {0} Facture créée, -Operation,Opération, Operation Time must be greater than 0 for Operation {0},Temps de l'Opération doit être supérieur à 0 pour l'Opération {0}, "Operation {0} longer than any available working hours in workstation {1}, break down the operation into multiple operations","Opération {0} plus longue que toute heure de travail disponible dans la station de travail {1}, veuillez séparer l'opération en plusieurs opérations", Operations,Opérations, @@ -1647,7 +1519,6 @@ Opportunity,Opportunité, Opportunity Amount,Montant de l'opportunité, "Optional. Sets company's default currency, if not specified.","Optionnel. Défini la devise par défaut de l'entreprise, si non spécifié.", Optional. This setting will be used to filter in various transactions.,Facultatif. Ce paramètre sera utilisé pour filtrer différentes transactions., -Options,Options, Order Count,Compte de Commandes, Order Entry,Saisie de Commande, Order Value,Valeur de la commande, @@ -1660,9 +1531,9 @@ Orders,Commandes, Orders released for production.,Commandes validées pour la production., Organization,Organisation, Organization Name,Nom de l'Organisation, -Other,Autre, Other Reports,Autres rapports, "Other outward supplies(Nil rated,Exempted)","Autres livraisons sortantes (cotations nulles, exemptées)", +Others,Autres, Out Qty,Qté Sortante, Out Value,Valeur Sortante, Out of Order,Hors service, @@ -1676,7 +1547,6 @@ Outward taxable supplies(zero rated),Fournitures taxables à la sortie (détaxé Overdue,En retard, Overlap in scoring between {0} and {1},Chevauchement dans la notation entre {0} et {1}, Overlapping conditions found between:,Conditions qui coincident touvées entre :, -Owner,Responsable, PAN,Numéro de compte permanent (PAN), POS,PDV, POS Profile,Profil PDV, @@ -1691,7 +1561,6 @@ Paid Amount,Montant payé, Paid Amount cannot be greater than total negative outstanding amount {0},Le Montant Payé ne peut pas être supérieur au montant impayé restant {0}, Paid amount + Write Off Amount can not be greater than Grand Total,Le Montant Payé + Montant Repris ne peut pas être supérieur au Total Général, Paid and Not Delivered,Payé et non livré, -Parameter,Paramètre, Parent Item {0} must not be a Stock Item,L'Article Parent {0} ne doit pas être un Élément de Stock, Parents Teacher Meeting Attendance,Participation à la réunion parents-professeurs, Partially Depreciated,Partiellement déprécié, @@ -1751,7 +1620,6 @@ Pending activities for today,Activités en Attente pour aujourd'hui, Pension Funds,Fonds de Pension, Percentage Allocation should be equal to 100%,Pourcentage d'Allocation doit être égale à 100 %, Perception Analysis,Analyse de perception, -Period,Période, Period Closing Entry,Écriture de Clôture de la Période, Period Closing Voucher,Bon de Clôture de la Période, Periodicity,Périodicité, @@ -1778,7 +1646,6 @@ Please create purchase receipt or purchase invoice for the item {0},Veuillez cr Please define grade for Threshold 0%,Veuillez définir une note pour le Seuil 0%, Please enable Applicable on Booking Actual Expenses,Veuillez activer l'option : Applicable sur la base de l'enregistrement des dépenses réelles, Please enable Applicable on Purchase Order and Applicable on Booking Actual Expenses,Veuillez activer les options : Applicable sur la base des bons de commande d'achat et Applicable sur la base des bons de commande d'achat, -Please enable pop-ups,Veuillez autoriser les pop-ups, Please enter 'Is Subcontracted' as Yes or No,Veuillez entrer Oui ou Non pour 'Est sous-traitée', Please enter API Consumer Key,"Veuillez entrer la clé ""API Consumer Key""", Please enter API Consumer Secret,"Veuillez entrer la clé ""API Consumer Secret""", @@ -1834,7 +1701,6 @@ Please select BOM for Item in Row {0},Veuillez sélectionnez une nomenclature po Please select BOM in BOM field for Item {0},Veuillez sélectionner une nomenclature dans le champ nomenclature pour l’Article {0}, Please select Category first,Veuillez d’abord sélectionner une Catégorie, Please select Charge Type first,Veuillez d’abord sélectionner le Type de Facturation, -Please select Company,Veuillez sélectionner une Société, Please select Company and Posting Date to getting entries,Veuillez sélectionner la société et la date de comptabilisation pour obtenir les écritures, Please select Company first,Veuillez d’abord sélectionner une Société, Please select Completion Date for Completed Asset Maintenance Log,Veuillez sélectionner la date d'achèvement pour le journal de maintenance des actifs terminé, @@ -1875,7 +1741,6 @@ Please select the Multiple Tier Program type for more than one collection rules. Please select the assessment group other than 'All Assessment Groups',Sélectionnez un groupe d'évaluation autre que «Tous les Groupes d'Évaluation», Please select the document type first,Veuillez d’abord sélectionner le type de document, Please select weekly off day,Veuillez sélectionnez les jours de congé hebdomadaires, -Please select {0},Veuillez sélectionner {0}, Please select {0} first,Veuillez d’abord sélectionner {0}, Please set 'Apply Additional Discount On',Veuillez définir ‘Appliquer Réduction Supplémentaire Sur ‘, Please set 'Asset Depreciation Cost Center' in Company {0},Veuillez définir 'Centre de Coûts des Amortissements d’Actifs’ de la Société {0}, @@ -1941,7 +1806,6 @@ Prescription Dosage,Dosage de la prescription, Prescription Duration,Durée de la prescription, Prescriptions,Les prescriptions, Prev,Précédent, -Preview,Aperçu, Previous Financial Year is not closed,L’Exercice Financier Précédent n’est pas fermé, Price,Prix, Price List,Liste de prix, @@ -1959,13 +1823,11 @@ Pricing Rule {0} is updated,La règle de tarification {0} est mise à jour, Pricing Rules are further filtered based on quantity.,Les Règles de Tarification sont d'avantage filtrés en fonction de la quantité., Primary Address Details,Détails de l'adresse principale, Primary Contact Details,Détails du contact principal, -Print Format,Format d'Impression, Print IRS 1099 Forms,Imprimer les formulaires IRS 1099, Print Report Card,Imprimer le rapport, Print Settings,Paramètres d'impression, Print and Stationery,Impression et Papeterie, Print settings updated in respective print format,Paramètres d'impression mis à jour avec le format d'impression indiqué, -Print taxes with zero amount,Impression de taxes avec un montant nul, Printing and Branding,Impression et Marque, Private Equity,Capital Investissement, Procedure,Procédure, @@ -2012,15 +1874,12 @@ Prospecting,Prospection, Provisional Profit / Loss (Credit),Gain / Perte (Crédit) Provisoire, Publications,Des publications, Publish Items on Website,Publier les Articles sur le Site Web, -Published,Publié, Publishing,Édition, Purchase,achat, Purchase Amount,Montant de l'Achat, Purchase Date,Date d'Achat, Purchase Invoice,Facture d’Achat, Purchase Invoice {0} is already submitted,La Facture d’Achat {0} est déjà soumise, -Purchase Manager,Responsable des Achats, -Purchase Master Manager,Responsable des Données d’Achats, Purchase Order,Commande d'Achat, Purchase Order Amount,Montant de la Commande d'Achat, Purchase Order Amount(Company Currency),Montant de la Commande d'Achat (devise de la société), @@ -2035,7 +1894,6 @@ Purchase Price List,Liste des Prix d'Achat, Purchase Receipt,Reçu d’Achat, Purchase Receipt {0} is not submitted,Le Reçu d’Achat {0} n'est pas soumis, Purchase Tax Template,Modèle de Taxes pour les Achats, -Purchase User,Utilisateur Acheteur, Purchase orders help you plan and follow up on your purchases,Les Bons de Commande vous aider à planifier et à assurer le suivi de vos achats, Purchasing,Achat, Purpose must be one of {0},L'Objet doit être parmi {0}, @@ -2065,7 +1923,6 @@ Quantity to Make,Quantité à faire, Quantity to Manufacture must be greater than 0.,La quantité à produire doit être supérieur à 0., Quantity to Produce,Quantité à produire, Quantity to Produce can not be less than Zero,La quantité à produire ne peut être inférieure à zéro, -Query Options,Options de Requête, Queued for replacing the BOM. It may take a few minutes.,En file d'attente pour remplacer la nomenclature. Cela peut prendre quelques minutes., Queued for updating latest price in all Bill of Materials. It may take a few minutes.,Mise à jour des prix les plus récents dans toutes les nomenclatures en file d'attente. Cela peut prendre quelques minutes., Quick Journal Entry,Écriture Rapide dans le Journal, @@ -2080,10 +1937,8 @@ Quotations received from Suppliers.,Devis reçus des Fournisseurs., Quotations: ,Devis :, Quotes to Leads or Customers.,Devis de Lead ou Clients., RFQs are not allowed for {0} due to a scorecard standing of {1},Les Appels d'Offres ne sont pas autorisés pour {0} en raison d'une note de {1} sur la fiche d'évaluation, -Range,Plage, Rate,Prix, Rate:,Prix:, -Rating,Évaluation, Raw Material,Matières Premières, Raw Materials,Matières premières, Raw Materials cannot be blank.,Matières Premières ne peuvent pas être vides., @@ -2099,35 +1954,25 @@ Receipt,Reçu, Receipt document must be submitted,Le reçu doit être soumis, Receivable,Créance, Receivable Account,Compte Débiteur, -Received,Reçu, Received On,Reçu le, Received Quantity,Quantité reçue, Received Stock Entries,Entrées de stock reçues, Receiver List is empty. Please create Receiver List,La Liste de Destinataires est vide. Veuillez créer une Liste de Destinataires, -Recipients,Destinataires, Reconcile,Réconcilier, "Record of all communications of type email, phone, chat, visit, etc.","Enregistrement de toutes les communications de type email, téléphone, chat, visite, etc.", Records,Dossiers, -Redirect URL,URL de Redirection, Ref,Ref, Ref Date,Date de Réf., -Reference,Référence, Reference #{0} dated {1},Référence #{0} datée du {1}, -Reference Date,Date de Référence, Reference Doctype must be one of {0},Doctype de la Référence doit être parmi {0}, -Reference Document,Document de Référence, -Reference Document Type,Type du document de référence, Reference No & Reference Date is required for {0},N° et Date de Référence sont nécessaires pour {0}, Reference No and Reference Date is mandatory for Bank transaction,Le N° de Référence et la Date de Référence sont nécessaires pour une Transaction Bancaire, Reference No is mandatory if you entered Reference Date,N° de Référence obligatoire si vous avez entré une date, Reference No.,Numéro de référence, Reference Number,Numéro de réference, -Reference Type,Type de référence, "Reference: {0}, Item Code: {1} and Customer: {2}","Référence: {0}, Code de l'article: {1} et Client: {2}", References,Références, -Refresh Token,Jeton de Rafraîchissement, Register,registre, -Rejected,Rejeté, Related,en relation, Relation with Guardian1,Relation avec Tuteur1, Relation with Guardian2,Relation avec Tuteur2, @@ -2139,17 +1984,12 @@ Remarks,Remarques, Reminder to update GSTIN Sent,Rappel pour mettre à jour GSTIN envoyé, Remove item if charges is not applicable to that item,Retirer l'article si les charges ne lui sont pas applicables, Removed items with no change in quantity or value.,Les articles avec aucune modification de quantité ou de valeur ont étés retirés., -Reopen,Ré-ouvrir, Reorder Level,Niveau de réapprovisionnement, Reorder Qty,Qté de Réapprovisionnement, Repeat Customer Revenue,Revenus de Clients Récurrents, Repeat Customers,Clients Récurrents, Replace BOM and update latest price in all BOMs,Remplacer la nomenclature et actualiser les prix les plus récents dans toutes les nomenclatures, -Replied,Répondu, -Report,Rapport, -Report Type,Type de Rapport, Report Type is mandatory,Le Type de Rapport est nécessaire, -Reports,Rapports, Reqd By Date,Requis par date, Reqd Qty,Qté obligatoire, Request for Quotation,Appel d'Offre, @@ -2208,7 +2048,6 @@ Root cannot be edited.,La racine ne peut pas être modifiée., Root cannot have a parent cost center,Racine ne peut pas avoir un centre de coûts parent, Round Off,Arrondi, Rounded Total,Total arrondi, -Route,Route, Row # {0}: ,Ligne # {0} :, Row # {0}: Batch No must be same as {1} {2},Ligne # {0} : Le N° de Lot doit être le même que {1} {2}, Row # {0}: Cannot return more than {1} for Item {2},Ligne # {0} : Vous ne pouvez pas retourner plus de {1} pour l’Article {2}, @@ -2297,8 +2136,6 @@ Sales Funnel,Entonnoir de vente, Sales Invoice,Facture de vente, Sales Invoice {0} has already been submitted,La Facture Vente {0} a déjà été transmise, Sales Invoice {0} must be cancelled before cancelling this Sales Order,Facture de Vente {0} doit être annulée avant l'annulation de cette Commande Client, -Sales Manager,Responsable des Ventes, -Sales Master Manager,Directeur des Ventes, Sales Order,Commande client, Sales Order Item,Article de la Commande Client, Sales Order required for Item {0},Commande Client requise pour l'Article {0}, @@ -2314,11 +2151,9 @@ Sales Return,Retour de Ventes, Sales Summary,Récapitulatif des ventes, Sales Tax Template,Modèle de la Taxe de Vente, Sales Team,Équipe des Ventes, -Sales User,Chargé de Ventes, Sales and Returns,Ventes et retours, Sales campaigns.,Campagnes de vente., Sales orders are not available for production,Aucune commande client n'est disponible pour la production, -Salutation,Salutations, Same Company is entered more than once,La même Société a été entrée plus d'une fois, Same item cannot be entered multiple times.,Le même article ne peut pas être entré plusieurs fois., Same supplier has been entered multiple times,Le même fournisseur a été saisi plusieurs fois, @@ -2326,7 +2161,6 @@ Sample Collection,Collecte d'Échantillons, Sample quantity {0} cannot be more than received quantity {1},La quantité d'échantillon {0} ne peut pas dépasser la quantité reçue {1}, Sanctioned,Sanctionné, Sand,Le sable, -Saturday,Samedi, Saving {0},Enregistrement {0}, Scan Barcode,Scan Code Barre, Schedule,Calendrier, @@ -2334,18 +2168,15 @@ Schedule Admission,Calendrier d'admission, Schedule Course,Cours Calendrier, Schedule Date,Date du Calendrier, Schedule Discharge,Décharge horaire, -Scheduled,Prévu, Scheduled Upto,Programmé jusqu'à, "Schedules for {0} overlaps, do you want to proceed after skiping overlaped slots ?","Les plannings pour {0} se chevauchent, voulez-vous continuer sans prendre en compte les créneaux qui se chevauchent ?", Score cannot be greater than Maximum Score,Score ne peut pas être supérieure à Score maximum, Scorecards,Fiches d'Évaluation, Scrapped,Mis au rebut, -Search,Rechercher, Search Results,Résultats de la recherche, Search Sub Assemblies,Rechercher les Sous-Ensembles, "Search by item code, serial number, batch no or barcode","Recherche par code article, numéro de série, numéro de lot ou code-barres", "Seasonality for setting budgets, targets etc.","Saisonnalité de l'établissement des budgets, des objectifs, etc.", -Secret Key,Clef Secrète, Secretary,secrétaire, Section Code,Code de section, Secured Loans,Prêts garantis, @@ -2355,7 +2186,6 @@ See All Articles,Voir tous les articles, See all open tickets,Voir tous les tickets ouverts, See past orders,Voir les commandes passées, See past quotations,Voir les citations passées, -Select,Sélectionner, Select Alternate Item,Sélectionnez un autre élément, Select Attribute Values,Sélectionner les valeurs d'attribut, Select BOM,Sélectionner une nomenclature, @@ -2369,7 +2199,6 @@ Select Company...,Sélectionner la Société ..., Select Customer,Sélectionnez un client, Select Days,Choisissez des jours, Select Default Supplier,Sélectionner le Fournisseur par Défaut, -Select DocType,Sélectionner le DocType, Select Fiscal Year...,Sélectionner Exercice ..., Select Item (optional),Sélectionnez l'Article (facultatif), Select Items based on Delivery Date,Sélectionnez les articles en fonction de la Date de Livraison, @@ -2399,11 +2228,9 @@ Selling Price List,Liste de prix de vente, Selling Rate,Prix de vente, "Selling must be checked, if Applicable For is selected as {0}","Vente doit être vérifiée, si ""Applicable pour"" est sélectionné comme {0}", Send Grant Review Email,Envoyer un email d'examen de la demande de subvention, -Send Now,Envoyer Maintenant, Send SMS,Envoyer un SMS, Send mass SMS to your contacts,Envoyer un SMS en masse à vos contacts, Sensitivity,Sensibilité, -Sent,Envoyé, Serial No and Batch,N° de Série et lot, Serial No is mandatory for Item {0},N° de Série est obligatoire pour l'Article {0}, Serial No {0} does not belong to Batch {1},Le numéro de série {0} n'appartient pas au lot {1}, @@ -2428,7 +2255,6 @@ Serialized Inventory,Inventaire Sérialisé, Series Updated,Série mise à jour, Series Updated Successfully,Mise à jour des Séries Réussie, Series is mandatory,Série est obligatoire, -Service,Service, Service Level Agreement,Contrat de niveau de service, Service Level Agreement.,Contrat de niveau de service., Service Level.,Niveau de service., @@ -2455,7 +2281,6 @@ Setting up Email Account,Configuration du Compte Email, Setting up Employees,Configuration des Employés, Setting up Taxes,Configuration des Impôts, Setting up company,Création d'entreprise, -Settings,Paramètres, "Settings for online shopping cart such as shipping rules, price list etc.","Paramètres du panier tels que les règles de livraison, liste de prix, etc.", Settings for website homepage,Paramètres de la page d'accueil du site, Settings for website product listing,Paramètres pour la liste de produits de sites Web, @@ -2481,7 +2306,6 @@ Shipping rule only applicable for Selling,Règle d'expédition applicable unique Shopify Supplier,Fournisseur Shopify, Shopping Cart,Panier, Shopping Cart Settings,Paramètres du panier, -Short Name,Nom Court, Shortage Qty,Qté de Pénurie, Show Completed,Montrer terminé, Show Cumulative Amount,Afficher le montant cumulatif, @@ -2500,7 +2324,6 @@ Silt,Limon, Single Variant,Variante unique, Single unit of an Item.,Seule unité d'un Article., "Skipping Leave Allocation for the following employees, as Leave Allocation records already exists against them. {0}","Attribution des congés de congé pour les employés suivants, car des dossiers de répartition des congés existent déjà contre eux. {0}", -Slideshow,Diaporama, Slots for {0} are not added to the schedule,Les créneaux pour {0} ne sont pas ajoutés à l'agenda, Small,Petit, Soap & Detergent,Savons & Détergents, @@ -2513,8 +2336,6 @@ Some emails are invalid,Certains emails sont invalides, Some information is missing,Certaines informations sont manquantes, Something went wrong!,Quelque chose a mal tourné !, "Sorry, Serial Nos cannot be merged","Désolé, les N° de Série ne peut pas être fusionnés", -Source,Source, -Source Name,Nom de la Source, Source Warehouse,Entrepôt source, Source and Target Location cannot be same,Les localisations source et cible ne peuvent pas être identiques, Source and target warehouse cannot be same for row {0},L'entrepôt source et destination ne peuvent être similaire dans la ligne {0}, @@ -2529,14 +2350,12 @@ Sports,Sportif, Standard Buying,Achat standard, Standard Selling,Vente standard, Standard contract terms for Sales or Purchase.,Termes contractuels standards pour Ventes ou Achats, -Start Date,Date de Début, Start Date of Agreement can't be greater than or equal to End Date.,La date de début de l'accord ne peut être supérieure ou égale à la date de fin., Start Year,Année de début, Start date should be less than end date for Item {0},La date de début doit être antérieure à la date de fin pour l'Article {0}, Start date should be less than end date for task {0},La date de début doit être inférieure à la date de fin de la tâche {0}, Start day is greater than end day in task '{0}',La date de début est supérieure à la date de fin dans la tâche '{0}', Start on,Démarrer, -State,Etat, State/UT Tax,Taxe Etat / UT, Statement of Account,Relevé de compte, Status must be one of {0},Le statut doit être l'un des {0}, @@ -2569,8 +2388,6 @@ Stock cannot be updated against Delivery Note {0},Stock ne peut pas être mis à Stock cannot be updated against Purchase Receipt {0},Stock ne peut pas être mis à jour pour le Reçu d'Achat {0}, Stock cannot exist for Item {0} since has variants,Stock ne peut pas exister pour l'Article {0} puisqu'il a des variantes, Stock transactions before {0} are frozen,Les transactions du stock avant {0} sont gelées, -Stop,Arrêter, -Stopped,Arrêté, "Stopped Work Order cannot be cancelled, Unstop it first to cancel","Un ordre de fabrication arrêté ne peut être annulé, Re-démarrez le pour pouvoir l'annuler", Stores,Magasins, Student,Étudiant, @@ -2601,8 +2418,6 @@ Sub Assemblies,Sous-Ensembles, Sub Type,Sous type, Sub-contracting,Sous-traitant, Subcontract,Sous-traiter, -Subject,Sujet, -Submit,Valider, Submit this Work Order for further processing.,Valider cet ordre de fabrication pour continuer son traitement., Subscription,Abonnement, Subscription Management,Gestion des abonnements, @@ -2615,10 +2430,8 @@ Successfully created payment entries,Ecritures de paiement créées avec succès Successfully deleted all transactions related to this company!,Suppression de toutes les transactions liées à cette société avec succès !, Sum of Scores of Assessment Criteria needs to be {0}.,Somme des Scores de Critères d'Évaluation doit être {0}., Sum of points for all goals should be 100. It is {0},Somme des points pour tous les objectifs devraient être 100. Il est {0}, -Summary,Résumé, Summary for this month and pending activities,Résumé du mois et des activités en suspens, Summary for this week and pending activities,Résumé de la semaine et des activités en suspens, -Sunday,Dimanche, Suplier,Fournisseur, Supplier,Fournisseur, Supplier Group,Groupe de fournisseurs, @@ -2648,20 +2461,15 @@ Susceptible,Sensible, Sync has been temporarily disabled because maximum retries have been exceeded,La synchronisation a été temporairement désactivée car les tentatives maximales ont été dépassées, Syntax error in condition: {0},Erreur de syntaxe dans la condition: {0}, Syntax error in formula or condition: {0},Erreur de syntaxe dans la formule ou condition : {0}, -System Manager,Responsable Système, TDS Rate %,Pourcentage de TDS, Tap items to add them here,Choisissez des articles pour les ajouter ici, -Target,Cible, Target ({}),Cible ({}), Target On,Cible sur, Target Warehouse,Entrepôt cible, Target warehouse is mandatory for row {0},L’Entrepôt cible est obligatoire pour la ligne {0}, -Task,Tâche, -Tasks,Tâches, Tasks have been created for managing the {0} disease (on row {1}),Des tâches ont été créées pour gérer la maladie {0} (sur la ligne {1}), Tax,Taxe, Tax Assets,Actifs d'Impôts, -Tax Category,Catégorie de taxe, Tax Category for overriding tax rates.,Catégorie de taxe pour les taux de taxe prépondérants., "Tax Category has been changed to ""Total"" because all the Items are non-stock items","La Catégorie de Taxe a été changée à ""Total"" car tous les articles sont des articles hors stock", Tax ID,Numéro d'identification fiscale, @@ -2769,11 +2577,9 @@ Timesheet {0} is already completed or cancelled,La Feuille de Temps {0} est déj Timesheets,Feuilles de temps, "Timesheets help keep track of time, cost and billing for activites done by your team","Les Feuilles de Temps aident au suivi du temps, coût et facturation des activités effectuées par votre équipe", Titles for print templates e.g. Proforma Invoice.,Titres pour les modèles d'impression e.g. Facture Proforma., -To,À, To Address 1,Ligne d'adresse 1 (Destination), To Address 2,Ligne d'adresse 2 (Destination), To Bill,À Facturer, -To Date,Jusqu'au, To Date cannot be before From Date,La date de fin ne peut être antérieure à la date de début, To Date cannot be less than From Date,La date de fin ne peut pas précéder la date de début, To Date must be greater than From Date,La date de fin doit être supérieure à la date de début, @@ -2809,6 +2615,7 @@ Total (Credit),Total (Crédit), Total (Without Tax),Total (hors taxes), Total Achieved,Total Obtenu, Total Actual,Total réel, +Total Allocated Leaves,Total des congés alloués, Total Amount,Montant total, Total Amount Credited,Montant total crédité, Total Applicable Charges in Purchase Receipt Items table must be same as Total Taxes and Charges,Total des Frais Applicables dans la Table des Articles de Reçus d’Achat doit être égal au Total des Taxes et Frais, @@ -2888,7 +2695,6 @@ Types of activities for Time Logs,Types d'activités pour Journaux de Temps, UOM,UdM, UOM Conversion factor is required in row {0},Facteur de conversion de l'UdM est obligatoire dans la ligne {0}, UOM coversion factor required for UOM: {0} in Item: {1},Facteur de coversion UdM requis pour l'UdM : {0} dans l'Article : {1}, -URL,URL, Unable to find exchange rate for {0} to {1} for key date {2}. Please create a Currency Exchange record manually,Impossible de trouver le taux de change pour {0} à {1} pour la date clé {2}. Veuillez créer une entrée de taux de change manuellement, Unable to find score starting at {0}. You need to have standing scores covering 0 to 100,Impossible de trouver un score démarrant à {0}. Vous devez avoir des scores couvrant 0 à 100, Unable to find variable: ,Impossible de trouver une variable:, @@ -2902,7 +2708,6 @@ Unknown,Inconnu, Unpaid,Impayé, Unsecured Loans,Prêts non garantis, Unsubscribe from this Email Digest,Se Désinscire de ce Compte Rendu par Email, -Unsubscribed,Désinscrit, Until,Jusqu'à, Unverified Webhook Data,Données de Webhook non vérifiées, Update Account Name / Number,Mettre à jour le nom / numéro du compte, @@ -2918,8 +2723,7 @@ Updating Variants...,Mise à jour des variantes ..., Upload your letter head and logo. (you can edit them later).,Charger votre en-tête et logo. (vous pouvez les modifier ultérieurement)., Upper Income,Revenu Élevé, Use Sandbox,Utiliser Sandbox, -User,Utilisateur, -User ID,Identifiant d'utilisateur, +Used Leaves,Congés utilisés, User ID not set for Employee {0},ID de l'Utilisateur non défini pour l'Employé {0}, User Remark,Remarque de l'Utilisateur, User has not applied rule on the invoice {0},L'utilisateur n'a pas appliqué la règle sur la facture {0}, @@ -2929,14 +2733,12 @@ User {0} does not exist,Utilisateur {0} n'existe pas, User {0} doesn't have any default POS Profile. Check Default at Row {1} for this User.,L'utilisateur {0} n'a aucun profil POS par défaut. Vérifiez par défaut à la ligne {1} pour cet utilisateur., User {0} is already assigned to Employee {1},Utilisateur {0} est déjà attribué à l'Employé {1}, User {0} is already assigned to Healthcare Practitioner {1},L'utilisateur {0} est déjà attribué à un professionnel de la santé {1}, -Users,Utilisateurs, Utility Expenses,Frais de Services d'Utilité Publique, Valid From Date must be lesser than Valid Upto Date.,La date de début de validité doit être inférieure à la date de mise en service valide., Valid Till,Valable Jusqu'au, Valid from and valid upto fields are mandatory for the cumulative,Les champs valides à partir de et valables jusqu'à sont obligatoires pour le cumulatif., Valid from date must be less than valid upto date,La date de début de validité doit être inférieure à la date de validité, Valid till date cannot be before transaction date,La date de validité ne peut pas être avant la date de transaction, -Validity,Validité, Validity period of this quotation has ended.,La période de validité de ce devis a pris fin., Valuation Rate,Taux de Valorisation, Valuation Rate is mandatory if Opening Stock entered,Le Taux de Valorisation est obligatoire si un Stock Initial est entré, @@ -2991,7 +2793,6 @@ Warehouse {0} does not exist,L'entrepôt {0} n'existe pas, Warehouses with child nodes cannot be converted to ledger,Les entrepôts avec nœuds enfants ne peuvent pas être convertis en livre, Warehouses with existing transaction can not be converted to group.,Les entrepôts avec des transactions existantes ne peuvent pas être convertis en groupe., Warehouses with existing transaction can not be converted to ledger.,Les entrepôts avec des transactions existantes ne peuvent pas être convertis en livre., -Warning,Avertissement, Warning: Another {0} # {1} exists against stock entry {2},Attention : Un autre {0} {1} # existe pour l'écriture de stock {2}, Warning: Invalid SSL certificate on attachment {0},Attention : certificat SSL non valide sur la pièce jointe {0}, Warning: Invalid attachment {0},Attention : Pièce jointe non valide {0}, @@ -3001,16 +2802,9 @@ Warning: System will not check overbilling since amount for Item {0} in {1} is z Warranty,garantie, Warranty Claim,Réclamation de Garantie, Warranty Claim against Serial No.,Réclamation de Garantie pour le N° de Série., -Website,Site Web, Website Image should be a public file or website URL,L'Image du Site Web doit être un fichier public ou l'URL d'un site web, Website Image {0} attached to Item {1} cannot be found,Image pour le Site Web {0} attachée à l'Article {1} ne peut pas être trouvée, -Website Manager,Responsable du Site Web, -Website Settings,Paramètres du Site web, -Wednesday,Mercredi, -Week,Semaine, -Weekly,Hebdomadaire, "Weight is mentioned,\nPlease mention ""Weight UOM"" too","Poids est mentionné,\nVeuillez aussi mentionner ""UdM de Poids""", -Welcome email sent,Email de bienvenue envoyé, Welcome to ERPNext,Bienvenue sur ERPNext, What do you need help with?,Avec quoi avez vous besoin d'aide ?, What does it do?,Qu'est-ce que ça fait ?, @@ -3073,9 +2867,7 @@ disabled user,utilisateur désactivé, "e.g. ""Build tools for builders""","e.g. ""Construire des outils pour les constructeurs""", "e.g. ""Primary School"" or ""University""","e.g. ""École Primaire"" ou ""Université""", "e.g. Bank, Cash, Credit Card","e.g. Cash, Banque, Carte de crédit", -hidden,Masqué, modified,modifié, -old_parent,grand_parent, on,sur, {0} '{1}' is disabled,{0} '{1}' est désactivé(e), {0} '{1}' not in Fiscal Year {2},{0} '{1}' n'est pas dans l’Exercice {2}, @@ -3108,7 +2900,6 @@ on,sur, {0} hours,{0} heures, {0} in row {1},{0} dans la ligne {1}, {0} is blocked so this transaction cannot proceed,{0} est bloqué donc cette transaction ne peut pas continuer, -{0} is mandatory,{0} est obligatoire, {0} is mandatory for Item {1},{0} est obligatoire pour l’Article {1}, {0} is mandatory. Maybe Currency Exchange record is not created for {1} to {2}.,{0} est obligatoire. Peut-être qu’un enregistrement de Taux de Change n'est pas créé pour {1} et {2}., {0} is not a stock Item,{0} n'est pas un Article de stock, @@ -3168,37 +2959,8 @@ on,sur, {0}: {1} does not exists,{0} : {1} n’existe pas, {0}: {1} not found in Invoice Details table,{0} : {1} introuvable dans la table de Détails de la Facture, {} of {},{} de {}, -Assigned To,Assigné À, -Chat,Chat, Completed By,Effectué par, -Day of Week,Jour de la semaine, -"Dear System Manager,","Cher Administrateur Système ,", -Default Value,Valeur par Défaut, -Email Group,Groupe Email, -Email Settings,Paramètres d'Email, -Email not sent to {0} (unsubscribed / disabled),Email pas envoyé à {0} (désabonné / désactivé), -Error Message,Message d'erreur, -Fieldtype,Type de Champ, -Help Articles,Articles d'Aide, -ID,ID, -Import,Importer, -Language,Langue, -Likes,Aime, -Merge with existing,Fusionner avec existant, -Orientation,Orientation, -Parent,Parent, Payment Failed,Le Paiement a Échoué, -Personal,Personnel, -Post,Poster, -Postal Code,code postal, -Provider,Fournisseur, -Read Only,Lecture Seule, -Recipient,Destinataire, -Reviews,Avis, -Sender,Expéditeur, -There were errors while sending email. Please try again.,Il y a eu des erreurs lors de l'envoi d’emails. Veuillez essayer à nouveau., -Values Changed,Valeurs Modifiées, -or,ou, Ageing Range 4,Gamme de vieillissement 4, Allocated amount cannot be greater than unadjusted amount,Le montant alloué ne peut être supérieur au montant non ajusté, Allocated amount cannot be negative,Le montant alloué ne peut être négatif, @@ -3224,22 +2986,7 @@ Rules for applying different promotional schemes.,Règles d'application de diff Show {0},Montrer {0}, Target Details,Détails de la cible, {0} already has a Parent Procedure {1}.,{0} a déjà une procédure parent {1}., -API,API, -Annual,Annuel, -Change,Changement, -Contact Email,Email du Contact, -From Date,A partir du, -Group By,Par groupe, -Invalid URL,URL invalide, -Landscape,Paysage, -Naming Series,Masque de numérotation, -No data to export,Aucune donnée à exporter, -Portrait,Portrait, Print Heading,Imprimer Titre, -Scheduler Inactive,Planificateur inactif, -Scheduler is inactive. Cannot import data.,Le planificateur est inactif. Impossible d'importer des données., -Show Document,Afficher le document, -Show Traceback,Afficher le traçage, Video,Vidéo, % Of Grand Total,% Du grand total, Company is a mandatory filter.,La société est un filtre obligatoire., @@ -3257,20 +3004,11 @@ Accounting Dimension {0} is required for 'Balance Sheet' account {1}.,La Accounting Dimension {0} is required for 'Profit and Loss' account {1}.,La dimension de comptabilité {0} est requise pour le compte 'Bénéfices et pertes' {1}., Accounting Masters,Maîtres Comptables, Accounting Period overlaps with {0},La période comptable chevauche avec {0}, -Activity,Activité, -Add / Manage Email Accounts.,Ajouter / Gérer les Comptes de Messagerie., -Add Child,Ajouter une Sous-Catégorie, -Add Multiple,Ajout Multiple, -Add Participants,Ajouter des participants, Add to Featured Item,Ajouter à l'article en vedette, Add your review,Ajouter votre avis, Add/Edit Coupon Conditions,Ajouter / Modifier les conditions du coupon, Added to Featured Items,Ajouté aux articles en vedette, -Added {0} ({1}),Ajouté {0} ({1}), -Address Line 1,Adresse Ligne 1, -Addresses,Adresses, Admission End Date should be greater than Admission Start Date.,La date de fin d'admission doit être supérieure à la date de début d'admission., -All,Tout, All bank transactions have been created,Toutes les transactions bancaires ont été créées, All the depreciations has been booked,Toutes les amortissements ont été comptabilisés, Allow Resetting Service Level Agreement from Support Settings.,Autoriser la réinitialisation du contrat de niveau de service à partir des paramètres de support., @@ -3305,17 +3043,12 @@ Bank accounts added,Comptes bancaires ajoutés, Batch no is required for batched item {0},Le numéro de lot est requis pour l'article en lot {0}., Billing Date,Date de facturation, Billing Interval Count cannot be less than 1,Le nombre d'intervalles de facturation ne peut pas être inférieur à 1, -Blue,Bleu, -Book,Livre, Book Appointment,Prendre rendez-vous, -Brand,Marque, -Browse,Feuilleter, Call Connected,Appel connecté, Call Disconnected,Appel déconnecté, Call Missed,Appel manqué, Call Summary,Résumé d'appel, Call Summary Saved,Résumé de l'appel enregistré, -Cancelled,Annulé, Cannot Calculate Arrival Time as Driver Address is Missing.,Impossible de calculer l'heure d'arrivée car l'adresse du conducteur est manquante., Cannot Optimize Route as Driver Address is Missing.,Impossible d'optimiser l'itinéraire car l'adresse du pilote est manquante., Cannot complete task {0} as its dependant task {1} are not ccompleted / cancelled.,Impossible de terminer la tâche {0} car sa tâche dépendante {1} n'est pas terminée / annulée., @@ -3324,26 +3057,19 @@ Cannot find a matching Item. Please select some other value for {0}.,Impossible "Capacity Planning Error, planned start time can not be same as end time","Erreur de planification de capacité, l'heure de début prévue ne peut pas être identique à l'heure de fin", Categories,Catégories, Changes in {0},Changements dans {0}, -Chart,Graphique, Choose a corresponding payment,Choisissez un paiement correspondant, Click on the link below to verify your email and confirm the appointment,Cliquez sur le lien ci-dessous pour vérifier votre email et confirmer le rendez-vous, -Close,Fermer, Communication,Communication, Compact Item Print,Impression de l'Article Compacté, -Company,Société, Company of asset {0} and purchase document {1} doesn't matches.,La société de l'actif {0} et le document d'achat {1} ne correspondent pas., Compare BOMs for changes in Raw Materials and Operations,Comparer les nomenclatures aux modifications apportées aux matières premières et aux opérations, Compare List function takes on list arguments,La fonction de comparaison de liste accepte les arguments de liste, -Complete,Terminé, -Completed,Terminé, Completed Quantity,Quantité terminée, Connect your Exotel Account to ERPNext and track call logs,Connectez votre compte Exotel à ERPNext et suivez les journaux d'appels, Connect your bank accounts to ERPNext,Connectez vos comptes bancaires à ERPNext, Contact Seller,Contacter le vendeur, -Continue,Continuer, Cost Center: {0} does not exist,Centre de coûts: {0} n'existe pas, Couldn't Set Service Level Agreement {0}.,Impossible de définir le contrat de service {0}., -Country,Pays, Country Code in File does not match with country code set up in the system,Le code de pays dans le fichier ne correspond pas au code de pays configuré dans le système, Create New Contact,Créer un nouveau contact, Create New Lead,Créer une nouvelle lead, @@ -3354,34 +3080,20 @@ Creating bank entries...,Création d'entrées bancaires ..., Credit limit is already defined for the Company {0},La limite de crédit est déjà définie pour la société {0}., Ctrl + Enter to submit,Ctrl + Entrée pour valider, Ctrl+Enter to submit,Ctrl + Entrée pour valider, -Currency,Devise, -Current Status,Statut Actuel, Customer PO,Commande d'Achat client, -Daily,Quotidien, -Date,Date, Date of Birth cannot be greater than Joining Date.,La date de naissance ne peut pas être supérieure à la date d'adhésion., -Dear,Cher/Chère, -Default,Par Défaut, Define coupon codes.,Définissez les codes promo., Delayed Days,Jours retardés, -Delete,Supprimer, Delivered Quantity,Quantité livrée, Delivery Notes,Bons de livraison, Depreciated Amount,Montant amorti, -Description,Description, -Designation,Désignation, Difference Value,Valeur de différence, Dimension Filter,Filtre de dimension, -Disabled,Desactivé, Disbursement and Repayment,Décaissement et remboursement, Distance cannot be greater than 4000 kms,La distance ne peut pas dépasser 4000 km, Do you want to submit the material request,Voulez-vous valider la demande de matériel, -Doctype,Doctype, Document {0} successfully uncleared,Document {0} non effacé avec succès, -Download Template,Télécharger le Modèle, Dr,Dr, -Due Date,Date d'Échéance, -Duplicate,Dupliquer, Duplicate Project with Tasks,Projet en double avec tâches, Duplicate project has been created,Un projet en double a été créé, E-Way Bill JSON can only be generated from a submitted document,E-Way Bill JSON ne peut être généré qu'à partir d'un document soumis, @@ -3391,7 +3103,6 @@ ERPNext could not find any matching payment entry,ERPNext n'a trouvé aucune ent Earliest Age,Âge le plus précoce, Edit Details,Modifier les détails, Either GST Transporter ID or Vehicle No is required if Mode of Transport is Road,Un numéro d'identification de transporteur ou un numéro de véhicule est requis si le mode de transport est la route., -Email,Email, Email Campaigns,Campagnes de courrier électronique, Employee ID is linked with another instructor,L'ID de l'employé est lié à un autre instructeur, Employee Tax and Benefits,Impôt et avantages sociaux des employés, @@ -3403,21 +3114,13 @@ End Time,Heure de Fin, Energy Point Leaderboard,Point de classement énergétique, Enter API key in Google Settings.,Entrez la clé API dans les paramètres Google., Enter Supplier,Entrez le fournisseur, -Enter Value,Entrez une Valeur, -Entity Type,Type d'entité, -Error,Erreur, Error in Exotel incoming call,Erreur dans un appel entrant Exotel, Error: {0} is mandatory field,Erreur: {0} est un champ obligatoire, Exception occurred while reconciling {0},Une exception s'est produite lors de la réconciliation {0}, Expected and Discharge dates cannot be less than Admission Schedule date,Les dates prévues et de sortie ne peuvent pas être inférieures à la date du calendrier d'admission, -Expired,Expiré, -Export,Exporter, -Export not allowed. You need {0} role to export.,Pas autorisé à exporter. Vous devez avoir le rôle {0} pour exporter., Failed to add Domain,Impossible d'ajouter le domaine, Fetch Items from Warehouse,Récupérer des articles de l'entrepôt, Fetching...,Aller chercher..., -Field,Champ, -Filters,Filtres, Finding linked payments,Trouver des paiements liés, Fleet Management,Gestion de flotte, Following fields are mandatory to create address:,Les champs suivants sont obligatoires pour créer une adresse:, @@ -3433,28 +3136,17 @@ Future Payment Ref,Paiement futur Ref, Future Payments,Paiements futurs, GST HSN Code does not exist for one or more items,Le code HSN de la TPS n’existe pas pour un ou plusieurs articles, Generate E-Way Bill JSON,Générer E-Way Bill JSON, -Get Items,Obtenir les Articles, Get Outstanding Documents,Obtenez des documents en suspens, -Goal,Objectif, Greater Than Amount,Plus grand que le montant, -Green,Vert, -Group,Groupe, Group By Customer,Regrouper par client, Group By Supplier,Regrouper par fournisseur, -Group Node,Noeud de Groupe, Group Warehouses cannot be used in transactions. Please change the value of {0},Les entrepôts de groupe ne peuvent pas être utilisés dans les transactions. Veuillez modifier la valeur de {0}, -Help,Aidez-moi, -Help Article,Article d’Aide, "Helps you keep tracks of Contracts based on Supplier, Customer and Employee","Vous aide à garder une trace des contrats en fonction du fournisseur, client et employé", Helps you manage appointments with your leads,Vous aide à gérer les rendez-vous avec vos leads, -Home,Accueil, IBAN is not valid,IBAN n'est pas valide, -Import Data from CSV / Excel files.,Importer des données à partir de fichiers CSV / Excel, -In Progress,En cours, Incoming call from {0},Appel entrant du {0}, Incorrect Warehouse,Entrepôt incorrect, Invalid Barcode. There is no Item attached to this barcode.,Code à barres invalide. Il n'y a pas d'article attaché à ce code à barres., -Invalid credentials,les informations d'identification invalides, Issue Priority.,Priorité d'émission., Issue Type.,Type de probleme., "It seems that there is an issue with the server's stripe configuration. In case of failure, the amount will get refunded to your account.","Il semble qu'il y a un problème avec la configuration de Stripe sur le serveur. En cas d'erreur, le montant est remboursé sur votre compte.", @@ -3470,13 +3162,11 @@ Latest Age,Dernier âge, Leaves Taken,Feuilles prises, Less Than Amount,Moins que le montant, Liabilities,Passifs, -Loading...,Chargement en Cours ..., Loan Applications from customers and employees.,Demandes de prêt des clients et des employés., Loan Processes,Processus de prêt, Loan Type for interest and penalty rates,Type de prêt pour les taux d'intérêt et de pénalité, Loans,Les prêts, Loans provided to customers and employees.,Prêts accordés aux clients et aux employés., -Location,Lieu, Looks like someone sent you to an incomplete URL. Please ask them to look into it.,On dirait que quelqu'un vous a envoyé vers URL incomplète. Veuillez leur demander d’analyser l’erreur., Make Journal Entry,Faire une écriture de journal, Make Purchase Invoice,Faire la facture d'achat, @@ -3485,12 +3175,6 @@ Mark Work From Home,Mark Work From Home, Master,Maître, Max strength cannot be less than zero.,La force maximale ne peut pas être inférieure à zéro., Maximum attempts for this quiz reached!,Nombre maximal de tentatives pour ce quiz atteint!, -Message,Message, -Missing Values Required,Valeurs Manquantes Requises, -Mobile No,N° Mobile, -Mobile Number,Numéro de Mobile, -Month,Mois, -Name,Nom, Near you,Près de toi, Net Profit/Loss,Résultat net, New Expense,Nouvelle dépense, @@ -3509,10 +3193,8 @@ No outstanding invoices require exchange rate revaluation,Aucune facture en atte No reviews yet,Pas encore d'avis, No views yet,Pas encore de vue, Non stock items,Articles hors stock, -Not Allowed,Non Autorisé, Not allowed to create accounting dimension for {0},Non autorisé à créer une dimension comptable pour {0}, Not permitted. Please disable the Lab Test Template,Pas permis. Veuillez désactiver le modèle de test de laboratoire, -Note,Note, Notes: ,Remarques :, On Converting Opportunity,Sur l'opportunité de conversion, On Purchase Order Submission,Sur soumission de commande, @@ -3520,13 +3202,11 @@ On Sales Order Submission,Envoi de commande client, On Task Completion,En fin de tâche, On {0} Creation,Sur {0} Creation, Only .csv and .xlsx files are supported currently,Seuls les fichiers .csv et .xlsx sont actuellement pris en charge., -Open,Ouvert, Open Contact,Contact ouvert, Open Lead,Ouvrir le Lead, Opening and Closing,Ouverture et fermeture, Operating Cost as per Work Order / BOM,Coût d'exploitation selon l'ordre de fabrication / nomenclature, Order Amount,Montant de la commande, -Page {0} of {1},Page {0} sur {1}, Paid amount cannot be less than {0},Le montant payé ne peut pas être inférieur à {0}, Parent Company must be a group company,La société mère doit être une société du groupe, Passing Score value should be between 0 and 100,La note de passage doit être comprise entre 0 et 100, @@ -3535,11 +3215,9 @@ Pause,Pause, Pay,Payer, Payment Document Type,Type de document de paiement, Payment Name,Nom du paiement, -Pending,En Attente, Performance,Performance, Period based On,Période basée sur, Perpetual inventory required for the company {0} to view this report.,Inventaire permanent requis pour que la société {0} puisse consulter ce rapport., -Phone,Téléphone, Pick List,Liste de sélection, Plaid authentication error,Erreur d'authentification du plaid, Plaid public token error,Erreur de jeton public Plaid, @@ -3570,14 +3248,11 @@ Please set up the Campaign Schedule in the Campaign {0},Configurez le calendrier Please set valid GSTIN No. in Company Address for company {0},Veuillez définir un numéro GSTIN valide dans l'adresse de l'entreprise pour l'entreprise {0}, Please set {0},Veuillez définir {0},customer Please setup a default bank account for company {0},Veuillez configurer un compte bancaire par défaut pour la société {0}., -Please specify,Veuillez spécifier, Please specify a {0},Veuillez spécifier un {0},lead -Priority,Priorité, Priority has been changed to {0}.,La priorité a été changée en {0}., Priority {0} has been repeated.,La priorité {0} a été répétée., Processing XML Files,Traitement des fichiers XML, Profitability,Rentabilité, -Project,Projet, Provide the academic year and set the starting and ending date.,Indiquez l'année universitaire et définissez la date de début et de fin., Public token is missing for this bank,Un jeton public est manquant pour cette banque, Publish 1 Item,Publier 1 élément, @@ -3595,30 +3270,22 @@ Qty of Finished Goods Item,Quantité de produits finis, Quality Inspection required for Item {0} to submit,Inspection de qualité requise pour que l'élément {0} soit envoyé, Quantity to Manufacture,Quantité à fabriquer, Quantity to Manufacture can not be zero for the operation {0},La quantité à fabriquer ne peut pas être nulle pour l'opération {0}, -Quarterly,Trimestriel, -Queued,File d'Attente, -Quick Entry,Écriture Rapide, Quiz {0} does not exist,Le questionnaire {0} n'existe pas, Quotation Amount,Montant du devis, Rate or Discount is required for the price discount.,Le prix ou la remise est requis pour la remise., -Reason,Raison, Reconcile Entries,Réconcilier les entrées, Reconcile this account,Réconcilier ce compte, Reconciled,Réconcilié, Recruitment,Recrutement, -Red,Rouge, Release date must be in the future,La date de sortie doit être dans le futur, Relieving Date must be greater than or equal to Date of Joining,La date de libération doit être supérieure ou égale à la date d'adhésion, -Rename,Renommer, Rename Not Allowed,Renommer non autorisé, Report Item,Élément de rapport, Report this Item,Signaler cet article, Reserved Qty for Subcontract: Raw materials quantity to make subcontracted items.,Quantité réservée pour la sous-traitance: quantité de matières premières pour fabriquer des articles sous-traités., -Reset,Réinitialiser, Reset Service Level Agreement,Réinitialiser l'accord de niveau de service, Resetting Service Level Agreement.,Réinitialisation de l'accord de niveau de service., Return amount cannot be greater unclaimed amount,Le montant du retour ne peut pas être supérieur au montant non réclamé, -Review,La revue, Room,Chambre, Room Type,Type de chambre, Row # ,Ligne #, @@ -3643,47 +3310,36 @@ Row {0}:Sibling Date of Birth cannot be greater than today.,Ligne {0}: la date d Row({0}): {1} is already discounted in {2},Ligne ({0}): {1} est déjà réduit dans {2}., Rows Added in {0},Lignes ajoutées dans {0}, Rows Removed in {0},Lignes supprimées dans {0}, -Save,sauvegarder, Save Item,Enregistrer l'élément, Saved Items,Articles sauvegardés, Search Items ...,Rechercher des articles ..., Search for a payment,Rechercher un paiement, Search for anything ...,Rechercher n'importe quoi ..., -Search results for,Résultats de recherche pour, Select Difference Account,Sélectionnez compte différentiel, Select a Default Priority.,Sélectionnez une priorité par défaut., Select a company,Sélectionnez une entreprise, Select finance book for the item {0} at row {1},Sélectionnez le livre de financement pour l'élément {0} à la ligne {1}., Select only one Priority as Default.,Sélectionnez une seule priorité par défaut., Seller Information,Information du vendeur, -Send,Envoyer, Send a message,Envoyer un message, -Sending,Envoi, Sends Mails to lead or contact based on a Campaign schedule,Envoie des courriers à diriger ou à contacter en fonction d'un calendrier de campagne, Serial Number Created,Numéro de série créé, Serial Numbers Created,Numéros de série créés, Serial no(s) required for serialized item {0},N ° de série requis pour l'article sérialisé {0}, Series,Séries, -Server Error,Erreur du Serveur, Service Level Agreement has been changed to {0}.,L'accord de niveau de service a été remplacé par {0}., Service Level Agreement was reset.,L'accord de niveau de service a été réinitialisé., Service Level Agreement with Entity Type {0} and Entity {1} already exists.,L'accord de niveau de service avec le type d'entité {0} et l'entité {1} existe déjà., Set Meta Tags,Définir les balises méta, Set {0} in company {1},Définissez {0} dans l'entreprise {1}, -Setup,Configuration, Shift Management,Gestion des quarts, Show Future Payments,Afficher les paiements futurs, Show Linked Delivery Notes,Afficher les bons de livraison liés, Show Sales Person,Afficher le vendeur, Show Stock Ageing Data,Afficher les données sur le vieillissement des stocks, Show Warehouse-wise Stock,Afficher le stock entre les magasins, -Size,Taille, Something went wrong while evaluating the quiz.,Quelque chose s'est mal passé lors de l'évaluation du quiz., -Sr,Sr, -Start,Démarrer, Start Date cannot be before the current date,La date de début ne peut pas être antérieure à la date du jour, -Start Time,Heure de Début, -Status,Statut, Status must be Cancelled or Completed,Le statut doit être annulé ou complété, Stock Balance Report,Rapport de solde des stocks, Stock Entry has been already created against this Pick List,Une entrée de stock a déjà été créée dans cette liste de choix, @@ -3692,10 +3348,8 @@ Stock Value ({0}) and Account Balance ({1}) are out of sync for account {2} and Stores - {0},Magasins - {0}, Student with email {0} does not exist,Étudiant avec le courrier électronique {0} n'existe pas, Submit Review,Poster un commentaire, -Submitted,Valider, Supplier Addresses And Contacts,Adresses et contacts des fournisseurs, Synchronize this account,Synchroniser ce compte, -Tag,Étiquette, Target Location is required while receiving Asset {0} from an employee,L'emplacement cible est requis lors de la réception de l'élément {0} d'un employé, Target Location is required while transferring Asset {0},L'emplacement cible est requis lors du transfert de l'élément {0}, Target Location or To Employee is required while receiving Asset {0},L'emplacement cible ou l'employé est requis lors de la réception de l'élément {0}, @@ -3703,7 +3357,6 @@ Task's {0} End Date cannot be after Project's End Date.,La date de fin {0} de la Task's {0} Start Date cannot be after Project's End Date.,La date de début {0} de la tâche ne peut pas être postérieure à la date de fin du projet., Tax Account not specified for Shopify Tax {0},Compte de taxe non spécifié pour Shopify Tax {0}, Tax Total,Total de la taxe, -Template,Modèle, The Campaign '{0}' already exists for the {1} '{2}',La campagne '{0}' existe déjà pour le {1} '{2}'., The difference between from time and To Time must be a multiple of Appointment,La différence entre from time et To Time doit être un multiple de Appointment, The field Asset Account cannot be blank,Le champ Compte d'actif ne peut pas être vide, @@ -3720,19 +3373,13 @@ This bank account is already synchronized,Ce compte bancaire est déjà synchron This bank transaction is already fully reconciled,Cette transaction bancaire est déjà totalement réconciliée, This page keeps track of items you want to buy from sellers.,Cette page répertorie les articles que vous souhaitez acheter auprès des vendeurs., This page keeps track of your items in which buyers have showed some interest.,Cette page conserve une trace de vos articles pour lesquels les acheteurs ont manifesté un certain intérêt., -Thursday,Jeudi, -Title,Titre, "To allow over billing, update ""Over Billing Allowance"" in Accounts Settings or the Item.","Pour autoriser la facturation excédentaire, mettez à jour "Provision de facturation excédentaire" dans les paramètres de compte ou le poste.", "To allow over receipt / delivery, update ""Over Receipt/Delivery Allowance"" in Stock Settings or the Item.","Pour autoriser le dépassement de réception / livraison, mettez à jour "Limite de dépassement de réception / livraison" dans les paramètres de stock ou le poste.", -Total,Total, Total Payment Request amount cannot be greater than {0} amount,Le montant total de la demande de paiement ne peut être supérieur à {0}., Total payments amount can't be greater than {},Le montant total des paiements ne peut être supérieur à {}, -Totals,Totaux, Transactions already retreived from the statement,Transactions déjà extraites de la déclaration, Transfer Material to Supplier,Transfert de matériel au fournisseur, Transport Receipt No and Date are mandatory for your chosen Mode of Transport,Le numéro de reçu de transport et la date sont obligatoires pour le mode de transport choisi, -Tuesday,Mardi, -Type,Type, Unable to find the time slot in the next {0} days for the operation {1}.,Impossible de trouver l'intervalle de temps dans les {0} jours suivants pour l'opération {1}., Unable to update remote activity,Impossible de mettre à jour l'activité à distance, Unknown Caller,Appelant inconnu, @@ -3740,13 +3387,10 @@ Unlink external integrations,Dissocier les intégrations externes, Unpublish Item,Annuler la publication, Unreconciled,Non réconcilié, Unsupported GST Category for E-Way Bill JSON generation,Catégorie GST non prise en charge pour la génération e-Way Bill JSON, -Update,Mettre à Jour, Update Taxes for Items,Mettre à jour les taxes pour les articles, "Upload a bank statement, link or reconcile a bank account","Télécharger un relevé bancaire, un lien ou un rapprochement d'un compte bancaire", Upload a statement,Télécharger une déclaration, Use a name that is different from previous project name,Utilisez un nom différent du nom du projet précédent, -User {0} is disabled,Utilisateur {0} est désactivé, -Users and Permissions,Utilisateurs et Autorisations, Valuation Rate required for Item {0} at row {1},Taux de valorisation requis pour le poste {0} à la ligne {1}, Values Out Of Sync,Valeurs désynchronisées, Vehicle Type is required if Mode of Transport is Road,Le type de véhicule est requis si le mode de transport est la route, @@ -3755,15 +3399,11 @@ Verify Email,Vérifier les courriels, View,Vue, View all issues from {0},Afficher tous les problèmes de {0}, View call log,Voir le journal des appels, -Warehouse,Entrepôt, Warehouse not found against the account {0},Entrepôt introuvable sur le compte {0}, -Welcome to {0},Bienvenue sur {0}, Why do think this Item should be removed?,Pourquoi pensez-vous que cet élément devrait être supprimé?, Work Order {0}: Job Card not found for the operation {1},Bon de travail {0}: carte de travail non trouvée pour l'opération {1}, Workday {0} has been repeated.,La journée de travail {0} a été répétée., XML Files Processed,Fichiers XML traités, -Year,Année, -Yearly,Annuel, You are not allowed to enroll for this course,Vous n'êtes pas autorisé à vous inscrire à ce cours, You are not enrolled in program {0},Vous n'êtes pas inscrit au programme {0}, You can Feature upto 8 items.,Vous pouvez présenter jusqu'à 8 éléments., @@ -3776,7 +3416,6 @@ Your Featured Items,Vos articles en vedette, Your Items,Vos articles, Your Profile,Votre profil, Your rating:,Votre note :, -and,et, e-Way Bill already exists for this document,e-Way Bill existe déjà pour ce document, woocommerce - {0},woocommerce - {0}, {0} Coupon used are {1}. Allowed quantity is exhausted,Le {0} coupon utilisé est {1}. La quantité autorisée est épuisée, @@ -3788,7 +3427,6 @@ woocommerce - {0},woocommerce - {0}, {0} is not a company bank account,{0} n'est pas un compte bancaire d'entreprise, {0} is not a group node. Please select a group node as parent cost center,{0} n'est pas un nœud de groupe. Veuillez sélectionner un nœud de groupe comme centre de coûts parent, {0} is not the default supplier for any items.,{0} n'est le fournisseur par défaut d'aucun élément., -{0} is required,{0} est nécessaire, {0}: {1} must be less than {2},{0}: {1} doit être inférieur à {2}, {} is required to generate E-Way Bill JSON,{} est requis pour générer e-Way Bill JSON, "Invalid lost reason {0}, please create a new lost reason","Motif perdu non valide {0}, veuillez créer un nouveau motif perdu", @@ -3797,20 +3435,6 @@ Total Expense,Dépense totale, Total Expense This Year,Dépenses totales cette année, Total Income,Revenu total, Total Income This Year,Revenu total cette année, -Barcode,code à barre, -Clear,Clair, -Comments,Commentaires, -DocType,DocType, -Download,Télécharger, -Left,Parti, -Link,Lien, -New,Nouveau, -Print,Impression, -Reference Name,Nom de référence, -Refresh,Actualiser, -Success,Succès, -Time,Temps, -Value,Valeur, Actual,Réel, Add to Cart,Ajouter au Panier, Days Since Last Order,Jours depuis la dernière commande, @@ -3824,10 +3448,6 @@ Sales Person,Vendeur, To date cannot be before From date,La date de fin ne peut être antérieure à la date de début, Write Off,Reprise, {0} Created,{0} Créé, -Email Id,Identifiant Email, -No,Non, -Reference Doctype,DocType de la Référence, -Yes,Oui, Actual ,Réel, Add to cart,Ajouter au Panier, Budget,Budget, @@ -3838,16 +3458,13 @@ Download as JSON,Télécharger en JSON, End date can not be less than start date,La date de Fin ne peut pas être antérieure à la Date de Début, For Default Supplier (Optional),Pour le fournisseur par défaut (facultatif), From date cannot be greater than To date,La Date Initiale ne peut pas être postérieure à la Date Finale, -Group by,Grouper Par, In stock,En stock, Item name,Libellé de l'article, Minimum Qty,Quantité minimum, More details,Plus de détails, Nature of Supplies,Nature des fournitures, -No Items found.,Aucun article trouvé., No students found,Aucun étudiant trouvé, Not in stock,En rupture, -Not permitted,Pas permis, Open Issues ,Tickets ouverts, Open Projects ,Projets ouverts, Open To Do ,ToDo ouvertes, @@ -3872,8 +3489,6 @@ Write off,Reprise, hours,heures, received from,reçu de, to,à, -Cards,Cartes, -Percentage,Pourcentage, Failed to setup defaults for country {0}. Please contact support@erpnext.com,Échec de la configuration des paramètres par défaut pour le pays {0}. Veuillez contacter support@erpnext.com, Row #{0}: Item {1} is not a Serialized/Batched Item. It cannot have a Serial No/Batch No against it.,Ligne # {0}: l'article {1} n'est pas un article sérialisé / en lot. Il ne peut pas avoir de numéro de série / de lot contre lui., Please set {0},Veuillez définir {0}, @@ -3911,9 +3526,6 @@ Note: Item {0} added multiple times,Remarque: l'élément {0} a été ajouté pl YouTube,Youtube, Vimeo,Vimeo, Publish Date,Date de publication, -Duration,Durée, -Advanced Settings,Réglages avancés, -Path,Chemin, Components,Composants, Verified By,Vérifié Par, Invalid naming series (. missing) for {0},Masque de numérotation non valide (. Manquante) pour {0}, @@ -4230,7 +3842,6 @@ Is Finance Cost Adjustment,Est un ajustement des coûts financiers, Is Income Tax Liability,Est une dette d'impôt sur le revenu, Is Income Tax Expense,Est une dépense d'impôt sur le revenu, Cash Flow Mapping Accounts,Comptes du Mapping des Flux de Trésorerie, -account,Compte, Cash Flow Mapping Template,Modèle de Mapping des Flux de Trésorerie, Cash Flow Mapping Template Details,Détails du Modèle de Mapping des Flux de Trésorerie, POS-CLO-,POS-CLO-, @@ -4474,7 +4085,6 @@ Payment Schedule,Calendrier de paiement, Invoice Portion,Pourcentage de facturation, Payment Amount,Montant du paiement, Payment Term Name,Nom du terme de paiement, -Due Date Based On,Date d'échéance basée sur, Day(s) after invoice date,Jour (s) après la date de la facture, Day(s) after the end of the invoice month,Jour (s) après la fin du mois de facture, Month(s) after the end of the invoice month,Mois (s) après la fin du mois de la facture, @@ -4769,7 +4379,6 @@ Asset Account,Compte d'actif, (including),(compris), ACC-SH-.YYYY.-,ACC-SH-.YYYY.-, Folio no.,No. de Folio, -Address and Contacts,Adresse et Contacts, Contact List,Liste de contacts, Hidden list maintaining the list of contacts linked to Shareholder,Liste cachée maintenant la liste des contacts liés aux actionnaires, Specify conditions to calculate shipping amount,Spécifier les conditions pour calculer le montant de la livraison, @@ -5157,9 +4766,6 @@ Supplier Scorecard Scoring Criteria,Critères de Notation de la Fiche d'Évaluat Score,Score, Supplier Scorecard Scoring Standing,Classement de la Fiche d'Évaluation Fournisseur, Standing Name,Nom du Classement, -Purple,Violet, -Yellow,jaune, -Orange,orange, Min Grade,Note Minimale, Max Grade,Note Maximale, Warn Purchase Orders,Avertir lors de Bons de Commande, @@ -5194,7 +4800,6 @@ Unverified,Non vérifié, Customer Details,Détails du client, Phone Number,Numéro de téléphone, Skype ID,ID Skype, -Linked Documents,Documents liés, Appointment With,Rendez-vous avec, Calendar Event,Événement de calendrier, Appointment Booking Settings,Paramètres de réservation de rendez-vous, @@ -5212,7 +4817,6 @@ Success Settings,Paramètres de réussite, Success Redirect URL,URL de redirection réussie, "Leave blank for home.\nThis is relative to site URL, for example ""about"" will redirect to ""https://yoursitename.com/about""","Laissez vide pour la maison. Ceci est relatif à l'URL du site, par exemple "about" redirigera vers "https://yoursitename.com/about"", Appointment Booking Slots,Horaires de prise de rendez-vous, -Day Of Week,Jour de la Semaine, From Time ,Horaire de Début, Campaign Email Schedule,Calendrier des e-mails de campagne, Send After (days),Envoyer après (jours), @@ -5255,7 +4859,6 @@ Campaign Name,Nom de la Campagne, Follow Up,Suivre, Next Contact By,Contact Suivant Par, Next Contact Date,Date du Prochain Contact, -Ends On,Se termine le, Address & Contact,Adresse & Contact, Mobile No.,N° Mobile., Lead Type,Type de Lead, @@ -5302,8 +4905,6 @@ Social Media Post,Publication sur les réseaux sociaux, Post Status,Statut du message, Posted,Publié, Share On,Partager sur, -Twitter,Twitter, -LinkedIn,LinkedIn, Twitter Post Id,Identifiant de publication Twitter, LinkedIn Post Id,Identifiant de publication LinkedIn, Tweet,Tweet, @@ -5853,7 +5454,6 @@ Require Result Value,Nécessite la Valeur du Résultat, Normal Test Template,Modèle de Test Normal, Patient Demographics,Démographie du Patient, HLC-PAT-.YYYY.-,HLC-PAT-. AAAA.-, -Middle Name (optional),Prénom (facultatif), Inpatient Status,Statut d'hospitalisation, "If ""Link Customer to Patient"" is checked in Healthcare Settings and an existing Customer is not selected then, a Customer will be created for this Patient for recording transactions in Accounts module.","Si «Lier le client au patient» est coché dans les paramètres de soins de santé et qu'un client existant n'est pas sélectionné, un client sera créé pour ce patient pour enregistrer les transactions dans le module Comptes.", Personal and Social History,Antécédents Personnels et Sociaux, @@ -6180,7 +5780,6 @@ Maintenance Schedule Detail,Détails de l'Échéancier d'Entretien, Scheduled Date,Date Prévue, Actual Date,Date Réelle, Maintenance Schedule Item,Article de Calendrier d'Entretien, -Random,aléatoire, No of Visits,Nb de Visites, MAT-MVS-.YYYY.-,MAT-MVS-. AAAA.-, Maintenance Date,Date de l'Entretien, @@ -6430,7 +6029,6 @@ Member Since,Membre depuis, Payment ID,ID de paiement, Membership Settings,Paramètres d'adhésion, Enable RazorPay For Memberships,Activer RazorPay pour les adhésions, -RazorPay Settings,Paramètres de RazorPay, Billing Cycle,Cycle de facturation, Billing Frequency,Fréquence de facturation, "The number of billing cycles for which the customer should be charged. For example, if a customer is buying a 1-year membership that should be billed on a monthly basis, this value should be 12.","Le nombre de cycles de facturation pour lesquels le client doit être facturé. Par exemple, si un client achète un abonnement d'un an qui doit être facturé sur une base mensuelle, cette valeur doit être de 12.", @@ -7009,7 +6607,7 @@ Leave blank to use the standard Delivery Note format,Laissez vide pour utiliser Send with Attachment,Envoyer avec pièce jointe, Delay between Delivery Stops,Délai entre les arrêts de livraison, Delivery Stop,Étape de Livraison, -Lock,Fermer à clé, +Lock,Verrouiller, Visited,Visité, Order Information,Informations sur la commande, Contact Information,Informations de contact, @@ -8191,7 +7789,6 @@ Topics updated,Sujets mis à jour, Academic Term and Program,Terme académique et programme, Please remove this item and try to submit again or update the posting time.,Veuillez supprimer cet élément et réessayer de le valider ou mettre à jour l'heure de publication., Failed to Authenticate the API key.,Échec de l'authentification de la clé API., -Invalid Credentials,Les informations d'identification invalides, URL can only be a string,L'URL ne peut être qu'une chaîne, "Here is your webhook secret, this will be shown to you only once.","Voici votre secret de webhook, il ne vous sera montré qu'une seule fois.", The payment for this membership is not paid. To generate invoice fill the payment details,"Le paiement de cette adhésion n'est pas payé. Pour générer une facture, remplissez les détails du paiement", @@ -8756,7 +8353,6 @@ Journal Energy Point,Historique des points d'énergies, Billing Address Details,Adresse de facturation (détails) Supplier Address Details,Adresse Fournisseur (détails) Retail,Commerce, -Users,Utilisateurs, Permission Manager,Gestion des permissions, Fetch Timesheet,Récuprer les temps saisis, Get Supplier Group Details,Appliquer les informations depuis le Groupe de fournisseur, From 55dbcee36a2acf4aa41c66147c263a85ef606f81 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Fri, 20 Oct 2023 17:16:54 +0530 Subject: [PATCH 11/25] refactor: gain_loss posting date fields in the allocation table --- .../payment_reconciliation_allocation.json | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/payment_reconciliation_allocation/payment_reconciliation_allocation.json b/erpnext/accounts/doctype/payment_reconciliation_allocation/payment_reconciliation_allocation.json index ec718aa70d31..2fddd85732e7 100644 --- a/erpnext/accounts/doctype/payment_reconciliation_allocation/payment_reconciliation_allocation.json +++ b/erpnext/accounts/doctype/payment_reconciliation_allocation/payment_reconciliation_allocation.json @@ -151,11 +151,16 @@ "fieldtype": "Link", "label": "Cost Center", "options": "Cost Center" + }, + { + "fieldname": "gain_loss_posting_date", + "fieldtype": "Date", + "label": "Difference Posting Date" } ], "istable": 1, "links": [], - "modified": "2023-09-03 07:52:33.684217", + "modified": "2023-10-23 10:44:56.066303", "modified_by": "Administrator", "module": "Accounts", "name": "Payment Reconciliation Allocation", From 5323bb7beeb6526d16bcb19fc2f3acd3a95927e6 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Sun, 22 Oct 2023 08:59:52 +0530 Subject: [PATCH 12/25] refactor: introduce fields in popup --- .../payment_reconciliation/payment_reconciliation.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.js b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.js index d9f00befa902..7599b5e85205 100644 --- a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.js +++ b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.js @@ -229,6 +229,7 @@ erpnext.accounts.PaymentReconciliationController = class PaymentReconciliationCo this.data = []; const dialog = new frappe.ui.Dialog({ title: __("Select Difference Account"), + size: 'extra-large', fields: [ { fieldname: "allocation", @@ -252,6 +253,13 @@ erpnext.accounts.PaymentReconciliationController = class PaymentReconciliationCo in_list_view: 1, read_only: 1 }, { + fieldtype:'Date', + fieldname:"gain_loss_posting_date", + label: __("Posting Date"), + in_list_view: 1, + reqd: 1, + }, { + fieldtype:'Link', options: 'Account', in_list_view: 1, @@ -285,6 +293,7 @@ erpnext.accounts.PaymentReconciliationController = class PaymentReconciliationCo args.forEach(d => { frappe.model.set_value("Payment Reconciliation Allocation", d.docname, "difference_account", d.difference_account); + }); this.reconcile_payment_entries(); @@ -300,6 +309,7 @@ erpnext.accounts.PaymentReconciliationController = class PaymentReconciliationCo 'reference_name': d.reference_name, 'difference_amount': d.difference_amount, 'difference_account': d.difference_account, + 'gain_loss_posting_date': d.gain_loss_posting_date }); } }); From b099590b2c1dcd041b833af50e99eb3e7988c595 Mon Sep 17 00:00:00 2001 From: Richard Case <110036763+casesolved-co-uk@users.noreply.github.com> Date: Mon, 23 Oct 2023 07:10:07 +0100 Subject: [PATCH 13/25] fix: Quality Inspection Parameter migration - DuplicateEntryError due to case sensitivity (#37499) * fix: account for case-insensitive database primary key for parameter names * chore: linting --- .../convert_qi_parameter_to_link_field.py | 31 ++++++++++--------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/erpnext/patches/v13_0/convert_qi_parameter_to_link_field.py b/erpnext/patches/v13_0/convert_qi_parameter_to_link_field.py index efbb96c100a0..e53bdf8f19e3 100644 --- a/erpnext/patches/v13_0/convert_qi_parameter_to_link_field.py +++ b/erpnext/patches/v13_0/convert_qi_parameter_to_link_field.py @@ -3,23 +3,24 @@ def execute(): frappe.reload_doc("stock", "doctype", "quality_inspection_parameter") + params = set() - # get all distinct parameters from QI readigs table - reading_params = frappe.db.get_all( - "Quality Inspection Reading", fields=["distinct specification"] - ) - reading_params = [d.specification for d in reading_params] + # get all parameters from QI readings table + for (p,) in frappe.db.get_all( + "Quality Inspection Reading", fields=["specification"], as_list=True + ): + params.add(p.strip()) - # get all distinct parameters from QI Template as some may be unused in QI - template_params = frappe.db.get_all( - "Item Quality Inspection Parameter", fields=["distinct specification"] - ) - template_params = [d.specification for d in template_params] + # get all parameters from QI Template as some may be unused in QI + for (p,) in frappe.db.get_all( + "Item Quality Inspection Parameter", fields=["specification"], as_list=True + ): + params.add(p.strip()) - params = list(set(reading_params + template_params)) + # because db primary keys are case insensitive, so duplicates will cause an exception + params = set({x.casefold(): x for x in params}.values()) for parameter in params: - if not frappe.db.exists("Quality Inspection Parameter", parameter): - frappe.get_doc( - {"doctype": "Quality Inspection Parameter", "parameter": parameter, "description": parameter} - ).insert(ignore_permissions=True) + frappe.get_doc( + {"doctype": "Quality Inspection Parameter", "parameter": parameter, "description": parameter} + ).insert(ignore_permissions=True) From 7e600a6494d7f07c6fd2b8f1cc71857801a2573c Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Sun, 22 Oct 2023 20:26:45 +0530 Subject: [PATCH 14/25] refactor: pass gain loss posting date to controller --- .../payment_reconciliation/payment_reconciliation.js | 2 ++ .../payment_reconciliation/payment_reconciliation.py | 2 ++ .../payment_reconciliation_allocation.json | 1 + erpnext/accounts/utils.py | 4 +++- erpnext/controllers/accounts_controller.py | 6 ++++-- 5 files changed, 12 insertions(+), 3 deletions(-) diff --git a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.js b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.js index 7599b5e85205..fc90c3dec04f 100644 --- a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.js +++ b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.js @@ -293,6 +293,8 @@ erpnext.accounts.PaymentReconciliationController = class PaymentReconciliationCo args.forEach(d => { frappe.model.set_value("Payment Reconciliation Allocation", d.docname, "difference_account", d.difference_account); + frappe.model.set_value("Payment Reconciliation Allocation", d.docname, + "gain_loss_posting_date", d.gain_loss_posting_date); }); diff --git a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py index 3285a529d2d8..1626f25f3ee3 100644 --- a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py +++ b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py @@ -328,6 +328,7 @@ def allocate_entries(self, args): res.difference_amount = self.get_difference_amount(pay, inv, res["allocated_amount"]) res.difference_account = default_exchange_gain_loss_account res.exchange_rate = inv.get("exchange_rate") + res.update({"gain_loss_posting_date": pay.get("posting_date")}) if pay.get("amount") == 0: entries.append(res) @@ -434,6 +435,7 @@ def get_payment_details(self, row, dr_or_cr): "allocated_amount": flt(row.get("allocated_amount")), "difference_amount": flt(row.get("difference_amount")), "difference_account": row.get("difference_account"), + "difference_posting_date": row.get("gain_loss_posting_date"), "cost_center": row.get("cost_center"), } ) diff --git a/erpnext/accounts/doctype/payment_reconciliation_allocation/payment_reconciliation_allocation.json b/erpnext/accounts/doctype/payment_reconciliation_allocation/payment_reconciliation_allocation.json index 2fddd85732e7..5b8556e7c830 100644 --- a/erpnext/accounts/doctype/payment_reconciliation_allocation/payment_reconciliation_allocation.json +++ b/erpnext/accounts/doctype/payment_reconciliation_allocation/payment_reconciliation_allocation.json @@ -19,6 +19,7 @@ "is_advance", "section_break_5", "difference_amount", + "gain_loss_posting_date", "column_break_7", "difference_account", "exchange_rate", diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py index 555ed4ffa2ed..f2691fb9806d 100644 --- a/erpnext/accounts/utils.py +++ b/erpnext/accounts/utils.py @@ -679,7 +679,9 @@ def update_reference_in_payment_entry( if not skip_ref_details_update_for_pe: payment_entry.set_missing_ref_details() payment_entry.set_amounts() - payment_entry.make_exchange_gain_loss_journal() + payment_entry.make_exchange_gain_loss_journal( + frappe._dict({"difference_posting_date": d.difference_posting_date}) + ) if not do_not_save: payment_entry.save(ignore_permissions=True) diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py index cc5d643c1473..6efe631a29f0 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -1178,7 +1178,9 @@ def make_exchange_gain_loss_journal(self, args: dict = None) -> None: self.name, arg.get("referenced_row"), ): - posting_date = frappe.db.get_value(arg.voucher_type, arg.voucher_no, "posting_date") + posting_date = arg.get("difference_posting_date") or frappe.db.get_value( + arg.voucher_type, arg.voucher_no, "posting_date" + ) je = create_gain_loss_journal( self.company, posting_date, @@ -1261,7 +1263,7 @@ def make_exchange_gain_loss_journal(self, args: dict = None) -> None: je = create_gain_loss_journal( self.company, - self.posting_date, + args.get("difference_posting_date") if args else self.posting_date, self.party_type, self.party, party_account, From 514d5434a3ae24e2c7839fbd76a115d6c0841513 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Mon, 23 Oct 2023 12:32:10 +0530 Subject: [PATCH 15/25] test: varying posting date for gain loss journal --- .../tests/test_accounts_controller.py | 69 ++++++++++++++++++- 1 file changed, 68 insertions(+), 1 deletion(-) diff --git a/erpnext/controllers/tests/test_accounts_controller.py b/erpnext/controllers/tests/test_accounts_controller.py index 391258fde778..97d3c5c32de3 100644 --- a/erpnext/controllers/tests/test_accounts_controller.py +++ b/erpnext/controllers/tests/test_accounts_controller.py @@ -7,7 +7,7 @@ from frappe import qb from frappe.query_builder.functions import Sum from frappe.tests.utils import FrappeTestCase, change_settings -from frappe.utils import add_days, flt, nowdate +from frappe.utils import add_days, flt, getdate, nowdate from erpnext import get_default_cost_center from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry @@ -614,6 +614,73 @@ def test_14_same_payment_split_against_invoice(self): self.assertEqual(exc_je_for_si, []) self.assertEqual(exc_je_for_pe, []) + def test_15_gain_loss_on_different_posting_date(self): + # Invoice in Foreign Currency + si = self.create_sales_invoice( + posting_date=add_days(nowdate(), -2), qty=2, conversion_rate=80, rate=1 + ) + # Payment + pe = ( + self.create_payment_entry(posting_date=add_days(nowdate(), -1), amount=2, source_exc_rate=75) + .save() + .submit() + ) + + # There should be outstanding in both currencies + si.reload() + self.assertEqual(si.outstanding_amount, 2) + self.assert_ledger_outstanding(si.doctype, si.name, 160.0, 2.0) + + # Reconcile the remaining amount + pr = frappe.get_doc("Payment Reconciliation") + pr.company = self.company + pr.party_type = "Customer" + pr.party = self.customer + pr.receivable_payable_account = self.debit_usd + pr.get_unreconciled_entries() + self.assertEqual(len(pr.invoices), 1) + self.assertEqual(len(pr.payments), 1) + invoices = [x.as_dict() for x in pr.invoices] + payments = [x.as_dict() for x in pr.payments] + pr.allocate_entries(frappe._dict({"invoices": invoices, "payments": payments})) + pr.allocation[0].gain_loss_posting_date = add_days(nowdate(), 1) + pr.reconcile() + + # Exchange Gain/Loss Journal should've been created. + exc_je_for_si = self.get_journals_for(si.doctype, si.name) + exc_je_for_pe = self.get_journals_for(pe.doctype, pe.name) + self.assertNotEqual(exc_je_for_si, []) + self.assertEqual(len(exc_je_for_si), 1) + self.assertEqual(len(exc_je_for_pe), 1) + self.assertEqual(exc_je_for_si[0], exc_je_for_pe[0]) + + self.assertEqual( + frappe.db.get_value("Journal Entry", exc_je_for_si[0].parent, "posting_date"), + getdate(add_days(nowdate(), 1)), + ) + + self.assertEqual(len(pr.invoices), 0) + self.assertEqual(len(pr.payments), 0) + + # There should be no outstanding + si.reload() + self.assertEqual(si.outstanding_amount, 0) + self.assert_ledger_outstanding(si.doctype, si.name, 0.0, 0.0) + + # Cancel Payment + pe.reload() + pe.cancel() + + si.reload() + self.assertEqual(si.outstanding_amount, 2) + self.assert_ledger_outstanding(si.doctype, si.name, 160.0, 2.0) + + # Exchange Gain/Loss Journal should've been cancelled + exc_je_for_si = self.get_journals_for(si.doctype, si.name) + exc_je_for_pe = self.get_journals_for(pe.doctype, pe.name) + self.assertEqual(exc_je_for_si, []) + self.assertEqual(exc_je_for_pe, []) + def test_20_journal_against_sales_invoice(self): # Invoice in Foreign Currency si = self.create_sales_invoice(qty=1, conversion_rate=80, rate=1) From 2b64e1ca8b3e9162d4320552e1104385f010841f Mon Sep 17 00:00:00 2001 From: Imesha Sudasingha Date: Mon, 23 Oct 2023 15:28:52 +0530 Subject: [PATCH 16/25] chore: typo in description (#37636) chore: typo in description --- erpnext/stock/doctype/item/item.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/stock/doctype/item/item.json b/erpnext/stock/doctype/item/item.json index 54491bbee362..c13d3ebe0f01 100644 --- a/erpnext/stock/doctype/item/item.json +++ b/erpnext/stock/doctype/item/item.json @@ -379,7 +379,7 @@ "options": "fa fa-rss" }, { - "description": "Will also apply for variants unless overrridden", + "description": "Will also apply for variants unless overridden", "fieldname": "reorder_levels", "fieldtype": "Table", "label": "Reorder level based on Warehouse", @@ -961,4 +961,4 @@ "states": [], "title_field": "item_name", "track_changes": 1 -} \ No newline at end of file +} From a432290a828478265a8a463d05aea818c2b75914 Mon Sep 17 00:00:00 2001 From: s-aga-r Date: Mon, 23 Oct 2023 16:26:00 +0530 Subject: [PATCH 17/25] fix: ignore qty msg if From Voucher is set --- .../stock_reservation_entry.py | 38 +++++++++++-------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.py b/erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.py index c7a9e16d0ed0..81e9dfa69baf 100644 --- a/erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.py +++ b/erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.py @@ -833,13 +833,15 @@ def create_stock_reservation_entries_for_so_items( # Skip if Non-Stock Item. if not is_stock_item: - frappe.msgprint( - _("Row #{0}: Stock cannot be reserved for a non-stock Item {1}").format( - item.idx, frappe.bold(item.item_code) - ), - title=_("Stock Reservation"), - indicator="yellow", - ) + if not from_voucher_type: + frappe.msgprint( + _("Row #{0}: Stock cannot be reserved for a non-stock Item {1}").format( + item.idx, frappe.bold(item.item_code) + ), + title=_("Stock Reservation"), + indicator="yellow", + ) + item.db_set("reserve_stock", 0) continue @@ -858,13 +860,15 @@ def create_stock_reservation_entries_for_so_items( # Stock is already reserved for the item, notify the user and skip the item. if unreserved_qty <= 0: - frappe.msgprint( - _("Row #{0}: Stock is already reserved for the Item {1}.").format( - item.idx, frappe.bold(item.item_code) - ), - title=_("Stock Reservation"), - indicator="yellow", - ) + if not from_voucher_type: + frappe.msgprint( + _("Row #{0}: Stock is already reserved for the Item {1}.").format( + item.idx, frappe.bold(item.item_code) + ), + title=_("Stock Reservation"), + indicator="yellow", + ) + continue available_qty_to_reserve = get_available_qty_to_reserve(item.item_code, item.warehouse) @@ -872,7 +876,7 @@ def create_stock_reservation_entries_for_so_items( # No stock available to reserve, notify the user and skip the item. if available_qty_to_reserve <= 0: frappe.msgprint( - _("Row #{0}: No available stock to reserve for the Item {1} in Warehouse {2}.").format( + _("Row #{0}: Stock not available to reserve for the Item {1} in Warehouse {2}.").format( item.idx, frappe.bold(item.item_code), frappe.bold(item.warehouse) ), title=_("Stock Reservation"), @@ -898,7 +902,9 @@ def create_stock_reservation_entries_for_so_items( # Partial Reservation if qty_to_be_reserved < unreserved_qty: - if not item.get("qty_to_reserve") or qty_to_be_reserved < flt(item.get("qty_to_reserve")): + if not from_voucher_type and ( + not item.get("qty_to_reserve") or qty_to_be_reserved < flt(item.get("qty_to_reserve")) + ): msg = _("Row #{0}: Only {1} available to reserve for the Item {2}").format( item.idx, frappe.bold(str(qty_to_be_reserved / item.conversion_factor) + " " + item.uom), From adf313a6d3308f957b4876574e455ca750b22106 Mon Sep 17 00:00:00 2001 From: s-aga-r Date: Mon, 23 Oct 2023 17:52:59 +0530 Subject: [PATCH 18/25] test: add test case for auto-reservation from PR --- .../test_stock_reservation_entry.py | 89 ++++++++++++++++++- 1 file changed, 85 insertions(+), 4 deletions(-) diff --git a/erpnext/stock/doctype/stock_reservation_entry/test_stock_reservation_entry.py b/erpnext/stock/doctype/stock_reservation_entry/test_stock_reservation_entry.py index 9ea35ecacb1f..f4c74a8aacbd 100644 --- a/erpnext/stock/doctype/stock_reservation_entry/test_stock_reservation_entry.py +++ b/erpnext/stock/doctype/stock_reservation_entry/test_stock_reservation_entry.py @@ -5,6 +5,7 @@ import frappe from frappe.tests.utils import FrappeTestCase, change_settings +from frappe.utils import today from erpnext.selling.doctype.sales_order.sales_order import create_pick_list, make_delivery_note from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order @@ -28,10 +29,6 @@ def setUp(self) -> None: items={self.sr_item.name: self.sr_item}, warehouse=self.warehouse, qty=100 ) - def tearDown(self) -> None: - cancel_all_stock_reservation_entries() - return super().tearDown() - @change_settings("Stock Settings", {"allow_negative_stock": 0}) def test_validate_stock_reservation_settings(self) -> None: from erpnext.stock.doctype.stock_reservation_entry.stock_reservation_entry import ( @@ -568,6 +565,90 @@ def test_stock_reservation_from_pick_list(self): # Test - 3: Reserved Serial/Batch Nos should be equal to Picked Serial/Batch Nos. self.assertSetEqual(picked_sb_details, reserved_sb_details) + @change_settings( + "Stock Settings", + { + "allow_negative_stock": 0, + "enable_stock_reservation": 1, + "auto_reserve_serial_and_batch": 1, + "pick_serial_and_batch_based_on": "FIFO", + "auto_reserve_stock_for_sales_order_on_purchase": 1, + }, + ) + def test_stock_reservation_from_purchase_receipt(self): + from erpnext.buying.doctype.purchase_order.purchase_order import make_purchase_receipt + from erpnext.selling.doctype.sales_order.sales_order import make_material_request + from erpnext.stock.doctype.material_request.material_request import make_purchase_order + + items_details = create_items() + create_material_receipt(items_details, self.warehouse, qty=10) + + item_list = [] + for item_code, properties in items_details.items(): + item_list.append( + { + "item_code": item_code, + "warehouse": self.warehouse, + "qty": randint(11, 100), + "uom": properties.stock_uom, + "rate": randint(10, 400), + } + ) + + so = make_sales_order( + item_list=item_list, + warehouse=self.warehouse, + ) + + mr = make_material_request(so.name) + mr.schedule_date = today() + mr.save().submit() + + po = make_purchase_order(mr.name) + po.supplier = "_Test Supplier" + po.save().submit() + + pr = make_purchase_receipt(po.name) + pr.save().submit() + + for item in pr.items: + sre, status, reserved_qty = frappe.db.get_value( + "Stock Reservation Entry", + { + "from_voucher_type": "Purchase Receipt", + "from_voucher_no": pr.name, + "from_voucher_detail_no": item.name, + }, + ["name", "status", "reserved_qty"], + ) + + # Test - 1: SRE status should be `Reserved`. + self.assertEqual(status, "Reserved") + + # Test - 2: SRE Reserved Qty should be equal to PR Item Qty. + self.assertEqual(reserved_qty, item.qty) + + if item.serial_and_batch_bundle: + sb_details = frappe.db.get_all( + "Serial and Batch Entry", + filters={"parent": item.serial_and_batch_bundle}, + fields=["serial_no", "batch_no", "qty"], + as_list=True, + ) + reserved_sb_details = frappe.db.get_all( + "Serial and Batch Entry", + filters={"parent": sre}, + fields=["serial_no", "batch_no", "qty"], + as_list=True, + ) + + # Test - 3: Reserved Serial/Batch Nos should be equal to PR Item Serial/Batch Nos. + self.assertEqual(set(sb_details), set(reserved_sb_details)) + + def tearDown(self) -> None: + cancel_all_stock_reservation_entries() + return super().tearDown() + def create_items() -> dict: items_properties = [ From 24788ddcc085fb825d2b14145a82ced02842f512 Mon Sep 17 00:00:00 2001 From: s-aga-r Date: Mon, 23 Oct 2023 18:00:58 +0530 Subject: [PATCH 19/25] chore: add SRE link in PR Connections --- .../doctype/purchase_receipt/purchase_receipt_dashboard.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt_dashboard.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt_dashboard.py index b3ae7b58b498..71489fbb4948 100644 --- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt_dashboard.py +++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt_dashboard.py @@ -10,6 +10,7 @@ def get_data(): "Landed Cost Voucher": "receipt_document", "Auto Repeat": "reference_document", "Purchase Receipt": "return_against", + "Stock Reservation Entry": "from_voucher_no", }, "internal_links": { "Material Request": ["items", "material_request"], @@ -18,7 +19,10 @@ def get_data(): "Quality Inspection": ["items", "quality_inspection"], }, "transactions": [ - {"label": _("Related"), "items": ["Purchase Invoice", "Landed Cost Voucher", "Asset"]}, + { + "label": _("Related"), + "items": ["Purchase Invoice", "Landed Cost Voucher", "Asset", "Stock Reservation Entry"], + }, { "label": _("Reference"), "items": ["Material Request", "Purchase Order", "Quality Inspection", "Project"], From 3bfb7b79f297ff1ab6c80c810431ecebd6bedecb Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Mon, 23 Oct 2023 18:23:45 +0530 Subject: [PATCH 20/25] refactor: Remove expense included in valuation accounts (#37632) * refactor: Remove expense included in valuation accounts * test: Deprecate tests * test: Depricate tests * test: Depricate tests --- .../purchase_invoice/purchase_invoice.py | 39 +-------- .../sales_invoice/test_sales_invoice.py | 36 -------- erpnext/manufacturing/doctype/bom/bom.py | 8 +- ...se_account_in_landed_cost_voucher_taxes.py | 42 ---------- erpnext/setup/doctype/company/company.js | 3 - erpnext/setup/doctype/company/company.json | 20 +---- erpnext/setup/doctype/company/company.py | 3 - .../purchase_receipt/purchase_receipt.py | 14 +--- .../purchase_receipt/test_purchase_receipt.py | 82 ------------------- .../doctype/stock_entry/test_stock_entry.py | 12 +-- .../subcontracting_receipt.py | 6 +- 11 files changed, 17 insertions(+), 248 deletions(-) delete mode 100644 erpnext/patches/v12_0/set_expense_account_in_landed_cost_voucher_taxes.py diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py index 2f08b65ac6be..97ee5cc93bee 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py @@ -585,13 +585,12 @@ def make_gl_entries(self, gl_entries=None, from_repost=False): def get_gl_entries(self, warehouse_account=None): self.auto_accounting_for_stock = erpnext.is_perpetual_inventory_enabled(self.company) + self.asset_received_but_not_billed = self.get_company_default("asset_received_but_not_billed") + if self.auto_accounting_for_stock: self.stock_received_but_not_billed = self.get_company_default("stock_received_but_not_billed") - self.expenses_included_in_valuation = self.get_company_default("expenses_included_in_valuation") - self.asset_received_but_not_billed = self.get_company_default("asset_received_but_not_billed") else: self.stock_received_but_not_billed = None - self.expenses_included_in_valuation = None self.negative_expense_to_be_booked = 0.0 gl_entries = [] @@ -913,40 +912,6 @@ def make_item_gl_entries(self, gl_entries): ) ) - # If asset is bought through this document and not linked to PR - if self.update_stock and item.landed_cost_voucher_amount: - expenses_included_in_asset_valuation = self.get_company_default( - "expenses_included_in_asset_valuation" - ) - # Amount added through landed-cost-voucher - gl_entries.append( - self.get_gl_dict( - { - "account": expenses_included_in_asset_valuation, - "against": expense_account, - "cost_center": item.cost_center, - "remarks": self.get("remarks") or _("Accounting Entry for Stock"), - "credit": flt(item.landed_cost_voucher_amount), - "project": item.project or self.project, - }, - item=item, - ) - ) - - gl_entries.append( - self.get_gl_dict( - { - "account": expense_account, - "against": expenses_included_in_asset_valuation, - "cost_center": item.cost_center, - "remarks": self.get("remarks") or _("Accounting Entry for Stock"), - "debit": flt(item.landed_cost_voucher_amount), - "project": item.project or self.project, - }, - item=item, - ) - ) - # update gross amount of asset bought through this document assets = frappe.db.get_all( "Asset", filters={"purchase_invoice": self.name, "item_code": item.item_code} diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py index 16477324e6dd..231b3bf7fe22 100644 --- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -2500,12 +2500,6 @@ def test_inter_company_transaction_without_default_warehouse(self): "stock_received_but_not_billed", "Stock Received But Not Billed - _TC1", ) - frappe.db.set_value( - "Company", - "_Test Company 1", - "expenses_included_in_valuation", - "Expenses Included In Valuation - _TC1", - ) # begin test si = create_sales_invoice( @@ -2545,36 +2539,6 @@ def test_inter_company_transaction_without_default_warehouse(self): frappe.local.enable_perpetual_inventory["_Test Company 1"] = old_perpetual_inventory frappe.db.set_single_value("Stock Settings", "allow_negative_stock", old_negative_stock) - def test_sle_for_target_warehouse(self): - se = make_stock_entry( - item_code="138-CMS Shoe", - target="Finished Goods - _TC", - company="_Test Company", - qty=1, - basic_rate=500, - ) - - si = frappe.copy_doc(test_records[0]) - si.update_stock = 1 - si.set_warehouse = "Finished Goods - _TC" - si.set_target_warehouse = "Stores - _TC" - si.get("items")[0].warehouse = "Finished Goods - _TC" - si.get("items")[0].target_warehouse = "Stores - _TC" - si.insert() - si.submit() - - sles = frappe.get_all( - "Stock Ledger Entry", filters={"voucher_no": si.name}, fields=["name", "actual_qty"] - ) - - # check if both SLEs are created - self.assertEqual(len(sles), 2) - self.assertEqual(sum(d.actual_qty for d in sles), 0.0) - - # tear down - si.cancel() - se.cancel() - def test_internal_transfer_gl_entry(self): si = create_sales_invoice( company="_Test Company with perpetual inventory", diff --git a/erpnext/manufacturing/doctype/bom/bom.py b/erpnext/manufacturing/doctype/bom/bom.py index 023166849dbf..229f8853fff0 100644 --- a/erpnext/manufacturing/doctype/bom/bom.py +++ b/erpnext/manufacturing/doctype/bom/bom.py @@ -1196,12 +1196,12 @@ def get_children(parent=None, is_root=False, **filters): def add_additional_cost(stock_entry, work_order): # Add non stock items cost in the additional cost stock_entry.additional_costs = [] - expenses_included_in_valuation = frappe.get_cached_value( - "Company", work_order.company, "expenses_included_in_valuation" + default_expense_account = frappe.get_cached_value( + "Company", work_order.company, "default_expense_account" ) - add_non_stock_items_cost(stock_entry, work_order, expenses_included_in_valuation) - add_operations_cost(stock_entry, work_order, expenses_included_in_valuation) + add_non_stock_items_cost(stock_entry, work_order, default_expense_account) + add_operations_cost(stock_entry, work_order, default_expense_account) def add_non_stock_items_cost(stock_entry, work_order, expense_account): diff --git a/erpnext/patches/v12_0/set_expense_account_in_landed_cost_voucher_taxes.py b/erpnext/patches/v12_0/set_expense_account_in_landed_cost_voucher_taxes.py deleted file mode 100644 index 9588e026d34c..000000000000 --- a/erpnext/patches/v12_0/set_expense_account_in_landed_cost_voucher_taxes.py +++ /dev/null @@ -1,42 +0,0 @@ -import frappe - - -def execute(): - frappe.reload_doctype("Landed Cost Taxes and Charges") - - company_account_map = frappe._dict( - frappe.db.sql( - """ - SELECT name, expenses_included_in_valuation from `tabCompany` - """ - ) - ) - - for company, account in company_account_map.items(): - frappe.db.sql( - """ - UPDATE - `tabLanded Cost Taxes and Charges` t, `tabLanded Cost Voucher` l - SET - t.expense_account = %s - WHERE - l.docstatus = 1 - AND l.company = %s - AND t.parent = l.name - """, - (account, company), - ) - - frappe.db.sql( - """ - UPDATE - `tabLanded Cost Taxes and Charges` t, `tabStock Entry` s - SET - t.expense_account = %s - WHERE - s.docstatus = 1 - AND s.company = %s - AND t.parent = s.name - """, - (account, company), - ) diff --git a/erpnext/setup/doctype/company/company.js b/erpnext/setup/doctype/company/company.js index 4973dab505e1..23b93dc1618c 100644 --- a/erpnext/setup/doctype/company/company.js +++ b/erpnext/setup/doctype/company/company.js @@ -221,7 +221,6 @@ erpnext.company.setup_queries = function(frm) { ["cost_center", {}], ["round_off_cost_center", {}], ["depreciation_cost_center", {}], - ["expenses_included_in_asset_valuation", {"account_type": "Expenses Included In Asset Valuation"}], ["capital_work_in_progress_account", {"account_type": "Capital Work in Progress"}], ["asset_received_but_not_billed", {"account_type": "Asset Received But Not Billed"}], ["unrealized_profit_loss_account", {"root_type": ["in", ["Liability", "Asset"]]}], @@ -236,8 +235,6 @@ erpnext.company.setup_queries = function(frm) { $.each([ ["stock_adjustment_account", {"root_type": "Expense", "account_type": "Stock Adjustment"}], - ["expenses_included_in_valuation", - {"root_type": "Expense", "account_type": "Expenses Included in Valuation"}], ["stock_received_but_not_billed", {"root_type": "Liability", "account_type": "Stock Received But Not Billed"}], ["service_received_but_not_billed", diff --git a/erpnext/setup/doctype/company/company.json b/erpnext/setup/doctype/company/company.json index 24d7da45b841..b9ff3dddd196 100644 --- a/erpnext/setup/doctype/company/company.json +++ b/erpnext/setup/doctype/company/company.json @@ -80,7 +80,6 @@ "accumulated_depreciation_account", "depreciation_expense_account", "series_for_depreciation_entry", - "expenses_included_in_asset_valuation", "column_break_40", "disposal_account", "depreciation_cost_center", @@ -103,11 +102,10 @@ "enable_provisional_accounting_for_non_stock_items", "default_inventory_account", "stock_adjustment_account", - "default_in_transit_warehouse", "column_break_32", "stock_received_but_not_billed", "default_provisional_account", - "expenses_included_in_valuation", + "default_in_transit_warehouse", "dashboard_tab" ], "fields": [ @@ -469,14 +467,6 @@ "no_copy": 1, "options": "Account" }, - { - "fieldname": "expenses_included_in_valuation", - "fieldtype": "Link", - "ignore_user_permissions": 1, - "label": "Expenses Included In Valuation", - "no_copy": 1, - "options": "Account" - }, { "fieldname": "accumulated_depreciation_account", "fieldtype": "Link", @@ -496,12 +486,6 @@ "fieldtype": "Data", "label": "Series for Asset Depreciation Entry (Journal Entry)" }, - { - "fieldname": "expenses_included_in_asset_valuation", - "fieldtype": "Link", - "label": "Expenses Included In Asset Valuation", - "options": "Account" - }, { "fieldname": "column_break_40", "fieldtype": "Column Break" @@ -782,7 +766,7 @@ "image_field": "company_logo", "is_tree": 1, "links": [], - "modified": "2023-09-10 21:53:13.860791", + "modified": "2023-10-23 10:19:24.322898", "modified_by": "Administrator", "module": "Setup", "name": "Company", diff --git a/erpnext/setup/doctype/company/company.py b/erpnext/setup/doctype/company/company.py index b05696ad9696..3413702c5aae 100644 --- a/erpnext/setup/doctype/company/company.py +++ b/erpnext/setup/doctype/company/company.py @@ -92,7 +92,6 @@ def validate_default_accounts(self): ["Default Income Account", "default_income_account"], ["Stock Received But Not Billed Account", "stock_received_but_not_billed"], ["Stock Adjustment Account", "stock_adjustment_account"], - ["Expense Included In Valuation Account", "expenses_included_in_valuation"], ] for account in accounts: @@ -384,7 +383,6 @@ def set_default_accounts(self): "depreciation_expense_account": "Depreciation", "capital_work_in_progress_account": "Capital Work in Progress", "asset_received_but_not_billed": "Asset Received But Not Billed", - "expenses_included_in_asset_valuation": "Expenses Included In Asset Valuation", "default_expense_account": "Cost of Goods Sold", } @@ -394,7 +392,6 @@ def set_default_accounts(self): "stock_received_but_not_billed": "Stock Received But Not Billed", "default_inventory_account": "Stock", "stock_adjustment_account": "Stock Adjustment", - "expenses_included_in_valuation": "Expenses Included In Valuation", } ) diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py index 9fdb01a66214..d89d8057a8b0 100644 --- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py @@ -491,7 +491,6 @@ def make_divisional_loss_gl_entry(item, outgoing_amount): return # divisional loss adjustment - expenses_included_in_valuation = self.get_company_default("expenses_included_in_valuation") valuation_amount_as_per_doc = ( flt(outgoing_amount, d.precision("base_net_amount")) + flt(item.landed_cost_voucher_amount) @@ -505,13 +504,10 @@ def make_divisional_loss_gl_entry(item, outgoing_amount): ) if divisional_loss: - if self.is_return or flt(item.item_tax_amount): - loss_account = expenses_included_in_valuation - else: - loss_account = ( - self.get_company_default("default_expense_account", ignore_validation=True) - or stock_asset_rbnb - ) + loss_account = ( + self.get_company_default("default_expense_account", ignore_validation=True) + or stock_asset_rbnb + ) cost_center = item.cost_center or frappe.get_cached_value( "Company", self.company, "cost_center" @@ -684,10 +680,8 @@ def make_tax_gl_entries(self, gl_entries): if negative_expense_to_be_booked and valuation_tax: # Backward compatibility: - # If expenses_included_in_valuation account has been credited in against PI # and charges added via Landed Cost Voucher, # post valuation related charges on "Stock Received But Not Billed" - # introduced in 2014 for backward compatibility of expenses already booked in expenses_included_in_valuation account against_account = ", ".join([d.account for d in gl_entries if flt(d.debit) > 0]) total_valuation_amount = sum(valuation_tax.values()) amount_including_divisional_loss = negative_expense_to_be_booked diff --git a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py index 1af7b9aefc2d..e998b842d13a 100644 --- a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py @@ -957,88 +957,6 @@ def test_make_purchase_invoice_from_pr_with_returned_qty_duplicate_items(self): pr1.reload() pr1.cancel() - def test_stock_transfer_from_purchase_receipt(self): - pr1 = make_purchase_receipt( - warehouse="Work In Progress - TCP1", company="_Test Company with perpetual inventory" - ) - - pr = make_purchase_receipt( - company="_Test Company with perpetual inventory", warehouse="Stores - TCP1", do_not_save=1 - ) - - pr.supplier_warehouse = "" - pr.items[0].from_warehouse = "Work In Progress - TCP1" - - pr.submit() - - gl_entries = get_gl_entries("Purchase Receipt", pr.name) - sl_entries = get_sl_entries("Purchase Receipt", pr.name) - - self.assertFalse(gl_entries) - - expected_sle = {"Work In Progress - TCP1": -5, "Stores - TCP1": 5} - - for sle in sl_entries: - self.assertEqual(expected_sle[sle.warehouse], sle.actual_qty) - - pr.cancel() - pr1.cancel() - - def test_stock_transfer_from_purchase_receipt_with_valuation(self): - create_warehouse( - "_Test Warehouse for Valuation", - company="_Test Company with perpetual inventory", - properties={"account": "_Test Account Stock In Hand - TCP1"}, - ) - - pr1 = make_purchase_receipt( - warehouse="_Test Warehouse for Valuation - TCP1", - company="_Test Company with perpetual inventory", - ) - - pr = make_purchase_receipt( - company="_Test Company with perpetual inventory", warehouse="Stores - TCP1", do_not_save=1 - ) - - pr.items[0].from_warehouse = "_Test Warehouse for Valuation - TCP1" - pr.supplier_warehouse = "" - - pr.append( - "taxes", - { - "charge_type": "On Net Total", - "account_head": "_Test Account Shipping Charges - TCP1", - "category": "Valuation and Total", - "cost_center": "Main - TCP1", - "description": "Test", - "rate": 9, - }, - ) - - pr.submit() - - gl_entries = get_gl_entries("Purchase Receipt", pr.name) - sl_entries = get_sl_entries("Purchase Receipt", pr.name) - - expected_gle = [ - ["Stock In Hand - TCP1", 272.5, 0.0], - ["_Test Account Stock In Hand - TCP1", 0.0, 250.0], - ["_Test Account Shipping Charges - TCP1", 0.0, 22.5], - ] - - expected_sle = {"_Test Warehouse for Valuation - TCP1": -5, "Stores - TCP1": 5} - - for sle in sl_entries: - self.assertEqual(expected_sle[sle.warehouse], sle.actual_qty) - - for i, gle in enumerate(gl_entries): - self.assertEqual(gle.account, expected_gle[i][0]) - self.assertEqual(gle.debit, expected_gle[i][1]) - self.assertEqual(gle.credit, expected_gle[i][2]) - - pr.cancel() - pr1.cancel() - def test_po_to_pi_and_po_to_pr_worflow_full(self): """Test following behaviour: - Create PO diff --git a/erpnext/stock/doctype/stock_entry/test_stock_entry.py b/erpnext/stock/doctype/stock_entry/test_stock_entry.py index cc8a108bc972..3e0610ef6ed0 100644 --- a/erpnext/stock/doctype/stock_entry/test_stock_entry.py +++ b/erpnext/stock/doctype/stock_entry/test_stock_entry.py @@ -449,9 +449,7 @@ def test_repack_with_additional_costs(self): repack.posting_date = nowdate() repack.posting_time = nowtime() - expenses_included_in_valuation = frappe.get_value( - "Company", company, "expenses_included_in_valuation" - ) + default_expense_account = frappe.get_value("Company", company, "default_expense_account") items = get_multiple_items() repack.items = [] @@ -462,12 +460,12 @@ def test_repack_with_additional_costs(self): "additional_costs", [ { - "expense_account": expenses_included_in_valuation, + "expense_account": default_expense_account, "description": "Actual Operating Cost", "amount": 1000, }, { - "expense_account": expenses_included_in_valuation, + "expense_account": default_expense_account, "description": "Additional Operating Cost", "amount": 200, }, @@ -506,9 +504,7 @@ def test_repack_with_additional_costs(self): self.check_gl_entries( "Stock Entry", repack.name, - sorted( - [[stock_in_hand_account, 1200, 0.0], ["Expenses Included In Valuation - TCP1", 0.0, 1200.0]] - ), + sorted([[stock_in_hand_account, 1200, 0.0], ["Cost of Goods Sold - TCP1", 0.0, 1200.0]]), ) def check_stock_ledger_entries(self, voucher_type, voucher_no, expected_sle): diff --git a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py index 6aecaf98a5dd..7e06444e1efd 100644 --- a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py +++ b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py @@ -410,7 +410,6 @@ def get_gl_entries(self, warehouse_account=None): def make_item_gl_entries(self, gl_entries, warehouse_account=None): stock_rbnb = self.get_company_default("stock_received_but_not_billed") - expenses_included_in_valuation = self.get_company_default("expenses_included_in_valuation") warehouse_with_no_account = [] @@ -482,10 +481,7 @@ def make_item_gl_entries(self, gl_entries, warehouse_account=None): divisional_loss = flt(item.amount - stock_value_diff, item.precision("amount")) if divisional_loss: - if self.is_return: - loss_account = expenses_included_in_valuation - else: - loss_account = item.expense_account + loss_account = item.expense_account self.add_gl_entry( gl_entries=gl_entries, From 6942ab10125cfaf07c526df53a7c88bffcc5b9da Mon Sep 17 00:00:00 2001 From: s-aga-r Date: Mon, 23 Oct 2023 19:12:55 +0530 Subject: [PATCH 21/25] chore: patch to update `From Voucher` details --- erpnext/patches.txt | 1 + .../v15_0/update_sre_from_voucher_details.py | 15 +++++++++++++++ 2 files changed, 16 insertions(+) create mode 100644 erpnext/patches/v15_0/update_sre_from_voucher_details.py diff --git a/erpnext/patches.txt b/erpnext/patches.txt index d59fe0ec4c8f..53bddb562c03 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -340,5 +340,6 @@ erpnext.patches.v14_0.update_invoicing_period_in_subscription execute:frappe.delete_doc("Page", "welcome-to-erpnext") erpnext.patches.v15_0.delete_payment_gateway_doctypes erpnext.patches.v14_0.create_accounting_dimensions_in_sales_order_item +erpnext.patches.v15_0.update_sre_from_voucher_details # below migration patch should always run last erpnext.patches.v14_0.migrate_gl_to_payment_ledger \ No newline at end of file diff --git a/erpnext/patches/v15_0/update_sre_from_voucher_details.py b/erpnext/patches/v15_0/update_sre_from_voucher_details.py new file mode 100644 index 000000000000..a9653ccbf432 --- /dev/null +++ b/erpnext/patches/v15_0/update_sre_from_voucher_details.py @@ -0,0 +1,15 @@ +import frappe +from frappe.query_builder.functions import IfNull + + +def execute(): + sre = frappe.qb.DocType("Stock Reservation Entry") + ( + frappe.qb.update(sre) + .set(sre.from_voucher_type, "Pick List") + .set(sre.from_voucher_no, sre.against_pick_list) + .set(sre.from_voucher_detail_no, sre.against_pick_list_item) + .where( + (IfNull(sre.against_pick_list, "") != "") & (IfNull(sre.against_pick_list_item, "") != "") + ) + ).run() From 23df4205f8abfca6764d84665cb9877703c1a470 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Thu, 19 Oct 2023 11:32:21 +0530 Subject: [PATCH 22/25] fix: overallocation on Payment with PO/SO --- erpnext/accounts/utils.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py index f2691fb9806d..1c7052f8ffb6 100644 --- a/erpnext/accounts/utils.py +++ b/erpnext/accounts/utils.py @@ -645,7 +645,7 @@ def update_reference_in_payment_entry( "outstanding_amount": d.outstanding_amount, "allocated_amount": d.allocated_amount, "exchange_rate": d.exchange_rate if d.exchange_gain_loss else payment_entry.get_exchange_rate(), - "exchange_gain_loss": d.exchange_gain_loss, # only populated from invoice in case of advance allocation + "exchange_gain_loss": d.exchange_gain_loss, "account": d.account, } @@ -658,22 +658,21 @@ def update_reference_in_payment_entry( existing_row.reference_doctype, existing_row.reference_name ).set_total_advance_paid() - original_row = existing_row.as_dict().copy() - existing_row.update(reference_details) + if d.allocated_amount <= existing_row.allocated_amount: + existing_row.allocated_amount -= d.allocated_amount - if d.allocated_amount < original_row.allocated_amount: new_row = payment_entry.append("references") new_row.docstatus = 1 for field in list(reference_details): - new_row.set(field, original_row[field]) + new_row.set(field, reference_details[field]) - new_row.allocated_amount = original_row.allocated_amount - d.allocated_amount else: new_row = payment_entry.append("references") new_row.docstatus = 1 new_row.update(reference_details) payment_entry.flags.ignore_validate_update_after_submit = True + payment_entry.clear_unallocated_reference_document_rows() payment_entry.setup_party_account_field() payment_entry.set_missing_values() if not skip_ref_details_update_for_pe: From 946228d783cb58cd2809f4b0bc0a854c49cc4060 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Thu, 19 Oct 2023 14:03:21 +0530 Subject: [PATCH 23/25] test: overalloction on reconciliation when PO is involved --- .../test_payment_reconciliation.py | 183 +++++++++++++++++- 1 file changed, 178 insertions(+), 5 deletions(-) diff --git a/erpnext/accounts/doctype/payment_reconciliation/test_payment_reconciliation.py b/erpnext/accounts/doctype/payment_reconciliation/test_payment_reconciliation.py index 1d843abde1d9..48d1cf2cc266 100644 --- a/erpnext/accounts/doctype/payment_reconciliation/test_payment_reconciliation.py +++ b/erpnext/accounts/doctype/payment_reconciliation/test_payment_reconciliation.py @@ -14,6 +14,7 @@ from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice from erpnext.accounts.party import get_party_account +from erpnext.buying.doctype.purchase_order.test_purchase_order import create_purchase_order from erpnext.stock.doctype.item.test_item import create_item test_dependencies = ["Item"] @@ -151,6 +152,64 @@ def create_payment_entry(self, amount=100, posting_date=nowdate(), customer=None payment.posting_date = posting_date return payment + def create_purchase_invoice( + self, qty=1, rate=100, posting_date=nowdate(), do_not_save=False, do_not_submit=False + ): + """ + Helper function to populate default values in sales invoice + """ + pinv = make_purchase_invoice( + qty=qty, + rate=rate, + company=self.company, + customer=self.supplier, + item_code=self.item, + item_name=self.item, + cost_center=self.cost_center, + warehouse=self.warehouse, + debit_to=self.debit_to, + parent_cost_center=self.cost_center, + update_stock=0, + currency="INR", + is_pos=0, + is_return=0, + return_against=None, + income_account=self.income_account, + expense_account=self.expense_account, + do_not_save=do_not_save, + do_not_submit=do_not_submit, + ) + return pinv + + def create_purchase_order( + self, qty=1, rate=100, posting_date=nowdate(), do_not_save=False, do_not_submit=False + ): + """ + Helper function to populate default values in sales invoice + """ + pord = create_purchase_order( + qty=qty, + rate=rate, + company=self.company, + customer=self.supplier, + item_code=self.item, + item_name=self.item, + cost_center=self.cost_center, + warehouse=self.warehouse, + debit_to=self.debit_to, + parent_cost_center=self.cost_center, + update_stock=0, + currency="INR", + is_pos=0, + is_return=0, + return_against=None, + income_account=self.income_account, + expense_account=self.expense_account, + do_not_save=do_not_save, + do_not_submit=do_not_submit, + ) + return pord + def clear_old_entries(self): doctype_list = [ "GL Entry", @@ -163,13 +222,11 @@ def clear_old_entries(self): for doctype in doctype_list: qb.from_(qb.DocType(doctype)).delete().where(qb.DocType(doctype).company == self.company).run() - def create_payment_reconciliation(self): + def create_payment_reconciliation(self, party_is_customer=True): pr = frappe.new_doc("Payment Reconciliation") pr.company = self.company - pr.party_type = ( - self.party_type if hasattr(self, "party_type") and self.party_type else "Customer" - ) - pr.party = self.customer + pr.party_type = "Customer" if party_is_customer else "Supplier" + pr.party = self.customer if party_is_customer else self.supplier pr.receivable_payable_account = get_party_account(pr.party_type, pr.party, pr.company) pr.from_invoice_date = pr.to_invoice_date = pr.from_payment_date = pr.to_payment_date = nowdate() return pr @@ -931,6 +988,7 @@ def test_reconciliation_purchase_invoice_against_return(self): if invoice.invoice_number == pi.name: invoices.append(invoice.as_dict()) break + for payment in pr.payments: if payment.reference_name == pi_return.name: payments.append(payment.as_dict()) @@ -941,6 +999,121 @@ def test_reconciliation_purchase_invoice_against_return(self): # Should not raise frappe.exceptions.ValidationError: Total Debit must be equal to Total Credit. pr.reconcile() + def test_reconciliation_from_purchase_order_to_multiple_invoices(self): + """ + Reconciling advance payment from PO/SO to multiple invoices should not cause overallocation + """ + + self.supplier = "_Test Supplier" + + pi1 = self.create_purchase_invoice(qty=10, rate=100) + pi2 = self.create_purchase_invoice(qty=10, rate=100) + po = self.create_purchase_order(qty=20, rate=100) + pay = get_payment_entry(po.doctype, po.name) + # Overpay Puchase Order + pay.paid_amount = 3000 + pay.save().submit() + # assert total allocated and unallocated before reconciliation + self.assertEqual( + ( + pay.references[0].reference_doctype, + pay.references[0].reference_name, + pay.references[0].allocated_amount, + ), + (po.doctype, po.name, 2000), + ) + self.assertEqual(pay.total_allocated_amount, 2000) + self.assertEqual(pay.unallocated_amount, 1000) + self.assertEqual(pay.difference_amount, 0) + + pr = self.create_payment_reconciliation(party_is_customer=False) + pr.get_unreconciled_entries() + + self.assertEqual(len(pr.invoices), 2) + self.assertEqual(len(pr.payments), 2) + + for x in pr.payments: + self.assertEqual((x.reference_type, x.reference_name), (pay.doctype, pay.name)) + + invoices = [x.as_dict() for x in pr.invoices] + payments = [x.as_dict() for x in pr.payments] + pr.allocate_entries(frappe._dict({"invoices": invoices, "payments": payments})) + # partial allocation on pi1 and full allocate on pi2 + pr.allocation[0].allocated_amount = 100 + pr.reconcile() + + # assert references and total allocated and unallocated amount + pay.reload() + self.assertEqual(len(pay.references), 3) + self.assertEqual( + ( + pay.references[0].reference_doctype, + pay.references[0].reference_name, + pay.references[0].allocated_amount, + ), + (po.doctype, po.name, 900), + ) + self.assertEqual( + ( + pay.references[1].reference_doctype, + pay.references[1].reference_name, + pay.references[1].allocated_amount, + ), + (pi1.doctype, pi1.name, 100), + ) + self.assertEqual( + ( + pay.references[2].reference_doctype, + pay.references[2].reference_name, + pay.references[2].allocated_amount, + ), + (pi2.doctype, pi2.name, 1000), + ) + self.assertEqual(pay.total_allocated_amount, 2000) + self.assertEqual(pay.unallocated_amount, 1000) + self.assertEqual(pay.difference_amount, 0) + + pr.get_unreconciled_entries() + self.assertEqual(len(pr.invoices), 1) + self.assertEqual(len(pr.payments), 2) + + invoices = [x.as_dict() for x in pr.invoices] + payments = [x.as_dict() for x in pr.payments] + pr.allocate_entries(frappe._dict({"invoices": invoices, "payments": payments})) + pr.reconcile() + + # assert references and total allocated and unallocated amount + pay.reload() + self.assertEqual(len(pay.references), 3) + # PO references should be removed now + self.assertEqual( + ( + pay.references[0].reference_doctype, + pay.references[0].reference_name, + pay.references[0].allocated_amount, + ), + (pi1.doctype, pi1.name, 100), + ) + self.assertEqual( + ( + pay.references[1].reference_doctype, + pay.references[1].reference_name, + pay.references[1].allocated_amount, + ), + (pi2.doctype, pi2.name, 1000), + ) + self.assertEqual( + ( + pay.references[2].reference_doctype, + pay.references[2].reference_name, + pay.references[2].allocated_amount, + ), + (pi1.doctype, pi1.name, 900), + ) + self.assertEqual(pay.total_allocated_amount, 2000) + self.assertEqual(pay.unallocated_amount, 1000) + self.assertEqual(pay.difference_amount, 0) + def make_customer(customer_name, currency=None): if not frappe.db.exists("Customer", customer_name): From 547993f80103fa192563a82447c39fe122918767 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Thu, 19 Oct 2023 14:57:05 +0530 Subject: [PATCH 24/25] refactor(test): make use of utility methods --- .../test_payment_reconciliation.py | 79 ++++++++++++------- 1 file changed, 51 insertions(+), 28 deletions(-) diff --git a/erpnext/accounts/doctype/payment_reconciliation/test_payment_reconciliation.py b/erpnext/accounts/doctype/payment_reconciliation/test_payment_reconciliation.py index 48d1cf2cc266..71bc498b494f 100644 --- a/erpnext/accounts/doctype/payment_reconciliation/test_payment_reconciliation.py +++ b/erpnext/accounts/doctype/payment_reconciliation/test_payment_reconciliation.py @@ -86,26 +86,44 @@ def create_customer(self): self.customer5 = make_customer("_Test PR Customer 5", "EUR") def create_account(self): - account_name = "Debtors EUR" - if not frappe.db.get_value( - "Account", filters={"account_name": account_name, "company": self.company} - ): - acc = frappe.new_doc("Account") - acc.account_name = account_name - acc.parent_account = "Accounts Receivable - _PR" - acc.company = self.company - acc.account_currency = "EUR" - acc.account_type = "Receivable" - acc.insert() - else: - name = frappe.db.get_value( - "Account", - filters={"account_name": account_name, "company": self.company}, - fieldname="name", - pluck=True, - ) - acc = frappe.get_doc("Account", name) - self.debtors_eur = acc.name + accounts = [ + { + "attribute": "debtors_eur", + "account_name": "Debtors EUR", + "parent_account": "Accounts Receivable - _PR", + "account_currency": "EUR", + "account_type": "Receivable", + }, + { + "attribute": "creditors_usd", + "account_name": "Payable USD", + "parent_account": "Accounts Payable - _PR", + "account_currency": "USD", + "account_type": "Payable", + }, + ] + + for x in accounts: + x = frappe._dict(x) + if not frappe.db.get_value( + "Account", filters={"account_name": x.account_name, "company": self.company} + ): + acc = frappe.new_doc("Account") + acc.account_name = x.account_name + acc.parent_account = x.parent_account + acc.company = self.company + acc.account_currency = x.account_currency + acc.account_type = x.account_type + acc.insert() + else: + name = frappe.db.get_value( + "Account", + filters={"account_name": x.account_name, "company": self.company}, + fieldname="name", + pluck=True, + ) + acc = frappe.get_doc("Account", name) + setattr(self, x.attribute, acc.name) def create_sales_invoice( self, qty=1, rate=100, posting_date=nowdate(), do_not_save=False, do_not_submit=False @@ -963,9 +981,13 @@ def test_no_difference_amount_for_base_currency_accounts(self): self.assertEqual(pr.allocation[0].difference_amount, 0) def test_reconciliation_purchase_invoice_against_return(self): - pi = make_purchase_invoice( - supplier="_Test Supplier USD", currency="USD", conversion_rate=50 - ).submit() + self.supplier = "_Test Supplier USD" + pi = self.create_purchase_invoice(qty=5, rate=50, do_not_submit=True) + pi.supplier = self.supplier + pi.currency = "USD" + pi.conversion_rate = 50 + pi.credit_to = self.creditors_usd + pi.save().submit() pi_return = frappe.get_doc(pi.as_dict()) pi_return.name = None @@ -975,11 +997,12 @@ def test_reconciliation_purchase_invoice_against_return(self): pi_return.items[0].qty = -pi_return.items[0].qty pi_return.submit() - self.company = "_Test Company" - self.party_type = "Supplier" - self.customer = "_Test Supplier USD" - - pr = self.create_payment_reconciliation() + pr = frappe.get_doc("Payment Reconciliation") + pr.company = self.company + pr.party_type = "Supplier" + pr.party = self.supplier + pr.receivable_payable_account = self.creditors_usd + pr.from_invoice_date = pr.to_invoice_date = pr.from_payment_date = pr.to_payment_date = nowdate() pr.get_unreconciled_entries() invoices = [] From 4dff2c7a0dad1de840a2b1f53d51e9fe1682fa7f Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Tue, 24 Oct 2023 08:09:22 +0530 Subject: [PATCH 25/25] chore: fix flakiness `test_sales_order_partial_advance_payment` --- erpnext/selling/doctype/sales_order/test_sales_order.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py index 83689a2b0bab..d8b5878aa300 100644 --- a/erpnext/selling/doctype/sales_order/test_sales_order.py +++ b/erpnext/selling/doctype/sales_order/test_sales_order.py @@ -1784,10 +1784,10 @@ def test_sales_order_partial_advance_payment(self): si.submit() pe.load_from_db() - self.assertEqual(pe.references[0].reference_name, si.name) - self.assertEqual(pe.references[0].allocated_amount, 200) - self.assertEqual(pe.references[1].reference_name, so.name) - self.assertEqual(pe.references[1].allocated_amount, 300) + self.assertEqual(pe.references[0].reference_name, so.name) + self.assertEqual(pe.references[0].allocated_amount, 300) + self.assertEqual(pe.references[1].reference_name, si.name) + self.assertEqual(pe.references[1].allocated_amount, 200) def test_delivered_item_material_request(self): "SO -> MR (Manufacture) -> WO. Test if WO Qty is updated in SO."