Exemplo n.º 1
0
    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,
                         result_processor=lambda x: x['data'])
        return res
Exemplo n.º 2
0
    def create(self,
               user_id,
               name,
               department=None,
               position=None,
               mobile=None,
               gender=0,
               tel=None,
               email=None,
               weixin_id=None,
               extattr=None):
        """
        创建成员
        详情请参考 http://qydev.weixin.qq.com/wiki/index.php?title=管理成员
        """
        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

        return self._post('client/create', data=user_data)
Exemplo n.º 3
0
    def search_device(self,
                      identifiers=None,
                      apply_id=None,
                      begin=0,
                      count=10):
        """
        查询设备列表
        详情请参考
        http://mp.weixin.qq.com/wiki/15/b9e012f917e3484b7ed02771156411f3.html

        :param identifiers: 设备 ID 信息列表
        :param apply_id: 批次ID,申请设备ID超出500个时所返回批次ID
        :param begin: 设备列表的起始索引值
        :param count: 待查询的设备个数
        :return: 设备列表
        """
        data = optionaldict()
        data['begin'] = begin
        data['count'] = count
        data['apply_id'] = apply_id
        if identifiers:
            data['device_identifiers'] = identifiers
        res = self._post('shakearound/device/search',
                         data=data,
                         result_processor=lambda x: x['data'])
        return res
Exemplo n.º 4
0
    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):
        """
        设置企业号应用
        详情请参考 http://qydev.weixin.qq.com/wiki/index.php?title=设置企业号应用

        :param agent_id: 企业应用的 id
        :param name: 企业应用名称
        :param description: 企业应用详情
        :param redirect_domain: 企业应用可信域名
        :param logo_media_id: 企业应用头像的mediaid,通过多媒体接口上传图片获得mediaid
        :param report_location_flag: 企业应用是否打开地理位置上报 0:不上报;1:进入会话上报;2:持续上报
        :param is_report_user: 是否接收用户变更通知
        :param is_report_enter: 是否上报用户进入应用事件
        :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['isreportuser'] = 1 if is_report_user else 0
        agent_data['isreportenter'] = 1 if is_report_enter else 0
        return self._post('agent/set', data=agent_data)
Exemplo n.º 5
0
    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)
Exemplo n.º 6
0
    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)
Exemplo n.º 7
0
    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)
Exemplo n.º 8
0
    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)
Exemplo n.º 9
0
    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
Exemplo n.º 10
0
    def search(self,
               query,
               category,
               uid=None,
               latitude=None,
               longitude=None,
               city=None,
               region=None):
        """
        发送语义理解请求
        详情请参考
        http://mp.weixin.qq.com/wiki/0/0ce78b3c9524811fee34aba3e33f3448.html

        :param query: 输入文本串
        :param category: 需要使用的服务类型,多个可传入列表
        :param uid: 可选,用户唯一id(非开发者id),用户区分公众号下的不同用户(建议填入用户openid)
        :param latitude: 可选,纬度坐标,与经度同时传入;与城市二选一传入
        :param longitude: 可选,经度坐标,与纬度同时传入;与城市二选一传入
        :param city: 可选,城市名称,与经纬度二选一传入
        :param region: 可选,区域名称,在城市存在的情况下可省;与经纬度二选一传入
        :return: 返回的 JSON 数据包

        使用示例::

            from wechatpy import WeChatClient

            client = WeChatClient('appid', 'secret')
            res = client.semantic.search(
                '查一下明天从北京到上海的南航机票',
                'flight,hotel',
                city='北京'
            )

        """
        if isinstance(category, (tuple, list)):
            category = ','.join(category)

        data = optionaldict()
        data['query'] = query
        data['category'] = category
        data['uid'] = uid
        data['latitude'] = latitude
        data['longitude'] = longitude
        data['city'] = city
        data['region'] = region
        data['appid'] = self._client.appid
        return self._post(
            url='https://api.weixin.qq.com/semantic/semproxy/search',
            data=data)
Exemplo n.º 11
0
    def create(self, name, parent_id=1, order=None, id=None):
        """
        创建部门
        详情请参考 http://qydev.weixin.qq.com/wiki/index.php?title=管理部门

        :param name: 部门名称,长度限制为 1~64 个字符
        :param parent_id: 父亲部门 id ,根部门 id 为 1
        :return: 返回的 JSON 数据包
        """
        department_data = optionaldict()
        department_data['name'] = name
        department_data['parentid'] = parent_id
        department_data['order'] = order
        department_data['id'] = id
        return self._post('department/create', data=dict(department_data))
Exemplo n.º 12
0
    def convert_to_openid(self, user_id, agent_id=None):
        """
        user_id 转成 openid

        详情请参考
        http://qydev.weixin.qq.com/wiki/index.php?title=Userid%E4%B8%8Eopenid%E4%BA%92%E6%8D%A2%E6%8E%A5%E5%8F%A3

        :param user_id: 企业号内的成员 ID
        :param agent_id: 可选,需要发送红包的应用ID,若只是使用微信支付和企业转账,则无需该参数
        :return: 返回的 JSON 数据包
        """
        data = optionaldict()
        data['userid'] = user_id
        data['agentid'] = agent_id
        return self._post('client/convert_to_openid', data=data)
Exemplo n.º 13
0
    def update(self, id, name=None, parent_id=None, order=None):
        """
        更新部门
        详情请参考 http://qydev.weixin.qq.com/wiki/index.php?title=管理部门

        :param id: 部门 id
        :param name: 部门名称
        :param parent_id: 父亲部门 id
        :param order: 在父部门中的次序,从 1 开始,数字越大排序越靠后
        :return: 返回的 JSON 数据包
        """
        department_data = optionaldict()
        department_data['id'] = id
        department_data['name'] = name
        department_data['parentid'] = parent_id
        department_data['order'] = order
        return self._post('department/update', data=dict(department_data))
Exemplo n.º 14
0
    def set_test_whitelist(self, userids=None, usernames=None):
        """
        设置测试人员白名单

        注意:每次设置均被视为一次重置,而非增量设置。openid、微信号合计最多设置10个。

        详情请参考
        http://mp.weixin.qq.com/wiki/15/1007691d0f1c10a0588c6517f12ed70f.html

        :param userids: 可选,测试人员的 openid 列表
        :param usernames: 可选,测试人员的微信号列表
        :return: 返回的 JSON 数据包
        """
        data = optionaldict(
            openid=userids,
            username=usernames
        )
        return self._post('testwhitelist/set', data=data)
Exemplo n.º 15
0
    def send_video(self, agent_id, user_ids, media_id, title=None,
                   description=None, party_ids='', tag_ids='', safe=0):
        video_data = optionaldict()
        video_data['media_id'] = media_id
        video_data['title'] = title
        video_data['description'] = description

        return self._send_message(
            agent_id,
            user_ids,
            party_ids,
            tag_ids,
            msg={
                'msgtype': 'video',
                'video': dict(video_data),
                'safe': safe
            }
        )
Exemplo n.º 16
0
    def _request(self, method, url_or_endpoint, **kwargs):
        http_client = AsyncHTTPClient()
        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

        headers = {}
        params = kwargs.pop('params', {})

        params = urlencode(dict((k, to_binary(v)) for k, v in params.items()))
        url = '{0}?{1}'.format(url, params)

        data = kwargs.get('data')
        if isinstance(data, dict):
            data = optionaldict(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')
        else:
            body = data

        req = HTTPRequest(url=url,
                          method=method.upper(),
                          headers=headers,
                          body=body)
        res = yield http_client.fetch(req)
        if res.error is not None:
            raise WeChatClientException(errcode=None,
                                        errmsg=None,
                                        client=self,
                                        request=req,
                                        response=res)

        result = self._handle_result(res)
        raise Return(result)
Exemplo n.º 17
0
    def list_devices(self, shop_id=None, page_index=1, page_size=20):
        """
        查询设备

        详情请参考
        http://mp.weixin.qq.com/wiki/10/6232005bdc497f7cf8e19d4e843c70d2.html

        :param shop_id: 可选,门店 ID
        :param page_index: 可选,分页下标,默认从1开始
        :param page_size: 可选,每页的个数,默认20个,最大20个
        :return: 返回的 JSON 数据包
        """
        data = optionaldict(shop_id=shop_id,
                            pageindex=page_index,
                            pagesize=page_size)
        res = self._post('device/list',
                         data=data,
                         result_processor=lambda x: x['data'])
        return res
Exemplo n.º 18
0
    def close_session(self, openid, account, text=None):
        """
        多客服关闭会话
        详情请参考
        http://mp.weixin.qq.com/wiki/2/6c20f3e323bdf5986cfcb33cbd3b829a.html

        :param openid: 客户 openid
        :param account: 完整客服账号
        :param text: 附加信息,可选
        :return: 返回的 JSON 数据包
        """
        data = optionaldict(
            openid=openid,
            kf_account=account,
            text=text
        )
        return self._post(
            'https://api.weixin.qq.com/customservice/kfsession/close',
            data=data
        )
Exemplo n.º 19
0
    def list_product(self, offset=0, limit=10, status=None, key=None):
        """
        批量查询商品信息

        详情请参考
        http://mp.weixin.qq.com/wiki/15/7fa787701295b884410b5163e13313af.html

        :param offset: 可选,批量查询的起始位置,从 0 开始,包含该起始位置
        :param limit: 可选,批量查询的数量,默认为 10
        :param status: 可选,支持按状态拉取。on为发布状态,off为未发布状态,
                       check为审核中状态,reject为审核未通过状态,all为所有状态
        :param key: 支持按部分编码内容拉取。填写该参数后,可将编码内容中包含所传参数的商品信息拉出
        :return: 返回的 JSON 数据包
        """
        data = optionaldict(
            offset=offset,
            limit=limit,
            status=status,
            keystr=key,
        )
        return self._post('product/getlist', data=data)
Exemplo n.º 20
0
    def apply_device_id(self, quantity, reason, poi_id=None, comment=None):
        """
        申请设备ID
        详情请参考
        http://mp.weixin.qq.com/wiki/15/b9e012f917e3484b7ed02771156411f3.html

        :param quantity: 申请的设备ID的数量,单次新增设备超过500个,需走人工审核流程
        :param reason: 申请理由,不超过100个字
        :param poi_id: 可选,设备关联的门店ID
        :param comment: 可选,备注,不超过15个汉字或30个英文字母
        :return: 申请的设备信息
        """
        data = optionaldict()
        data['quantity'] = quantity
        data['apply_reason'] = reason
        data['poi_id'] = poi_id
        data['comment'] = comment
        res = self._post('shakearound/device/applyid',
                         data=data,
                         result_processor=lambda x: x['data'])
        return res
Exemplo n.º 21
0
    def invite_user(self,
                    url,
                    token,
                    encoding_aes_key,
                    user_ids=None,
                    party_ids=None,
                    tag_ids=None,
                    invite_tips=None):
        """
        邀请成员关注
        详情请参考
        http://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)