11import functools
22import json
3- from datetime import datetime
3+ from datetime import datetime , timezone
44
55import httpx
66import pytz
1313 ApiSuccess ,
1414 GeniusApiResponse ,
1515)
16- from app .core .config import EULER_DASHBOARD_API_URL , GENIUS_API_URL
16+ from app .core .config import (
17+ EULER_DASHBOARD_API_URL ,
18+ GENIUS_API_URL ,
19+ GENIUS_LIST_ORDERS_API ,
20+ )
1721from app .core .logger import logger
1822from app .core .transport .http_client import create_http_client
1923
@@ -155,6 +159,142 @@ async def _make_genius_api_request(
155159 )
156160
157161
162+ async def _make_list_orders_api_request (
163+ params : FunctionCallParams , payload_details : dict
164+ ) -> GeniusApiResponse :
165+ """
166+ Generic helper to make requests to the Juspay List Orders API.
167+ Returns a GeniusApiResponse object.
168+ """
169+ if not euler_token :
170+ logger .error (
171+ "Tool Error: [list_orders_request] Juspay tool called without required euler_token."
172+ )
173+ return ApiFailure (
174+ error = {"Tool Error" : "[list_orders_request] Juspay tool is not configured." }
175+ )
176+
177+ start_time_str = params .arguments .get ("startTime" )
178+ end_time_str = params .arguments .get ("endTime" )
179+
180+ try :
181+ ist = pytz .timezone ("Asia/Kolkata" )
182+ utc = pytz .utc
183+ if not start_time_str :
184+ now_ist = datetime .now (ist )
185+ start_time_ist = now_ist .replace (hour = 0 , minute = 0 , second = 0 , microsecond = 0 )
186+ else :
187+ start_time_ist = ist .localize (
188+ datetime .strptime (start_time_str , "%Y-%m-%d %H:%M:%S" )
189+ )
190+ start_time_utc = start_time_ist .astimezone (utc )
191+
192+ if end_time_str :
193+ end_time_ist = ist .localize (
194+ datetime .strptime (end_time_str , "%Y-%m-%d %H:%M:%S" )
195+ )
196+ else :
197+ end_time_ist = datetime .now (ist )
198+ end_time_utc = end_time_ist .astimezone (utc )
199+
200+ except Exception as e :
201+ logger .error (
202+ f"Tool Error: [list_orders_request] Error converting time for Juspay API: { e } "
203+ )
204+ return ApiFailure (
205+ error = {
206+ "Tool Error" : f" [list_orders_request] Invalid time format provided. Please use 'YYYY-MM-DD HH:MM:SS' in IST. Error: { e } "
207+ }
208+ )
209+
210+ time_field = (
211+ "order_created_at"
212+ if payload_details .get ("domain" ) == "ordersELS"
213+ else "date_created"
214+ )
215+
216+ end_time_str = end_time_utc .strftime ("%Y-%m-%dT%H:%M:%SZ" )
217+ start_time_str = start_time_utc .strftime ("%Y-%m-%dT%H:%M:%SZ" )
218+
219+ end_time_dt = end_time_utc .fromisoformat (end_time_str .replace ("Z" , "+00:00" ))
220+ start_time_dt = start_time_utc .fromisoformat (start_time_str .replace ("Z" , "+00:00" ))
221+
222+ if end_time_dt .tzinfo is None :
223+ end_time_dt = end_time_dt .replace (tzinfo = timezone .utc )
224+ if start_time_dt .tzinfo is None :
225+ start_time_dt = start_time_dt .replace (tzinfo = timezone .utc )
226+
227+ date_from_ts = int (start_time_dt .timestamp ())
228+ date_to_ts = int (end_time_dt .timestamp ())
229+
230+ qFilters = {
231+ "and" : {
232+ "right" : {
233+ "field" : time_field ,
234+ "condition" : "LessThanEqual" ,
235+ "val" : str (date_to_ts ),
236+ },
237+ "left" : {
238+ "field" : time_field ,
239+ "condition" : "GreaterThanEqual" ,
240+ "val" : str (date_from_ts ),
241+ },
242+ }
243+ }
244+
245+ full_payload = {
246+ ** payload_details ,
247+ "filters" : {"dateCreated" : {"lte" : end_time_str , "gte" : start_time_str }},
248+ "qFilters" : qFilters ,
249+ }
250+ headers = {
251+ "Content-Type" : "application/json" ,
252+ "x-web-logintoken" : euler_token ,
253+ }
254+
255+ logger .info (
256+ f"Requesting Juspay List Orders API with payload: { json .dumps (full_payload )} "
257+ )
258+
259+ try :
260+ async with create_http_client (timeout = 10.0 ) as client :
261+ response = await client .post (
262+ GENIUS_LIST_ORDERS_API , json = full_payload , headers = headers
263+ )
264+ response .raise_for_status ()
265+ response_text = response .text
266+ logger .info (f"Received Raw Juspay API text response: { response_text } " )
267+ return ApiSuccess (data = response_text )
268+ except httpx .TimeoutException :
269+ logger .error (
270+ "Tool Error: [list_orders_api_request] Juspay API request timed out after 10 seconds."
271+ )
272+ return ApiFailure (
273+ error = {
274+ "Tool Error" : "[list_orders_api_request] It is taking too much time to process. Please try again."
275+ }
276+ )
277+ except httpx .HTTPStatusError as e :
278+ logger .error (
279+ f"Tool Error: [list_orders_api_request] HTTP error calling Juspay API: { e .response .status_code } - { e .response .text } "
280+ )
281+ return ApiFailure (
282+ error = {
283+ "Tool Error" : f" [list_orders_api_request] Juspay API error: { e .response .status_code } " ,
284+ "details" : e .response .text ,
285+ }
286+ )
287+ except Exception as e :
288+ logger .error (
289+ f"Tool Error: [list_orders_api_request] Unexpected error calling Juspay API: { e } "
290+ )
291+ return ApiFailure (
292+ error = {
293+ "Tool Error" : f" [list_orders_api_request] An unexpected error occurred: { e } "
294+ }
295+ )
296+
297+
158298def handle_genius_response (func ):
159299 """
160300 A decorator that takes a tool function, executes it, and handles the
@@ -427,6 +567,20 @@ def get_success_transactional_data_by_time(
427567 return _make_genius_api_request (params , payload_details )
428568
429569
570+ @handle_genius_response
571+ def get_last_n_orders (params : FunctionCallParams ):
572+ logger .info (f"Fetching last placed order with params: { params .arguments } " )
573+
574+ analytics_payload = {
575+ "domain" : "txnsELS" ,
576+ "offset" : 0 ,
577+ "sortDimension" : "order_created_at" ,
578+ "limit" : params .arguments .get ("limit" , 1 ),
579+ }
580+
581+ return _make_list_orders_api_request (params , analytics_payload )
582+
583+
430584async def get_gmv_order_value_payment_method_wise_by_time (params : FunctionCallParams ):
431585 logger .info (f"Fetching real-time GMV with params: { params .arguments } " )
432586 payload_details = {
@@ -1666,6 +1820,19 @@ async def update_euler_offer(params: FunctionCallParams):
16661820 required = time_input_schema ["required" ],
16671821)
16681822
1823+ get_last_n_orders_function = FunctionSchema (
1824+ name = "get_last_n_orders" ,
1825+ description = "Retrieves the most recently placed orders within a specified time range, sorted by creation time in descending order." ,
1826+ properties = {
1827+ ** time_input_schema ["properties" ],
1828+ "limit" : {
1829+ "type" : "number" ,
1830+ "description" : "Maximum number of recent orders to retrieve. Defaults to 1 to get the single most recent order. Increase this value to get multiple recent orders (e.g., 5 for last 5 orders, 10 for last 10 orders)." ,
1831+ },
1832+ },
1833+ required = time_input_schema ["required" ],
1834+ )
1835+
16691836gmv_order_value_payment_method_wise_function = FunctionSchema (
16701837 name = "get_gmv_order_value_payment_method_wise_by_time" ,
16711838 description = "Get the total Gross Merchandise Value (GMV) for each payment method within a specified time range. The results can be summed to calculate the total payment method GMV/sales. Use this to understand the revenue contribution of each payment method and the overall sales performance. Default to today if no timeframe specified." ,
@@ -1905,6 +2072,7 @@ async def update_euler_offer(params: FunctionCallParams):
19052072 list_offers_by_filter_function ,
19062073 delete_euler_offer_function ,
19072074 update_euler_offer_function ,
2075+ get_last_n_orders_function ,
19082076 ]
19092077)
19102078
@@ -1921,4 +2089,5 @@ async def update_euler_offer(params: FunctionCallParams):
19212089 "list_offers_by_filter" : list_offers_by_filter ,
19222090 "delete_euler_offer" : delete_euler_offer ,
19232091 "update_euler_offer" : update_euler_offer ,
2092+ "get_last_n_orders" : get_last_n_orders ,
19242093}
0 commit comments