#!/usr/bin/env python3 import json, difflib postman_json_text = '''{ "TemplateDocument": { "Href": "https://apiuatna11.springcm.com/v2/bccae332-c7db-4892-ab85-257df0f70fea/documents/a0cbc0e6-d87d-459e-8d63-66baa47878f3" }, "DataXML": "AC-0000102/04/2026123 Main St, Denver, CO 802021Missing comparable sale adjustment detail.Added adjustment rationale and supporting calculations.2Neighborhood trend explanation insufficient.Expanded market trend narrative with MLS evidence.3Photo date stamps were not included.Re-uploaded photos with date metadata and captions.3", "DestinationDocumentName": "Review_AC-00001.docx", "DestinationFolder": { "Href": "https://apiuatna11.springcm.com/v2/bccae332-c7db-4892-ab85-257df0f70fea/folders/12220442-b12e-f111-84fc-88e9a4bd0d9c" } } ''' # Parse the Postman JSON postman = json.loads(postman_json_text) # Reconstruct the Apex payload (simulate AppraiserCasePayloadBuilder output) payload = { 'AppraiserCaseNumber': 'AC-00001', 'AppraiserFieldReviewDate': '02/04/2026', 'PropertyAddress': '123 Main St, Denver, CO 80202', 'DeficiencyList': [ {'deficiencyNumber': '1', 'description': 'Missing comparable sale adjustment detail.', 'resolution': 'Added adjustment rationale and supporting calculations.'}, {'deficiencyNumber': '2', 'description': 'Neighborhood trend explanation insufficient.', 'resolution': 'Expanded market trend narrative with MLS evidence.'}, {'deficiencyNumber': '3', 'description': 'Photo date stamps were not included.', 'resolution': 'Re-uploaded photos with date metadata and captions.'} ] } # Function to mimic buildDataXml from Apex implementation def escape_xml(s): if s is None: return '' return s.replace('&','&').replace('<','<').replace('>','>').replace('"','"').replace("'","'") def build_data_xml(payload): xml = '' # Emit flat fields first (Apex iterates payload.keySet() which is not ordered in Python dict, but we'll follow this order) # We'll follow the same ordering as in Postman: AppraiserCaseNumber, AppraiserFieldReviewDate, PropertyAddress for key in ['AppraiserCaseNumber','AppraiserFieldReviewDate','PropertyAddress']: v = payload.get(key) xml += f'<{key}>' + escape_xml(str(v) if v is not None else '') + f'' # Emit DeficiencyList nested structure deficiencies = payload.get('DeficiencyList') if deficiencies: xml += '' for d in deficiencies: xml += '' xml += '' + escape_xml(str(d.get('deficiencyNumber'))) + '' xml += '' + escape_xml(str(d.get('description'))) + '' xml += '' + escape_xml(str(d.get('resolution'))) + '' xml += '' xml += '' xml += '' + str(len(deficiencies)) + '' xml += '' return xml apex_data_xml = build_data_xml(payload) apex_request = { 'TemplateDocument': {'Href': postman['TemplateDocument']['Href']}, 'DataXML': apex_data_xml, 'DestinationDocumentName': postman['DestinationDocumentName'], 'DestinationFolder': {'Href': postman['DestinationFolder']['Href']} } # Compare postman vs apex print('Comparing top-level fields:') for key in ['TemplateDocument','DestinationDocumentName','DestinationFolder']: p = postman.get(key) a = apex_request.get(key) equal = (p == a) print(f' - {key}:', 'MATCH' if equal else 'DIFFER') # Compare DataXML postman_xml = postman['DataXML'] apex_xml = apex_request['DataXML'] if postman_xml == apex_xml: print('\nDataXML: EXACT MATCH') else: print('\nDataXML: DIFFER') # show diff pd = postman_xml.split('><') ad = apex_xml.split('><') diff = difflib.unified_diff(pd, ad, fromfile='postman_xml', tofile='apex_xml', lineterm='') print('\n'.join(diff)) # also show small head/tail print('\n-- Postman head 200 chars --\n', postman_xml[:200]) print('\n-- Apex head 200 chars --\n', apex_xml[:200]) # Additionally print whether other top-level objects match (TemplateDocument Href and Folder Href) print('\nTemplateDocument.Href match:', postman['TemplateDocument']['Href'] == apex_request['TemplateDocument']['Href']) print('DestinationFolder.Href match:', postman['DestinationFolder']['Href'] == apex_request['DestinationFolder']['Href']) # Print apex_data_xml for inspection print('\n--- Apex DataXML ---\n') print(apex_data_xml)