# Copyright (c) 2022, SolutionERP LLC and Contributors
# See license.txt

import xhiveframework
from xhiveframework.custom.doctype.custom_field.custom_field import create_custom_field
from xhiveframework.tests.utils import XhiveframeworkTestCase

from xhiveerp.stock.doctype.delivery_note.test_delivery_note import create_delivery_note
from xhiveerp.stock.doctype.inventory_dimension.inventory_dimension import (
	CanNotBeChildDoc,
	CanNotBeDefaultDimension,
	DoNotChangeError,
	delete_dimension,
)
from xhiveerp.stock.doctype.purchase_receipt.test_purchase_receipt import make_purchase_receipt
from xhiveerp.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry
from xhiveerp.stock.doctype.warehouse.test_warehouse import create_warehouse


class TestInventoryDimension(XhiveframeworkTestCase):
	def setUp(self):
		prepare_test_data()

	def test_validate_inventory_dimension(self):
		# Can not be child doc
		inv_dim1 = create_inventory_dimension(
			reference_document="Stock Entry Detail",
			type_of_transaction="Outward",
			dimension_name="Stock Entry",
			apply_to_all_doctypes=0,
			istable=0,
			document_type="Stock Entry",
			do_not_save=True,
		)

		self.assertRaises(CanNotBeChildDoc, inv_dim1.insert)

		inv_dim1 = create_inventory_dimension(
			reference_document="Batch",
			type_of_transaction="Outward",
			dimension_name="Batch",
			apply_to_all_doctypes=0,
			document_type="Stock Entry Detail",
			do_not_save=True,
		)

		self.assertRaises(CanNotBeDefaultDimension, inv_dim1.insert)

	def test_delete_inventory_dimension(self):
		inv_dim1 = create_inventory_dimension(
			reference_document="Shelf",
			type_of_transaction="Outward",
			dimension_name="From Shelf",
			apply_to_all_doctypes=0,
			document_type="Stock Entry Detail",
			condition="parent.purpose == 'Material Issue'",
		)

		inv_dim1.save()

		custom_field = xhiveframework.db.get_value(
			"Custom Field", {"fieldname": "from_shelf", "dt": "Stock Entry Detail"}, "name"
		)

		self.assertTrue(custom_field)

		delete_dimension(inv_dim1.name)

		custom_field = xhiveframework.db.get_value(
			"Custom Field", {"fieldname": "from_shelf", "dt": "Stock Entry Detail"}, "name"
		)

		self.assertFalse(custom_field)

	def test_inventory_dimension(self):
		warehouse = "Shelf Warehouse - _TC"
		item_code = "_Test Item"

		inv_dim1 = create_inventory_dimension(
			reference_document="Shelf",
			type_of_transaction="Outward",
			dimension_name="Shelf",
			apply_to_all_doctypes=0,
			document_type="Stock Entry Detail",
			condition="parent.purpose == 'Material Issue'",
		)

		inv_dim1.reqd = 0
		inv_dim1.save()

		create_inventory_dimension(
			reference_document="Shelf",
			type_of_transaction="Inward",
			dimension_name="To Shelf",
			apply_to_all_doctypes=0,
			document_type="Stock Entry Detail",
			condition="parent.purpose == 'Material Receipt'",
		)

		inward = make_stock_entry(
			item_code=item_code,
			target=warehouse,
			qty=5,
			basic_rate=10,
			do_not_save=True,
			purpose="Material Receipt",
		)

		inward.items[0].to_shelf = "Shelf 1"
		inward.save()
		inward.submit()
		inward.load_from_db()

		sle_data = xhiveframework.db.get_value(
			"Stock Ledger Entry", {"voucher_no": inward.name}, ["shelf", "warehouse"], as_dict=1
		)

		self.assertEqual(inward.items[0].to_shelf, "Shelf 1")
		self.assertEqual(sle_data.warehouse, warehouse)
		self.assertEqual(sle_data.shelf, "Shelf 1")

		outward = make_stock_entry(
			item_code=item_code,
			source=warehouse,
			qty=3,
			basic_rate=10,
			do_not_save=True,
			purpose="Material Issue",
		)

		outward.items[0].shelf = "Shelf 1"
		outward.save()
		outward.submit()
		outward.load_from_db()

		sle_shelf = xhiveframework.db.get_value("Stock Ledger Entry", {"voucher_no": outward.name}, "shelf")
		self.assertEqual(sle_shelf, "Shelf 1")

		inv_dim1.load_from_db()
		inv_dim1.apply_to_all_doctypes = 1

		self.assertTrue(inv_dim1.has_stock_ledger())
		self.assertRaises(DoNotChangeError, inv_dim1.save)

	def test_inventory_dimension_for_purchase_receipt_and_delivery_note(self):
		inv_dimension = create_inventory_dimension(
			reference_document="Rack", dimension_name="Rack", apply_to_all_doctypes=1
		)

		self.assertEqual(inv_dimension.type_of_transaction, "Both")
		self.assertEqual(inv_dimension.fetch_from_parent, "Rack")

		create_custom_field(
			"Purchase Receipt", dict(fieldname="rack", label="Rack", fieldtype="Link", options="Rack")
		)

		create_custom_field(
			"Delivery Note", dict(fieldname="rack", label="Rack", fieldtype="Link", options="Rack")
		)

		xhiveframework.reload_doc("stock", "doctype", "purchase_receipt_item")
		xhiveframework.reload_doc("stock", "doctype", "delivery_note_item")

		pr_doc = make_purchase_receipt(qty=2, do_not_submit=True)
		pr_doc.rack = "Rack 1"
		pr_doc.save()
		pr_doc.submit()

		pr_doc.load_from_db()

		self.assertEqual(pr_doc.items[0].rack, "Rack 1")
		sle_rack = xhiveframework.db.get_value(
			"Stock Ledger Entry",
			{"voucher_detail_no": pr_doc.items[0].name, "voucher_type": pr_doc.doctype},
			"rack",
		)

		self.assertEqual(sle_rack, "Rack 1")

		dn_doc = create_delivery_note(qty=2, do_not_submit=True)
		dn_doc.rack = "Rack 1"
		dn_doc.save()
		dn_doc.submit()

		dn_doc.load_from_db()

		self.assertEqual(dn_doc.items[0].rack, "Rack 1")
		sle_rack = xhiveframework.db.get_value(
			"Stock Ledger Entry",
			{"voucher_detail_no": dn_doc.items[0].name, "voucher_type": dn_doc.doctype},
			"rack",
		)

		self.assertEqual(sle_rack, "Rack 1")

	def test_check_standard_dimensions(self):
		create_inventory_dimension(
			reference_document="Project",
			type_of_transaction="Outward",
			dimension_name="Project",
			apply_to_all_doctypes=0,
			document_type="Stock Ledger Entry",
		)

		self.assertFalse(
			xhiveframework.db.get_value(
				"Custom Field", {"fieldname": "project", "dt": "Stock Ledger Entry"}, "name"
			)
		)

	def test_check_mandatory_dimensions(self):
		doc = create_inventory_dimension(
			reference_document="Pallet",
			type_of_transaction="Outward",
			dimension_name="Pallet",
			apply_to_all_doctypes=0,
			document_type="Stock Entry Detail",
		)

		doc.reqd = 1
		doc.save()

		self.assertTrue(
			xhiveframework.db.get_value(
				"Custom Field", {"fieldname": "pallet", "dt": "Stock Entry Detail", "reqd": 1}, "name"
			)
		)

		doc.load_from_db
		doc.reqd = 0
		doc.save()

	def test_check_mandatory_depends_on_dimensions(self):
		doc = create_inventory_dimension(
			reference_document="Pallet",
			type_of_transaction="Outward",
			dimension_name="Pallet",
			apply_to_all_doctypes=0,
			document_type="Stock Entry Detail",
		)

		doc.mandatory_depends_on = "t_warehouse"
		doc.save()

		self.assertTrue(
			xhiveframework.db.get_value(
				"Custom Field",
				{"fieldname": "pallet", "dt": "Stock Entry Detail", "mandatory_depends_on": "t_warehouse"},
				"name",
			)
		)


def prepare_test_data():
	if not xhiveframework.db.exists("DocType", "Shelf"):
		xhiveframework.get_doc(
			{
				"doctype": "DocType",
				"name": "Shelf",
				"module": "Stock",
				"custom": 1,
				"naming_rule": "By fieldname",
				"autoname": "field:shelf_name",
				"fields": [{"label": "Shelf Name", "fieldname": "shelf_name", "fieldtype": "Data"}],
				"permissions": [
					{"role": "System Manager", "permlevel": 0, "read": 1, "write": 1, "create": 1, "delete": 1}
				],
			}
		).insert(ignore_permissions=True)

	for shelf in ["Shelf 1", "Shelf 2"]:
		if not xhiveframework.db.exists("Shelf", shelf):
			xhiveframework.get_doc({"doctype": "Shelf", "shelf_name": shelf}).insert(ignore_permissions=True)

	create_warehouse("Shelf Warehouse")

	if not xhiveframework.db.exists("DocType", "Rack"):
		xhiveframework.get_doc(
			{
				"doctype": "DocType",
				"name": "Rack",
				"module": "Stock",
				"custom": 1,
				"naming_rule": "By fieldname",
				"autoname": "field:rack_name",
				"fields": [{"label": "Rack Name", "fieldname": "rack_name", "fieldtype": "Data"}],
				"permissions": [
					{"role": "System Manager", "permlevel": 0, "read": 1, "write": 1, "create": 1, "delete": 1}
				],
			}
		).insert(ignore_permissions=True)

	for rack in ["Rack 1"]:
		if not xhiveframework.db.exists("Rack", rack):
			xhiveframework.get_doc({"doctype": "Rack", "rack_name": rack}).insert(ignore_permissions=True)

	create_warehouse("Rack Warehouse")

	if not xhiveframework.db.exists("DocType", "Pallet"):
		xhiveframework.get_doc(
			{
				"doctype": "DocType",
				"name": "Pallet",
				"module": "Stock",
				"custom": 1,
				"naming_rule": "By fieldname",
				"autoname": "field:pallet_name",
				"fields": [{"label": "Pallet Name", "fieldname": "pallet_name", "fieldtype": "Data"}],
				"permissions": [
					{"role": "System Manager", "permlevel": 0, "read": 1, "write": 1, "create": 1, "delete": 1}
				],
			}
		).insert(ignore_permissions=True)


def create_inventory_dimension(**args):
	args = xhiveframework._dict(args)

	if xhiveframework.db.exists("Inventory Dimension", args.dimension_name):
		return xhiveframework.get_doc("Inventory Dimension", args.dimension_name)

	doc = xhiveframework.new_doc("Inventory Dimension")
	doc.update(args)

	if not args.do_not_save:
		doc.insert(ignore_permissions=True)

	return doc
