| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154 |
- class SaveRemoteAddressTool:
- name = 'save_remote_address'
- route_path = '/mcp/tools/saveRemoteAddress'
- backend = 'base'
- def __init__(self, api_client=None):
- self.api_client = api_client
- def metadata(self):
- return {
- 'name': self.name,
- 'description': (
- '使用场景:新增地址库,或修改已有地址库的名称和启用状态。'
- '新增时不要传编号,必须带名称、状态,以及至少一条地址明细。'
- '编辑时必须传query_remote_address_list返回的编号,只修改名称和状态,不能提交明细。'
- '没有地址明细的地址库不能保存。'
- '状态用1表示启用,用0表示禁用。'
- '国家可以填国家二字码或中文名称。发件人国家和收件人国家至少填一个。'
- '结束邮编不能单独填写,必须同时有开始邮编。'
- '禁止使用:手填不存在的编号、导入文件、删除明细、修改已有明细。'
- '参数只用于工具内部调用;最终回答只能展示中文业务名称和地址库编号。'
- ),
- 'input_schema': {
- 'type': 'object',
- 'properties': {
- 'address_no': {
- 'type': 'string',
- 'minLength': 1,
- 'maxLength': 20,
- 'description': '要编辑的地址库编号,格式为PY加数字。新增时不要传。',
- },
- 'remote_name': {
- 'type': 'string',
- 'minLength': 1,
- 'maxLength': 100,
- 'description': '地址库名称。',
- },
- 'status': {
- 'type': 'integer',
- 'enum': [0, 1],
- 'description': '1启用,0禁用。',
- },
- 'details': {
- 'type': 'array',
- 'maxItems': 200,
- 'description': '新增时的地址明细。编辑时不要传。',
- 'items': {
- 'type': 'object',
- 'properties': {
- 'shipper_country': {'type': 'string', 'maxLength': 50},
- 'shipper_province': {'type': 'string', 'maxLength': 20},
- 'shipper_city': {'type': 'string', 'maxLength': 20},
- 'shipper_start_postcode': {'type': 'string', 'maxLength': 10},
- 'shipper_end_postcode': {'type': 'string', 'maxLength': 10},
- 'country': {'type': 'string', 'maxLength': 50},
- 'province': {'type': 'string', 'maxLength': 20},
- 'city': {'type': 'string', 'maxLength': 20},
- 'start_postcode': {'type': 'string', 'maxLength': 10},
- 'end_postcode': {'type': 'string', 'maxLength': 10},
- },
- 'additionalProperties': False,
- },
- },
- },
- 'required': ['remote_name', 'status'],
- 'additionalProperties': False,
- },
- }
- def call(
- self,
- remote_name,
- status,
- address_no=None,
- details=None,
- request_id='rq_save_remote_address',
- ):
- if self.api_client is None:
- raise RuntimeError('api client is required for save_remote_address')
- if not isinstance(remote_name, str) or not remote_name.strip() or len(remote_name.strip()) > 100:
- raise ValueError('remote_name is invalid')
- if isinstance(status, bool) or status not in (0, 1):
- raise ValueError('status is invalid')
- payload = {
- 'remote_name': remote_name.strip(),
- 'status': status,
- }
- if address_no is not None:
- if not isinstance(address_no, str):
- raise ValueError('address_no is invalid')
- address_no = address_no.strip()
- if address_no:
- if len(address_no) > 20:
- raise ValueError('address_no is invalid')
- payload['address_no'] = address_no
- if details is not None:
- payload['details'] = self._details(details)
- if payload.get('address_no') and payload.get('details'):
- raise ValueError('details is invalid')
- if not payload.get('address_no') and not payload.get('details'):
- raise ValueError('details is invalid')
- return self.api_client.call_tool(
- self.name, self.route_path, payload, request_id,
- )
- @staticmethod
- def _details(details):
- if not isinstance(details, list) or not details or len(details) > 200:
- raise ValueError('details is invalid')
- fields = (
- 'shipper_country', 'shipper_province', 'shipper_city',
- 'shipper_start_postcode', 'shipper_end_postcode',
- 'country', 'province', 'city', 'start_postcode', 'end_postcode',
- )
- postcode_fields = {
- 'shipper_start_postcode', 'shipper_end_postcode',
- 'start_postcode', 'end_postcode',
- }
- rows = []
- for detail in details:
- if not isinstance(detail, dict) or set(detail) - set(fields):
- raise ValueError('details is invalid')
- row = {}
- for field in fields:
- if field not in detail:
- continue
- value = detail[field]
- if not isinstance(value, str):
- raise ValueError('details is invalid')
- value = value.strip()
- limit = 10 if field in postcode_fields else (50 if field in ('shipper_country', 'country') else 20)
- if len(value) > limit:
- raise ValueError('details is invalid')
- if field in postcode_fields and value and not _postcode(value):
- raise ValueError('details is invalid')
- if value:
- row[field] = value
- if not row.get('shipper_country') and not row.get('country'):
- raise ValueError('details is invalid')
- if row.get('shipper_end_postcode') and not row.get('shipper_start_postcode'):
- raise ValueError('details is invalid')
- if row.get('end_postcode') and not row.get('start_postcode'):
- raise ValueError('details is invalid')
- rows.append(row)
- return rows
- def _postcode(value):
- for character in value:
- if ('0' <= character <= '9') or ('A' <= character <= 'Z') or ('a' <= character <= 'z') or character in ' -':
- continue
- return False
- return True
|