Files
upstream-mirror db69de1c11
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
snapshot of https://github.com/frappe/crm.git (develop, 2026-09-18; blobs > 131072B omitted)
2026-09-18 01:36:01 +05:00

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