diff --git a/erpnext/accounts/deferred_revenue.py b/erpnext/accounts/deferred_revenue.py index 3afb4bc8c6a..bc773772554 100644 --- a/erpnext/accounts/deferred_revenue.py +++ b/erpnext/accounts/deferred_revenue.py @@ -174,6 +174,8 @@ def make_gl_entries(doc, credit_account, debit_account, against, # GL Entry for crediting the amount in the deferred expense from erpnext.accounts.general_ledger import make_gl_entries + if amount == 0: return + gl_entries = [] gl_entries.append( doc.get_gl_dict({ diff --git a/erpnext/accounts/doctype/account/account.py b/erpnext/accounts/doctype/account/account.py index 68efe377190..cccced8e0be 100644 --- a/erpnext/accounts/doctype/account/account.py +++ b/erpnext/accounts/doctype/account/account.py @@ -100,7 +100,10 @@ class Account(NestedSet): if ancestors: if frappe.get_value("Company", self.company, "allow_account_creation_against_child_company"): return - frappe.throw(_("Please add the account to root level Company - %s" % ancestors[0])) + + if not frappe.db.get_value("Account", + {'account_name': self.account_name, 'company': ancestors[0]}, 'name'): + frappe.throw(_("Please add the account to root level Company - %s" % ancestors[0])) else: descendants = get_descendants_of('Company', self.company) if not descendants: return @@ -114,21 +117,7 @@ class Account(NestedSet): if not parent_acc_name_map: return - for company in descendants: - if not parent_acc_name_map.get(company): - frappe.throw(_("While creating account for child Company {0}, parent account {1} not found. Please create the parent account in corresponding COA") - .format(company, parent_acc_name)) - - doc = frappe.copy_doc(self) - doc.flags.ignore_root_company_validation = True - doc.update({ - "company": company, - "account_currency": None, - "parent_account": parent_acc_name_map[company] - }) - doc.save() - frappe.msgprint(_("Account {0} is added in the child company {1}") - .format(doc.name, company)) + self.create_account_for_child_company(parent_acc_name_map, descendants, parent_acc_name) def validate_group_or_ledger(self): if self.get("__islocal"): @@ -170,6 +159,49 @@ class Account(NestedSet): if frappe.db.get_value("GL Entry", {"account": self.name}): frappe.throw(_("Currency can not be changed after making entries using some other currency")) + def create_account_for_child_company(self, parent_acc_name_map, descendants, parent_acc_name): + for company in descendants: + if not parent_acc_name_map.get(company): + frappe.throw(_("While creating account for child Company {0}, parent account {1} not found. Please create the parent account in corresponding COA") + .format(company, parent_acc_name)) + + filters = { + "account_name": self.account_name, + "company": company + } + + if self.account_number: + filters["account_number"] = self.account_number + + child_account = frappe.db.get_value("Account", filters, 'name') + + if not child_account: + doc = frappe.copy_doc(self) + doc.flags.ignore_root_company_validation = True + doc.update({ + "company": company, + # parent account's currency should be passed down to child account's curreny + # if it is None, it picks it up from default company currency, which might be unintended + "account_currency": self.account_currency, + "parent_account": parent_acc_name_map[company] + }) + + doc.save() + frappe.msgprint(_("Account {0} is added in the child company {1}") + .format(doc.name, company)) + elif child_account: + # update the parent company's value in child companies + doc = frappe.get_doc("Account", child_account) + parent_value_changed = False + for field in ['account_type', 'account_currency', + 'freeze_account', 'balance_must_be']: + if doc.get(field) != self.get(field): + parent_value_changed = True + doc.set(field, self.get(field)) + + if parent_value_changed: + doc.save() + def convert_group_to_ledger(self): if self.check_if_child_exists(): throw(_("Account with child nodes cannot be converted to ledger")) diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.json b/erpnext/accounts/doctype/payment_entry/payment_entry.json index 96e1e1eb162..5a53a0e4214 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.json +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.json @@ -1791,6 +1791,41 @@ "translatable": 0, "unique": 0 }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "default": "Draft", + "fetch_if_empty": 0, + "fieldname": "status", + "fieldtype": "Select", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Status", + "length": 0, + "no_copy": 0, + "options": "\nDraft\nSubmitted\nCancelled", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -2205,7 +2240,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2019-03-27 17:39:54.163016", + "modified": "2019-11-06 15:15:45.223497", "modified_by": "Administrator", "module": "Accounts", "name": "Payment Entry", diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py index d57f2c59052..21634c1df3c 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.py +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py @@ -60,6 +60,7 @@ class PaymentEntry(AccountsController): self.validate_duplicate_entry() self.validate_allocated_amount() self.ensure_supplier_is_not_blocked() + self.set_status() def on_submit(self): self.setup_party_account_field() @@ -69,6 +70,7 @@ class PaymentEntry(AccountsController): self.update_outstanding_amounts() self.update_advance_paid() self.update_expense_claim() + self.set_status() def on_cancel(self): @@ -78,6 +80,7 @@ class PaymentEntry(AccountsController): self.update_advance_paid() self.update_expense_claim() self.delink_advance_entry_references() + self.set_status() def update_outstanding_amounts(self): self.set_missing_ref_details(force=True) @@ -274,6 +277,14 @@ class PaymentEntry(AccountsController): frappe.throw(_("Against Journal Entry {0} does not have any unmatched {1} entry") .format(d.reference_name, dr_or_cr)) + def set_status(self): + if self.docstatus == 2: + self.status = 'Cancelled' + elif self.docstatus == 1: + self.status = 'Submitted' + else: + self.status = 'Draft' + def set_amounts(self): self.set_amounts_in_company_currency() self.set_total_allocated_amount() diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index 60446d0e86c..db843e6a4c7 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -350,7 +350,7 @@ class SalesInvoice(SellingController): timesheet.calculate_percentage_billed() timesheet.flags.ignore_validate_update_after_submit = True timesheet.set_status() - timesheet.save() + timesheet.save(ignore_permissions=True) def update_time_sheet_detail(self, timesheet, args, sales_invoice): for data in timesheet.time_logs: diff --git a/erpnext/accounts/report/trial_balance/trial_balance.py b/erpnext/accounts/report/trial_balance/trial_balance.py index 5758b0bc6b1..e0c539ef90d 100644 --- a/erpnext/accounts/report/trial_balance/trial_balance.py +++ b/erpnext/accounts/report/trial_balance/trial_balance.py @@ -75,8 +75,7 @@ def get_data(filters): accumulate_values_into_parents(accounts, accounts_by_name) data = prepare_data(accounts, filters, total_row, parent_children_map, company_currency) - data = filter_out_zero_value_rows(data, parent_children_map, - show_zero_values=filters.get("show_zero_values")) + data = filter_out_zero_value_rows(data, parent_children_map, show_zero_values=filters.get("show_zero_values")) return data @@ -175,33 +174,11 @@ def calculate_values(accounts, gl_entries_by_account, opening_balances, filters, d["closing_debit"] = d["opening_debit"] + d["debit"] d["closing_credit"] = d["opening_credit"] + d["credit"] - total_row["debit"] += d["debit"] - total_row["credit"] += d["credit"] - if d["root_type"] == "Asset" or d["root_type"] == "Equity" or d["root_type"] == "Expense": - d["opening_debit"] -= d["opening_credit"] - d["closing_debit"] -= d["closing_credit"] + prepare_opening_closing(d) - # For opening - check_opening_closing_has_negative_value(d, "opening_debit", "opening_credit") - - # For closing - check_opening_closing_has_negative_value(d, "closing_debit", "closing_credit") - - if d["root_type"] == "Liability" or d["root_type"] == "Income": - d["opening_credit"] -= d["opening_debit"] - d["closing_credit"] -= d["closing_debit"] - - # For opening - check_opening_closing_has_negative_value(d, "opening_credit", "opening_debit") - - # For closing - check_opening_closing_has_negative_value(d, "closing_credit", "closing_debit") - - total_row["opening_debit"] += d["opening_debit"] - total_row["closing_debit"] += d["closing_debit"] - total_row["opening_credit"] += d["opening_credit"] - total_row["closing_credit"] += d["closing_credit"] + for field in value_fields: + total_row[field] += d[field] return total_row @@ -215,6 +192,10 @@ def prepare_data(accounts, filters, total_row, parent_children_map, company_curr data = [] for d in accounts: + # Prepare opening closing for group account + if parent_children_map.get(d.account): + prepare_opening_closing(d) + has_value = False row = { "account": d.name, @@ -301,11 +282,16 @@ def get_columns(): } ] -def check_opening_closing_has_negative_value(d, dr_or_cr, switch_to_column): - # If opening debit has negetive value then move it to opening credit and vice versa. +def prepare_opening_closing(row): + dr_or_cr = "debit" if row["root_type"] in ["Asset", "Equity", "Expense"] else "credit" + reverse_dr_or_cr = "credit" if dr_or_cr == "debit" else "debit" - if d[dr_or_cr] < 0: - d[switch_to_column] = abs(d[dr_or_cr]) - d[dr_or_cr] = 0.0 - else: - d[switch_to_column] = 0.0 + for col_type in ["opening", "closing"]: + valid_col = col_type + "_" + dr_or_cr + reverse_col = col_type + "_" + reverse_dr_or_cr + row[valid_col] -= row[reverse_col] + if row[valid_col] < 0: + row[reverse_col] = abs(row[valid_col]) + row[valid_col] = 0.0 + else: + row[reverse_col] = 0.0 \ No newline at end of file diff --git a/erpnext/hr/doctype/employee/employee.py b/erpnext/hr/doctype/employee/employee.py index d925b144889..d1f3991f0e1 100755 --- a/erpnext/hr/doctype/employee/employee.py +++ b/erpnext/hr/doctype/employee/employee.py @@ -157,10 +157,11 @@ class Employee(NestedSet): def validate_status(self): if self.status == 'Left': reports_to = frappe.db.get_all('Employee', - filters={'reports_to': self.name} + filters={'reports_to': self.name, 'status': "Active"}, + fields = ['name','employee_name'] ) if reports_to: - link_to_employees = [frappe.utils.get_link_to_form('Employee', employee.name) for employee in reports_to] + link_to_employees = [frappe.utils.get_link_to_form('Employee', employee.name, label=employee.employee_name) for employee in reports_to] throw(_("Employee status cannot be set to 'Left' as following employees are currently reporting to this employee: ") + ', '.join(link_to_employees), EmployeeLeftValidationError) if not self.relieving_date: diff --git a/erpnext/manufacturing/doctype/material_request_plan_item/material_request_plan_item.json b/erpnext/manufacturing/doctype/material_request_plan_item/material_request_plan_item.json index 11b85238af2..98cdbab5f58 100644 --- a/erpnext/manufacturing/doctype/material_request_plan_item/material_request_plan_item.json +++ b/erpnext/manufacturing/doctype/material_request_plan_item/material_request_plan_item.json @@ -1,5 +1,6 @@ { "allow_copy": 0, + "allow_events_in_timeline": 0, "allow_guest_to_view": 0, "allow_import": 0, "allow_rename": 0, @@ -14,10 +15,12 @@ "fields": [ { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "item_code", "fieldtype": "Link", "hidden": 0, @@ -41,14 +44,17 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "item_name", "fieldtype": "Data", "hidden": 0, @@ -72,14 +78,17 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "warehouse", "fieldtype": "Link", "hidden": 0, @@ -103,14 +112,17 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "column_break_4", "fieldtype": "Column Break", "hidden": 0, @@ -132,14 +144,17 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "quantity", "fieldtype": "Float", "hidden": 0, @@ -162,14 +177,51 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, + "fieldname": "uom", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "UOM", + "length": 0, + "no_copy": 0, + "options": "UOM", + "permlevel": 0, + "precision": "", + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fetch_if_empty": 0, "fieldname": "actual_qty", "fieldtype": "Float", "hidden": 0, @@ -192,14 +244,86 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 1, + "columns": 0, + "fetch_if_empty": 0, + "fieldname": "item_details", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Item Description", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, + "fieldname": "description", + "fieldtype": "Text Editor", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Description", + "length": 0, + "no_copy": 0, + "oldfieldname": "description", + "oldfieldtype": "Small Text", + "permlevel": 0, + "print_hide": 0, + "print_hide_if_no_value": 0, + "print_width": "300px", + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0, + "width": "300px" + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fetch_if_empty": 0, "fieldname": "min_order_qty", "fieldtype": "Float", "hidden": 0, @@ -222,14 +346,17 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 1, "columns": 0, + "fetch_if_empty": 0, "fieldname": "section_break_8", "fieldtype": "Section Break", "hidden": 0, @@ -252,14 +379,17 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "sales_order", "fieldtype": "Link", "hidden": 0, @@ -283,14 +413,17 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "requested_qty", "fieldtype": "Float", "hidden": 0, @@ -313,6 +446,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 } ], @@ -326,7 +460,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2018-02-15 13:08:30.535963", + "modified": "2019-11-08 14:59:58.805613", "modified_by": "Administrator", "module": "Manufacturing", "name": "Material Request Plan Item", @@ -340,5 +474,6 @@ "sort_field": "modified", "sort_order": "DESC", "track_changes": 1, - "track_seen": 0 -} \ No newline at end of file + "track_seen": 0, + "track_views": 0 +} diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.js b/erpnext/manufacturing/doctype/production_plan/production_plan.js index dbbf3d33f7c..cc59776d45f 100644 --- a/erpnext/manufacturing/doctype/production_plan/production_plan.js +++ b/erpnext/manufacturing/doctype/production_plan/production_plan.js @@ -122,6 +122,8 @@ frappe.ui.form.on('Production Plan', { item.quantity = d.quantity; item.sales_order = d.sales_order; item.warehouse = d.warehouse; + item.description = d.description; + item.uom = d.uom; }); } refresh_field('mr_items'); diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.py b/erpnext/manufacturing/doctype/production_plan/production_plan.py index 40b78f215ec..1d7963da544 100644 --- a/erpnext/manufacturing/doctype/production_plan/production_plan.py +++ b/erpnext/manufacturing/doctype/production_plan/production_plan.py @@ -472,7 +472,9 @@ def get_material_request_items(row, sales_order, company, ignore_existing_ordere or row.get('default_warehouse') or item_group_defaults.get("default_warehouse"), 'actual_qty': actual_qty, 'min_order_qty': row['min_order_qty'], - 'sales_order': sales_order + 'sales_order': sales_order, + 'description': row.get("description"), + 'uom': row.get("purchase_uom") or row.get("stock_uom") } def get_sales_orders(self): diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 37a91d07783..3928c639ca4 100755 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -607,3 +607,4 @@ erpnext.patches.v11_1.set_quotation_status erpnext.patches.v11_1.update_default_supplier_in_item_defaults erpnext.patches.v11_1.set_status_for_material_request_type_manufacture erpnext.patches.v11_1.set_produced_qty_field_in_sales_order_for_work_order +erpnext.patches.v11_1.set_payment_entry_status \ No newline at end of file diff --git a/erpnext/patches/v11_1/set_payment_entry_status.py b/erpnext/patches/v11_1/set_payment_entry_status.py new file mode 100644 index 00000000000..fafbec6a9a7 --- /dev/null +++ b/erpnext/patches/v11_1/set_payment_entry_status.py @@ -0,0 +1,9 @@ +import frappe + +def execute(): + frappe.reload_doctype("Payment Entry") + frappe.db.sql("""update `tabPayment Entry` set status = CASE + WHEN docstatus = 1 THEN 'Submitted' + WHEN docstatus = 2 THEN 'Cancelled' + ELSE 'Draft' + END;""") \ No newline at end of file diff --git a/erpnext/regional/india/utils.py b/erpnext/regional/india/utils.py index 015aefb8b35..c03f68558ba 100644 --- a/erpnext/regional/india/utils.py +++ b/erpnext/regional/india/utils.py @@ -60,8 +60,8 @@ def validate_gstin_check_digit(gstin, label='GSTIN'): total += digit factor = 2 if factor == 1 else 1 if gstin[-1] != code_point_chars[((mod - (total % mod)) % mod)]: - frappe.throw(_("Invalid {0}! The check digit validation has failed. " + - "Please ensure you've typed the {0} correctly.".format(label))) + frappe.throw(_("""Invalid {0}! The check digit validation has failed. + Please ensure you've typed the {0} correctly.""".format(label))) def get_itemised_tax_breakup_header(item_doctype, tax_accounts): if frappe.get_meta(item_doctype).has_field('gst_hsn_code'): diff --git a/erpnext/shopping_cart/cart.py b/erpnext/shopping_cart/cart.py index a9861e83c16..c1ae739365f 100644 --- a/erpnext/shopping_cart/cart.py +++ b/erpnext/shopping_cart/cart.py @@ -454,9 +454,8 @@ def get_applicable_shipping_rules(party=None, quotation=None): shipping_rules = get_shipping_rules(quotation) if shipping_rules: - rule_label_map = frappe.db.get_values("Shipping Rule", shipping_rules, "label") # we need this in sorted order as per the position of the rule in the settings page - return [[rule, rule_label_map.get(rule)] for rule in shipping_rules] + return [[rule, rule] for rule in shipping_rules] def get_shipping_rules(quotation=None, cart_settings=None): if not quotation: diff --git a/erpnext/stock/doctype/packed_item/packed_item.py b/erpnext/stock/doctype/packed_item/packed_item.py index cf725272051..b45d5389d46 100644 --- a/erpnext/stock/doctype/packed_item/packed_item.py +++ b/erpnext/stock/doctype/packed_item/packed_item.py @@ -7,7 +7,6 @@ from __future__ import unicode_literals import frappe, json from frappe.utils import cstr, flt from erpnext.stock.get_item_details import get_item_details - from frappe.model.document import Document class PackedItem(Document): @@ -31,8 +30,11 @@ def get_bin_qty(item, warehouse): return det and det[0] or frappe._dict() def update_packing_list_item(doc, packing_item_code, qty, main_item_row, description): + if doc.amended_from: + old_packed_items_map = get_old_packed_item_details(doc.packed_items) + else: + old_packed_items_map = False item = get_packing_item_details(packing_item_code, doc.company) - # check if exists exists = 0 for d in doc.get("packed_items"): @@ -52,11 +54,10 @@ def update_packing_list_item(doc, packing_item_code, qty, main_item_row, descrip pi.uom = item.stock_uom pi.qty = flt(qty) pi.description = description - if not pi.warehouse: + if not pi.warehouse and not doc.amended_from: pi.warehouse = (main_item_row.warehouse if ((doc.get('is_pos') or not item.default_warehouse) and main_item_row.warehouse) else item.default_warehouse) - - if not pi.batch_no: + if not pi.batch_no and not doc.amended_from: pi.batch_no = cstr(main_item_row.get("batch_no")) if not pi.target_warehouse: pi.target_warehouse = main_item_row.get("target_warehouse") @@ -64,9 +65,13 @@ def update_packing_list_item(doc, packing_item_code, qty, main_item_row, descrip pi.actual_qty = flt(bin.get("actual_qty")) pi.projected_qty = flt(bin.get("projected_qty")) + if old_packed_items_map: + pi.batch_no = old_packed_items_map.get((packing_item_code, main_item_row.item_code))[0].batch_no + pi.serial_no = old_packed_items_map.get((packing_item_code, main_item_row.item_code))[0].serial_no + pi.warehouse = old_packed_items_map.get((packing_item_code, main_item_row.item_code))[0].warehouse + def make_packing_list(doc): """make packing list for Product Bundle item""" - if doc.get("_action") and doc._action == "update_after_submit": return parent_items = [] @@ -108,8 +113,14 @@ def get_items_from_product_bundle(args): "qty": flt(args["quantity"]) * flt(item.qty) }) items.append(get_item_details(args)) - + return items - + def on_doctype_update(): - frappe.db.add_index("Packed Item", ["item_code", "warehouse"]) \ No newline at end of file + frappe.db.add_index("Packed Item", ["item_code", "warehouse"]) + +def get_old_packed_item_details(old_packed_items): + old_packed_items_map = {} + for items in old_packed_items: + old_packed_items_map.setdefault((items.item_code ,items.parent_item), []).append(items.as_dict()) + return old_packed_items_map \ No newline at end of file diff --git a/erpnext/stock/report/stock_ledger/stock_ledger.py b/erpnext/stock/report/stock_ledger/stock_ledger.py index af5e5e9f0a0..44779ae90ad 100644 --- a/erpnext/stock/report/stock_ledger/stock_ledger.py +++ b/erpnext/stock/report/stock_ledger/stock_ledger.py @@ -19,10 +19,26 @@ def execute(filters=None): if opening_row: data.append(opening_row) + actual_qty = stock_value = 0 + for sle in sl_entries: item_detail = item_details[sle.item_code] sle.update(item_detail) + + if filters.get("batch_no"): + actual_qty += sle.actual_qty + stock_value += sle.stock_value_difference + + if sle.voucher_type == 'Stock Reconciliation': + actual_qty = sle.qty_after_transaction + stock_value = sle.stock_value + + sle.update({ + "qty_after_transaction": actual_qty, + "stock_value": stock_value + }) + data.append(sle) if include_uom: @@ -67,7 +83,7 @@ def get_stock_ledger_entries(filters, items): return frappe.db.sql("""select concat_ws(" ", posting_date, posting_time) as date, item_code, warehouse, actual_qty, qty_after_transaction, incoming_rate, valuation_rate, - stock_value, voucher_type, voucher_no, batch_no, serial_no, company, project + stock_value, voucher_type, voucher_no, batch_no, serial_no, company, project, stock_value_difference from `tabStock Ledger Entry` sle where company = %(company)s and posting_date between %(from_date)s and %(to_date)s