diff --git a/erpnext/assets/doctype/asset_movement/asset_movement.py b/erpnext/assets/doctype/asset_movement/asset_movement.py index 25a06e463bb..c3248563440 100644 --- a/erpnext/assets/doctype/asset_movement/asset_movement.py +++ b/erpnext/assets/doctype/asset_movement/asset_movement.py @@ -5,7 +5,7 @@ import frappe from frappe import _ from frappe.model.document import Document -from frappe.utils import cstr, get_link_to_form +from frappe.utils import cstr, get_datetime, get_link_to_form from erpnext.assets.doctype.asset_activity.asset_activity import add_asset_activity @@ -34,6 +34,7 @@ class AssetMovement(Document): for d in self.assets: self.validate_asset(d) self.validate_movement(d) + self.validate_transaction_date(d) def validate_asset(self, d): status, company = frappe.db.get_value("Asset", d.asset, ["status", "company"]) @@ -51,6 +52,18 @@ class AssetMovement(Document): else: self.validate_employee(d) + def validate_transaction_date(self, d): + previous_movement_date = frappe.db.get_value( + "Asset Movement", + [["Asset Movement Item", "asset", "=", d.asset], ["docstatus", "=", 1]], + "transaction_date", + order_by="transaction_date desc", + ) + if previous_movement_date and get_datetime(previous_movement_date) > get_datetime( + self.transaction_date + ): + frappe.throw(_("Transaction date can't be earlier than previous movement date")) + def validate_location_and_employee(self, d): self.validate_location(d) self.validate_employee(d) diff --git a/erpnext/assets/doctype/asset_movement/test_asset_movement.py b/erpnext/assets/doctype/asset_movement/test_asset_movement.py index 29d9ba72328..33eaa7e7e4c 100644 --- a/erpnext/assets/doctype/asset_movement/test_asset_movement.py +++ b/erpnext/assets/doctype/asset_movement/test_asset_movement.py @@ -3,9 +3,9 @@ import frappe from frappe.tests import IntegrationTestCase -from frappe.utils import now +from frappe.utils import add_days, now -from erpnext.assets.doctype.asset.test_asset import create_asset_data +from erpnext.assets.doctype.asset.test_asset import create_asset, create_asset_data from erpnext.setup.doctype.employee.test_employee import make_employee from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_purchase_receipt @@ -146,6 +146,33 @@ class TestAssetMovement(IntegrationTestCase): movement1.cancel() self.assertEqual(frappe.db.get_value("Asset", asset.name, "location"), "Test Location") + def test_movement_transaction_date(self): + asset = create_asset(item_code="Macbook Pro", do_not_save=1) + asset.save().submit() + + if not frappe.db.exists("Location", "Test Location 2"): + frappe.get_doc({"doctype": "Location", "location_name": "Test Location 2"}).insert() + + asset_creation_date = frappe.db.get_value( + "Asset Movement", + [["Asset Movement Item", "asset", "=", asset.name], ["docstatus", "=", 1]], + "transaction_date", + ) + asset_movement = create_asset_movement( + purpose="Transfer", + company=asset.company, + assets=[ + { + "asset": asset.name, + "source_location": "Test Location", + "target_location": "Test Location 2", + } + ], + transaction_date=add_days(asset_creation_date, -1), + do_not_save=True, + ) + self.assertRaises(frappe.ValidationError, asset_movement.save) + def create_asset_movement(**args): args = frappe._dict(args) @@ -164,9 +191,10 @@ def create_asset_movement(**args): "reference_name": args.reference_name, } ) - - movement.insert() - movement.submit() + if not args.do_not_save: + movement.insert(ignore_if_duplicate=True) + if not args.do_not_submit: + movement.submit() return movement