mirror of
https://github.com/frappe/erpnext.git
synced 2026-05-26 16:34:46 +00:00
feat: multiple purchase invoice in asset repair doctype (#43460)
Co-authored-by: “rahulgupta8848” <“rahul.gupta@8848digital.com”>
This commit is contained in:
@@ -29,8 +29,9 @@ frappe.ui.form.on("Asset Repair", {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
frm.set_query("purchase_invoice", function () {
|
frm.set_query("purchase_invoice", "invoices", function () {
|
||||||
return {
|
return {
|
||||||
|
query: "erpnext.assets.doctype.asset_repair.asset_repair.get_purchase_invoice",
|
||||||
filters: {
|
filters: {
|
||||||
company: frm.doc.company,
|
company: frm.doc.company,
|
||||||
docstatus: 1,
|
docstatus: 1,
|
||||||
@@ -58,6 +59,16 @@ frappe.ui.form.on("Asset Repair", {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
frm.set_query("expense_account", "invoices", function () {
|
||||||
|
return {
|
||||||
|
filters: {
|
||||||
|
company: frm.doc.company,
|
||||||
|
is_group: ["=", 0],
|
||||||
|
report_type: ["=", "Profit and Loss"],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
refresh: function (frm) {
|
refresh: function (frm) {
|
||||||
|
|||||||
@@ -22,7 +22,8 @@
|
|||||||
"column_break_14",
|
"column_break_14",
|
||||||
"project",
|
"project",
|
||||||
"accounting_details",
|
"accounting_details",
|
||||||
"purchase_invoice",
|
"invoices",
|
||||||
|
"section_break_y7cc",
|
||||||
"capitalize_repair_cost",
|
"capitalize_repair_cost",
|
||||||
"stock_consumption",
|
"stock_consumption",
|
||||||
"column_break_8",
|
"column_break_8",
|
||||||
@@ -229,26 +230,30 @@
|
|||||||
"label": "Increase In Asset Life(Months)",
|
"label": "Increase In Asset Life(Months)",
|
||||||
"no_copy": 1
|
"no_copy": 1
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"fieldname": "purchase_invoice",
|
|
||||||
"fieldtype": "Link",
|
|
||||||
"label": "Purchase Invoice",
|
|
||||||
"mandatory_depends_on": "eval: doc.repair_status == 'Completed' && doc.repair_cost > 0",
|
|
||||||
"no_copy": 1,
|
|
||||||
"options": "Purchase Invoice"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"fetch_from": "asset.company",
|
"fetch_from": "asset.company",
|
||||||
"fieldname": "company",
|
"fieldname": "company",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"label": "Company",
|
"label": "Company",
|
||||||
"options": "Company"
|
"options": "Company"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "invoices",
|
||||||
|
"fieldtype": "Table",
|
||||||
|
"label": "Asset Repair Purchase Invoices",
|
||||||
|
"mandatory_depends_on": "eval: doc.repair_status == 'Completed' && doc.repair_cost > 0;",
|
||||||
|
"no_copy": 1,
|
||||||
|
"options": "Asset Repair Purchase Invoice"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "section_break_y7cc",
|
||||||
|
"fieldtype": "Section Break"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2024-06-13 16:14:14.398356",
|
"modified": "2024-09-30 13:02:06.931188",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Assets",
|
"module": "Assets",
|
||||||
"name": "Asset Repair",
|
"name": "Asset Repair",
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
import frappe
|
import frappe
|
||||||
from frappe import _
|
from frappe import _
|
||||||
|
from frappe.query_builder import DocType
|
||||||
from frappe.utils import add_months, cint, flt, get_link_to_form, getdate, time_diff_in_hours
|
from frappe.utils import add_months, cint, flt, get_link_to_form, getdate, time_diff_in_hours
|
||||||
|
|
||||||
import erpnext
|
import erpnext
|
||||||
@@ -28,6 +29,9 @@ class AssetRepair(AccountsController):
|
|||||||
from erpnext.assets.doctype.asset_repair_consumed_item.asset_repair_consumed_item import (
|
from erpnext.assets.doctype.asset_repair_consumed_item.asset_repair_consumed_item import (
|
||||||
AssetRepairConsumedItem,
|
AssetRepairConsumedItem,
|
||||||
)
|
)
|
||||||
|
from erpnext.assets.doctype.asset_repair_purchase_invoice.asset_repair_purchase_invoice import (
|
||||||
|
AssetRepairPurchaseInvoice,
|
||||||
|
)
|
||||||
|
|
||||||
actions_performed: DF.LongText | None
|
actions_performed: DF.LongText | None
|
||||||
amended_from: DF.Link | None
|
amended_from: DF.Link | None
|
||||||
@@ -41,9 +45,9 @@ class AssetRepair(AccountsController):
|
|||||||
downtime: DF.Data | None
|
downtime: DF.Data | None
|
||||||
failure_date: DF.Datetime
|
failure_date: DF.Datetime
|
||||||
increase_in_asset_life: DF.Int
|
increase_in_asset_life: DF.Int
|
||||||
|
invoices: DF.Table[AssetRepairPurchaseInvoice]
|
||||||
naming_series: DF.Literal["ACC-ASR-.YYYY.-"]
|
naming_series: DF.Literal["ACC-ASR-.YYYY.-"]
|
||||||
project: DF.Link | None
|
project: DF.Link | None
|
||||||
purchase_invoice: DF.Link | None
|
|
||||||
repair_cost: DF.Currency
|
repair_cost: DF.Currency
|
||||||
repair_status: DF.Literal["Pending", "Completed", "Cancelled"]
|
repair_status: DF.Literal["Pending", "Completed", "Cancelled"]
|
||||||
stock_consumption: DF.Check
|
stock_consumption: DF.Check
|
||||||
@@ -54,10 +58,15 @@ class AssetRepair(AccountsController):
|
|||||||
def validate(self):
|
def validate(self):
|
||||||
self.asset_doc = frappe.get_doc("Asset", self.asset)
|
self.asset_doc = frappe.get_doc("Asset", self.asset)
|
||||||
self.validate_dates()
|
self.validate_dates()
|
||||||
|
self.validate_purchase_invoice()
|
||||||
|
self.validate_purchase_invoice_repair_cost()
|
||||||
|
self.validate_purchase_invoice_expense_account()
|
||||||
self.update_status()
|
self.update_status()
|
||||||
|
|
||||||
if self.get("stock_items"):
|
if self.get("stock_items"):
|
||||||
self.set_stock_items_cost()
|
self.set_stock_items_cost()
|
||||||
|
|
||||||
|
self.calculate_repair_cost()
|
||||||
self.calculate_total_repair_cost()
|
self.calculate_total_repair_cost()
|
||||||
|
|
||||||
def validate_dates(self):
|
def validate_dates(self):
|
||||||
@@ -66,6 +75,31 @@ class AssetRepair(AccountsController):
|
|||||||
_("Completion Date can not be before Failure Date. Please adjust the dates accordingly.")
|
_("Completion Date can not be before Failure Date. Please adjust the dates accordingly.")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def validate_purchase_invoice(self):
|
||||||
|
query = expense_item_pi_query(self.company)
|
||||||
|
purchase_invoice_list = [item[0] for item in query.run()]
|
||||||
|
for pi in self.invoices:
|
||||||
|
if pi.purchase_invoice not in purchase_invoice_list:
|
||||||
|
frappe.throw(_("Expense item not present in Purchase Invoice"))
|
||||||
|
|
||||||
|
def validate_purchase_invoice_repair_cost(self):
|
||||||
|
for pi in self.invoices:
|
||||||
|
if flt(pi.repair_cost) > frappe.db.get_value(
|
||||||
|
"Purchase Invoice", pi.purchase_invoice, "base_net_total"
|
||||||
|
):
|
||||||
|
frappe.throw(_("Repair cost cannot be greater than purchase invoice base net total"))
|
||||||
|
|
||||||
|
def validate_purchase_invoice_expense_account(self):
|
||||||
|
for pi in self.invoices:
|
||||||
|
if pi.expense_account not in frappe.db.get_all(
|
||||||
|
"Purchase Invoice Item", {"parent": pi.purchase_invoice}, pluck="expense_account"
|
||||||
|
):
|
||||||
|
frappe.throw(
|
||||||
|
_("Expense account not present in Purchase Invoice {0}").format(
|
||||||
|
get_link_to_form("Purchase Invoice", pi.purchase_invoice)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
def update_status(self):
|
def update_status(self):
|
||||||
if self.repair_status == "Pending" and self.asset_doc.status != "Out of Order":
|
if self.repair_status == "Pending" and self.asset_doc.status != "Out of Order":
|
||||||
frappe.db.set_value("Asset", self.asset, "status", "Out of Order")
|
frappe.db.set_value("Asset", self.asset, "status", "Out of Order")
|
||||||
@@ -82,6 +116,9 @@ class AssetRepair(AccountsController):
|
|||||||
for item in self.get("stock_items"):
|
for item in self.get("stock_items"):
|
||||||
item.total_value = flt(item.valuation_rate) * flt(item.consumed_quantity)
|
item.total_value = flt(item.valuation_rate) * flt(item.consumed_quantity)
|
||||||
|
|
||||||
|
def calculate_repair_cost(self):
|
||||||
|
self.repair_cost = sum(flt(pi.repair_cost) for pi in self.invoices)
|
||||||
|
|
||||||
def calculate_total_repair_cost(self):
|
def calculate_total_repair_cost(self):
|
||||||
self.total_repair_cost = flt(self.repair_cost)
|
self.total_repair_cost = flt(self.repair_cost)
|
||||||
|
|
||||||
@@ -267,40 +304,39 @@ class AssetRepair(AccountsController):
|
|||||||
if flt(self.repair_cost) <= 0:
|
if flt(self.repair_cost) <= 0:
|
||||||
return
|
return
|
||||||
|
|
||||||
pi_expense_account = (
|
debit_against_account = set()
|
||||||
frappe.get_doc("Purchase Invoice", self.purchase_invoice).items[0].expense_account
|
|
||||||
)
|
|
||||||
|
|
||||||
|
for pi in self.invoices:
|
||||||
|
debit_against_account.add(pi.expense_account)
|
||||||
|
gl_entries.append(
|
||||||
|
self.get_gl_dict(
|
||||||
|
{
|
||||||
|
"account": pi.expense_account,
|
||||||
|
"credit": pi.repair_cost,
|
||||||
|
"credit_in_account_currency": pi.repair_cost,
|
||||||
|
"against": fixed_asset_account,
|
||||||
|
"voucher_type": self.doctype,
|
||||||
|
"voucher_no": self.name,
|
||||||
|
"cost_center": self.cost_center,
|
||||||
|
"posting_date": getdate(),
|
||||||
|
"company": self.company,
|
||||||
|
},
|
||||||
|
item=self,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
debit_against_account = ", ".join(debit_against_account)
|
||||||
gl_entries.append(
|
gl_entries.append(
|
||||||
self.get_gl_dict(
|
self.get_gl_dict(
|
||||||
{
|
{
|
||||||
"account": fixed_asset_account,
|
"account": fixed_asset_account,
|
||||||
"debit": self.repair_cost,
|
"debit": self.repair_cost,
|
||||||
"debit_in_account_currency": self.repair_cost,
|
"debit_in_account_currency": self.repair_cost,
|
||||||
"against": pi_expense_account,
|
"against": debit_against_account,
|
||||||
"voucher_type": self.doctype,
|
"voucher_type": self.doctype,
|
||||||
"voucher_no": self.name,
|
"voucher_no": self.name,
|
||||||
"cost_center": self.cost_center,
|
"cost_center": self.cost_center,
|
||||||
"posting_date": getdate(),
|
"posting_date": getdate(),
|
||||||
"against_voucher_type": "Purchase Invoice",
|
"against_voucher_type": "Purchase Invoice",
|
||||||
"against_voucher": self.purchase_invoice,
|
|
||||||
"company": self.company,
|
|
||||||
},
|
|
||||||
item=self,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
gl_entries.append(
|
|
||||||
self.get_gl_dict(
|
|
||||||
{
|
|
||||||
"account": pi_expense_account,
|
|
||||||
"credit": self.repair_cost,
|
|
||||||
"credit_in_account_currency": self.repair_cost,
|
|
||||||
"against": fixed_asset_account,
|
|
||||||
"voucher_type": self.doctype,
|
|
||||||
"voucher_no": self.name,
|
|
||||||
"cost_center": self.cost_center,
|
|
||||||
"posting_date": getdate(),
|
|
||||||
"company": self.company,
|
"company": self.company,
|
||||||
},
|
},
|
||||||
item=self,
|
item=self,
|
||||||
@@ -432,3 +468,31 @@ class AssetRepair(AccountsController):
|
|||||||
def get_downtime(failure_date, completion_date):
|
def get_downtime(failure_date, completion_date):
|
||||||
downtime = time_diff_in_hours(completion_date, failure_date)
|
downtime = time_diff_in_hours(completion_date, failure_date)
|
||||||
return round(downtime, 2)
|
return round(downtime, 2)
|
||||||
|
|
||||||
|
|
||||||
|
@frappe.whitelist()
|
||||||
|
def get_purchase_invoice(doctype, txt, searchfield, start, page_len, filters):
|
||||||
|
query = expense_item_pi_query(filters.get("company"))
|
||||||
|
return query.run(as_list=1)
|
||||||
|
|
||||||
|
|
||||||
|
def expense_item_pi_query(company):
|
||||||
|
PurchaseInvoice = DocType("Purchase Invoice")
|
||||||
|
PurchaseInvoiceItem = DocType("Purchase Invoice Item")
|
||||||
|
Item = DocType("Item")
|
||||||
|
|
||||||
|
query = (
|
||||||
|
frappe.qb.from_(PurchaseInvoice)
|
||||||
|
.join(PurchaseInvoiceItem)
|
||||||
|
.on(PurchaseInvoiceItem.parent == PurchaseInvoice.name)
|
||||||
|
.join(Item)
|
||||||
|
.on(Item.name == PurchaseInvoiceItem.item_code)
|
||||||
|
.select(PurchaseInvoice.name)
|
||||||
|
.where(
|
||||||
|
(Item.is_stock_item == 0)
|
||||||
|
& (Item.is_fixed_asset == 0)
|
||||||
|
& (PurchaseInvoice.company == company)
|
||||||
|
& (PurchaseInvoice.docstatus == 1)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return query
|
||||||
|
|||||||
@@ -126,15 +126,17 @@ class TestAssetRepair(unittest.TestCase):
|
|||||||
def test_increase_in_asset_value_due_to_repair_cost_capitalisation(self):
|
def test_increase_in_asset_value_due_to_repair_cost_capitalisation(self):
|
||||||
asset = create_asset(calculate_depreciation=1, submit=1)
|
asset = create_asset(calculate_depreciation=1, submit=1)
|
||||||
initial_asset_value = get_asset_value_after_depreciation(asset.name)
|
initial_asset_value = get_asset_value_after_depreciation(asset.name)
|
||||||
asset_repair = create_asset_repair(asset=asset, capitalize_repair_cost=1, submit=1)
|
asset_repair = create_asset_repair(
|
||||||
|
asset=asset, capitalize_repair_cost=1, item="_Test Non Stock Item", submit=1
|
||||||
|
)
|
||||||
asset.reload()
|
asset.reload()
|
||||||
|
|
||||||
increase_in_asset_value = get_asset_value_after_depreciation(asset.name) - initial_asset_value
|
increase_in_asset_value = get_asset_value_after_depreciation(asset.name) - initial_asset_value
|
||||||
self.assertEqual(asset_repair.repair_cost, increase_in_asset_value)
|
self.assertEqual(asset_repair.repair_cost, increase_in_asset_value)
|
||||||
|
|
||||||
def test_purchase_invoice(self):
|
def test_purchase_invoice(self):
|
||||||
asset_repair = create_asset_repair(capitalize_repair_cost=1, submit=1)
|
asset_repair = create_asset_repair(capitalize_repair_cost=1, item="_Test Non Stock Item", submit=1)
|
||||||
self.assertTrue(asset_repair.purchase_invoice)
|
self.assertTrue(asset_repair.invoices)
|
||||||
|
|
||||||
def test_gl_entries_with_perpetual_inventory(self):
|
def test_gl_entries_with_perpetual_inventory(self):
|
||||||
set_depreciation_settings_in_company(company="_Test Company with perpetual inventory")
|
set_depreciation_settings_in_company(company="_Test Company with perpetual inventory")
|
||||||
@@ -147,6 +149,7 @@ class TestAssetRepair(unittest.TestCase):
|
|||||||
"fixed_asset_account": "_Test Fixed Asset - TCP1",
|
"fixed_asset_account": "_Test Fixed Asset - TCP1",
|
||||||
"accumulated_depreciation_account": "_Test Accumulated Depreciations - TCP1",
|
"accumulated_depreciation_account": "_Test Accumulated Depreciations - TCP1",
|
||||||
"depreciation_expense_account": "_Test Depreciations - TCP1",
|
"depreciation_expense_account": "_Test Depreciations - TCP1",
|
||||||
|
"capital_work_in_progress_account": "CWIP Account - TCP1",
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
asset_category.save()
|
asset_category.save()
|
||||||
@@ -156,6 +159,9 @@ class TestAssetRepair(unittest.TestCase):
|
|||||||
stock_consumption=1,
|
stock_consumption=1,
|
||||||
warehouse="Stores - TCP1",
|
warehouse="Stores - TCP1",
|
||||||
company="_Test Company with perpetual inventory",
|
company="_Test Company with perpetual inventory",
|
||||||
|
pi_expense_account1="Administrative Expenses - TCP1",
|
||||||
|
pi_expense_account2="Legal Expenses - TCP1",
|
||||||
|
item="_Test Non Stock Item",
|
||||||
submit=1,
|
submit=1,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -181,16 +187,16 @@ class TestAssetRepair(unittest.TestCase):
|
|||||||
fixed_asset_account = get_asset_account(
|
fixed_asset_account = get_asset_account(
|
||||||
"fixed_asset_account", asset=asset_repair.asset, company=asset_repair.company
|
"fixed_asset_account", asset=asset_repair.asset, company=asset_repair.company
|
||||||
)
|
)
|
||||||
pi_expense_account = (
|
pi_expense_accounts = [pi.expense_account for pi in asset_repair.invoices]
|
||||||
frappe.get_doc("Purchase Invoice", asset_repair.purchase_invoice).items[0].expense_account
|
pi_repair_costs = [pi.repair_cost for pi in asset_repair.invoices]
|
||||||
)
|
|
||||||
stock_entry_expense_account = (
|
stock_entry_expense_account = (
|
||||||
frappe.get_doc("Stock Entry", {"asset_repair": asset_repair.name}).get("items")[0].expense_account
|
frappe.get_doc("Stock Entry", {"asset_repair": asset_repair.name}).get("items")[0].expense_account
|
||||||
)
|
)
|
||||||
|
|
||||||
expected_values = {
|
expected_values = {
|
||||||
fixed_asset_account: [asset_repair.total_repair_cost, 0],
|
fixed_asset_account: [asset_repair.total_repair_cost, 0],
|
||||||
pi_expense_account: [0, asset_repair.repair_cost],
|
pi_expense_accounts[0]: [0, pi_repair_costs[0]],
|
||||||
|
pi_expense_accounts[1]: [0, pi_repair_costs[1]],
|
||||||
stock_entry_expense_account: [0, 100],
|
stock_entry_expense_account: [0, 100],
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -203,6 +209,7 @@ class TestAssetRepair(unittest.TestCase):
|
|||||||
asset_repair = create_asset_repair(
|
asset_repair = create_asset_repair(
|
||||||
capitalize_repair_cost=1,
|
capitalize_repair_cost=1,
|
||||||
stock_consumption=1,
|
stock_consumption=1,
|
||||||
|
item="_Test Non Stock Item",
|
||||||
submit=1,
|
submit=1,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -231,8 +238,14 @@ class TestAssetRepair(unittest.TestCase):
|
|||||||
default_expense_account = frappe.get_cached_value(
|
default_expense_account = frappe.get_cached_value(
|
||||||
"Company", asset_repair.company, "default_expense_account"
|
"Company", asset_repair.company, "default_expense_account"
|
||||||
)
|
)
|
||||||
|
pi_expense_accounts = [pi.expense_account for pi in asset_repair.invoices]
|
||||||
|
|
||||||
expected_values = {fixed_asset_account: [1100, 0], default_expense_account: [0, 1100]}
|
expected_values = {
|
||||||
|
fixed_asset_account: [650, 0],
|
||||||
|
pi_expense_accounts[0]: [0, 250],
|
||||||
|
default_expense_account: [0, 100],
|
||||||
|
pi_expense_accounts[1]: [0, 300],
|
||||||
|
}
|
||||||
|
|
||||||
for d in gl_entries:
|
for d in gl_entries:
|
||||||
self.assertEqual(expected_values[d.account][0], d.debit)
|
self.assertEqual(expected_values[d.account][0], d.debit)
|
||||||
@@ -245,7 +258,7 @@ class TestAssetRepair(unittest.TestCase):
|
|||||||
self.assertEqual(first_asset_depr_schedule.status, "Active")
|
self.assertEqual(first_asset_depr_schedule.status, "Active")
|
||||||
|
|
||||||
initial_num_of_depreciations = num_of_depreciations(asset)
|
initial_num_of_depreciations = num_of_depreciations(asset)
|
||||||
create_asset_repair(asset=asset, capitalize_repair_cost=1, submit=1)
|
create_asset_repair(asset=asset, capitalize_repair_cost=1, item="_Test Non Stock Item", submit=1)
|
||||||
|
|
||||||
asset.reload()
|
asset.reload()
|
||||||
first_asset_depr_schedule.load_from_db()
|
first_asset_depr_schedule.load_from_db()
|
||||||
@@ -288,7 +301,6 @@ def create_asset_repair(**args):
|
|||||||
"asset_name": asset.asset_name,
|
"asset_name": asset.asset_name,
|
||||||
"failure_date": nowdate(),
|
"failure_date": nowdate(),
|
||||||
"description": "Test Description",
|
"description": "Test Description",
|
||||||
"repair_cost": 0,
|
|
||||||
"company": asset.company,
|
"company": asset.company,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@@ -351,16 +363,38 @@ def create_asset_repair(**args):
|
|||||||
|
|
||||||
if args.capitalize_repair_cost:
|
if args.capitalize_repair_cost:
|
||||||
asset_repair.capitalize_repair_cost = 1
|
asset_repair.capitalize_repair_cost = 1
|
||||||
asset_repair.repair_cost = 1000
|
|
||||||
if asset.calculate_depreciation:
|
if asset.calculate_depreciation:
|
||||||
asset_repair.increase_in_asset_life = 12
|
asset_repair.increase_in_asset_life = 12
|
||||||
pi = make_purchase_invoice(
|
pi1 = make_purchase_invoice(
|
||||||
company=asset.company,
|
company=asset.company,
|
||||||
expense_account=frappe.db.get_value("Company", asset.company, "default_expense_account"),
|
item=args.item or "_Test Item",
|
||||||
|
expense_account=args.pi_expense_account1 or "Administrative Expenses - _TC",
|
||||||
cost_center=asset_repair.cost_center,
|
cost_center=asset_repair.cost_center,
|
||||||
warehouse=args.warehouse or create_warehouse("Test Warehouse", company=asset.company),
|
warehouse=args.warehouse or create_warehouse("Test Warehouse", company=asset.company),
|
||||||
|
rate="50",
|
||||||
)
|
)
|
||||||
asset_repair.purchase_invoice = pi.name
|
pi2 = make_purchase_invoice(
|
||||||
|
company=asset.company,
|
||||||
|
item=args.item or "_Test Item",
|
||||||
|
expense_account=args.pi_expense_account2 or "Legal Expenses - _TC",
|
||||||
|
cost_center=asset_repair.cost_center,
|
||||||
|
warehouse=args.warehouse or create_warehouse("Test Warehouse", company=asset.company),
|
||||||
|
rate="60",
|
||||||
|
)
|
||||||
|
invoices = [
|
||||||
|
{
|
||||||
|
"purchase_invoice": pi1.name,
|
||||||
|
"expense_account": args.pi_expense_account1 or "Administrative Expenses - _TC",
|
||||||
|
"repair_cost": args.pi_repair_cost1 or 250,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"purchase_invoice": pi2.name,
|
||||||
|
"expense_account": args.pi_expense_account2 or "Legal Expenses - _TC",
|
||||||
|
"repair_cost": args.pi_repair_cost2 or 300,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
for invoice in invoices:
|
||||||
|
asset_repair.append("invoices", invoice)
|
||||||
asset_repair.submit()
|
asset_repair.submit()
|
||||||
return asset_repair
|
return asset_repair
|
||||||
|
|||||||
@@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"actions": [],
|
||||||
|
"allow_rename": 1,
|
||||||
|
"creation": "2024-09-30 12:52:08.085813",
|
||||||
|
"doctype": "DocType",
|
||||||
|
"editable_grid": 1,
|
||||||
|
"engine": "InnoDB",
|
||||||
|
"field_order": [
|
||||||
|
"purchase_invoice",
|
||||||
|
"expense_account",
|
||||||
|
"repair_cost"
|
||||||
|
],
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldname": "purchase_invoice",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Purchase Invoice",
|
||||||
|
"options": "Purchase Invoice"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "expense_account",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Expense Account",
|
||||||
|
"options": "Account",
|
||||||
|
"reqd": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "repair_cost",
|
||||||
|
"fieldtype": "Currency",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Repair Cost",
|
||||||
|
"options": "Company:company:default_currency",
|
||||||
|
"reqd": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"index_web_pages_for_search": 1,
|
||||||
|
"istable": 1,
|
||||||
|
"links": [],
|
||||||
|
"modified": "2024-09-30 13:02:43.040762",
|
||||||
|
"modified_by": "Administrator",
|
||||||
|
"module": "Assets",
|
||||||
|
"name": "Asset Repair Purchase Invoice",
|
||||||
|
"owner": "Administrator",
|
||||||
|
"permissions": [],
|
||||||
|
"sort_field": "creation",
|
||||||
|
"sort_order": "DESC",
|
||||||
|
"states": []
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
# Copyright (c) 2024, Frappe Technologies Pvt. Ltd. and contributors
|
||||||
|
# For license information, please see license.txt
|
||||||
|
|
||||||
|
# import frappe
|
||||||
|
from frappe.model.document import Document
|
||||||
|
|
||||||
|
|
||||||
|
class AssetRepairPurchaseInvoice(Document):
|
||||||
|
# begin: auto-generated types
|
||||||
|
# This code is auto-generated. Do not modify anything in this block.
|
||||||
|
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from frappe.types import DF
|
||||||
|
|
||||||
|
expense_account: DF.Link
|
||||||
|
parent: DF.Data
|
||||||
|
parentfield: DF.Data
|
||||||
|
parenttype: DF.Data
|
||||||
|
purchase_invoice: DF.Link | None
|
||||||
|
repair_cost: DF.Currency
|
||||||
|
# end: auto-generated types
|
||||||
|
|
||||||
|
pass
|
||||||
@@ -153,7 +153,9 @@ class TestAssetValueAdjustment(unittest.TestCase):
|
|||||||
post_depreciation_entries(getdate("2023-08-21"))
|
post_depreciation_entries(getdate("2023-08-21"))
|
||||||
|
|
||||||
# create asset repair
|
# create asset repair
|
||||||
asset_repair = create_asset_repair(asset=asset_doc, capitalize_repair_cost=1, submit=1)
|
asset_repair = create_asset_repair(
|
||||||
|
asset=asset_doc, capitalize_repair_cost=1, item="_Test Non Stock Item", submit=1
|
||||||
|
)
|
||||||
|
|
||||||
first_asset_depr_schedule = get_asset_depr_schedule_doc(asset_doc.name, "Active")
|
first_asset_depr_schedule = get_asset_depr_schedule_doc(asset_doc.name, "Active")
|
||||||
self.assertEqual(first_asset_depr_schedule.status, "Active")
|
self.assertEqual(first_asset_depr_schedule.status, "Active")
|
||||||
@@ -177,8 +179,8 @@ class TestAssetValueAdjustment(unittest.TestCase):
|
|||||||
|
|
||||||
# Test gl entry creted from asset value adjustemnet
|
# Test gl entry creted from asset value adjustemnet
|
||||||
expected_gle = (
|
expected_gle = (
|
||||||
("_Test Difference Account - _TC", 5625.29, 0.0),
|
("_Test Difference Account - _TC", 5175.29, 0.0),
|
||||||
("_Test Fixed Asset - _TC", 0.0, 5625.29),
|
("_Test Fixed Asset - _TC", 0.0, 5175.29),
|
||||||
)
|
)
|
||||||
|
|
||||||
gle = frappe.db.sql(
|
gle = frappe.db.sql(
|
||||||
@@ -244,12 +246,12 @@ class TestAssetValueAdjustment(unittest.TestCase):
|
|||||||
["2023-05-31", 9983.33, 45408.05],
|
["2023-05-31", 9983.33, 45408.05],
|
||||||
["2023-06-30", 9983.33, 55391.38],
|
["2023-06-30", 9983.33, 55391.38],
|
||||||
["2023-07-31", 9983.33, 65374.71],
|
["2023-07-31", 9983.33, 65374.71],
|
||||||
["2023-08-31", 8133.33, 73508.04],
|
["2023-08-31", 8208.33, 73583.04],
|
||||||
["2023-09-30", 8133.33, 81641.37],
|
["2023-09-30", 8208.33, 81791.37],
|
||||||
["2023-10-31", 8133.33, 89774.7],
|
["2023-10-31", 8208.33, 89999.7],
|
||||||
["2023-11-30", 8133.33, 97908.03],
|
["2023-11-30", 8208.33, 98208.03],
|
||||||
["2023-12-31", 8133.33, 106041.36],
|
["2023-12-31", 8208.33, 106416.36],
|
||||||
["2024-01-15", 8133.35, 114174.71],
|
["2024-01-15", 8208.35, 114624.71],
|
||||||
]
|
]
|
||||||
|
|
||||||
schedules = [
|
schedules = [
|
||||||
|
|||||||
Reference in New Issue
Block a user