import json import unittest from pathlib import Path REPO_ROOT = Path(__file__).resolve().parents[1] CRM_PACK = REPO_ROOT / "salesforce-crm-standard" def load_json(path: Path): with path.open(encoding="utf-8") as handle: return json.load(handle) def ui_action(name: str): for action in load_json(CRM_PACK / "actions" / "ui_actions.json"): if action.get("name") == name: return action raise AssertionError(f"{name} UI action missing") def standard_action(name: str): for action in load_json(CRM_PACK / "actions" / "invocable_standard_actions.json"): if action.get("name") == name: return action raise AssertionError(f"{name} standard action missing") def mapping_group(source: str, target: str, action_type: str): for group in load_json(CRM_PACK / "field_mappings" / "standard_field_mappings.json"): if ( group.get("sourceObject") == source and group.get("targetObject") == target and group.get("actionType") == action_type ): return group raise AssertionError(f"{source}->{target}/{action_type} mapping group missing") def mapping_pairs(group: dict): return { (mapping.get("sourceField"), mapping.get("targetField")) for mapping in group.get("mappings", []) } def object_field_names(api_name: str): for object_spec in load_json(CRM_PACK / "objects" / "standard_objects_spec.json"): if object_spec.get("apiName") == api_name: return {field["apiName"] for field in object_spec["fields"]} raise AssertionError(f"{api_name} object spec missing") class CreateOrderContractsTest(unittest.TestCase): def test_quote_layout_places_accept_and_flow_backed_create_order_actions(self): layout = load_json(CRM_PACK / "layouts" / "quote_page_layout.json") self.assertEqual( layout["headerActions"], [ {"name": "Accept", "label": "Accept", "type": "Standard"}, { "name": "createOrder", "label": "Create Order", "type": "Standard", }, ], ) def test_create_order_action_is_invocable_flow_action_not_legacy_ui_action(self): legacy_names = { action.get("name") for action in load_json(CRM_PACK / "actions" / "ui_actions.json") } self.assertNotIn("CreateOrder", legacy_names) action = standard_action("createOrder") self.assertEqual(action["label"], "Create Order") self.assertEqual(action["flowDeveloperName"], "Std_CreateOrderFromQuote") self.assertEqual(action["rendererId"], "app-pack:crm/action-renderer/create-record-from-source") self.assertEqual(action["targetObjects"], ["Quote"]) self.assertEqual( action["visibilityCondition"], "record.Status == 'Accepted' && record.AccountId != null", ) self.assertEqual( action["inputs"], [ { "apiName": "quoteId", "dataType": "id", "isRequired": True, "uiSection": "Quote", "uiMode": "hidden", "targetObject": "Quote", "targetFieldAPIName": "Id", "sortOrder": 0, } ], ) self.assertEqual( action["outputs"], [ { "apiName": "orderId", "dataType": "reference", "referenceTo": "Order", "sortOrder": 0, } ], ) def test_create_order_action_declares_permissions_and_internal_scopes(self): action = standard_action("createOrder") guards = { (guard["requiredObject"], guard["requiredOperation"]) for guard in action["inputGuards"] } self.assertEqual( guards, { ("Quote", "Read"), ("Account", "Read"), ("Order", "Create"), ("QuoteLineItem", "Read"), ("OrderItem", "Create"), }, ) scopes = { (scope["objectApiName"], scope["operation"]) for scope in action["internalAccessScopes"] } self.assertEqual( scopes, { ("_System_Object", "Read"), ("_System_RecordType", "Read"), }, ) def test_create_order_field_mappings_cover_flat_quote_to_order_copy(self): order_pairs = mapping_pairs(mapping_group("Quote", "Order", "createOrder")) self.assertTrue( { ("AccountId", "AccountId"), ("ContractId", "ContractId"), ("OpportunityId", "OpportunityId"), ("Pricebook2Id", "Pricebook2Id"), ("CurrencyIsoCode", "CurrencyIsoCode"), ("Description", "Description"), ("GrandTotal", "TotalAmount"), }.issubset(order_pairs) ) self.assertNotIn(("ContactId", "BillToContactId"), order_pairs) self.assertNotIn(("OwnerId", "OwnerId"), order_pairs) self.assertNotIn(("Status", "Status"), order_pairs) order_fields = object_field_names("Order") for _source_field, target_field in order_pairs: self.assertIn(target_field, order_fields) def test_create_order_field_mappings_cover_quote_line_items_to_order_items(self): order_item_pairs = mapping_pairs( mapping_group("QuoteLineItem", "OrderItem", "createOrder") ) self.assertTrue( { ("Product2Id", "Product2Id"), ("PricebookEntryId", "PricebookEntryId"), ("Quantity", "Quantity"), ("UnitPrice", "UnitPrice"), ("ListPrice", "ListPrice"), ("TotalPrice", "TotalPrice"), ("Description", "Description"), ("ServiceDate", "ServiceDate"), }.issubset(order_item_pairs) ) quote_line_item_fields = object_field_names("QuoteLineItem") order_item_fields = object_field_names("OrderItem") for source_field, target_field in order_item_pairs: self.assertIn(source_field, quote_line_item_fields) self.assertIn(target_field, order_item_fields) def test_create_order_flow_validates_quote_and_resolves_order_record_type(self): flow = load_json(CRM_PACK / "flows" / "Std_CreateOrderFromQuote.flow.json") lookups = {lookup["name"]: lookup for lookup in flow["recordLookups"]} self.assertEqual(lookups["GetQuote"]["object"], "Quote") self.assertEqual(lookups["GetSourceQuoteRecordType"]["object"], "_System_RecordType") self.assertEqual(lookups["GetOrderObjectMetadata"]["object"], "_System_Object") self.assertEqual(lookups["GetMatchingOrderRecordType"]["object"], "_System_RecordType") self.assertEqual(lookups["GetDefaultOrderRecordType"]["object"], "_System_RecordType") self.assertEqual(lookups["GetQuoteLineItems"]["object"], "QuoteLineItem") self.assertFalse(lookups["GetQuoteLineItems"]["getFirstRecordOnly"]) default_name_filter = next( filter_ for filter_ in lookups["GetDefaultOrderRecordType"]["filters"] if filter_["field"] == "Name" ) self.assertEqual(default_name_filter["value"], {"stringValue": "New"}) decisions = {decision["name"]: decision for decision in flow["decisions"]} self.assertEqual( decisions["ValidateQuoteAccepted"]["rules"][0]["connector"]["targetReference"], "FailQuoteNotAccepted", ) self.assertEqual( decisions["ValidateQuoteHasAccount"]["rules"][0]["connector"]["targetReference"], "FailQuoteMissingAccount", ) self.assertEqual( decisions["ChooseOrderRecordType"]["rules"][0]["connector"]["targetReference"], "GetDefaultOrderRecordType", ) self.assertEqual( decisions["ChooseOrderRecordType"]["defaultConnector"]["targetReference"], "GetQuoteLineItems", ) self.assertEqual( decisions["ValidateOrderRecordTypeResolved"]["defaultConnector"]["targetReference"], "GetQuoteLineItems", ) custom_errors = { error["name"]: error["customErrorMessages"][0]["errorMessage"] for error in flow["customErrors"] } self.assertIn("FailInvalidQuoteId", custom_errors) self.assertIn("FailQuoteNotAccepted", custom_errors) self.assertIn("FailQuoteMissingAccount", custom_errors) self.assertIn("FailMissingOrderRecordType", custom_errors) def test_create_order_flow_creates_order_with_flow_owned_defaults(self): flow = load_json(CRM_PACK / "flows" / "Std_CreateOrderFromQuote.flow.json") create = next( record_create for record_create in flow["recordCreates"] if record_create["name"] == "CreateOrder" ) self.assertEqual(create["object"], "Order") self.assertEqual( create["fieldMapping"], { "sourceObject": "Quote", "sourceReference": "$quote", "targetObject": "Order", "actionType": "createOrder", }, ) self.assertEqual(create["assignRecordIdToReference"], "orderId") self.assertEqual(create["connector"], {"targetReference": "CopyQuoteLineItems"}) assignments = { assignment["field"]: assignment["value"] for assignment in create["inputAssignments"] } self.assertEqual(assignments["QuoteId"], {"elementReference": "quoteId"}) self.assertEqual(assignments["RecordTypeId"], {"elementReference": "$orderRecordType.Id"}) self.assertEqual(assignments["Status"], "Draft") self.assertEqual(assignments["EffectiveDate"], {"elementReference": "$Flow.CurrentDate"}) self.assertNotIn("BillToContactId", assignments) self.assertNotIn("BillingStreet", assignments) self.assertNotIn("BillingCity", assignments) self.assertNotIn("BillingState", assignments) self.assertNotIn("BillingPostalCode", assignments) self.assertNotIn("BillingCountry", assignments) def test_create_order_flow_copies_quote_line_items_to_order_items(self): flow = load_json(CRM_PACK / "flows" / "Std_CreateOrderFromQuote.flow.json") loops = {loop["name"]: loop for loop in flow["loops"]} creates = {create["name"]: create for create in flow["recordCreates"]} self.assertEqual( loops["CopyQuoteLineItems"], { "name": "CopyQuoteLineItems", "label": "Copy QuoteLineItems", "locationX": 40, "locationY": 1440, "collectionReference": "$quoteLineItems", "assignNextValueToReference": "$currentQuoteLineItem", "iterationOrder": "Asc", "nextValueConnector": { "targetReference": "CreateOrderItem", }, }, ) create = creates["CreateOrderItem"] self.assertEqual(create["object"], "OrderItem") self.assertEqual( create["fieldMapping"], { "sourceObject": "QuoteLineItem", "sourceReference": "$currentQuoteLineItem", "targetObject": "OrderItem", "actionType": "createOrder", }, ) self.assertEqual( create["inputAssignments"], [ { "field": "OrderId", "value": { "elementReference": "orderId", }, } ], ) self.assertEqual(create["connector"], {"targetReference": "CopyQuoteLineItems"}) def test_accept_action_transitions_approved_quote_to_accepted(self): action = ui_action("Accept") config = action["config"] self.assertEqual(action["label"], "Accept") self.assertEqual(action["type"], "UpdateStatus") self.assertEqual(action["objectApiName"], "Quote") self.assertEqual(config["statusField"], "Status") self.assertEqual(config["targetStatus"], "Accepted") self.assertEqual(config["visibilityCondition"], "record.Status == 'Approved'") if __name__ == "__main__": unittest.main()