Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: refactor Asset Repair and Stock Entry linkage to resolve amendme… (backport #41919) #42058

Merged
merged 4 commits into from
Jul 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 3 additions & 10 deletions erpnext/accounts/doctype/budget/budget.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,9 +151,7 @@ def validate_expense_against_budget(args, expense_amount=0):
"Company", args.get("company"), "exception_budget_approver_role"
)

if not frappe.get_cached_value(
"Budget", {"fiscal_year": args.fiscal_year, "company": args.company}
): # nosec
if not frappe.get_cached_value("Budget", {"fiscal_year": args.fiscal_year, "company": args.company}): # nosec
return

if not args.account:
Expand Down Expand Up @@ -188,13 +186,8 @@ def validate_expense_against_budget(args, expense_amount=0):

if frappe.get_cached_value("DocType", doctype, "is_tree"):
lft, rgt = frappe.get_cached_value(doctype, args.get(budget_against), ["lft", "rgt"])
condition = """and exists(select name from `tab%s`
where lft<=%s and rgt>=%s and name=b.%s)""" % (
doctype,
lft,
rgt,
budget_against,
) # nosec
condition = f"""and exists(select name from `tab{doctype}`
where lft<={lft} and rgt>={rgt} and name=b.{budget_against})""" # nosec
args.is_tree = True
else:
condition = f"and b.{budget_against}={frappe.db.escape(args.get(budget_against))}"
Expand Down
4 changes: 1 addition & 3 deletions erpnext/accounts/doctype/gl_entry/gl_entry.py
Original file line number Diff line number Diff line change
Expand Up @@ -329,9 +329,7 @@ def update_outstanding_amt(

if against_voucher_type == "Sales Invoice":
party_account = frappe.get_cached_value(against_voucher_type, against_voucher, "debit_to")
account_condition = "and account in ({0}, {1})".format(
frappe.db.escape(account), frappe.db.escape(party_account)
)
account_condition = f"and account in ({frappe.db.escape(account)}, {frappe.db.escape(party_account)})"
else:
account_condition = f" and account = {frappe.db.escape(account)}"

Expand Down
45 changes: 39 additions & 6 deletions erpnext/assets/doctype/asset_repair/asset_repair.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,14 @@ frappe.ui.form.on("Asset Repair", {
};
};

frm.fields_dict.warehouse.get_query = function (doc) {
frm.set_query("warehouse", "stock_items", function () {
return {
filters: {
is_group: 0,
company: doc.company,
company: frm.doc.company,
},
};
};
});

frm.set_query("serial_and_batch_bundle", "stock_items", (doc, cdt, cdn) => {
let row = locals[cdt][cdn];
Expand Down Expand Up @@ -79,23 +79,56 @@ frappe.ui.form.on("Asset Repair", {
});
}

if (frm.doc.repair_status == "Completed") {
if (frm.doc.repair_status == "Completed" && !frm.doc.completion_date) {
frm.set_value("completion_date", frappe.datetime.now_datetime());
}
},

stock_items_on_form_rendered() {
erpnext.setup_serial_or_batch_no();
},

stock_consumption: function (frm) {
if (!frm.doc.stock_consumption) {
frm.clear_table("stock_items");
frm.refresh_field("stock_items");
}
},

purchase_invoice: function (frm) {
if (frm.doc.purchase_invoice) {
frappe.call({
method: "frappe.client.get_value",
args: {
doctype: "Purchase Invoice",
fieldname: "base_net_total",
filters: { name: frm.doc.purchase_invoice },
},
callback: function (r) {
if (r.message) {
frm.set_value("repair_cost", r.message.base_net_total);
}
},
});
} else {
frm.set_value("repair_cost", 0);
}
},
});

frappe.ui.form.on("Asset Repair Consumed Item", {
item_code: function (frm, cdt, cdn) {
warehouse: function (frm, cdt, cdn) {
var item = locals[cdt][cdn];

if (!item.item_code) {
frappe.msgprint(__("Please select an item code before setting the warehouse."));
frappe.model.set_value(cdt, cdn, "warehouse", "");
return;
}

let item_args = {
item_code: item.item_code,
warehouse: frm.doc.warehouse,
warehouse: item.warehouse,
qty: item.consumed_quantity,
serial_no: item.serial_no,
company: frm.doc.company,
Expand Down
26 changes: 5 additions & 21 deletions erpnext/assets/doctype/asset_repair/asset_repair.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,14 @@
"column_break_14",
"project",
"accounting_details",
"repair_cost",
"purchase_invoice",
"capitalize_repair_cost",
"stock_consumption",
"column_break_8",
"purchase_invoice",
"repair_cost",
"stock_consumption_details_section",
"warehouse",
"stock_items",
"total_repair_cost",
"stock_entry",
"asset_depreciation_details_section",
"increase_in_asset_life",
"section_break_9",
Expand Down Expand Up @@ -122,7 +120,8 @@
"default": "0",
"fieldname": "repair_cost",
"fieldtype": "Currency",
"label": "Repair Cost"
"label": "Repair Cost",
"read_only": 1
},
{
"fieldname": "amended_from",
Expand Down Expand Up @@ -218,13 +217,6 @@
"label": "Total Repair Cost",
"read_only": 1
},
{
"depends_on": "stock_consumption",
"fieldname": "warehouse",
"fieldtype": "Link",
"label": "Warehouse",
"options": "Warehouse"
},
{
"depends_on": "capitalize_repair_cost",
"fieldname": "asset_depreciation_details_section",
Expand All @@ -251,20 +243,12 @@
"fieldtype": "Link",
"label": "Company",
"options": "Company"
},
{
"fieldname": "stock_entry",
"fieldtype": "Link",
"label": "Stock Entry",
"no_copy": 1,
"options": "Stock Entry",
"read_only": 1
}
],
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
"modified": "2022-08-16 15:55:25.023471",
"modified": "2024-06-13 16:14:14.398356",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset Repair",
Expand Down
94 changes: 43 additions & 51 deletions erpnext/assets/doctype/asset_repair/asset_repair.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,20 +47,25 @@ class AssetRepair(AccountsController):
repair_cost: DF.Currency
repair_status: DF.Literal["Pending", "Completed", "Cancelled"]
stock_consumption: DF.Check
stock_entry: DF.Link | None
stock_items: DF.Table[AssetRepairConsumedItem]
total_repair_cost: DF.Currency
warehouse: DF.Link | None
# end: auto-generated types

def validate(self):
self.asset_doc = frappe.get_doc("Asset", self.asset)
self.validate_dates()
self.update_status()

if self.get("stock_items"):
self.set_stock_items_cost()
self.calculate_total_repair_cost()

def validate_dates(self):
if self.completion_date and (self.failure_date > self.completion_date):
frappe.throw(
_("Completion Date can not be before Failure Date. Please adjust the dates accordingly.")
)

def update_status(self):
if self.repair_status == "Pending" and self.asset_doc.status != "Out of Order":
frappe.db.set_value("Asset", self.asset, "status", "Out of Order")
Expand Down Expand Up @@ -105,22 +110,22 @@ def before_submit(self):
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()

add_asset_activity(
self.asset,
_("Asset updated after completion of Asset Repair {0}").format(
get_link_to_form("Asset Repair", self.name)
),
)
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()

add_asset_activity(
self.asset,
_("Asset updated after completion of Asset Repair {0}").format(
get_link_to_form("Asset Repair", self.name)
),
)

def before_cancel(self):
self.asset_doc = frappe.get_doc("Asset", self.asset)
Expand All @@ -136,29 +141,28 @@ def before_cancel(self):
self.asset_doc.total_asset_cost -= self.repair_cost
self.asset_doc.additional_asset_cost -= self.repair_cost

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()

add_asset_activity(
self.asset,
_("Asset updated after cancellation of Asset Repair {0}").format(
get_link_to_form("Asset Repair", self.name)
),
)
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()

add_asset_activity(
self.asset,
_("Asset updated after cancellation of Asset Repair {0}").format(
get_link_to_form("Asset Repair", self.name)
),
)

def after_delete(self):
frappe.get_doc("Asset", self.asset).set_status()
Expand All @@ -170,11 +174,6 @@ def check_repair_status(self):
def check_for_stock_items_and_warehouse(self):
if not self.get("stock_items"):
frappe.throw(_("Please enter Stock Items consumed during the Repair."), title=_("Missing Items"))
if not self.warehouse:
frappe.throw(
_("Please enter Warehouse from which Stock Items consumed during the Repair were taken."),
title=_("Missing Warehouse"),
)

def increase_asset_value(self):
total_value_of_stock_consumed = self.get_total_value_of_stock_consumed()
Expand Down Expand Up @@ -208,14 +207,15 @@ def decrease_stock_quantity(self):
stock_entry = frappe.get_doc(
{"doctype": "Stock Entry", "stock_entry_type": "Material Issue", "company": self.company}
)
stock_entry.asset_repair = self.name

for stock_item in self.get("stock_items"):
self.validate_serial_no(stock_item)

stock_entry.append(
"items",
{
"s_warehouse": self.warehouse,
"s_warehouse": stock_item.warehouse,
"item_code": stock_item.item_code,
"qty": stock_item.consumed_quantity,
"basic_rate": stock_item.valuation_rate,
Expand All @@ -228,8 +228,6 @@ def decrease_stock_quantity(self):
stock_entry.insert()
stock_entry.submit()

self.db_set("stock_entry", stock_entry.name)

def validate_serial_no(self, stock_item):
if not stock_item.serial_and_batch_bundle and frappe.get_cached_value(
"Item", stock_item.item_code, "has_serial_no"
Expand All @@ -247,12 +245,6 @@ def validate_serial_no(self, stock_item):
"Serial and Batch Bundle", stock_item.serial_and_batch_bundle, values_to_update
)

def increase_stock_quantity(self):
if self.stock_entry:
stock_entry = frappe.get_doc("Stock Entry", self.stock_entry)
stock_entry.flags.ignore_links = True
stock_entry.cancel()

def make_gl_entries(self, cancel=False):
if flt(self.total_repair_cost) > 0:
gl_entries = self.get_gl_entries()
Expand Down Expand Up @@ -316,7 +308,7 @@ def get_gl_entries_for_consumed_items(self, gl_entries, fixed_asset_account):
return

# creating GL Entries for each row in Stock Items based on the Stock Entry created for it
stock_entry = frappe.get_doc("Stock Entry", self.stock_entry)
stock_entry = frappe.get_doc("Stock Entry", {"asset_repair": self.name})

default_expense_account = None
if not erpnext.is_perpetual_inventory_enabled(self.company):
Expand Down Expand Up @@ -357,7 +349,7 @@ def get_gl_entries_for_consumed_items(self, gl_entries, fixed_asset_account):
"cost_center": self.cost_center,
"posting_date": getdate(),
"against_voucher_type": "Stock Entry",
"against_voucher": self.stock_entry,
"against_voucher": stock_entry.name,
"company": self.company,
},
item=self,
Expand Down
Loading
Loading