Merge pull request #34257 from deepeshgarg007/opening_entry
feat: Closing balance for period closing and reporting
diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py
index e1d58a0..b5b7ba8 100644
--- a/erpnext/assets/doctype/asset/asset.py
+++ b/erpnext/assets/doctype/asset/asset.py
@@ -474,17 +474,21 @@
@erpnext.allow_regional
def get_depreciation_amount(self, depreciable_value, fb_row):
if fb_row.depreciation_method in ("Straight Line", "Manual"):
- # if the Depreciation Schedule is being prepared for the first time
- if not self.flags.increase_in_asset_life:
- depreciation_amount = (
- flt(self.gross_purchase_amount) - flt(fb_row.expected_value_after_useful_life)
- ) / flt(fb_row.total_number_of_depreciations)
-
- # if the Depreciation Schedule is being modified after Asset Repair
- else:
+ # if the Depreciation Schedule is being modified after Asset Repair due to increase in asset life and value
+ if self.flags.increase_in_asset_life:
depreciation_amount = (
flt(fb_row.value_after_depreciation) - flt(fb_row.expected_value_after_useful_life)
) / (date_diff(self.to_date, self.available_for_use_date) / 365)
+ # if the Depreciation Schedule is being modified after Asset Repair due to increase in asset value
+ elif self.flags.increase_in_asset_value_due_to_repair:
+ depreciation_amount = (
+ flt(fb_row.value_after_depreciation) - flt(fb_row.expected_value_after_useful_life)
+ ) / flt(fb_row.total_number_of_depreciations)
+ # if the Depreciation Schedule is being prepared for the first time
+ else:
+ depreciation_amount = (
+ flt(self.gross_purchase_amount) - flt(fb_row.expected_value_after_useful_life)
+ ) / flt(fb_row.total_number_of_depreciations)
else:
depreciation_amount = flt(depreciable_value * (flt(fb_row.rate_of_depreciation) / 100))
@@ -617,11 +621,22 @@
return 200.0 / args.get("total_number_of_depreciations")
if args.get("depreciation_method") == "Written Down Value":
- if args.get("rate_of_depreciation") and on_validate:
+ if (
+ args.get("rate_of_depreciation")
+ and on_validate
+ and not self.flags.increase_in_asset_value_due_to_repair
+ ):
return args.get("rate_of_depreciation")
- value = flt(args.get("expected_value_after_useful_life")) / flt(self.gross_purchase_amount)
+ if self.flags.increase_in_asset_value_due_to_repair:
+ value = flt(args.get("expected_value_after_useful_life")) / flt(
+ args.get("value_after_depreciation")
+ )
+ else:
+ value = flt(args.get("expected_value_after_useful_life")) / flt(self.gross_purchase_amount)
+
depreciation_rate = math.pow(value, 1.0 / flt(args.get("total_number_of_depreciations"), 2))
+
return flt((100 * (1 - depreciation_rate)), float_precision)
def get_pro_rata_amt(self, row, depreciation_amount, from_date, to_date):
diff --git a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py
index 5912329..d23edfa 100644
--- a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py
+++ b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py
@@ -460,6 +460,16 @@
new_asset_depr_schedule_doc = frappe.copy_doc(current_asset_depr_schedule_doc)
+ if asset_doc.flags.increase_in_asset_value_due_to_repair and row.depreciation_method in (
+ "Written Down Value",
+ "Double Declining Balance",
+ ):
+ new_rate_of_depreciation = flt(
+ asset_doc.get_depreciation_rate(row), row.precision("rate_of_depreciation")
+ )
+ row.rate_of_depreciation = new_rate_of_depreciation
+ new_asset_depr_schedule_doc.rate_of_depreciation = new_rate_of_depreciation
+
new_asset_depr_schedule_doc.make_depr_schedule(asset_doc, row, date_of_disposal)
new_asset_depr_schedule_doc.set_accumulated_depreciation(row, date_of_disposal, date_of_return)
diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.py b/erpnext/assets/doctype/asset_repair/asset_repair.py
index a7172a7..a913ee4 100644
--- a/erpnext/assets/doctype/asset_repair/asset_repair.py
+++ b/erpnext/assets/doctype/asset_repair/asset_repair.py
@@ -43,53 +43,57 @@
def before_submit(self):
self.check_repair_status()
- if self.get("stock_consumption") or self.get("capitalize_repair_cost"):
- self.increase_asset_value()
- if self.get("stock_consumption"):
- self.check_for_stock_items_and_warehouse()
- self.decrease_stock_quantity()
- if self.get("capitalize_repair_cost"):
- self.make_gl_entries()
- if (
- frappe.db.get_value("Asset", self.asset, "calculate_depreciation")
- and self.increase_in_asset_life
- ):
- self.modify_depreciation_schedule()
+ self.asset_doc.flags.increase_in_asset_value_due_to_repair = False
- notes = _(
- "This schedule was created when Asset {0} was repaired through Asset Repair {1}."
- ).format(
- get_link_to_form(self.asset_doc.doctype, self.asset_doc.name),
- get_link_to_form(self.doctype, self.name),
- )
- self.asset_doc.flags.ignore_validate_update_after_submit = True
- make_new_active_asset_depr_schedules_and_cancel_current_ones(self.asset_doc, notes)
- self.asset_doc.save()
+ if self.get("stock_consumption") or self.get("capitalize_repair_cost"):
+ self.asset_doc.flags.increase_in_asset_value_due_to_repair = True
+
+ self.increase_asset_value()
+
+ if self.get("stock_consumption"):
+ self.check_for_stock_items_and_warehouse()
+ self.decrease_stock_quantity()
+ if self.get("capitalize_repair_cost"):
+ self.make_gl_entries()
+ if self.asset_doc.calculate_depreciation and self.increase_in_asset_life:
+ self.modify_depreciation_schedule()
+
+ notes = _(
+ "This schedule was created when Asset {0} was repaired through Asset Repair {1}."
+ ).format(
+ get_link_to_form(self.asset_doc.doctype, self.asset_doc.name),
+ get_link_to_form(self.doctype, self.name),
+ )
+ self.asset_doc.flags.ignore_validate_update_after_submit = True
+ make_new_active_asset_depr_schedules_and_cancel_current_ones(self.asset_doc, notes)
+ self.asset_doc.save()
def before_cancel(self):
self.asset_doc = frappe.get_doc("Asset", self.asset)
- if self.get("stock_consumption") or self.get("capitalize_repair_cost"):
- self.decrease_asset_value()
- if self.get("stock_consumption"):
- self.increase_stock_quantity()
- if self.get("capitalize_repair_cost"):
- self.ignore_linked_doctypes = ("GL Entry", "Stock Ledger Entry")
- self.make_gl_entries(cancel=True)
- self.db_set("stock_entry", None)
- if (
- frappe.db.get_value("Asset", self.asset, "calculate_depreciation")
- and self.increase_in_asset_life
- ):
- self.revert_depreciation_schedule_on_cancellation()
+ self.asset_doc.flags.increase_in_asset_value_due_to_repair = False
- notes = _("This schedule was created when Asset {0}'s Asset Repair {1} was cancelled.").format(
- get_link_to_form(self.asset_doc.doctype, self.asset_doc.name),
- get_link_to_form(self.doctype, self.name),
- )
- self.asset_doc.flags.ignore_validate_update_after_submit = True
- make_new_active_asset_depr_schedules_and_cancel_current_ones(self.asset_doc, notes)
- self.asset_doc.save()
+ if self.get("stock_consumption") or self.get("capitalize_repair_cost"):
+ self.asset_doc.flags.increase_in_asset_value_due_to_repair = True
+
+ self.decrease_asset_value()
+
+ if self.get("stock_consumption"):
+ self.increase_stock_quantity()
+ if self.get("capitalize_repair_cost"):
+ self.ignore_linked_doctypes = ("GL Entry", "Stock Ledger Entry")
+ self.make_gl_entries(cancel=True)
+ self.db_set("stock_entry", None)
+ if self.asset_doc.calculate_depreciation and self.increase_in_asset_life:
+ self.revert_depreciation_schedule_on_cancellation()
+
+ notes = _("This schedule was created when Asset {0}'s Asset Repair {1} was cancelled.").format(
+ get_link_to_form(self.asset_doc.doctype, self.asset_doc.name),
+ get_link_to_form(self.doctype, self.name),
+ )
+ self.asset_doc.flags.ignore_validate_update_after_submit = True
+ make_new_active_asset_depr_schedules_and_cancel_current_ones(self.asset_doc, notes)
+ self.asset_doc.save()
def after_delete(self):
frappe.get_doc("Asset", self.asset).set_status()
diff --git a/erpnext/buying/doctype/supplier/supplier.py b/erpnext/buying/doctype/supplier/supplier.py
index 120b2f8..01b5c8f 100644
--- a/erpnext/buying/doctype/supplier/supplier.py
+++ b/erpnext/buying/doctype/supplier/supplier.py
@@ -125,18 +125,9 @@
def on_trash(self):
if self.supplier_primary_contact:
- frappe.db.sql(
- """
- UPDATE `tabSupplier`
- SET
- supplier_primary_contact=null,
- supplier_primary_address=null,
- mobile_no=null,
- email_id=null,
- primary_address=null
- WHERE name=%(name)s""",
- {"name": self.name},
- )
+ self.db_set("supplier_primary_contact", None)
+ if self.supplier_primary_address:
+ self.db_set("supplier_primary_address", None)
delete_contact_and_address("Supplier", self.name)
diff --git a/erpnext/manufacturing/doctype/job_card/job_card.js b/erpnext/manufacturing/doctype/job_card/job_card.js
index 619e6bd..5305db3 100644
--- a/erpnext/manufacturing/doctype/job_card/job_card.js
+++ b/erpnext/manufacturing/doctype/job_card/job_card.js
@@ -83,7 +83,7 @@
// and if stock mvt for WIP is required
if (frm.doc.work_order) {
frappe.db.get_value('Work Order', frm.doc.work_order, ['skip_transfer', 'status'], (result) => {
- if (result.skip_transfer === 1 || result.status == 'In Process') {
+ if (result.skip_transfer === 1 || result.status == 'In Process' || frm.doc.transferred_qty > 0) {
frm.trigger("prepare_timer_buttons");
}
});
diff --git a/erpnext/public/js/templates/crm_notes.html b/erpnext/public/js/templates/crm_notes.html
index fddeb1c..53df933 100644
--- a/erpnext/public/js/templates/crm_notes.html
+++ b/erpnext/public/js/templates/crm_notes.html
@@ -17,7 +17,7 @@
{{ frappe.avatar(notes[i].added_by) }}
</div>
<div class="col-xs-10">
- <div class="mr-2 title font-weight-bold">
+ <div class="mr-2 title font-weight-bold ellipsis" title="{{ strip_html(notes[i].added_by) }}">
{{ strip_html(notes[i].added_by) }}
</div>
<div class="time small text-muted">
diff --git a/erpnext/selling/doctype/customer/customer.py b/erpnext/selling/doctype/customer/customer.py
index d9dab33..baa316f 100644
--- a/erpnext/selling/doctype/customer/customer.py
+++ b/erpnext/selling/doctype/customer/customer.py
@@ -272,18 +272,9 @@
def on_trash(self):
if self.customer_primary_contact:
- frappe.db.sql(
- """
- UPDATE `tabCustomer`
- SET
- customer_primary_contact=null,
- customer_primary_address=null,
- mobile_no=null,
- email_id=null,
- primary_address=null
- WHERE name=%(name)s""",
- {"name": self.name},
- )
+ self.db_set("customer_primary_contact", None)
+ if self.customer_primary_address:
+ self.db_set("customer_primary_address", None)
delete_contact_and_address("Customer", self.name)
if self.lead_name:
diff --git a/erpnext/selling/report/sales_partner_target_variance_based_on_item_group/item_group_wise_sales_target_variance.py b/erpnext/selling/report/sales_partner_target_variance_based_on_item_group/item_group_wise_sales_target_variance.py
index f34f3e3..7d28f2b 100644
--- a/erpnext/selling/report/sales_partner_target_variance_based_on_item_group/item_group_wise_sales_target_variance.py
+++ b/erpnext/selling/report/sales_partner_target_variance_based_on_item_group/item_group_wise_sales_target_variance.py
@@ -44,20 +44,30 @@
if not sales_users_data:
return
- sales_users, item_groups = [], []
+ sales_users = []
+ sales_user_wise_item_groups = {}
for d in sales_users_data:
if d.parent not in sales_users:
sales_users.append(d.parent)
- if d.item_group not in item_groups:
- item_groups.append(d.item_group)
+ sales_user_wise_item_groups.setdefault(d.parent, [])
+ if d.item_group:
+ sales_user_wise_item_groups[d.parent].append(d.item_group)
date_field = "transaction_date" if filters.get("doctype") == "Sales Order" else "posting_date"
- actual_data = get_actual_data(filters, item_groups, sales_users, date_field, sales_field)
+ actual_data = get_actual_data(filters, sales_users, date_field, sales_field)
- return prepare_data(filters, sales_users_data, actual_data, date_field, period_list, sales_field)
+ return prepare_data(
+ filters,
+ sales_users_data,
+ sales_user_wise_item_groups,
+ actual_data,
+ date_field,
+ period_list,
+ sales_field,
+ )
def get_columns(filters, period_list, partner_doctype):
@@ -142,7 +152,15 @@
return columns
-def prepare_data(filters, sales_users_data, actual_data, date_field, period_list, sales_field):
+def prepare_data(
+ filters,
+ sales_users_data,
+ sales_user_wise_item_groups,
+ actual_data,
+ date_field,
+ period_list,
+ sales_field,
+):
rows = {}
target_qty_amt_field = "target_qty" if filters.get("target_on") == "Quantity" else "target_amount"
@@ -173,9 +191,9 @@
for r in actual_data:
if (
r.get(sales_field) == d.parent
- and r.item_group == d.item_group
and period.from_date <= r.get(date_field)
and r.get(date_field) <= period.to_date
+ and (not sales_user_wise_item_groups.get(d.parent) or r.item_group == d.item_group)
):
details[p_key] += r.get(qty_or_amount_field, 0)
details[variance_key] = details.get(p_key) - details.get(target_key)
@@ -186,7 +204,7 @@
return rows
-def get_actual_data(filters, item_groups, sales_users_or_territory_data, date_field, sales_field):
+def get_actual_data(filters, sales_users_or_territory_data, date_field, sales_field):
fiscal_year = get_fiscal_year(fiscal_year=filters.get("fiscal_year"), as_dict=1)
dates = [fiscal_year.year_start_date, fiscal_year.year_end_date]
@@ -213,7 +231,6 @@
WHERE
`tab{child_doc}`.parent = `tab{parent_doc}`.name
and `tab{parent_doc}`.docstatus = 1 and {cond}
- and `tab{child_doc}`.item_group in ({item_groups})
and `tab{parent_doc}`.{date_field} between %s and %s""".format(
cond=cond,
date_field=date_field,
@@ -221,9 +238,8 @@
child_table=child_table,
parent_doc=filters.get("doctype"),
child_doc=filters.get("doctype") + " Item",
- item_groups=",".join(["%s"] * len(item_groups)),
),
- tuple(sales_users_or_territory_data + item_groups + dates),
+ tuple(sales_users_or_territory_data + dates),
as_dict=1,
)
diff --git a/erpnext/selling/report/sales_person_target_variance_based_on_item_group/sales_person_target_variance_based_on_item_group.py b/erpnext/selling/report/sales_person_target_variance_based_on_item_group/sales_person_target_variance_based_on_item_group.py
index dda2466..8207122 100644
--- a/erpnext/selling/report/sales_person_target_variance_based_on_item_group/sales_person_target_variance_based_on_item_group.py
+++ b/erpnext/selling/report/sales_person_target_variance_based_on_item_group/sales_person_target_variance_based_on_item_group.py
@@ -8,6 +8,4 @@
def execute(filters=None):
- data = []
-
return get_data_column(filters, "Sales Person")