Some checks failed
Frontend / Unit Tests & Coverage (push) Has been skipped
Regenerate POT file (translatable strings) / Regenerate POT file (develop) (push) Failing after 1m13s
Regenerate POT file (translatable strings) / Regenerate POT file (main-hotfix) (push) Failing after 6s
Server / Tests (frappe ${{ matrix.frappe-branch }}) (push) Has been skipped
Server / Resolve frappe matrix (push) Failing after 1s
Frontend / Lint (push) Failing after 1s
Frontend / Production Build (push) Failing after 1s
Server / Coverage Wrap Up (push) Has been skipped
Frontend / Coverage Wrap Up (push) Has been skipped
139 lines
4.7 KiB
Python
139 lines
4.7 KiB
Python
import unittest
|
|
from importlib.util import find_spec
|
|
|
|
import frappe
|
|
from frappe.tests.utils import FrappeTestCase
|
|
|
|
# Skip tests that import erpnext when it isn't installed. CI only installs
|
|
# ERPNext when integration code under crm/integrations/erpnext/** is touched.
|
|
ERPNEXT_INSTALLED = find_spec("erpnext") is not None
|
|
|
|
# Doctypes whose sync behaviour moved from override_doctype_class to doc_events
|
|
SYNC_DOCTYPES = ("Item", "User Permission", "DocShare")
|
|
|
|
|
|
class TestSyncHookWiring(FrappeTestCase):
|
|
def test_sync_doctypes_not_class_overridden(self):
|
|
from crm.hooks import override_doctype_class
|
|
|
|
for doctype in SYNC_DOCTYPES:
|
|
self.assertNotIn(doctype, override_doctype_class)
|
|
|
|
def test_doc_event_handlers_are_importable(self):
|
|
from crm.hooks import doc_events
|
|
|
|
for doctype in SYNC_DOCTYPES:
|
|
for handlers in doc_events[doctype].values():
|
|
for path in handlers:
|
|
self.assertTrue(callable(frappe.get_attr(path)), path)
|
|
|
|
|
|
class TestFindTargetFor(FrappeTestCase):
|
|
def test_returns_none_for_unknown_doctype(self):
|
|
from crm.integrations.erpnext.utils import find_target_for
|
|
|
|
self.assertIsNone(find_target_for("Some Other DocType", "X"))
|
|
|
|
def test_returns_none_when_inputs_missing(self):
|
|
from crm.integrations.erpnext.utils import find_target_for
|
|
|
|
self.assertIsNone(find_target_for(None, "X"))
|
|
self.assertIsNone(find_target_for("Item", None))
|
|
|
|
|
|
class TestItemRateFallback(FrappeTestCase):
|
|
def test_item_price_takes_precedence_over_standard_rate(self):
|
|
from crm.integrations.erpnext import item
|
|
|
|
doc = frappe._dict(
|
|
name="ITM-A", stock_uom="Nos", standard_rate=50, image=None, disabled=0, description="d"
|
|
)
|
|
original = item.get_item_price_rate
|
|
item.get_item_price_rate = lambda code, uom=None: 999
|
|
try:
|
|
data = item._catalogue_data(doc)
|
|
finally:
|
|
item.get_item_price_rate = original
|
|
self.assertEqual(data["standard_rate"], 999)
|
|
|
|
def test_falls_back_to_standard_rate_when_no_item_price(self):
|
|
from crm.integrations.erpnext import item
|
|
|
|
doc = frappe._dict(
|
|
name="ITM-B", stock_uom="Nos", standard_rate=50, image=None, disabled=0, description="d"
|
|
)
|
|
original = item.get_item_price_rate
|
|
item.get_item_price_rate = lambda code, uom=None: None
|
|
try:
|
|
data = item._catalogue_data(doc)
|
|
finally:
|
|
item.get_item_price_rate = original
|
|
self.assertEqual(data["standard_rate"], 50)
|
|
|
|
def test_none_rate_coerces_to_zero_when_no_item_price(self):
|
|
from crm.integrations.erpnext import item
|
|
|
|
doc = frappe._dict(
|
|
name="ITM-D", stock_uom="Nos", standard_rate=None, image=None, disabled=0, description="d"
|
|
)
|
|
original = item.get_item_price_rate
|
|
item.get_item_price_rate = lambda code, uom=None: None
|
|
try:
|
|
data = item._catalogue_data(doc)
|
|
finally:
|
|
item.get_item_price_rate = original
|
|
self.assertEqual(data["standard_rate"], 0)
|
|
|
|
@unittest.skipUnless(ERPNEXT_INSTALLED, "erpnext not installed")
|
|
def test_get_item_price_rate_uses_default_price_list_and_general_party(self):
|
|
from erpnext.stock import get_item_details
|
|
|
|
from crm.integrations.erpnext import item
|
|
|
|
captured = {}
|
|
orig_single = frappe.db.get_single_value
|
|
orig_get_item_price = get_item_details.get_item_price
|
|
frappe.db.get_single_value = lambda doctype, field: "Standard Selling"
|
|
|
|
def fake_get_item_price(pctx, item_code, **kwargs):
|
|
captured.update(pctx=dict(pctx), item_code=item_code, kwargs=kwargs)
|
|
return [frappe._dict(name="IP-1", price_list_rate=77, uom="Nos")]
|
|
|
|
get_item_details.get_item_price = fake_get_item_price
|
|
try:
|
|
rate = item.get_item_price_rate("ITM-C", "Nos")
|
|
finally:
|
|
frappe.db.get_single_value = orig_single
|
|
get_item_details.get_item_price = orig_get_item_price
|
|
self.assertEqual(rate, 77)
|
|
self.assertEqual(captured["item_code"], "ITM-C")
|
|
self.assertEqual(captured["pctx"]["price_list"], "Standard Selling")
|
|
self.assertEqual(captured["pctx"]["uom"], "Nos")
|
|
self.assertIn("transaction_date", captured["pctx"])
|
|
# No customer/supplier and ignore_party unset -> ERPNext selects general prices only
|
|
self.assertNotIn("customer", captured["pctx"])
|
|
self.assertFalse(captured["kwargs"].get("ignore_party"))
|
|
|
|
@unittest.skipUnless(ERPNEXT_INSTALLED, "erpnext not installed")
|
|
def test_get_item_price_rate_returns_none_without_default_price_list(self):
|
|
from crm.integrations.erpnext import item
|
|
|
|
original = frappe.db.get_single_value
|
|
frappe.db.get_single_value = lambda doctype, field: None
|
|
try:
|
|
self.assertIsNone(item.get_item_price_rate("ITM-X"))
|
|
finally:
|
|
frappe.db.get_single_value = original
|
|
|
|
|
|
class TestCascadeFlag(FrappeTestCase):
|
|
def test_flag_round_trip(self):
|
|
from crm.integrations.erpnext.utils import CASCADE_FLAG, in_cascade
|
|
|
|
self.assertFalse(in_cascade())
|
|
frappe.flags[CASCADE_FLAG] = True
|
|
try:
|
|
self.assertTrue(in_cascade())
|
|
finally:
|
|
frappe.flags[CASCADE_FLAG] = False
|