Skip to content

Commit ed7dac3

Browse files
committed
Added tool to fetch n most recent orders
1 parent d2b39c3 commit ed7dac3

File tree

2 files changed

+172
-2
lines changed

2 files changed

+172
-2
lines changed

app/agents/voice/automatic/tools/juspay/analytics.py

Lines changed: 171 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import functools
22
import json
3-
from datetime import datetime
3+
from datetime import datetime, timezone
44

55
import httpx
66
import pytz
@@ -13,7 +13,11 @@
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+
)
1721
from app.core.logger import logger
1822
from 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+
158298
def 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+
430584
async 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+
16691836
gmv_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
}

app/core/config.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ def get_required_env(var_name: str) -> str:
8888

8989
# Juspay API configuration
9090
GENIUS_API_URL = "https://portal.juspay.in/api/q/query?api-type=genius-query"
91+
GENIUS_LIST_ORDERS_API = "https://portal.juspay.in/ec/v4/orders"
9192
EULER_DASHBOARD_API_URL = os.environ.get(
9293
"EULER_DASHBOARD_API_URL", "https://portal.juspay.in"
9394
)

0 commit comments

Comments
 (0)