async def add_contact_way(self, type, scene, style=None, remark=None, skip_verify=True, state=None, user=None, party=None): """ 配置客户联系「联系我」方式 https://work.weixin.qq.com/api/doc#90000/90135/91559 :param type: 联系方式类型,1-单人, 2-多人 :param scene: 场景,1-在小程序中联系,2-通过二维码联系 :param style: 在小程序中联系时使用的控件样式,详见附表 :param remark: 联系方式的备注信息,用于助记,不超过30个字符 :param skip_verify: 外部客户添加时是否无需验证,默认为true :param state: 企业自定义的state参数,用于区分不同的添加渠道,在调用“获取外部联系人详情”时会返回该参数值 :param user: 使用该联系方式的用户userID列表,在type为1时为必填,且只能有一个 :param party: 使用该联系方式的部门id列表,只在type为2时有效 :return: 返回的 JSON 数据包 """ data = optionaldict(type=type, scene=scene, style=style, remark=remark, skip_verify=skip_verify, state=state, user=user, party=party) return await self._post('externalcontact/add_contact_way', data=data)
def test_init_with_none(self): d = optionaldict( a=1, b=None ) self.assertEqual(1, d['a']) self.assertTrue('b' not in d)
def _request(self, method, url_or_endpoint, **kwargs): if not url_or_endpoint.startswith(("http://", "https://")): api_base_url = kwargs.pop("api_base_url", self.API_BASE_URL) url = "{base}{endpoint}".format(base=api_base_url, endpoint=url_or_endpoint) else: url = url_or_endpoint if isinstance(kwargs.get("data", ""), dict): data = optionaldict(kwargs["data"]) if "mchid" not in data: # F**k Tencent data.setdefault("mch_id", self.mch_id) data.setdefault("sub_mch_id", self.sub_mch_id) data.setdefault("nonce_str", random_string(32)) sign = calculate_signature(data, self.api_key) body = dict_to_xml(data, sign) body = body.encode("utf-8") kwargs["data"] = body # 商户证书 if self.mch_cert and self.mch_key: kwargs["cert"] = (self.mch_cert, self.mch_key) res = requests.request(method=method, url=url, **kwargs) try: res.raise_for_status() except requests.RequestException as reqe: raise WeChatPayException(return_code=None, client=self, request=reqe.request, response=reqe.response) return self._handle_result(res)
def create(self, project_id, category_id, content, amount, type, note=None, visiable=None, tag_ids=None, involve_members=None): """ 新建账目 详情请参考 http://docs.teambition.com/wiki/bookkeeping-entry#bookkeeping-entry-create :param project_id: 项目 ID :param category_id: 账目分类 ID :param content: 内容 :param amount: 金额 :param type: 类型,1 为收入,-1 为支出 :param note: 可选,备注 :param visiable: 可选,可见范围 :param tag_ids: 可选,标签 ID 列表 :param involve_members: 可选,参与者 ID 列表 :return: 返回的 JSON 数据包 """ data = optionaldict( _projectId=project_id, _entryCategoryId=category_id, content=content, amount=amount, type=type, note=note, visiable=visiable, tagIds=tag_ids, involveMembers=involve_members ) return self._post( 'api/entries', data=data )
def create_version(self, id, file_name, file_size, file_type, file_category, file_key, image_width=None, image_height=None, involve_members=None): """ 新建文件 详情请参考 http://docs.teambition.com/wiki/works-versions#works-versions-post :param id: 文件 ID :param file_name: 文件名 :param file_size: 文件大小 :param file_type: 文件类型 :param file_category: 文件类别 :param file_key: 使用 striker 服务上传后可得 :param image_width: 可选,图片宽度 :param image_height: 可选,图片高度 :param involve_members: 可选 :return: 返回的 JSON 数据包 """ data = optionaldict( fileName=file_name, fileSize=file_size, fileType=file_type, fileCategory=file_category, fileKey=file_key, imageWidth=image_width, imageHeight=image_height, involveMembers=involve_members ) return self._post( 'api/works/{0}/versions'.format(id), data=data )
def update_device(self, device_id=None, uuid=None, major=None, minor=None, comment=None): """ 更新设备信息 详情请参考 http://mp.weixin.qq.com/wiki/15/b9e012f917e3484b7ed02771156411f3.html :param device_id: 设备编号,若填了UUID、major、minor,则可不填设备编号,若二者都填,则以设备编号为优先 :param uuid: UUID :param major: major :param minor: minor :param comment: 设备的备注信息,不超过15个汉字或30个英文字母。 :return: 返回的 JSON 数据包 """ data = optionaldict() data['comment'] = comment data['device_identifier'] = { 'device_id': device_id, 'uuid': uuid, 'major': major, 'minor': minor } return self._post( 'shakearound/device/update', data=data )
def update_webhook(self, id, hook_id, callback_url=None, active=True, events=None, add_events=None, remove_events=None): """ 更新项目 webhook :param id: 项目 ID :param hook_id: webhook ID :param callback_url: 可选,回调地址,Teambition通过HEAD请求进行测试, 有事件被触发将发送POST请求 :param active: 可选,是否激活,默认为 True :param events: 可选,事件列表,默认为空 :param add_events: 可选,追加新的事件进去 :param remove_events: 可选,从原有的事件列表中移除 :return: 返回的 JSON 数据包 """ data = optionaldict( callbackURL=callback_url, active=active, events=events, addEvents=add_events, removeEvents=remove_events ) return self._put( 'api/projects/{0}/hooks/{1}'.format(id, hook_id), data=data )
def get_used_flow( self, start_date, end_date, ): """ 查询账号一段时间内使用的流量 查询整体账号一段时间内使用的总流量。 注:流量的统计不是实时的,每天统计一次。 :param start_date: 查询起始日期,时间格式为yyyy-mm-dd,如:2017-08-01 :param end_date: 查询结束日期,时间格式为yyyy-mm-dd,如:2017-08-01 """ if isinstance(start_date, datetime.date): start_date = start_date.strftime('%Y-%m-%d') if isinstance(end_date, datetime.date): end_date = end_date.strftime('%Y-%m-%d') return self._post( '/openapi/video_account/getUsedFlow', optionaldict({ 'partner_id': self.partner_id, 'start_date': start_date, 'end_date': end_date, }), result_processor=lambda x: x['flow'] )
def process_save(self, name, description, form_component_list=(), process_code=None, agentid=None): """ 保存审批模板 :param name: 模板名称 :param description: 模板描述 :param form_component_list: 表单列表 :param process_code: 模板的唯一码 :param agentid: 企业微应用标识 """ form_component_list = [ form.get_dict() if isinstance(form, FieldBase) else form for form in form_component_list ] return self._top_request("dingtalk.oapi.process.save", { "saveProcessRequest": optionaldict({ "agentid": agentid, "process_code": process_code, "name": name, "description": description, "fake_mode": True, "form_component_list": form_component_list }) }, result_processor=lambda x: x['process_code'])
def invite_user(self, url, token, encoding_aes_key, user_ids=None, party_ids=None, tag_ids=None, invite_tips=None): """ 邀请成员关注(deprecated) https://qydev.weixin.qq.com/wiki/index.php?title=异步任务接口 :param url: 企业应用接收企业微信推送请求的访问协议和地址,支持http或https协议 :param token: 用于生成签名 :param encoding_aes_key: 用于消息体的加密,是AES密钥的Base64编码 :param user_ids: 可选,成员ID列表,多个接收者用‘|’分隔,最多支持1000个。 :param party_ids: 可选,部门ID列表,多个接收者用‘|’分隔,最多支持100个。 :param tag_ids: 可选,标签ID列表,多个接收者用‘|’分隔。 :param invite_tips: 可选,推送到微信上的提示语 :return: 返回的 JSON 数据包 """ data = optionaldict() data['callback'] = { 'url': url, 'token': token, 'encodingaeskey': encoding_aes_key } if isinstance(user_ids, (tuple, list)): user_ids = '|'.join(map(to_text, user_ids)) if isinstance(party_ids, (tuple, list)): party_ids = '|'.join(map(to_text, party_ids)) if isinstance(tag_ids, (tuple, list)): tag_ids = '|'.join(map(to_text, tag_ids)) data['touser'] = user_ids data['toparty'] = party_ids data['totag'] = tag_ids data['invite_tips'] = invite_tips return self._post('batch/inviteuser', data=data)
def get_wxa_code_unlimited(self, scene, width=430, auto_color=False, line_color={ "r": "0", "g": "0", "b": "0" }, page=None, is_hyaline=False): """ 创建小程序码(接口B:适用于需要的码数量极多,或仅临时使用的业务场景) 详情请参考 https://mp.weixin.qq.com/debug/wxadoc/dev/api/qrcode.html """ return self._post('wxa/getwxacodeunlimit', data=optionaldict( scene=scene, page=page, width=width, auto_color=auto_color, line_color=line_color, is_hyaline=is_hyaline, ))
def update( self, user_id, name=None, department=None, position=None, mobile=None, gender=None, tel=None, email=None, weixin_id=None, enable=None, extattr=None, **kwargs, ): """ 更新成员 https://work.weixin.qq.com/api/doc#90000/90135/90197 """ user_data = optionaldict() user_data["userid"] = user_id user_data["name"] = name user_data["gender"] = gender user_data["department"] = department user_data["position"] = position user_data["mobile"] = mobile user_data["tel"] = tel user_data["email"] = email user_data["weixinid"] = weixin_id user_data["extattr"] = extattr user_data["enable"] = enable user_data.update(kwargs) return self._post("user/update", data=user_data)
async def update(self, user_id, name=None, department=None, position=None, mobile=None, gender=None, tel=None, email=None, weixin_id=None, enable=None, extattr=None, **kwargs): """ 更新成员 https://work.weixin.qq.com/api/doc#90000/90135/90197 """ user_data = optionaldict() user_data['userid'] = user_id user_data['name'] = name user_data['gender'] = gender user_data['department'] = department user_data['position'] = position user_data['mobile'] = mobile user_data['tel'] = tel user_data['email'] = email user_data['weixinid'] = weixin_id user_data['extattr'] = extattr user_data['enable'] = enable user_data.update(kwargs) return await self._post('user/update', data=user_data)
async def update_contact_way(self, config_id, remark, skip_verify=True, style=None, state=None, user=None, party=None): """ 更新企业已配置的「联系我」方式 https://work.weixin.qq.com/api/doc#90000/90135/91559 :param config_id: 企业联系方式的配置id :param remark: 联系方式的备注信息,不超过30个字符,将覆盖之前的备注 :param skip_verify: 外部客户添加时是否无需验证 :param style: 样式,只针对“在小程序中联系”的配置生效 :param state: 企业自定义的state参数,用于区分不同的添加渠道,在调用“获取外部联系人详情”时会返回该参数值 :param user: 使用该联系方式的用户列表,将覆盖原有用户列表 :param party: 使用该联系方式的部门列表,将覆盖原有部门列表,只在配置的type为2时有效 :return: 返回的 JSON 数据包 """ data = optionaldict(config_id=config_id, remark=remark, skip_verify=skip_verify, style=style, state=state, user=user, party=party) return await self._post('externalcontact/update_contact_way', data=data)
def update(self, chat_id, op_user, name=None, owner=None, add_user_list=None, del_user_list=None): """ 修改会话 详情请参考 http://qydev.weixin.qq.com/wiki/index.php?title=企业会话接口说明 :param chat_id: 会话 ID :param op_user: 操作人 userid :param name: 会话标题 :param owner: 管理员userid,必须是该会话userlist的成员之一 :param add_user_list: 会话新增成员列表,成员用userid来标识 :param del_user_list: 会话退出成员列表,成员用userid来标识 :return: 返回的 JSON 数据包 """ data = optionaldict( chatid=chat_id, op_user=op_user, name=name, owner=owner, add_user_list=add_user_list, del_user_list=del_user_list, ) return self._post('chat/update', data=data)
def get_group_chat_info(self, chat_id: str) -> dict: """ 获取客户群详情 通过客户群ID,获取详情。包括群名、群成员列表、群成员入群时间、入群方式。 (客户群是由具有客户群使用权限的成员创建的外部群) 需注意的是,如果发生群信息变动,会立即收到群变更事件,但是部分信息是异步处理, 可能需要等一段时间调此接口才能得到最新结果 详细请查阅企业微信官方文档 `获取客户群详情`_ 章节。 :param chat_id: 客户群ID :return: 响应数据 .. note:: **权限说明:** - 需要使用 `客户联系secret`_ 或配置到 `可调用应用`_ 列表中的自建应用secret 来初始化 :py:class:`wechatpy.work.client.WeChatClient` 类。 - 第三方应用需具有“企业客户权限->客户基础信息”权限 - 对于第三方/自建应用,群主必须在应用的可见范围。 .. _获取客户群详情: https://work.weixin.qq.com/api/doc/90000/90135/92122 """ data = optionaldict(chat_id=chat_id) return self._post("externalcontact/groupchat/get", data=data)
def update(self, name=None, avatar_url=None, title=None, birthday=None, location=None, phone=None, website=None): """ 更新个人信息 详情请参考 http://docs.teambition.com/wiki/me#me-update-info :param name: 可选,姓名 :param avatar_url: 可选,头像地址 :param title: 可选,职位 :param birthday: 可选,出生日期 :param location: 可选,所在地 :param phone: 可选,手机号码 :param website: 可选,个人站点 :return: 返回的 JSON 数据包 """ data = optionaldict( name=name, avatarUrl=avatar_url, title=title, birthday=birthday, location=location, phone=phone, website=website, ) return self._put("api/users", data=data)
def add_group_welcome_template(self, template: dict, agentid: Optional[int] = None) -> dict: """ 添加群欢迎语素材 企业可通过此API向企业的入群欢迎语素材库中添加素材。每个企业的入群欢迎语素材库中, 最多容纳100个素材。 详细请查阅企业微信官方文档 `添加群欢迎语素材`_ 章节。 :param template: 群欢迎语素材内容,详细字段请参考微信文档 :param agentid: 授权方安装的应用agentid。仅旧的第三方多应用套件需要填此参数 :return: 响应数据 .. note:: **权限说明:** - 需要使用 `客户联系secret`_ 或配置到 `可调用应用`_ 列表中的自建应用secret 来初始化 :py:class:`wechatpy.work.client.WeChatClient` 类。 - 第三方应用需具有“企业客户权限->客户联系->配置入群欢迎语素材”权限 .. _添加群欢迎语素材: https://work.weixin.qq.com/api/doc/90000/90135/ 92366#%E6%B7%BB%E5%8A%A0%E5%85%A5%E7%BE%A4%E6%AC%A2%E8%BF%8E%E 8%AF%AD%E7%B4%A0%E6%9D%90 """ data = optionaldict() data.update(template) data["agentid"] = agentid return self._post("externalcontact/group_welcome_template/add", data=data)
def get(self, id=None, team_id=None, is_archived=False): """ 获取项目信息 详情请参考 http://docs.teambition.com/wiki/projects#projects-get :param id: 可选,不提供则返回用户所在的项目 :param team_id: 可选,团队 ID,提供可获取团队所在项目 :param is_archived: 返回归档的项目,默认为 False :return: 返回的 JSON 数据包 """ params = optionaldict( _teamId=team_id, isArchived=is_archived ) if id is None: endpoint = 'api/projects' else: endpoint = 'api/projects/{0}'.format(id) return self._get( endpoint, params=params )
def update_group_welcome_template(self, template: dict, template_id: str, agentid: Optional[int] = None) -> dict: """ 编辑群欢迎语素材 企业可通过此API编辑入群欢迎语素材库中的素材,且仅能够编辑调用方自己创建的入群欢迎语素材。 详细请查阅企业微信官方文档 `编辑群欢迎语素材`_ 章节。 :param template: 群欢迎语素材内容,详细字段请参考微信文档 :param template_id: 欢迎语素材id :param agentid: 授权方安装的应用agentid。仅旧的第三方多应用套件需要填此参数 :return: 响应数据 .. note:: **权限说明:** - 需要使用 `客户联系secret`_ 或配置到 `可调用应用`_ 列表中的自建应用secret 来初始化 :py:class:`wechatpy.work.client.WeChatClient` 类。 - 第三方应用需具有“企业客户权限->客户联系->配置入群欢迎语素材”权限 - 仅可编辑本应用创建的入群欢迎语素材 .. _添编辑群欢迎语素材: https://work.weixin.qq.com/api/doc/90000/90135/ 92366#%E7%BC%96%E8%BE%91%E5%85%A5%E7%BE%A4%E6%AC%A2%E8%BF%8E%E8% AF%AD%E7%B4%A0%E6%9D%90 """ data = optionaldict() data.update(template) data["template_id"] = template_id data["agentid"] = agentid return self._post("externalcontact/group_welcome_template/edit", data=data)
def create(self, title, project_id, parent_id=None, description=None, color=None): """ 新建文件集 详情请参考 http://docs.teambition.com/wiki/collections#collections-create :param title: 文件集标题 :param project_id: 项目 ID :param parent_id: 可选,父级 ID,默认为项目 ID :param description: 可选,描述 :param color: 可选,颜色,默认为空 :return: 返回的 JSON 数据包 """ data = optionaldict( title=title, _projectId=project_id, _parentId=parent_id or project_id, description=description, color=color ) return self._post( 'api/collections', data=data )
def del_group_welcome_template(self, template_id: str, agentid: Optional[int] = None) -> dict: """ 删除入群欢迎语素材 企业可通过此API删除入群欢迎语素材,且仅能删除调用方自己创建的入群欢迎语素材。 详细请查阅企业微信官方文档 `删除入群欢迎语素材`_ 章节。 :param template_id: 群欢迎语的素材id :param agentid: 授权方安装的应用agentid。仅旧的第三方多应用套件需要填此参数 :return: 响应数据 .. note:: **权限说明:** - 需要使用 `客户联系secret`_ 或配置到 `可调用应用`_ 列表中的自建应用secret 来初始化 :py:class:`wechatpy.work.client.WeChatClient` 类。 - 第三方应用需具有“企业客户权限->客户联系->配置入群欢迎语素材”权限 - 仅可删除本应用创建的入群欢迎语素材 .. _删除入群欢迎语素材: https://work.weixin.qq.com/api/doc/90000/90135/ 92366#%E5%88%A0%E9%99%A4%E5%85%A5%E7%BE%A4%E6%AC%A2%E8%BF%8E%E8 %AF%AD%E7%B4%A0%E6%9D%90 """ data = optionaldict(template_id=template_id, agentid=agentid) return self._post("externalcontact/group_welcome_template/del", data=data)
def create(self, content, tasklist_id, stage_id=None, executor_id=None, involve_members=None, due_date=None, priority=None, recurrence=None, tag_ids=None): """ 创建任务 详情请参考 http://docs.teambition.com/wiki/tasks#tasks-create :param content: 任务内容 :param tasklist_id: 任务分组 ID :param stage_id: 可选,阶段 ID,默认为任务分组的第一个阶段 :param executor_id: 可选,执行者 ID,默认为空 :param involve_members: 可选,参与者 ID 数组,默认为创建者和执行者 :param due_date: 可选,截止日期 :param priority: 可选,优先级,可选值为 0,1,2,对应普通、紧急、非常紧急 :param recurrence: 可选,重复规则列表 :param tag_ids: 可选,标签 ID 列表 :return: 返回的 JSON 数据包 """ data = optionaldict( content=content, _tasklistId=tasklist_id, _stageId=stage_id, _executorId=executor_id, involveMembers=involve_members, dueDate=due_date, priority=priority, recurrence=recurrence, tagIds=tag_ids ) return self._post( 'api/tasks', data=data )
def del_contact_way(self, config_id: str) -> dict: """ 删除企业已配置的「联系我」方式 删除一个已配置的「联系我」二维码或者「联系我」小程序按钮。 详细请查阅企业微信官方文档 `删除企业已配置的「联系我」方式`_ 章节。 :param config_id: 企业联系方式的配置id :return: 返回的 JSON 数据包 .. note:: **调用接口应满足如下的权限要求:** - 需要使用 `客户联系secret`_ 或配置到 `可调用应用`_ 列表中的自建应用secret 来初始化 :py:class:`wechatpy.work.client.WeChatClient` 类。 - 使用人员需要配置了 `客户联系功能`_。 - 第三方调用时,应用需具有 `企业客户权限`_。 - 第三方/自建应用调用时,传入的userid和partyid需要在此应用的可见范围内。 - 配置的使用成员必须在企业微信激活且已经过实名认证。 - 临时会话的二维码具有有效期,添加企业成员后仅能在指定有效期内进行会话, 仅支持医疗行业企业创建。 临时会话模式可以配置会话结束时自动发送给用户的结束语。 .. _删除企业已配置的「联系我」方式: https://work.weixin.qq.com/api/doc/90000 /90135/92572#%E5%88%A0%E9%99%A4%E4%BC%81%E4%B8%9A%E5%B7%B2%E9%85%8D %E7%BD%AE%E7%9A%84%E3%80%8C%E8%81%94%E7%B3%BB%E6%88%91%E3%80%8D%E6% 96%B9%E5%BC%8F """ data = optionaldict(config_id=config_id) return self._post("externalcontact/del_contact_way", data=data)
def get(self, id=None, parent_id=None, page=None, count=None, all=None): """ 获取文件信息 详情请参考 http://docs.teambition.com/wiki/works#works-get :param id: 可选,文件 ID :param parent_id: 可选,父级 ID :param page: 可选,当前页,默认为 1 :param count: 可选,每页数量,默认为 30 :param all: 可选,若提供此参数则返回所有 :return: 返回的 JSON 数据包 """ assert id or parent_id params = optionaldict( page=page, count=count, all=all ) if id: endpoint = 'api/works/{0}'.format(id) elif parent_id: endpoint = 'api/works' params['_parentId'] = parent_id return self._get(endpoint, params=params)
def get_unassigned_list(self, page_id: int = 0, page_size: int = 1000, cursor: Optional[str] = None) -> dict: """ 获取离职成员列表 企业和第三方可通过此接口,获取所有离职成员的客户列表,并可进一步调用 `分配在职或离职成员的客户`_ 接口将这些客户重新分配给其他企业成员。 详细请查阅企业微信官方文档 `获取离职成员列表`_ 章节。 :param page_id: 分页查询,要查询页号,从0开始 :param page_size: 每次返回的最大记录数,默认为1000,最大值为1000 :param cursor: 分页查询游标,字符串类型,适用于数据量较大的情况,如果使用该参数 则无需填写page_id,该参数由上一次调用返回 :return: 响应结果 .. note:: 当 ``page_id`` 为1,``page_size`` 为100时,表示取第101到第200条记录。 由于每个成员的客户数不超过5万,故 ``page_id * page_size`` 必须小于5万。 .. note:: **权限说明:** - 需要使用 `客户联系secret`_ 或配置到 `可调用应用`_ 列表中的自建应用secret 来初始化 :py:class:`wechatpy.work.client.WeChatClient` 类。 - 第三方应用需拥有“企业客户权限->客户联系->分配在职或离职成员的客户”权限 .. _获取离职成员列表: https://work.weixin.qq.com/api/doc/90000/90135/92124 """ data = optionaldict(page_id=page_id, page_size=page_size, cursor=cursor) return self._post("externalcontact/get_unassigned_list", data=data)
def get_by_filter(self, status=None, begin_time=None, end_time=None): filter_dict = optionaldict(status=status, begintime=begin_time, endtime=end_time) res = self._post( "merchant/order/getbyfilter", data=dict(filter_dict), result_processor=lambda x: x["order_list"] ) return res
def set( self, agent_id, name=None, description=None, redirect_domain=None, logo_media_id=None, report_location_flag=0, is_report_user=True, is_report_enter=True, ): """ 设置应用 https://work.weixin.qq.com/api/doc#90000/90135/90228 :param agent_id: 企业应用的id :param name: 企业应用名称,长度不超过32个utf8字符 :param description: 企业应用详情,长度为4至120个utf8字符 :param redirect_domain: 企业应用可信域名。注意:域名需通过所有权校验,否则jssdk功能将受限,此时返回错误码85005 :param logo_media_id: 企业应用头像的mediaid,通过素材管理接口上传图片获得mediaid,上传后会自动裁剪成方形和圆形两个头像 :param report_location_flag: 企业应用是否打开地理位置上报 0:不上报;1:进入会话上报; :param is_report_enter: 是否上报用户进入应用事件。0:不接收;1:接收。 :param is_report_user: 是否接收用户变更通知。0:不接收;1:接收。 :return: 返回的 JSON 数据包 """ agent_data = optionaldict() agent_data["agentid"] = agent_id agent_data["name"] = name agent_data["description"] = description agent_data["redirect_domain"] = redirect_domain agent_data["logo_mediaid"] = logo_media_id agent_data["report_location_flag"] = report_location_flag agent_data["isreportenter"] = 1 if is_report_enter else 0 agent_data["isreportuser"] = 1 if is_report_user else 0 return self._post("agent/set", data=agent_data)
def create(self, project_id, title, content, post_mode=None, visiable='members', involve_members=None, tag_ids=None, attachments=None): """ 新建分享 详情请参考 http://docs.teambition.com/wiki/posts#posts-create :param project_id: 项目 ID :param title: 标题 :param content: 内容 :param post_mode: 可选,分享模式 :param visiable: 可选,可见范围,默认为 members,可选 involves :param involve_members: 可选,参与者 ID 列表 :param tag_ids: 可选,标签 ID 列表 :param attachments: 可选,附件 ID 列表 :return: 返回的 JSON 数据包 """ data = optionaldict( _projectId=project_id, title=title, content=content, postMode=post_mode, visiable=visiable, involveMembers=involve_members, tagIds=tag_ids, attachments=attachments ) return self._post( 'api/posts', data=data )
def _request(self, method, url_or_endpoint, **kwargs): if not url_or_endpoint.startswith('https://'): api_base_url = kwargs["data"].pop('api_base_url', self._api_base_url) url = f"{api_base_url}{url_or_endpoint}" else: url = url_or_endpoint data = optionaldict(kwargs['data']) data.setdefault('mch_id', self._mch_id) data.setdefault('appid', self._appid) data.setdefault('nonce_str', self._nonce_str or random_string(32)) data.setdefault("notify_url", self._notify_url) sign = calculate_signature(data, self._api_key) body = dict_to_xml(data, sign) body = body.encode('utf-8') kwargs['data'] = body # 商户证书 kwargs['cert'] = (self._apiclient_cert_path, self._apiclient_key_path) res = requests.request( method=method, url=url, **kwargs ) try: res.raise_for_status() except requests.RequestException as reqe: raise reqe return self._handle_result(res)
def get_day_peak_user( self, start_date, end_date, product_type=0, ): """ 查询账号一段时间内每天的最高并发量 该接口用于获取账号一段时间内每天的最高并发量 :param start_date: 查询起始日期,格式如:2017-12-12 :param end_date: 查询结束日期,格式如:2017-12-28 :param product_type: 1:教育直播 2:小班课 4:企业直播 """ if isinstance(start_date, datetime.date): start_date = start_date.strftime('%Y-%m-%d') if isinstance(end_date, datetime.date): end_date = end_date.strftime('%Y-%m-%d') return self._post( '/openapi/live_account/getDayPeakUser', optionaldict({ 'partner_id': self.partner_id, 'product_type': product_type, 'start_date': start_date, 'end_date': end_date, }), result_processor=lambda x: x['peak_user'] )
def get_url_scheme(self, is_expire=False, expire_type=0, expire_time=None, expire_interval=None, jump_wxa=()): """ 获取小程序 scheme 码,适用于短信、邮件、外部网页、微信内等拉起小程序的业务场景。 详情请参考 https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/url-scheme/urlscheme.generate.html :param is_expire, 到期失效:True,永久有效:False 默认False, 永久有效上限10万 :params expire_type, 失效时间:0,失效间隔天数:1 :params expire_time, 到期失效的 scheme 码的失效时间, Unix 时间戳, is_expire 为 true 且 expire_type 为 0 时必填 :params expire_interval, 到期失效的 scheme 码的失效间隔天数。生成的到期失效 scheme 码在该间隔时间到达前有效。 最长间隔天数为365天。is_expire 为 true 且 expire_type 为 1 时必填 :params jump_wxa, 跳转到的目标小程序信息。 :rtype: requests.Response """ return self._post( "wxa/generatescheme", data=optionaldict( jump_wxa=jump_wxa, ie_expire=is_expire, expire_type=expire_type, expire_time=expire_time, expire_interval=expire_interval, ), )
def get_wxa_code_unlimited( self, scene, width=430, auto_color=False, line_color=None, page=None, is_hyaline=False, ): """ 创建小程序码(接口B:适用于需要的码数量极多,或仅临时使用的业务场景) 详情请参考 https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/qr-code/wxacode.getUnlimited.html """ if line_color is None: line_color = {"r": "0", "g": "0", "b": "0"} return self._post( "wxa/getwxacodeunlimit", data=optionaldict( scene=scene, page=page, width=width, auto_color=auto_color, line_color=line_color, is_hyaline=is_hyaline, ), )
def update_page(self, page_id, title, description, icon_url, page_url, comment=None): """ 编辑页面信息 详情请参考 http://mp.weixin.qq.com/wiki/5/6626199ea8757c752046d8e46cf13251.html :param page_id: 摇周边页面唯一ID :param title: 在摇一摇页面展示的主标题,不超过6个字 :param description: 在摇一摇页面展示的副标题,不超过7个字 :param icon_url: 在摇一摇页面展示的图片。图片需先上传至微信侧服务器, 用“素材管理-上传图片素材”接口上传图片,返回的图片URL再配置在此处 :param page_url: 跳转链接 :param comment: 可选,页面的备注信息,不超过15个字 :return: 页面信息 """ data = optionaldict() data['page_id'] = page_id data['title'] = title data['description'] = description data['icon_url'] = icon_url data['page_url'] = page_url data['comment'] = comment res = self._post( 'shakearound/page/update', data=data ) return res['data']
def send_template_message( self, user_id, template_id, data, form_id, page=None, color=None, emphasis_keyword=None, ): """ ⚠️已废弃 发送模板消息 详情请参考 https://mp.weixin.qq.com/debug/wxadoc/dev/api/notice.html """ tpl_data = optionaldict( touser=user_id, template_id=template_id, page=page, form_id=form_id, data=data, color=color, emphasis_keyword=emphasis_keyword, ) return self._post("cgi-bin/message/wxopen/template/send", data=tpl_data)
def bind_device_location(self, poi_id, device_id=None, uuid=None, major=None, minor=None): """ 配置设备与门店的关联关系 详情请参考 http://mp.weixin.qq.com/wiki/15/b9e012f917e3484b7ed02771156411f3.html :param poi_id: 待关联的门店ID :param device_id: 设备编号,若填了UUID、major、minor,则可不填设备编号,若二者都填,则以设备编号为优先 :param uuid: UUID :param major: major :param minor: minor :return: 返回的 JSON 数据包 """ data = optionaldict() data['poi_id'] = poi_id data['device_identifier'] = { 'device_id': device_id, 'uuid': uuid, 'major': major, 'minor': minor } return self._post( 'shakearound/device/bindlocation', data=data )
def create(self, name, description=None, logo=None, location=None, website=None): """ 创建新组织 详情请参考 http://docs.teambition.com/wiki/orgs#orgs-create :param name: 组织名字 :param description: 可选,描述 :param logo: 可选,组织 logo :param location: 可选,组织所在地 :param website: 可选,组织网站 :return: 返回的 JSON 数据包 """ data = optionaldict( name=name, description=description, logo=logo, location=location, website=website ) return self._post( 'api/organizations', data=data )
def create(self, name, description=None, logo=None, categroy=None, divider_index=None, organization_id=None): """ 新建项目 详情请参考 http://docs.teambition.com/wiki/projects#projects-create :param name: 项目名称 :param description: 可选,项目描述 :param logo: 可选,项目 logo :param category: 可选,项目类别 :param divider_index: 可选,dividers 中得 index,仅对拥有者有效 :param organization_id: 可选,组织 ID,创建组织项目时需要提供此参数 :return: 新建的项目信息 """ data = optionaldict( name=name, description=description, logo=logo, category=categroy, dividerIndex=divider_index, _organizationId=organization_id ) return self._post( 'api/projects', data=data )
def get_member_tasks(self, id, member_id, start_date=None, is_done=None, all=False, page=1, count=30): """ 获取组织成员任务 详情请参考 http://docs.teambition.com/wiki/orgs#orgs-get-member-tasks :param id: 组织 ID :param member_id: 成员 ID :param start_date: 可选,起始日期,默认为当周的起始日期 :param is_done: 可选,是否完成,默认为 False :param all: 可选,是否返回所有 :param page: 可选,页码 :param count: 可选,每页数量,默认为 30 :return: 返回的 JSON 数据包 """ params = optionaldict( startDate=start_date, isDone=is_done, all=all, page=page, count=count ) return self._get( 'api/organizations/{0}/members/{1}/tasks'.format(id, member_id), params=params )
def update(self, id, name=None, description=None, logo=None, category=None, is_archived=None, is_public=None): """ 更新项目 详情请参考 http://docs.teambition.com/wiki/projects#projects-update :param id: 路径参数 :param name: 项目名称 :param description: 可选,项目描述 :param logo: 可选,项目 logo :param category: 可选,项目类别 :param is_archived: 可选,是否归档 :param is_public: 是否公开,需要拥有者权限 :return: 返回的 JSON 数据包 """ data = optionaldict( name=name, description=description, logo=logo, category=category, isArchived=is_archived, isPublic=is_public ) return self._put( 'api/projects/{0}'.format(id), data=data )
def update(self, id, name=None, description=None, logo=None, location=None, website=None): """ 更新组织信息 详情请参考 http://docs.teambition.com/wiki/orgs#orgs-update :param id: 组织 ID :param name: 组织名字 :param description: 可选,描述 :param logo: 可选,组织 logo :param location: 可选,组织所在地 :param website: 可选,组织网站 :return: 返回的 JSON 数据包 """ data = optionaldict( name=name, description=description, logo=logo, location=location, website=website ) return self._put( 'api/organizations/{0}'.format(id), data=data )
def update(self, id, title=None, parent_id=None, description=None, color=None): """ 更新文件集 详情请参考 http://docs.teambition.com/wiki/collections#collections-update :param id: 文件集 ID :param title: 可选,文件集标题 :param parent_id: 可选,父级 ID :param description: 可选,描述 :param color: 可选,颜色,默认为空 :return: 返回的 JSON 数据包 """ data = optionaldict( title=title, _parentId=parent_id, description=description, color=color, isArchived=is_archived ) return self._put( 'api/collections/{0}'.format(id), data=data )
def create(self, title, project_id, parent_id=None, description=None, color=None): """ 新建文件集 详情请参考 http://docs.teambition.com/wiki/collections#collections-create :param title: 文件集标题 :param project_id: 项目 ID :param parent_id: 可选,父级 ID,默认为项目 ID :param description: 可选,描述 :param color: 可选,颜色,默认为空 :return: 返回的 JSON 数据包 """ data = optionaldict(title=title, _projectId=project_id, _parentId=parent_id or project_id, description=description, color=color) return self._post('api/collections', data=data)
def send_template(self, user_id, template_id, data, url=None, mini_program=None): """ 发送模板消息 详情请参考 https://mp.weixin.qq.com/wiki?id=mp1445241432&lang=zh_CN :param user_id: 用户 ID 。 就是你收到的 `Message` 的 source :param template_id: 模板 ID。在公众平台线上模板库中选用模板获得 :param url: 链接地址 :param data: 模板消息数据 :param mini_program: 跳小程序所需数据, 如:`{'appid': 'appid', 'pagepath': 'index?foo=bar'}` :return: 返回的 JSON 数据包 """ tpl_data = optionaldict( touser=user_id, template_id=template_id, url=url, miniprogram=mini_program, data=data, ) return self._post( 'message/template/send', data=tpl_data )
def update(self, id, title=None, parent_id=None, description=None, color=None): """ 更新文件集 详情请参考 http://docs.teambition.com/wiki/collections#collections-update :param id: 文件集 ID :param title: 可选,文件集标题 :param parent_id: 可选,父级 ID :param description: 可选,描述 :param color: 可选,颜色,默认为空 :return: 返回的 JSON 数据包 """ data = optionaldict(title=title, _parentId=parent_id, description=description, color=color, isArchived=is_archived) return self._put('api/collections/{0}'.format(id), data=data)
def import_tasks(self, tasklist_id, tasks, stage_id=None, executor_id=None, involve_members=None, due_date=None, visiable=None): """ 批量导入任务 一次允许50条, 仅支持任务标题列表 :param tasklist_id: 任务分组 ID :param tasks: 任务内容列表 :param stage_id: 可选,阶段 ID,默认分组的第一个阶段 :param executor_id: 可选,执行者 ID :param involve_members: 可选,参与者列表 :param due_date: 可选,截止日期 :param visiable: 可选,可见状态 :return: 返回的 JSON 数据包 """ data = optionaldict( tasks=tasks, _stageId=stage_id, _executorId=executor_id, involveMembers=involve_members, dueDate=due_date, visiable=visiable, ) return self._post( 'api/tasklists/{0}/import_tasks'.format(tasklist_id), data=data )
def create(self, chat_id=None, name=None, owner=None, user_list=None): """ 创建群聊会话 详情请参考 https://work.weixin.qq.com/api/doc#90000/90135/90245 限制说明: 只允许企业自建应用调用,且应用的可见范围必须是根部门; 群成员人数不可超过管理端配置的“群成员人数上限”,且最大不可超过500人; 每企业创建群数不可超过1000/天; :param chat_id: 群聊的唯一标志,不能与已有的群重复;字符串类型,最长32个字符。只允许字符0-9及字母a-zA-Z。如果不填,系统会随机生成群id :param name: 群聊名,最多50个utf8字符,超过将截断 :param owner: 指定群主的id。如果不指定,系统会随机从userlist中选一人作为群主 :param user_list: 会话成员列表,成员用userid来标识。至少2人,至多500人 :return: 返回的 JSON 数据包 """ data = optionaldict( chatid=chat_id, name=name, owner=owner, userlist=user_list, ) return self._post("appchat/create", data=data)
def create(self, parent_id, file_name, file_size, file_type, file_category, file_key, image_width=None, image_height=None, involve_members=None): """ 新建文件 详情请参考 http://docs.teambition.com/wiki/works#works-create :param parent_id: 所属目录 ID :param file_name: 文件名 :param file_size: 文件大小 :param file_type: 文件类型 :param file_category: 文件类别 :param file_key: 使用 striker 服务上传后可得 :param image_width: 可选,图片宽度 :param image_height: 可选,图片高度 :param involve_members: 可选 :return: 返回的 JSON 数据包 """ data = optionaldict( _parentId=parent_id, fileName=file_name, fileSize=file_size, fileType=file_type, fileCategory=file_category, fileKey=file_key, imageWidth=image_width, imageHeight=image_height, involveMembers=involve_members ) return self._post( 'api/works', data=data )
def update(self, chat_id, name=None, owner=None, add_user_list=None, del_user_list=None): """ 修改群聊会话 详情请参考 https://work.weixin.qq.com/api/doc#90000/90135/90246 :param chat_id: 群聊id :param name: 新的群聊名。若不需更新,请忽略此参数。最多50个utf8字符,超过将截断 :param owner: 新群主的id。若不需更新,请忽略此参数 :param add_user_list: 会话新增成员列表,成员用userid来标识 :param del_user_list: 会话退出成员列表,成员用userid来标识 :return: 返回的 JSON 数据包 """ data = optionaldict( chatid=chat_id, name=name, owner=owner, add_user_list=add_user_list, del_user_list=del_user_list, ) return self._post("appchat/update", data=data)
def create(self, content, object_id, object_type, attachments=None, mentions=None): """ 新建动态 详情请参考 http://docs.teambition.com/wiki/activities#activities-comment :param content: 内容 :param object_id: 所属对象 ID :param object_type: 所属对象类型,目前仅支持评论: post/task/event/entry/work :param attachments: 可选,附件 ID 列表 :param mentions: 可选,提及,格式为 {"user id": "@username"} :return: 返回的 JSON 数据包 """ data = optionaldict( content=content, _boundToObjectId=object_id, boundToObjectType=object_type, attachments=attachments, mentions=mentions ) return self._post( 'api/activities', data=data )
def get_login_linked( self, uid, class_id, course_id, life_time=86400, device_type=1 ): """ 获取唤醒客户端并进入教室链接 https://docs.eeo.cn/api/zh-hans/getLoginLinked.html :param uid: 用户 UID :param class_id: 课节 ID :param course_id: 课程 ID :param life_time: 密钥有效时长(单位:秒) :param device_type: 1代表 Windows/Mac OS 端;2代表 iOS 移动端;3代表 Android """ return self._post( params={'action': 'getLoginLinked'}, data=optionaldict({ 'uid': uid, 'lifeTime': life_time, 'courseId': course_id, 'classId': class_id, 'deviceType': device_type, }), )
def test_pickle_loads(self): d = optionaldict( a=1, b=None ) s = pickle.dumps(d) pickle.loads(s)
def send_template(self, user_id, template_id, data, url=None, mini_program=None): """ 发送模板消息 详情请参考 https://mp.weixin.qq.com/wiki?id=mp1445241432&lang=zh_CN :param user_id: 用户 ID 。 就是你收到的 `Message` 的 source :param template_id: 模板 ID。在公众平台线上模板库中选用模板获得 :param url: 链接地址 :param data: 模板消息数据 :param mini_program: 跳小程序所需数据, 如:`{'appid': 'appid', 'pagepath': 'index?foo=bar'}` :return: 返回的 JSON 数据包 """ tpl_data = optionaldict( touser=user_id, template_id=template_id, url=url, miniprogram=mini_program, data=data, ) return self._post('message/template/send', data=tpl_data)
def update(self, id, title=None, start_date=None, end_date=None, location=None, status=None, reminders=None, content=None): """ 更新日程 详情请参考 http://docs.teambition.com/wiki/events#events-update :param id: 日程 ID :param title: 内容 :param start_date: 开始时间 :param end_date: 结束时间 :param location: 可选,地点 :param status: 可选,状态 :param reminders: 可选,提醒 :param content: 可选,备注 """ data = optionaldict( title=title, startDate=start_date, endDate=end_date, location=location, status=status, reminders=reminders, content=content ) return self._put( 'api/events/{0}'.format(id), data=data )
def _request(self, method, url_or_endpoint, **kwargs): if not url_or_endpoint.startswith(('http://', 'https://')): api_base_url = kwargs.pop('api_base_url', self.API_BASE_URL) url = '{base}{endpoint}'.format(base=api_base_url, endpoint=url_or_endpoint) else: url = url_or_endpoint if isinstance(kwargs.get('data', ''), dict): data = optionaldict(kwargs['data']) if 'mchid' not in data: # F**k Tencent data.setdefault('mch_id', self.mch_id) data.setdefault('sub_mch_id', self.sub_mch_id) data.setdefault('nonce_str', random_string(32)) sign = calculate_signature(data, self.api_key) body = dict_to_xml(data, sign) body = body.encode('utf-8') kwargs['data'] = body # 商户证书 if self.mch_cert and self.mch_key: kwargs['cert'] = (self.mch_cert, self.mch_key) res = self._http.request(method=method, url=url, **kwargs) try: res.raise_for_status() except requests.RequestException as reqe: raise WeChatPayException(return_code=None, client=self, request=reqe.request, response=reqe.response) return self._handle_result(res)
def get_tasks(self, id, executor_id=None, is_done=False, all=False, page=1, limit=30, **kwargs): """ 获取阶段下得任务列表 详情请参考 http://docs.teambition.com/wiki/stages#stages-get-tasks :param id: 阶段 ID :param executor_id: 可选,执行者 ID :param is_done: 可选,是否已完成,默认为 False :param all: 可选,所有类型,包括完成与未完成 :param page: 可选,页码,默认为 1 :param limit: 可选,每页数量,默认为 30,最大值为 1000 :return: 返回的 JSON 数据包 """ params = optionaldict( isDone=is_done, _executorId=executor_id, all=all, page=page, limit=limit, **kwargs ) return self._get( 'api/stages/{0}/tasks'.format(id), params=params )
def get_partner_daily_cost( self, start_date, end_date, product_type=0, ): """ 查询直播账号每天使用的人次 该接口用于获取按人次/时长计费的账号,每天消耗的人次 :param start_date: 开始日期,格式如:2018-02-01 :param end_date: 结束日期,格式如:2018-02-15 :param product_type: 1:教育直播 4:企业直播 """ if isinstance(start_date, datetime.date): start_date = start_date.strftime('%Y-%m-%d') if isinstance(end_date, datetime.date): end_date = end_date.strftime('%Y-%m-%d') return self._post( '/openapi/live_account/getPartnerDailyCost', optionaldict({ 'partner_id': self.partner_id, 'product_type': product_type, 'start_date': start_date, 'end_date': end_date, }), result_processor=lambda x: x['cost'] )
def update(self, id, title=None, content=None, post_mode=None, attachments=None, pin=None): """ 更新分享 详情请参考 http://docs.teambition.com/wiki/posts#posts-update :param id: 分享 ID :param title: 可选,标题 :param content: 可选,内容 :param post_mode: 可选,分享模式 :param attachments: 可选,附件 ID 列表 :param pin: 可选,置顶状态,True/False :return: 返回的 JSON 数据包 """ data = optionaldict( title=title, content=content, postMode=post_mode, attachments=attachments, pin=pin ) return self._put( 'api/posts/{0}'.format(id), data=data )
def addpreentry(self, name, mobile, pre_entry_time=None, op_userid=None, extend_info=None): """ 智能人事添加企业待入职员工 :param name: 员工姓名 :param mobile: 手机号 :param pre_entry_time: 预期入职时间 :param op_userid: 操作人userid :param extend_info: 扩展信息 :return: """ if isinstance(pre_entry_time, (datetime.date, datetime.datetime)): pre_entry_time = pre_entry_time.strftime(self.DATE_TIME_FORMAT) if isinstance(extend_info, dict): extend_info = json.dumps(extend_info) return self._top_request( "dingtalk.oapi.smartwork.hrm.employee.addpreentry", { "param": optionaldict({ "name": name, "mobile": mobile, "pre_entry_time": pre_entry_time, "op_userid": op_userid, "extend_info": extend_info }) })