query_customer_payment_records.py 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. from datetime import date
  2. class QueryCustomerPaymentRecordsTool:
  3. name = 'query_customer_payment_records'
  4. route_path = '/mcp/tools/queryCustomerPaymentRecords'
  5. def __init__(self, api_client=None):
  6. self.api_client = api_client
  7. def metadata(self):
  8. return {
  9. 'name': self.name,
  10. 'description': (
  11. '分页查询单个客户的逐笔收款记录、已核销金额和未核销金额。必须先调用'
  12. 'list_customer_filter_options并使用客户名称筛选取得customer_id;不得根据名称猜测'
  13. 'customer_id,不得模糊查询或改用其他工具试查。收款日期可按闭区间筛选,'
  14. '起止日期同时提供时闭区间最多包含366个日历日。公司、员工、菜单权限和客户数据范围由'
  15. '当前设备会话确定,调用方不得覆盖。'
  16. ),
  17. 'input_schema': {
  18. 'type': 'object',
  19. 'properties': {
  20. 'customer_id': {'type': 'integer', 'minimum': 1},
  21. 'receive_date_start': {
  22. 'type': 'string', 'format': 'date',
  23. 'pattern': '^\\d{4}-\\d{2}-\\d{2}$',
  24. },
  25. 'receive_date_end': {
  26. 'type': 'string', 'format': 'date',
  27. 'pattern': '^\\d{4}-\\d{2}-\\d{2}$',
  28. },
  29. 'page': {
  30. 'type': 'integer', 'minimum': 1, 'maximum': 100,
  31. 'default': 1,
  32. },
  33. 'limit': {
  34. 'type': 'integer', 'minimum': 1, 'maximum': 100,
  35. 'default': 20,
  36. },
  37. },
  38. 'required': ['customer_id'],
  39. 'additionalProperties': False,
  40. },
  41. }
  42. def call(
  43. self,
  44. customer_id,
  45. receive_date_start=None,
  46. receive_date_end=None,
  47. page=1,
  48. limit=20,
  49. request_id='rq_query_customer_payment_records',
  50. ):
  51. if self.api_client is None:
  52. raise RuntimeError(
  53. 'api client is required for query_customer_payment_records'
  54. )
  55. start = self._optional_date(receive_date_start, 'receive_date_start')
  56. end = self._optional_date(receive_date_end, 'receive_date_end')
  57. if start and end:
  58. span = (date.fromisoformat(end) - date.fromisoformat(start)).days
  59. if span < 0 or span > 365:
  60. raise ValueError('receive date range is invalid')
  61. payload = {
  62. 'customer_id': self._positive_integer(customer_id, 'customer_id'),
  63. 'page': self._bounded_integer(page, 'page'),
  64. 'limit': self._bounded_integer(limit, 'limit'),
  65. }
  66. if start:
  67. payload['receive_date_start'] = start
  68. if end:
  69. payload['receive_date_end'] = end
  70. return self.api_client.call_tool(
  71. self.name, self.route_path, payload, request_id
  72. )
  73. @staticmethod
  74. def _positive_integer(value, field):
  75. if isinstance(value, bool) or not isinstance(value, int) or value < 1:
  76. raise ValueError('{0} is invalid'.format(field))
  77. return value
  78. @classmethod
  79. def _bounded_integer(cls, value, field):
  80. value = cls._positive_integer(value, field)
  81. if value > 100:
  82. raise ValueError('{0} is invalid'.format(field))
  83. return value
  84. @staticmethod
  85. def _optional_date(value, field):
  86. if value is None or value == '':
  87. return ''
  88. if not isinstance(value, str):
  89. raise ValueError('{0} is invalid'.format(field))
  90. try:
  91. parsed = date.fromisoformat(value)
  92. except ValueError:
  93. raise ValueError('{0} is invalid'.format(field))
  94. if parsed.isoformat() != value:
  95. raise ValueError('{0} is invalid'.format(field))
  96. return value