query_order_detail.py 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. class QueryOrderDetailTool:
  2. name = 'query_order_detail'
  3. route_path = '/mcp/tools/queryOrderDetail'
  4. sections = (
  5. '订单概览', '箱单信息', '箱单商品', 'DW授权信息', '附件信息',
  6. '入库信息', '查验信息', '订单轨迹', '操作日志',
  7. '应收与结算日志', '派送信息', '全部',
  8. )
  9. def __init__(self, api_client=None):
  10. self.api_client = api_client
  11. def metadata(self):
  12. return {
  13. 'name': self.name,
  14. 'description': (
  15. '使用场景:用户明确提供订单号并要求查看订单详情时使用。可查询订单概览、'
  16. '箱单、箱单商品、DW授权、附件、入库、查验、订单轨迹、操作日志、应收与'
  17. '结算日志及派送信息。用户要求完整详情时可使用“全部”一次取得所有模块;'
  18. '各明细模块仍按独立分页信息展示,任何模块为空都不能作为跳过其他模块的依据。'
  19. '本工具只用于单个订单的详情查询;用户要求订单列表、批量筛选或多个订单汇总时,'
  20. '必须改用 query_order_exact,不得使用本工具替代。即使用户提供了订单号,'
  21. '只要目标是列表或批量结果,也不能调用本工具。用户要求分别查询多个订单详情时,'
  22. '必须按订单号逐个调用本工具,每次只传一个订单号,不得合并成列表查询。'
  23. '只接受订单号,不接受订单ID、箱单ID、查验ID、公司、员工'
  24. '或权限字段。不得猜测号码类型或把同一号码跨工具试查。参数名仅用于工具'
  25. '调用;向用户回答时只能展示固定中文业务名称,不得展示内部参数名。'
  26. ),
  27. 'input_schema': {
  28. 'type': 'object',
  29. 'properties': {
  30. 'order_number': {
  31. 'type': 'string', 'minLength': 1, 'maxLength': 100,
  32. 'description': '明确的订单号。',
  33. },
  34. 'section': {
  35. 'type': 'string', 'enum': list(self.sections),
  36. 'default': '全部', 'description': '要查看的中文详情模块;未指定时返回全部模块。',
  37. },
  38. 'page': {
  39. 'type': 'integer', 'minimum': 1, 'maximum': 100,
  40. 'default': 1,
  41. },
  42. 'limit': {
  43. 'type': 'integer', 'minimum': 1, 'maximum': 100,
  44. 'default': 20,
  45. },
  46. },
  47. 'required': ['order_number'],
  48. 'additionalProperties': False,
  49. },
  50. }
  51. def call(
  52. self,
  53. order_number=None,
  54. section='全部',
  55. page=1,
  56. limit=20,
  57. request_id='rq_query_order_detail',
  58. ):
  59. if self.api_client is None:
  60. raise RuntimeError('api client is required for query_order_detail')
  61. if not isinstance(order_number, str):
  62. raise ValueError('order_number is required')
  63. order_number = order_number.strip()
  64. if not order_number or len(order_number) > 100:
  65. raise ValueError('order_number is required')
  66. if not isinstance(section, str) or section.strip() not in self.sections:
  67. raise ValueError('section is invalid')
  68. section = section.strip()
  69. page = self._bounded_integer(page, 'page')
  70. limit = self._bounded_integer(limit, 'limit')
  71. return self.api_client.call_tool(
  72. self.name,
  73. self.route_path,
  74. {
  75. 'order_number': order_number,
  76. 'section': section,
  77. 'page': page,
  78. 'limit': limit,
  79. },
  80. request_id,
  81. )
  82. @staticmethod
  83. def _bounded_integer(value, field):
  84. if isinstance(value, bool):
  85. raise ValueError('{0} is invalid'.format(field))
  86. if isinstance(value, int):
  87. number = value
  88. elif isinstance(value, str) and value.isdigit() and not value.startswith('0'):
  89. number = int(value)
  90. else:
  91. raise ValueError('{0} is invalid'.format(field))
  92. if number < 1 or number > 100:
  93. raise ValueError('{0} is invalid'.format(field))
  94. return number