Passing Complex Structures

I am trying to call an API that has nested parameters. Do I need to use a Preformatted text Expression structure to implement my parameters within my API call? See attached.

SAP.IM.GoodsMovement (Project Script)

# -----------------------------------------------------------------------------
# Project Name: 	NEI Manufacturing Execution System (MES)
# Author: 			Aisha M.Shiddat
# Date: 			8/27/2024
# Description: 		Reads Good Movement Header and transfers the new key assignment of the GM_CODE to the relevant transactions in Inventory Management
# -----------------------------------------------------------------------------
# Copyright (c) 2024 Charlotte Pipe and Foundry Company
# -----------------------------------------------------------------------------
#	NOTES:     WIP
#
#

def Post(ItemName, ItemValue,Structure,UserID):
	
	 
	#Instantiate the SAP API Class and set function to be called
	ECC = SAP.SAPClass.CSAP(UserID)
	ECC.URL = 'api/SAP/Inventory/GoodsMovement'
	ECC.Debug = True
    
    
    #GoodsMvt Header and GoodsMvt_Code are Mandatory Params
	#ECC.AddValue('GOODSMVT_HEADER','PSTNG_DATE')
	#ECC.AddValue('GOODSMVT_CODE', 'GM_CODE')
	#ECC.AddValue('GOODSMVT_ITEM', GmItem)
	
	
	#Instantiating the CStructure and CTable Class for complex objects
	CS1 = SAP.SAPClass.CStructure('GOODSMVT_HEADER')
	CS1.SetValue('PSTNG_DATE',list(ItemName)[1])
	
	CS2 = SAP.SAPClass.CStructure('GOODSMVT_CODE')
	CS2.SetValue('GM_CODE',list(ItemValue)[1])
	
	dict_one = {
		    "MOVE_TYPE":Structure[1]["MOVE_TYPE"],
            "ENTRY_QNT": Structure[1]["ENTRY_QNT"],
            "ENTRY_UOM":Structure[1]["ENTRY_UOM"],
            "PO_NUMBER": Structure[1]["PO_NUMBER"],
            "PO_ITEM":Structure[1]["PO_ITEM"],
            "MVT_IND":Structure[1]["MVT_IND"]
	}

	
	
	
    #table
	CS3 = SAP.SAPClass.CTable('GOODSMVT_ITEM')  
	CS3.SetValue('GOODSMVT_ITEM', dict_one)

	
	
	
	
	
	ECC.AddItem(CS1)
	ECC.AddItem(CS2)
	ECC.AddItem(CS3)
	


	PV = ECC.Post()
	
	
	return PV
	
	
	
	
	

Event Configuration on Receive Button

	
	#set variables/ params
	PONumber = self.parent.parent.getChild("Scrap_Receiving_Flex_Container").getChild("PO_No_Flex_Container").getChild("PO_No_Value").props.value
	grossWeight = self.parent.parent.getChild("Scrap_Receiving_Flex_Container").custom.gross_weight
	netWeight = self.parent.parent.getChild("Scrap_Receiving_Flex_Container").custom.net_weight
	scaleWeight = self.parent.parent.getChild("Scrap_Receiving_Flex_Container").custom.scale_weight
	receiptQty = self.parent.parent.getChild("Scrap_Receiving_Flex_Container").custom.receipt_qty
#	ItemName = {TODO}
#	ItemValue = {TODO}
#	Structure = {TODO}
	UserID = self.view.params.userId
	
	if(PONumber is not None):
		
		#call ZBAPI_GOODMVT_CREATE
		#create_gm = SAP.IM.GoodsMovement.Post(ItemName, ItemValue, Structure, UserID)
	
		#insert truck weight data into Raw Materials table 
		sd_params = {"po_number":PONumber, "gross_weight":grossWeight, "net_weight":netWeight, "scale_weight": scaleWeight, "receipt_qty":receiptQty}
		system.db.runNamedQuery("SAP/RM_UpdateExitWeight", sd_params)
	
	
		#Open confirmation view 
		system.perspective.openPopup('Exit Weight Confirmation', 'Inventory/Scrap_Receive_Confirmation View' )
   #	Invoke message handler
		system.perspective.sendMessage('refreshTable')
		
		#reset fields
		self.parent.parent.getChild("Scrap_Receiving_Flex_Container").getChild("PO_No_Flex_Container").getChild("PO_No_Value").props.value = " "
		self.parent.parent.getChild("Scrap_Receiving_Flex_Container").getChild("Gross Weight").getChild("FlexContainer_0").getChild("gross_weight_entry").props.value = " "
		self.parent.parent.getChild("Scrap_Receiving_Flex_Container").getChild("Scale_Weight_Container").getChild("scale_weight_entry").props.value = " "
		self.parent.parent.getChild("Scrap_Receiving_Flex_Container").getChild("Net Weight").getChild("FlexContainer_0").getChild("net_weight_entry").props.value = " "
		self.parent.parent.getChild("Scrap_Receiving_Flex_Container").getChild("Receipt Qty").getChild("receipt_qty_entry").props.value = " "
		
		self.parent.parent.parent.getChild("Shipment Detail").getChild("root").getChild("Shipment_Detail_Flex_Container").getChild("PO_No_Flex_Container").getChild("PO_No_Value").props.value = " "
		self.parent.parent.parent.getChild("Shipment Detail").getChild("root").getChild("Shipment_Detail_Flex_Container").getChild("BOL_No_Flex_Container").getChild("BOL_No_Value").props.text = " "
		self.parent.parent.parent.getChild("Shipment Detail").getChild("root").getChild("Shipment_Detail_Flex_Container").getChild("Scale_Weight_Container").getChild("scale_weight_input").props.text = " "
		
		self.parent.parent.parent.getChild("Scrap_Inspection").getChild("ColumnContainer").getChild("Contamination_Flex_Container").getChild("Cast_Iron_Container").getChild("Cast_Iron_RadioGroup").props.value = None
		self.parent.parent.parent.getChild("Scrap_Inspection").getChild("ColumnContainer").getChild("Contamination_Flex_Container").getChild("Enameled_Flex_Container").getChild("Enameled_RadioGroup").props.value = None
		self.parent.parent.parent.getChild("Scrap_Inspection").getChild("ColumnContainer").getChild("Contamination_Flex_Container").getChild("Steel_Flex_Container").getChild("Steel_RadioGroup").props.value = None
		self.parent.parent.parent.getChild("Scrap_Inspection").getChild("ColumnContainer").getChild("Contamination_Flex_Container").getChild("Non_Ferrous_Flex_Container").getChild("Non_Ferrous_RadioGroup").props.value = None
		self.parent.parent.parent.getChild("Scrap_Inspection").getChild("ColumnContainer").getChild("Contamination_Flex_Container").getChild("Non_Metallics_Flex_Container").getChild("Non_Metallics_RadioGroup").props.value = None
		self.parent.parent.parent.getChild("Scrap_Inspection").getChild("ColumnContainer").getChild("Contamination_Flex_Container").getChild("Material_Certification_Container").getChild("Material_Certification_RadioGroup").props.value = None
		self.parent.parent.parent.getChild("Scrap_Inspection").getChild("ColumnContainer").getChild("Scrap_Ins_Flex_Container").getChild("Size_Flex_Container").getChild("Transporation_Type_Flex_Container").getChild("Transportation_Type_Radio_Button").props.value = None
		self.parent.parent.parent.getChild("Scrap_Inspection").getChild("ColumnContainer").getChild("Scrap_Ins_Flex_Container").getChild("Size_Flex_Container").getChild("Larger_24_24_Flex_Container").getChild("Larger_24_24_RadioGroup").props.value = None
		self.parent.parent.parent.getChild("Scrap_Inspection").getChild("ColumnContainer").getChild("Scrap_Ins_Flex_Container").getChild("Size_Flex_Container").getChild("Weight_Over200_Flex_Container").getChild("Weight_Over200_RadioGroup").props.value = None
		self.parent.parent.parent.getChild("Scrap_Inspection").getChild("ColumnContainer").getChild("Scrap_Ins_Flex_Container").getChild("Size_Flex_Container").getChild("Environmental_Pass").props.selected = False
		self.parent.parent.parent.getChild("Scrap_Inspection").getChild("ColumnContainer").getChild("Scrap_Ins_Flex_Container").getChild("Size_Flex_Container").getChild("Inspected_By_Flex_Container").getChild("Inspected_By_Value").props.value = None
		self.parent.parent.parent.getChild("Scrap_Inspection").getChild("ColumnContainer").getChild("Scrap_Ins_Flex_Container").getChild("Size_Flex_Container").getChild("Disposition_Flex_Container").getChild("Disposition_Value").props.value = None
		self.parent.parent.parent.getChild("Scrap_Inspection").getChild("ColumnContainer").getChild("Scrap_Ins_Flex_Container").getChild("Size_Flex_Container").getChild("Comments_Flex_Container").getChild("Comments_Value").props.text = " "
		
		
PostMan Example (Calling API from SAP)

		
		
		
		
		
		

I doubt we'll be able to help without you sharing your SAP.* scripts.

That doesn't help us help you. We need to see how you are constructing the actual HTTP requests. You probably need logging at that point to demonstrate exactly how your request is put together.

(Do not use print in library scripts, particularly when Perspective or other gateway operations are involved. Use loggers.)

This is the API Class I am instantiating to call my API. Also, I don't see why I would need to Post the SAP Code. I'm able to call my API and pass my params in the script console in Ignition. I just need to know how to set up my view to call these parameters which consist of dictionaries and lists. (See the first script at the beginning of the page.)



import time

class CAPI(object):

	#
	# Constructor requires a Service ID and a UserID
	#
	def __init__(self,Service,UserID):
		
		self.Service = Service
		self.HostName = API.Util.GetHostName(Service)
		#self.ContentType = 'application/json; charset=utf-8'
		#self.ConnectTimeout = 5000
		#self.ReadTimeout = 30000
		self.Debug = False
		self.Trace = system.tag.readBlocking(['[default]API/%s/Trace' % Service])[0].value
		self.UserID = UserID
		self.URL = ''
		self.HTTPClient = system.net.httpClient(bypass_cert_validation = True)
		self.Headers = None
		self.Parameters = None
		self.Data = None
		
		self.Reset()

	#
	# Reset The CLass for subsequent use
	#
	def Reset(self):
		self.Headers = {}
		self.Parameters = {}
		self.Data = None
		self.Headers['UserID'] = self.UserID		
		
	#
	# Short version of the POST Execute Method
	#
	def Post(self):
		return self.Execute('POST')
		
	#
	# Short version of the GET Execute Method
	#
	def Get(self):
		return self.Execute('GET')

	#
	# General Execute Method
	#
	def Execute(self,Method):
		
		# initialization
		StartTime = time.time()
		FullUrl = 'https://%s/%s' % (self.HostName,self.URL)
		Results = {}
		PayloadSize = 0
		
		#Add Authorization Header and Tracking ID
		self.Headers['Authorization'] = 'Bearer ' + API.OAUTH.GetToken(self.Service)
		self.Headers['CPFTXID'] = API.Util.GetUID()
	
		if self.Debug:
			print 'URL:', FullUrl
			print 'HEADER:', self.Headers
			print 'PARAMETERS:',self.Parameters
			print 'DATA:', self.Data
		
		Response = self.HTTPClient.request(
			url = FullUrl,
			method = Method,
			params = self.Parameters,
			headers = self.Headers,
			data = self.Data)

		
		# Process Results
		Results['StatusCode'] = Response.statusCode
		Results['Response'] = Response.json		
		PayloadSize = len(Response.text)			
		
		
		EndTime = time.time()
		ElapsedTime = EndTime - StartTime
		Results['API_ElapsedTime'] = ElapsedTime
		
		#Log Metrics
		P = {'DateTimeEPOC':StartTime, 'URL':FullUrl, 'ResponseBytes':PayloadSize, 'ResponseET':ElapsedTime, 'Status':Response.statusCode}
		system.db.runSFNamedQuery('API/MetricsLog', P)
		
		if self.Debug:
			print Results
		
		
		
		#Trace
		if self.Trace == True:
			
			if self.Data is None:
				sBody = ''
			else:
				sBody = system.util.jsonEncode(self.Data)
			
			sParameters = system.util.jsonEncode(self.Parameters)
			sHeaders = system.util.jsonEncode(self.Headers)
				
			P = {'DateTimeEPOC':StartTime, 'URL':FullUrl, 'Headers':sHeaders, 'Parameters':sParameters, 'Body':sBody, 'Response':Response.text}
			system.db.runSFNamedQuery('API/Trace', P)
		
		
		return Results
		

I don't see any obvious error in your code (other than the use of print), as long as the API itself is expecting JSON payloads.