@@ -188,6 +188,7 @@ def get_forwarded_address():
188188def find_aog_item_by_grant_id (grant_id ):
189189 """
190190 Finds an AOG (Approval of Grants) item in Kissflow by Grant ID.
191+ Uses the admin endpoint to get all items and searches through them.
191192 Returns the item ID if found, None otherwise.
192193 """
193194 try :
@@ -201,31 +202,71 @@ def find_aog_item_by_grant_id(grant_id):
201202 logging .error ("Missing Kissflow configuration" )
202203 return None
203204
204- # Kissflow API endpoint to search for items
205- url = f"https://{ subdomain } .kissflow.com/process/2/{ account_id } /{ process_id } /items"
206-
207205 headers = {
208206 'Accept' : 'application/json' ,
209- 'Content-Type' : 'application/json' ,
210207 'X-Access-Key-Id' : access_key_id ,
211208 'X-Access-Key-Secret' : access_key_secret
212209 }
213210
214- # Search for items with matching Grant ID in Request_number field
215- params = {
216- 'filter' : f'Request_number eq "{ grant_id } "' ,
217- 'limit' : 1
218- }
219-
220- response = requests .get (url , headers = headers , params = params )
211+ # Use admin endpoint to get all items
212+ page_number = 1
213+ page_size = 100 # Get 100 items per page
221214
222- if response .status_code == 200 :
215+ while True :
216+ # Kissflow admin API endpoint to get all items
217+ url = f"https://{ subdomain } .kissflow.com/process/2/{ account_id } /admin/{ process_id } /item"
218+
219+ params = {
220+ 'page_number' : page_number ,
221+ 'page_size' : page_size ,
222+ 'apply_preference' : False
223+ }
224+
225+ response = requests .get (url , headers = headers , params = params )
226+
227+ if response .status_code != 200 :
228+ logging .error (f"Kissflow API error: { response .status_code } - { response .text } " )
229+ return None
230+
223231 data = response .json ()
224- items = data .get ('data' , [])
225- if items :
226- return items [0 ].get ('_id' )
227- else :
228- logging .error (f"Kissflow API error: { response .status_code } - { response .text } " )
232+
233+ # The response structure contains table data with items
234+ # Look for items in the response structure
235+ items_found = []
236+
237+ # Check if there's a table structure in the response
238+ for table_name , table_data in data .items ():
239+ if table_name == "Columns" or table_name == "Filter" :
240+ continue
241+
242+ if isinstance (table_data , list ):
243+ for page_data in table_data :
244+ if isinstance (page_data , dict ) and 'response' in page_data :
245+ items_found .extend (page_data ['response' ])
246+
247+ # Search through the items for matching Grant ID
248+ for item in items_found :
249+ # Check various possible field names for the Grant ID
250+ grant_id_fields = ['Request_number' , 'GrantId' , 'Grant_ID' , 'grant_id' , 'PONumber' ]
251+
252+ for field in grant_id_fields :
253+ if field in item and str (item [field ]) == str (grant_id ):
254+ logging .info (f"Found AOG item with ID { item .get ('_id' )} for Grant ID { grant_id } " )
255+ return item .get ('_id' )
256+
257+ # If we found fewer items than page_size, we've reached the end
258+ if len (items_found ) < page_size :
259+ break
260+
261+ page_number += 1
262+
263+ # Safety check to prevent infinite loops
264+ if page_number > 100 : # Max 10,000 items (100 pages * 100 items)
265+ logging .warning ("Reached maximum page limit while searching for Grant ID" )
266+ break
267+
268+ logging .warning (f"No AOG item found for Grant ID: { grant_id } " )
269+ return None
229270
230271 except Exception as e :
231272 logging .error (f"Error finding AOG item: { str (e )} " )
@@ -235,6 +276,7 @@ def find_aog_item_by_grant_id(grant_id):
235276def update_aog_kyc_comments (item_id , legal_identifier ):
236277 """
237278 Updates the KYC_Comments field in a Kissflow AOG item with the legal identifier.
279+ Uses the admin PUT endpoint to update item details.
238280 """
239281 try :
240282 subdomain = os .getenv ('KISSFLOW_SUBDOMAIN' , 'ethereum' )
@@ -247,24 +289,33 @@ def update_aog_kyc_comments(item_id, legal_identifier):
247289 logging .error ("Missing Kissflow configuration" )
248290 return False
249291
250- # Kissflow API endpoint to update an item
251- url = f"https://{ subdomain } .kissflow.com/process/2/{ account_id } /{ process_id } /items/{ item_id } "
252-
292+ # First, get the current item details to preserve existing data
253293 headers = {
254294 'Accept' : 'application/json' ,
255295 'Content-Type' : 'application/json' ,
256296 'X-Access-Key-Id' : access_key_id ,
257297 'X-Access-Key-Secret' : access_key_secret
258298 }
259299
260- # Update the KYC_Comments field
261- payload = {
262- 'KYC_Comments' : legal_identifier
263- }
300+ # Get current item details using admin endpoint
301+ get_url = f"https://{ subdomain } .kissflow.com/process/2/{ account_id } /admin/{ process_id } /item/{ item_id } "
302+ get_response = requests .get (get_url , headers = headers )
264303
265- response = requests .patch (url , headers = headers , json = payload )
304+ if get_response .status_code != 200 :
305+ logging .error (f"Failed to get current item details: { get_response .status_code } - { get_response .text } " )
306+ return False
307+
308+ current_item = get_response .json ()
309+
310+ # Update the KYC_Comments field while preserving other fields
311+ current_item ['KYC_Comments' ] = legal_identifier
266312
267- if response .status_code in [200 , 204 ]:
313+ # Use admin PUT endpoint to update the item
314+ put_url = f"https://{ subdomain } .kissflow.com/process/2/{ account_id } /admin/{ process_id } /{ item_id } "
315+
316+ response = requests .put (put_url , headers = headers , json = current_item )
317+
318+ if response .status_code == 200 :
268319 logging .info (f"Successfully updated AOG item { item_id } with legal identifier { legal_identifier } " )
269320 return True
270321 else :
0 commit comments