Exemple #1
0
class Hybrid:
    def __init__(self, client_id, client_secret, client_name, path_to_bq,
                 date_from, date_to):
        self.client_id = client_id
        self.access_token = ""
        self.client_secret = client_secret
        self.client_name = client_name
        self.data_set_id = f"{client_name}_Hybrid"
        self.path_to_bq = path_to_bq
        self.bq = BigQuery(path_to_bq)
        self.date_from = date_from
        self.date_to = date_to
        self.url = "https://api.hybrid.ru/"

        self.report_dict = {
            "CAMPAIGNS": {
                "fields": {
                    "Id": {
                        "type": "STRING",
                        "mode": "NULLABLE",
                        "description": "CampaignID :STRING"
                    },
                    "Name": {
                        "type": "STRING",
                        "mode": "NULLABLE",
                        "description": "Campaign name :STRING"
                    }
                }
            },
            "CAMPAIGN_STAT": {
                "fields": {
                    "Day": {
                        "type": "DATE",
                        "mode": "NULLABLE",
                        "description": "Day :DATE"
                    },
                    "ImpressionCount": {
                        "type": "INTEGER",
                        "mode": "NULLABLE",
                        "description": "Impressions :INTEGER"
                    },
                    "ClickCount": {
                        "type": "INTEGER",
                        "mode": "NULLABLE",
                        "description": "Clicks :INTEGER"
                    },
                    "Reach": {
                        "type": "INTEGER",
                        "mode": "NULLABLE",
                        "description": "Reach :INTEGER"
                    },
                    "CTR": {
                        "type": "FLOAT",
                        "mode": "NULLABLE",
                        "description": "CTR :FLOAT"
                    },
                    "id": {
                        "type": "STRING",
                        "mode": "NULLABLE",
                        "description": "CampaignID :STRING"
                    }
                }
            },
            "ADVERTISER_STAT": {
                "fields": {
                    "Day": {
                        "type": "DATE",
                        "mode": "NULLABLE",
                        "description": "Day :DATE"
                    },
                    "ImpressionCount": {
                        "type": "INTEGER",
                        "mode": "NULLABLE",
                        "description": "Impressions :INTEGER"
                    },
                    "ClickCount": {
                        "type": "INTEGER",
                        "mode": "NULLABLE",
                        "description": "Clicks :INTEGER"
                    },
                    "Reach": {
                        "type": "INTEGER",
                        "mode": "NULLABLE",
                        "description": "Reach :INTEGER"
                    },
                    "CTR": {
                        "type": "FLOAT",
                        "mode": "NULLABLE",
                        "description": "CTR :FLOAT"
                    }
                }
            }
        }
        self.tables_with_schema, self.fields = create_fields(
            client_name, "Hybrid", self.report_dict, None)

        self.bq.check_or_create_data_set(self.data_set_id)
        self.bq.check_or_create_tables(self.tables_with_schema,
                                       self.data_set_id)

    def hybrid_auth(self, **kwargs):
        body = {
            "grant_type": "client_credentials",
            "client_id": self.client_id,
            "client_secret": self.client_secret
        }
        body.update(kwargs)
        keys = requests.post(self.url + 'token', body).json()
        return keys['access_token']

    # def check_token_expires(self):
    #     try:
    #         keys = json.load(open(self.path_to_json + f"{self.client_name}.json", "r"))
    #         token_life_remaining = (datetime.fromtimestamp(keys['token_life']) - datetime.now()).seconds
    #         if token_life_remaining <= 60:
    #             access_token = self.hybrid_auth(refresh_token=keys['refresh_token'])
    #             return access_token
    #         else:
    #             return keys['access_token']
    #     except FileNotFoundError:
    #         access_token = self.hybrid_auth()
    #         return access_token

    def get_request(self, method, **kwargs):
        headers = {"Authorization": f"Bearer {self.access_token}"}
        response = requests.get(self.url + method,
                                headers=headers,
                                params=kwargs).json()

        return response

    def get_campaigns(self):
        access_token = self.hybrid_auth()
        Hybrid.access_token = access_token
        campaigns = self.get_request("v3.0/advertiser/campaigns")
        return campaigns

    def get_campaign_stat(self, campaign_ids_list):
        total_stat = []
        for ids in campaign_ids_list:
            params = {
                "from": self.date_from,
                "to": self.date_to,
                "campaignId": ids
            }
            stat = self.get_request("v3.0/campaign/Day", **params)
            if list(stat.keys()) != ['Statistic', 'Total']:
                sys.exit(list(stat.keys()))
            for element in stat['Statistic']:
                element['id'] = ids
                total_stat.append(element)
        return total_stat

    def get_advertiser_stat(self):
        params = {"from": self.date_from, "to": self.date_to}
        stat = self.get_request("v3.0/advertiser/Day", **params)
        if list(stat.keys()) != ['Statistic', 'Total']:
            sys.exit(list(stat.keys()))
        return stat['Statistic']

    def get_hybrid_report(self):
        campaigns = self.get_campaigns()
        campaign_df = pd.DataFrame(campaigns)
        campaign_ids = campaign_df['Id'].tolist()
        self.bq.insert_difference(campaign_df, self.fields, self.data_set_id,
                                  f"{self.client_name}_Hybrid_CAMPAIGNS", 'Id',
                                  'Id', "%Y-%m-%d")

        campaign_stat = self.get_campaign_stat(campaign_ids)
        campaign_stat_df = pd.DataFrame(campaign_stat)
        self.bq.data_to_insert(campaign_stat_df, self.fields, self.data_set_id,
                               f"{self.client_name}_Hybrid_CAMPAIGN_STAT",
                               "%Y-%m-%dT%H:%M:%S")

        advertiser_stat = self.get_advertiser_stat()
        advertiser_stat_df = pd.DataFrame(advertiser_stat)
        self.bq.data_to_insert(advertiser_stat_df, self.fields,
                               self.data_set_id,
                               f"{self.client_name}_Hybrid_ADVERTISER_STAT",
                               "%Y-%m-%dT%H:%M:%S")

        return []
class VKontakte:
    def __init__(self, access_token, account_id, client_id, client_name,
                 path_to_bq, date_from, date_to):
        self.__access_token = access_token
        self.data_set_id = f"{client_name}_VKontakte_{client_id}"
        self.__v = "5.101"
        self.__method_url = "https://api.vk.com/method/"
        self.account_id = account_id
        self.bq = BigQuery(path_to_bq)
        self.client_id = client_id
        self.client_name = client_name
        self.date_from = date_from
        self.date_to = date_to

        self.report_dict = {
            "CAMPAIGNS": {
                "fields": {
                    "id": {
                        "type": "INTEGER",
                        "mode": "NULLABLE",
                        "description": "Campaign ID :INTEGER"
                    },
                    "type": {
                        "type": "STRING",
                        "mode": "NULLABLE",
                        "description": "Campaign type :STRING"
                    },
                    "name": {
                        "type": "STRING",
                        "mode": "NULLABLE",
                        "description": "Campaign name :STRING"
                    }
                }
            },
            "ADS": {
                "fields": {
                    "id": {
                        "type": "INTEGER",
                        "mode": "NULLABLE",
                        "description": "Ad ID :INTEGER"
                    },
                    "campaign_id": {
                        "type": "INTEGER",
                        "mode": "NULLABLE",
                        "description": "Campaign ID :INTEGER"
                    },
                    "goal_type": {
                        "type": "INTEGER",
                        "mode": "NULLABLE",
                        "description": "Goal type :INTEGER"
                    },
                    "cost_type": {
                        "type": "INTEGER",
                        "mode": "NULLABLE",
                        "description": "Cost type :INTEGER"
                    },
                    "category1_id": {
                        "type": "INTEGER",
                        "mode": "NULLABLE",
                        "description": "Category1 ID :INTEGER"
                    },
                    "category2_id": {
                        "type": "INTEGER",
                        "mode": "NULLABLE",
                        "description": "Category2 ID :INTEGER"
                    },
                    "age_restriction": {
                        "type": "INTEGER",
                        "mode": "NULLABLE",
                        "description": "Age restriction :INTEGER"
                    },
                    "name": {
                        "type": "STRING",
                        "mode": "NULLABLE",
                        "description": "Ad name :STRING"
                    },
                    "ad_format": {
                        "type": "INTEGER",
                        "mode": "NULLABLE",
                        "description": "Ad format :INTEGER"
                    },
                    "ad_platform": {
                        "type": "STRING",
                        "mode": "NULLABLE",
                        "description": "Ad platform :STRING"
                    }
                }
            },
            "CAMPAIGN_STAT": {
                "fields": {
                    "day": {
                        "type": "DATE",
                        "mode": "NULLABLE",
                        "description": "Day :DATE"
                    },
                    "spent": {
                        "type": "FLOAT",
                        "mode": "NULLABLE",
                        "description": "Spent :FLOAT"
                    },
                    "impressions": {
                        "type": "INTEGER",
                        "mode": "NULLABLE",
                        "description": "Impressions :INTEGER"
                    },
                    "clicks": {
                        "type": "INTEGER",
                        "mode": "NULLABLE",
                        "description": "Clicks :INTEGER"
                    },
                    "reach": {
                        "type": "INTEGER",
                        "mode": "NULLABLE",
                        "description": "Reach :INTEGER"
                    },
                    "join_rate": {
                        "type": "INTEGER",
                        "mode": "NULLABLE",
                        "description": "Join to group :INTEGER"
                    },
                    "campaign_id": {
                        "type": "INTEGER",
                        "mode": "NULLABLE",
                        "description": "Campaign ID :INTEGER"
                    },
                    'lead_form_sends': {
                        "type": "INTEGER",
                        "mode": "NULLABLE",
                        "description": "Lead form :INTEGER"
                    },
                    'goals': {
                        "type": "INTEGER",
                        "mode": "NULLABLE",
                        "description": "Goals :INTEGER"
                    }
                }
            },
            "ADS_STAT": {
                "fields": {
                    "ad_id": {
                        "type": "INTEGER",
                        "mode": "NULLABLE",
                        "description": "Ad ID :INTEGER"
                    },
                    "clicks": {
                        "type": "INTEGER",
                        "mode": "NULLABLE",
                        "description": "Clicks :INTEGER"
                    },
                    "day": {
                        "type": "DATE",
                        "mode": "NULLABLE",
                        "description": "Day :DATE"
                    },
                    "impressions": {
                        "type": "INTEGER",
                        "mode": "NULLABLE",
                        "description": "Impressions :INTEGER"
                    },
                    "join_rate": {
                        "type": "INTEGER",
                        "mode": "NULLABLE",
                        "description": "Join to group :INTEGER"
                    },
                    "reach": {
                        "type": "INTEGER",
                        "mode": "NULLABLE",
                        "description": "Reach :INTEGER"
                    },
                    "spent": {
                        "type": "FLOAT",
                        "mode": "NULLABLE",
                        "description": "Spent :FLOAT"
                    },
                    'lead_form_sends': {
                        "type": "INTEGER",
                        "mode": "NULLABLE",
                        "description": "Lead form :INTEGER"
                    },
                    'goals': {
                        "type": "INTEGER",
                        "mode": "NULLABLE",
                        "description": "Goals :INTEGER"
                    }
                }
            },
            "SEX_STAT": {
                "fields": {
                    "impressions_rate": {
                        "type": "FLOAT",
                        "mode": "NULLABLE",
                        "description": "Imp rate :FLOAT"
                    },
                    "clicks_rate": {
                        "type": "FLOAT",
                        "mode": "NULLABLE",
                        "description": "Clicks rate :FLOAT"
                    },
                    "value": {
                        "type": "STRING",
                        "mode": "NULLABLE",
                        "description": "Param value :STRING"
                    },
                    "ad_id": {
                        "type": "INTEGER",
                        "mode": "NULLABLE",
                        "description": "Ad ID :INTEGER"
                    },
                    "day": {
                        "type": "DATE",
                        "mode": "NULLABLE",
                        "description": "Day :DATE"
                    }
                }
            },
            "AGE_STAT": {
                "fields": {
                    "impressions_rate": {
                        "type": "FLOAT",
                        "mode": "NULLABLE",
                        "description": "Imp rate :FLOAT"
                    },
                    "clicks_rate": {
                        "type": "FLOAT",
                        "mode": "NULLABLE",
                        "description": "Clicks rate :FLOAT"
                    },
                    "value": {
                        "type": "STRING",
                        "mode": "NULLABLE",
                        "description": "Param value :STRING"
                    },
                    "ad_id": {
                        "type": "INTEGER",
                        "mode": "NULLABLE",
                        "description": "Ad ID :INTEGER"
                    },
                    "day": {
                        "type": "DATE",
                        "mode": "NULLABLE",
                        "description": "Day :DATE"
                    }
                }
            },
            "SEX_AGE_STAT": {
                "fields": {
                    "impressions_rate": {
                        "type": "FLOAT",
                        "mode": "NULLABLE",
                        "description": "Imp rate :FLOAT"
                    },
                    "clicks_rate": {
                        "type": "FLOAT",
                        "mode": "NULLABLE",
                        "description": "Clicks rate :FLOAT"
                    },
                    "value": {
                        "type": "STRING",
                        "mode": "NULLABLE",
                        "description": "Param value :STRING"
                    },
                    "ad_id": {
                        "type": "INTEGER",
                        "mode": "NULLABLE",
                        "description": "Ad ID :INTEGER"
                    },
                    "day": {
                        "type": "DATE",
                        "mode": "NULLABLE",
                        "description": "Day :DATE"
                    }
                }
            },
            "CITIES_STAT": {
                "fields": {
                    "impressions_rate": {
                        "type": "FLOAT",
                        "mode": "NULLABLE",
                        "description": "Imp rate :FLOAT"
                    },
                    "clicks_rate": {
                        "type": "FLOAT",
                        "mode": "NULLABLE",
                        "description": "Clicks rate :FLOAT"
                    },
                    "value": {
                        "type": "STRING",
                        "mode": "NULLABLE",
                        "description": "Param value :STRING"
                    },
                    "ad_id": {
                        "type": "INTEGER",
                        "mode": "NULLABLE",
                        "description": "Ad ID :INTEGER"
                    },
                    "day": {
                        "type": "DATE",
                        "mode": "NULLABLE",
                        "description": "Day :DATE"
                    },
                    "name": {
                        "type": "STRING",
                        "mode": "NULLABLE",
                        "description": "City name :STRING"
                    }
                }
            },
            "POST_REACH": {
                "fields": {
                    "id": {
                        "type": "INTEGER",
                        "mode": "NULLABLE",
                        "description": "Ad ID :INTEGER"
                    },
                    "reach_subscribers": {
                        "type": "INTEGER",
                        "mode": "NULLABLE",
                        "description": "Reach subscribers :INTEGER"
                    },
                    "reach_total": {
                        "type": "INTEGER",
                        "mode": "NULLABLE",
                        "description": "Reach total :INTEGER"
                    },
                    "links": {
                        "type": "INTEGER",
                        "mode": "NULLABLE",
                        "description": "Link :INTEGER"
                    },
                    "to_group": {
                        "type": "INTEGER",
                        "mode": "NULLABLE",
                        "description": "To group :INTEGER"
                    },
                    "join_group": {
                        "type": "INTEGER",
                        "mode": "NULLABLE",
                        "description": "Join group :INTEGER"
                    },
                    "report": {
                        "type": "INTEGER",
                        "mode": "NULLABLE",
                        "description": "Report :INTEGER"
                    },
                    "hide": {
                        "type": "INTEGER",
                        "mode": "NULLABLE",
                        "description": "Hide :INTEGER"
                    },
                    "unsubscribe": {
                        "type": "INTEGER",
                        "mode": "NULLABLE",
                        "description": "Unsubscribe :INTEGER"
                    },
                    "video_views_start": {
                        "type": "INTEGER",
                        "mode": "NULLABLE",
                        "description": "Video start :INTEGER"
                    },
                    "video_views_3s": {
                        "type": "INTEGER",
                        "mode": "NULLABLE",
                        "description": "Video 3s :INTEGER"
                    },
                    "video_views_10s": {
                        "type": "INTEGER",
                        "mode": "NULLABLE",
                        "description": "Video 10s :INTEGER"
                    },
                    "video_views_25p": {
                        "type": "INTEGER",
                        "mode": "NULLABLE",
                        "description": "Video 25p :INTEGER"
                    },
                    "video_views_50p": {
                        "type": "INTEGER",
                        "mode": "NULLABLE",
                        "description": "Video 50p :INTEGER"
                    },
                    "video_views_75p": {
                        "type": "INTEGER",
                        "mode": "NULLABLE",
                        "description": "Video 75p :INTEGER"
                    },
                    "video_views_100p": {
                        "type": "INTEGER",
                        "mode": "NULLABLE",
                        "description": "Video 100p :INTEGER"
                    }
                }
            },
            "LEAD_FORMS": {
                "fields": {
                    "form_id": {
                        "type": "INTEGER",
                        "mode": "NULLABLE",
                        "description": "Form ID :INTEGER"
                    },
                    "group_id": {
                        "type": "INTEGER",
                        "mode": "NULLABLE",
                        "description": "Group ID :INTEGER"
                    },
                    "name": {
                        "type": "STRING",
                        "mode": "NULLABLE",
                        "description": "Name :STRING"
                    },
                    "title": {
                        "type": "STRING",
                        "mode": "NULLABLE",
                        "description": "Title :STRING"
                    },
                    "description": {
                        "type": "STRING",
                        "mode": "NULLABLE",
                        "description": "Description :STRING"
                    },
                    "site_link_url": {
                        "type": "STRING",
                        "mode": "NULLABLE",
                        "description": "Site link URL :STRING"
                    },
                    "url": {
                        "type": "STRING",
                        "mode": "NULLABLE",
                        "description": "URL :STRING"
                    }
                }
            },
            "LEADS": {
                "fields": {
                    "lead_id": {
                        "type": "INTEGER",
                        "mode": "NULLABLE",
                        "description": "Lead ID :INTEGER"
                    },
                    "user_id": {
                        "type": "INTEGER",
                        "mode": "NULLABLE",
                        "description": "User ID :INTEGER"
                    },
                    "date": {
                        "type": "DATE",
                        "mode": "NULLABLE",
                        "description": "Day :DATE"
                    },
                    "first_name": {
                        "type": "STRING",
                        "mode": "NULLABLE",
                        "description": "First name :STRING"
                    },
                    "phone_number": {
                        "type": "STRING",
                        "mode": "NULLABLE",
                        "description": "Phone number :STRING"
                    },
                    "patronymic_name": {
                        "type": "STRING",
                        "mode": "NULLABLE",
                        "description": "Patronymic name :STRING"
                    },
                    "last_name": {
                        "type": "STRING",
                        "mode": "NULLABLE",
                        "description": "Last name :STRING"
                    },
                    "email": {
                        "type": "STRING",
                        "mode": "NULLABLE",
                        "description": "Email :STRING"
                    }
                }
            },
            "GROUP_ACTIVITY": {
                "fields": {
                    "copies": {
                        "type": "INTEGER",
                        "mode": "NULLABLE",
                        "description": "Copies :INTEGER"
                    },
                    "hidden": {
                        "type": "INTEGER",
                        "mode": "NULLABLE",
                        "description": "Hidden :INTEGER"
                    },
                    "likes": {
                        "type": "INTEGER",
                        "mode": "NULLABLE",
                        "description": "Likes :INTEGER"
                    },
                    "subscribed": {
                        "type": "INTEGER",
                        "mode": "NULLABLE",
                        "description": "Subscribed :INTEGER"
                    },
                    "unsubscribed": {
                        "type": "INTEGER",
                        "mode": "NULLABLE",
                        "description": "Unsubscribed :INTEGER"
                    },
                    "day": {
                        "type": "DATE",
                        "mode": "NULLABLE",
                        "description": "Site link URL :DATE"
                    }
                }
            },
            "GROUP_AGE_STAT": {
                "fields": {
                    "value": {
                        "type": "STRING",
                        "mode": "NULLABLE",
                        "description": "Age param :STRING"
                    },
                    "count": {
                        "type": "INTEGER",
                        "mode": "NULLABLE",
                        "description": "Count of users :INTEGER"
                    },
                    "day": {
                        "type": "DATE",
                        "mode": "NULLABLE",
                        "description": "Day :DATE"
                    }
                }
            },
            "GROUP_CITIES_STAT": {
                "fields": {
                    "count": {
                        "type": "INTEGER",
                        "mode": "NULLABLE",
                        "description": "Count of users :INTEGER"
                    },
                    "name": {
                        "type": "STRING",
                        "mode": "NULLABLE",
                        "description": "City name :STRING"
                    },
                    "value": {
                        "type": "STRING",
                        "mode": "NULLABLE",
                        "description": "City ID :STRING"
                    },
                    "day": {
                        "type": "DATE",
                        "mode": "NULLABLE",
                        "description": "Day :DATE"
                    }
                }
            },
            "GROUP_COUNTRIES_STAT": {
                "fields": {
                    "code": {
                        "type": "STRING",
                        "mode": "NULLABLE",
                        "description": "Country code :STRING"
                    },
                    "count": {
                        "type": "INTEGER",
                        "mode": "NULLABLE",
                        "description": "Count of users :INTEGER"
                    },
                    "name": {
                        "type": "STRING",
                        "mode": "NULLABLE",
                        "description": "Country name :STRING"
                    },
                    "value": {
                        "type": "STRING",
                        "mode": "NULLABLE",
                        "description": "Country ID :STRING"
                    },
                    "day": {
                        "type": "DATE",
                        "mode": "NULLABLE",
                        "description": "Day :DATE"
                    }
                }
            },
            "GROUP_SEX_STAT": {
                "fields": {
                    "value": {
                        "type": "STRING",
                        "mode": "NULLABLE",
                        "description": "Gender param :STRING"
                    },
                    "count": {
                        "type": "INTEGER",
                        "mode": "NULLABLE",
                        "description": "Count of users :INTEGER"
                    },
                    "day": {
                        "type": "DATE",
                        "mode": "NULLABLE",
                        "description": "Day :DATE"
                    }
                }
            },
            "GROUP_SEX_AGE_STAT": {
                "fields": {
                    "value": {
                        "type": "STRING",
                        "mode": "NULLABLE",
                        "description": "Age & Gender param :STRING"
                    },
                    "count": {
                        "type": "INTEGER",
                        "mode": "NULLABLE",
                        "description": "Count of users :INTEGER"
                    },
                    "day": {
                        "type": "DATE",
                        "mode": "NULLABLE",
                        "description": "Day :DATE"
                    }
                }
            }
        }

        self.tables_with_schema, self.fields = create_fields(
            client_name, "VKontakte", self.report_dict, client_id)
        self.bq.check_or_create_data_set(self.data_set_id)
        self.bq.check_or_create_tables(self.tables_with_schema,
                                       self.data_set_id)

        "https://oauth.vk.com/authorize?client_id=7446867&display=page&redirect_uri=http://localhost:8000/auth/vkontakte&scope=pages,ads,offline,groups,stats,email&response_type=code&v=5.103"
        "https://oauth.vk.com/access_token?client_id=7446867&client_secret=3yU3omb66HfxRlujOKxJ&redirect_uri=http://localhost:8000/auth/vkontakte&code=26ffc758fd72e8f81c"

    def __request(self, method, request_type='get', **kwargs):
        if "access_token" not in kwargs:
            params = {'access_token': self.__access_token, 'v': self.__v}
            for key, value in kwargs.items():
                params[key] = value
        else:
            params = kwargs
        request_data = requests.request(request_type,
                                        self.__method_url + method,
                                        params=params)
        return self.__get_errors(request_data, method, request_type, params)

    def __get_errors(self, response, method, request_type, params):
        if response.status_code == 200:
            if 'error' in response.json():
                if response.json()['error']['error_code'] == 100:
                    for param in response.json()['error']['request_params']:
                        if param['value'] == 'ads.getPostsReach':
                            print("error")
                            time.sleep(3)
                            return self.__request(method, request_type,
                                                  **params)
                error_msg = response.json()['error']['error_msg']
                error_code = response.json()['error']['error_code']
                raise Exception(
                    f"Error code: {error_code}. Error msg: {error_msg}")
            elif 'response' in response.json():
                return response.json()['response']
            else:
                raise Exception("Это что-то новое")

        else:
            raise Exception("Status code not 200", response.status_code,
                            response.content)

    def get_campaigns(self):
        campaigns = self.__request('ads.getCampaigns',
                                   request_type='get',
                                   account_id=self.account_id,
                                   include_deleted=1,
                                   client_id=self.client_id)
        keys = ["id", "type", "name"]
        campaigns = pop_keys(keys, campaigns)
        campaign_ids = [campaign_id['id'] for campaign_id in campaigns]
        campaigns_df = pd.DataFrame(campaigns).fillna(0)
        self.bq.insert_difference(
            campaigns_df, self.fields, self.data_set_id,
            f"{self.client_name}_VKontakte_{self.client_id}_CAMPAIGNS", 'id',
            'id', "%Y-%m-%d")

        return campaign_ids, campaigns_df

    def get_ads(self, campaign_ids):
        campaign_ids = my_slice(campaign_ids, 100)
        ads_list = []
        for campaign_ids_list in campaign_ids:
            campaign_ids_string = ",".join([str(x) for x in campaign_ids_list])
            ads = self.__request('ads.getAds',
                                 request_type='get',
                                 account_id=self.account_id,
                                 campaign_ids=f"[{campaign_ids_string}]",
                                 client_id=self.client_id)
            ads_list += ads
            time.sleep(2)
        keys = [
            "id", "campaign_id", "goal_type", "cost_type", "category1_id",
            "category2_id", "age_restriction", "name", "ad_format",
            "ad_platform"
        ]
        ads = pop_keys(keys, ads_list)
        return ads

    def get_demographics(self, demographics_list_ids, limit=2000):
        data_keys = {"sex": [], "age": [], "sex_age": [], "cities": []}
        demographics_list = my_slice(demographics_list_ids, limit)
        for demographics_id_list in demographics_list:
            demographics_ids_string = ",".join(
                [str(x) for x in demographics_id_list])
            demographics_response = self.__request('ads.getDemographics',
                                                   request_type='get',
                                                   account_id=self.account_id,
                                                   ids_type="ad",
                                                   ids=demographics_ids_string,
                                                   period="day",
                                                   date_from=self.date_from,
                                                   date_to=self.date_to)

            for one in demographics_response:
                for element in one['stats']:
                    for key, value in element.items():
                        if key in ['sex', 'age', 'sex_age', 'cities']:
                            for one_element in value:
                                arr = one_element.copy()
                                arr[one['type'] + '_id'] = one['id']
                                arr['day'] = element['day']
                                data_keys[key].append(arr)

        return data_keys['sex'], data_keys['age'], data_keys[
            'sex_age'], data_keys['cities']

    def get_day_stats(self, ids_type, list_of_ids, limit=2000):
        day_stat_list = []
        ids_list = my_slice(list_of_ids, limit)
        for ids_stat_list in ids_list:
            ids_stat_string = ",".join([str(x) for x in ids_stat_list])
            day_stats = self.__request('ads.getStatistics',
                                       request_type='get',
                                       account_id=self.account_id,
                                       ids_type=ids_type,
                                       ids=ids_stat_string,
                                       period="day",
                                       date_from=self.date_from,
                                       date_to=self.date_to)
            for DayStat in day_stats:
                for stat in DayStat['stats']:
                    stat[DayStat['type'] + "_id"] = DayStat['id']
                    day_stat_list.append(stat)
            time.sleep(2)
        keys = [
            "day", "spent", "impressions", "clicks", "reach", "join_rate",
            "campaign_id", 'lead_form_sends', 'goals', "ad_id"
        ]
        day_stat_list = pop_keys(keys, day_stat_list)
        return day_stat_list

    def get_leads_forms(self, group_id):
        lead_forms = self.__request("leadForms.list",
                                    request_type='get',
                                    group_id=group_id)
        keys = [
            "form_id", "group_id", "name", "title", "description",
            "site_link_url", "url"
        ]
        lead_forms = pop_keys(keys, lead_forms)
        return lead_forms

    def get_all_leads(self, group_id):
        result = []
        lead_forms = self.get_leads_forms(group_id)
        forms = [form['form_id'] for form in lead_forms]
        for form_id in forms:

            leads = self.get_leads_form_id(group_id, form_id)
            time.sleep(1)
            for lead in leads:
                middle_list = {}
                for lead_key, lead_value in lead.items():
                    if lead_key == 'answers':
                        for element in lead_value:
                            middle_list[
                                element['key']] = element['answer']['value']
                    elif lead_key == 'date':
                        middle_list[lead_key] = datetime.strftime(
                            datetime.fromtimestamp(int(lead_value)),
                            "%Y-%m-%d")
                    else:
                        middle_list[lead_key] = lead_value
                result.append(middle_list)

        keys = [
            "lead_id", "user_id", "date", "first_name", "phone_number",
            "patronymic_name", "last_name", "email"
        ]
        result = pop_keys(keys, result)
        return result

    def get_leads_form_id(self,
                          group_id,
                          form_id,
                          next_page_token=None,
                          result_list=None):
        if result_list is None:
            result_list = []
        params = {"group_id": group_id, "form_id": form_id, "limit": 1000}
        if next_page_token is not None:
            params['next_page_token'] = next_page_token
        leads = self.__request("leadForms.getLeads",
                               request_type='get',
                               **params)
        result_list += leads['leads']
        if "next_page_token" in leads:
            next_page_token = leads['next_page_token']
            time.sleep(3)
            return self.get_leads_form_id(group_id,
                                          form_id,
                                          next_page_token=next_page_token)
        return result_list

    def get_group_stat(self, group_id):
        date_from = (datetime.strptime(self.date_from, "%Y-%m-%d") +
                     timedelta(hours=0, minutes=0, seconds=0)).timestamp()
        date_to = (datetime.strptime(self.date_to, "%Y-%m-%d") +
                   timedelta(hours=23, minutes=59, seconds=59)).timestamp()
        stats = self.__request("stats.get",
                               request_type='get',
                               group_id=group_id,
                               timestamp_from=date_from,
                               timestamp_to=date_to,
                               extended=1,
                               stats_groups="activity,visitors")

        result = {
            "activity": [],
            "age": [],
            "cities": [],
            "countries": [],
            "sex": [],
            "sex_age": []
        }
        for stat in stats:
            day = datetime.strftime(
                datetime.fromtimestamp(stat['period_from']), "%Y-%m-%d")
            stat['activity']['day'] = day
            result['activity'].append(stat['activity'])
            stat = stat['visitors']
            for visitor_stat_key, visitor_stat_value in stat.items():
                if visitor_stat_key in [
                        "age", "cities", "countries", "sex", "sex_age"
                ]:
                    for element in visitor_stat_value:
                        element['day'] = day
                    result[visitor_stat_key] += visitor_stat_value

        return result["age"], result["cities"], result["countries"], result[
            "sex"], result["sex_age"], result["activity"]

    def get_groups(self, list_of_groups=None, offset=0):
        if list_of_groups is None:
            list_of_groups = []
        groups = self.__request('groups.get',
                                request_type='get',
                                filter="admin,editor,moder,advertiser",
                                count=1000,
                                offset=offset,
                                extended=1)
        count = groups['count']
        list_of_groups += groups['items']
        if len(list_of_groups) < count:
            offset += 1000
            return self.get_groups(list_of_groups=list_of_groups,
                                   offset=offset)
        return list_of_groups

    def get_my_user_id(self):
        my_user_id = self.__request('users.get', request_type='get')
        my_user_id = my_user_id[0]
        return my_user_id['id'], my_user_id['first_name'], my_user_id[
            'last_name']

    def post_reach(self, ids_type, list_of_ids):
        day_stat_list = []
        while list_of_ids:
            day_stats = self.__request('ads.getPostsReach',
                                       request_type='get',
                                       account_id=self.account_id,
                                       ids_type=ids_type,
                                       ids=list_of_ids.pop(0))

            day_stat_list += day_stats
            time.sleep(3)
        return day_stat_list

    def report_lead_forms(self, group_id):
        leads_forms = self.get_leads_forms(group_id)
        leads_forms_df = pd.DataFrame(leads_forms).fillna(0)
        table_id = f"{self.client_name}_VKontakte_{self.client_id}_LEAD_FORMS"
        self.bq.get_delete_query(
            f"DELETE FROM `{self.data_set_id}.{table_id}` WHERE form_id != ''")

        self.bq.data_to_insert(leads_forms_df, self.fields, self.data_set_id,
                               table_id, "%Y-%m-%d")

    def report_leads(self, group_id):
        leads = self.get_all_leads(group_id)
        leads_df = pd.DataFrame(leads).fillna(0)
        # TODO: Проверять лиды за прошедший период (по датам)
        self.bq.insert_difference(
            leads_df, self.fields, self.data_set_id,
            f"{self.client_name}_VKontakte_{self.client_id}_LEADS", 'lead_id',
            'lead_id', "%Y-%m-%d")

    def report_post_reach(self, ads_df):
        post_ad_ids = ads_df[ads_df['ad_format'] == 9]['id'].tolist()

        post_reach = self.post_reach("ad", post_ad_ids.copy())
        post_reach_df = pd.DataFrame(post_reach).fillna(0)
        table_id = f"{self.client_name}_VKontakte_{self.client_id}_POST_REACH"

        self.bq.delete_and_insert(post_reach_df,
                                  self.fields,
                                  self.data_set_id,
                                  table_id,
                                  "%Y-%m-%d",
                                  id=post_ad_ids)

    def report_group_stat(self, group_id):
        age, cities, countries, sex, sex_age, activity = self.get_group_stat(
            group_id)
        sex_df = pd.DataFrame(sex).fillna(0)

        self.bq.data_to_insert(
            sex_df, self.fields, self.data_set_id,
            f"{self.client_name}_VKontakte_{self.client_id}_GROUP_SEX_STAT",
            "%Y-%m-%d")

        age_df = pd.DataFrame(age).fillna(0)
        self.bq.data_to_insert(
            age_df, self.fields, self.data_set_id,
            f"{self.client_name}_VKontakte_{self.client_id}_GROUP_AGE_STAT",
            "%Y-%m-%d")

        sex_age_df = pd.DataFrame(sex_age).fillna(0)
        self.bq.data_to_insert(
            sex_age_df, self.fields, self.data_set_id,
            f"{self.client_name}_VKontakte_{self.client_id}_GROUP_SEX_AGE_STAT",
            "%Y-%m-%d")

        cities_df = pd.DataFrame(cities).fillna(0)
        self.bq.data_to_insert(
            cities_df, self.fields, self.data_set_id,
            f"{self.client_name}_VKontakte_{self.client_id}_GROUP_CITIES_STAT",
            "%Y-%m-%d")

        activity_df = pd.DataFrame(activity).fillna(0)
        self.bq.data_to_insert(
            activity_df, self.fields, self.data_set_id,
            f"{self.client_name}_VKontakte_{self.client_id}_GROUP_ACTIVITY",
            "%Y-%m-%d")

        countries_df = pd.DataFrame(countries).fillna(0)
        self.bq.data_to_insert(
            countries_df, self.fields, self.data_set_id,
            f"{self.client_name}_VKontakte_{self.client_id}_GROUP_COUNTRIES_STAT",
            "%Y-%m-%d")

    def report_demographics(self, ads_ids):
        sex, age, sex_age, cities = self.get_demographics(ads_ids, 100)
        sex_df = pd.DataFrame(sex).fillna(0)
        self.bq.data_to_insert(
            sex_df, self.fields, self.data_set_id,
            f"{self.client_name}_VKontakte_{self.client_id}_SEX_STAT",
            "%Y-%m-%d")

        age_df = pd.DataFrame(age).fillna(0)
        self.bq.data_to_insert(
            age_df, self.fields, self.data_set_id,
            f"{self.client_name}_VKontakte_{self.client_id}_AGE_STAT",
            "%Y-%m-%d")

        sex_age_df = pd.DataFrame(sex_age).fillna(0)
        self.bq.data_to_insert(
            sex_age_df, self.fields, self.data_set_id,
            f"{self.client_name}_VKontakte_{self.client_id}_SEX_AGE_STAT",
            "%Y-%m-%d")

        cities_df = pd.DataFrame(cities).fillna(0)
        self.bq.data_to_insert(
            cities_df, self.fields, self.data_set_id,
            f"{self.client_name}_VKontakte_{self.client_id}_CITIES_STAT",
            "%Y-%m-%d")

    def report_campaigns_stat(self, campaign_ids):
        campaign_stat = self.get_day_stats("campaign", campaign_ids, 100)
        campaign_ids_with_stat = [
            campaign_id['campaign_id'] for campaign_id in campaign_stat
        ]
        campaign_stat_df = pd.DataFrame(campaign_stat).fillna(0)
        self.bq.data_to_insert(
            campaign_stat_df, self.fields, self.data_set_id,
            f"{self.client_name}_VKontakte_{self.client_id}_CAMPAIGN_STAT",
            "%Y-%m-%d")

        return campaign_ids_with_stat

    def report_ads(self, campaign_ids_with_stat):
        ads = self.get_ads(campaign_ids_with_stat)
        ads_ids = [ad_id['id'] for ad_id in ads]
        ads_df = pd.DataFrame(ads).fillna(0)
        self.bq.insert_difference(
            ads_df, self.fields, self.data_set_id,
            f"{self.client_name}_VKontakte_{self.client_id}_ADS", 'id', 'id',
            "%Y-%m-%d")

        return ads_ids, ads_df

    def report_ads_stat(self, ads_ids_with_stat):
        ads_stat = self.get_day_stats("ad", ads_ids_with_stat, 100)
        ads_stat_df = pd.DataFrame(ads_stat).fillna(0)
        self.bq.data_to_insert(
            ads_stat_df, self.fields, self.data_set_id,
            f"{self.client_name}_VKontakte_{self.client_id}_ADS_STAT",
            "%Y-%m-%d")