Example #1
0
def main():
    # работа с параметрами командной строки, получение настроек запуска программы, как то: работа в offline-режиме,
    # имя пилота ранее зарегистрированного и для которого имеется аутентификационный токен, регистрация нового и т.д.
    argv_prms = console_app.get_argv_prms()

    sde_type_ids = eve_sde_tools.read_converted(argv_prms["workspace_cache_files_dir"], "typeIDs")
    sde_inv_names = eve_sde_tools.read_converted(argv_prms["workspace_cache_files_dir"], "invNames")
    sde_inv_items = eve_sde_tools.read_converted(argv_prms["workspace_cache_files_dir"], "invItems")
    sde_market_groups = eve_sde_tools.read_converted(argv_prms["workspace_cache_files_dir"], "marketGroups")
    sde_icon_ids = eve_sde_tools.read_converted(argv_prms["workspace_cache_files_dir"], "iconIDs")
    sde_bp_materials = eve_sde_tools.read_converted(argv_prms["workspace_cache_files_dir"], "blueprints")

    # удаление из списка чертежей тех, которые не published (надо соединить typeIDs и blueprints, отбросив часть)
    for t in [t for t in sde_type_ids if t in sde_bp_materials.keys() and sde_type_ids[t].get('published')==False]:
        del sde_bp_materials[t]

    """
    === Сведения по рассчёту цены ===
    
    Данные из .yaml:
    36:
     basePrice: 32.0
     groupID: 18
     iconID: 401
     marketGroupID: 1857
     name:
      en: Mexallon
     portionSize: 1
     published: true
     volume: 0.01
    ---
    Данные из https://esi.evetech.net/ui/#/Market/get_markets_prices :
    {
     "adjusted_price": 44.1,
     "average_price": 92.64,
     "type_id": 36
    }
    ---
    Ситуация на рынке https://image.prntscr.com/image/0Oqy5FlqRniAstG2wvSd7A.png :
    Sell: 85 ISK
    Buy: 88.64 ISK
    ----
    Текущая стоимость, которую показывает Евка https://image.prntscr.com/image/-8liCZ8TRHWIaSpZ6Kzhew.png :
    92.6 ISK
    ---
    Полезная информация https://www.reddit.com/r/Eve/comments/5zegqw/how_does_ccp_calculate_averageadjusted_price/ :
    adjusted_price - средняя за 28 дней
    """

    corps_accounting = {}
    eve_market_prices_data = None
    various_characters_data = {}
    for pilot_name in argv_prms["character_names"]:
        # настройка Eve Online ESI Swagger interface
        auth = esi.EveESIAuth(
            '{}/auth_cache'.format(argv_prms["workspace_cache_files_dir"]),
            debug=True)
        client = esi.EveESIClient(
            auth,
            keep_alive=True,
            debug=argv_prms["verbose_mode"],
            logger=True,
            user_agent='Q.Industrialist v{ver}'.format(ver=__version__))
        interface = esi.EveOnlineInterface(
            client,
            q_industrialist_settings.g_client_scope,
            cache_dir='{}/esi_cache'.format(argv_prms["workspace_cache_files_dir"]),
            offline_mode=argv_prms["offline_mode"])

        authz = interface.authenticate(pilot_name)
        character_id = authz["character_id"]
        character_name = authz["character_name"]

        # Public information about a character
        character_data = interface.get_esi_data(
            "characters/{}/".format(character_id),
            fully_trust_cache=True)
        # Public information about a corporation
        corporation_data = interface.get_esi_data(
            "corporations/{}/".format(character_data["corporation_id"]),
            fully_trust_cache=True)
        # The token’s character need to be a member of the corporation
        # corporation_members_data = interface.get_esi_data(
        #     "corporations/{}/members/".format(character_data["corporation_id"]),
        #     fully_trust_cache=True)

        corporation_id = character_data["corporation_id"]
        corporation_name = corporation_data["name"]
        print("\n{} is from '{}' corporation".format(character_name, corporation_name))
        sys.stdout.flush()

        if eve_market_prices_data is None:
            try:
                # Public information about market prices
                eve_market_prices_data = interface.get_esi_data("markets/prices/")
                print("\nEVE market has {} prices".format(len(eve_market_prices_data) if not (eve_market_prices_data is None) else 0))
                sys.stdout.flush()
            except requests.exceptions.HTTPError as err:
                status_code = err.response.status_code
                if status_code == 404:  # 2020.12.03 поломался доступ к ценам маркета (ССР-шники "внесли правки")
                    eve_market_prices_data = []
                else:
                    raise
            except:
                print(sys.exc_info())
                raise

        try:
            # Requires role(s): Accountant, Junior_Accountant
            corp_wallets_data = interface.get_esi_paged_data(
                "corporations/{}/wallets/".format(corporation_id))
            print("'{}' corporation has {} wallet divisions\n".format(corporation_name, len(corp_wallets_data)))
            sys.stdout.flush()
        except requests.exceptions.HTTPError as err:
            status_code = err.response.status_code
            if status_code == 500:  # 2021.01.28 поломался доступ к кошелькам, Internal Server Error
                corp_wallets_data = []
            else:
                raise
        except:
            print(sys.exc_info())
            raise

        # Requires role(s): Accountant, Junior_Accountant
        corp_wallet_journal_data = [None, None, None, None, None, None, None]
        for w in corp_wallets_data:
            division = w["division"]
            try:
                corp_wallet_journal_data[division-1] = interface.get_esi_paged_data(
                    "corporations/{}/wallets/{}/journal/".format(corporation_id, division))
                print("'{}' corporation has {} wallet#{} transactions\n".format(corporation_name, len(corp_wallet_journal_data[division-1]), division))
                sys.stdout.flush()
            except requests.exceptions.HTTPError as err:
                status_code = err.response.status_code
                if status_code == 404:  # 2020.11.26 поломался доступ к журналу кошелька (ССР-шники "внесли правки")
                    corp_wallet_journal_data[division-1] = None
                elif status_code == 500:  # 2021.01.28 поломался доступ к кошелькам, Internal Server Error
                    corp_wallets_data = []
                else:
                    raise
            except:
                print(sys.exc_info())
                raise

        # Requires one of the following EVE corporation role(s): Director
        corp_divisions_data = interface.get_esi_data(
            "corporations/{}/divisions/".format(corporation_id),
            fully_trust_cache=True)
        print("'{}' corporation has {} hangar and {} wallet names\n".format(corporation_name, len(corp_divisions_data["hangar"]) if "hangar" in corp_divisions_data else 0, len(corp_divisions_data["wallet"]) if "wallet" in corp_divisions_data else 0))
        sys.stdout.flush()

        # Requires role(s): Director
        corp_assets_data = interface.get_esi_paged_data(
            "corporations/{}/assets/".format(corporation_id))
        print("\n'{}' corporation has {} assets".format(corporation_name, len(corp_assets_data)))
        sys.stdout.flush()

        # Получение названий контейнеров, станций, и т.п. - всё что переименовывается ingame
        corp_ass_named_ids = eve_esi_tools.get_assets_named_ids(corp_assets_data)
        # Requires role(s): Director
        corp_ass_names_data = interface.get_esi_piece_data(
            "corporations/{}/assets/names/".format(corporation_id),
            corp_ass_named_ids)
        print("\n'{}' corporation has {} custom asset's names".format(corporation_name, len(corp_ass_names_data)))
        sys.stdout.flush()
        del corp_ass_named_ids

        # TODO: Получение идентификаторов коробок, в которых хранятся персональные ассеты (хардкодим тут)
        pers_ass_location_ids: typing.List[int] = [int(an['item_id']) for an in corp_ass_names_data
                                                   if re.search(r"^{pers}.+$", an['name']) or re.search(r"^\.{pers}.+$", an['name'])]
        # для того, чтобы сильно не переделывать алгоритм - просто удаляем из корпассетов личные предметы
        pers_ass_location_ids: typing.Set[int] = set(pers_ass_location_ids)
        corp_assets_data = [a for a in corp_assets_data if int(a['location_id']) not in pers_ass_location_ids]
        del pers_ass_location_ids

        # Поиск тех станций, которые не принадлежат корпорации (на них имеется офис, но самой станции в ассетах нет)
        foreign_structures_data = {}
        foreign_structures_ids = eve_esi_tools.get_foreign_structures_ids(corp_assets_data)
        foreign_structures_forbidden_ids = []
        if len(foreign_structures_ids) > 0:
            # Requires: access token
            for structure_id in foreign_structures_ids:
                try:
                    universe_structure_data = interface.get_esi_data(
                        "universe/structures/{}/".format(structure_id),
                        fully_trust_cache=True)
                    foreign_structures_data.update({str(structure_id): universe_structure_data})
                except requests.exceptions.HTTPError as err:
                    status_code = err.response.status_code
                    if status_code == 403:  # это нормально, что часть структур со временем могут оказаться Forbidden
                        foreign_structures_forbidden_ids.append(structure_id)
                    else:
                        raise
                except:
                    print(sys.exc_info())
                    raise
        print("\n'{}' corporation has offices in {} foreign stations".format(corporation_name, len(foreign_structures_data)))
        if len(foreign_structures_forbidden_ids) > 0:
            print("\n'{}' corporation has offices in {} forbidden stations : {}".format(corporation_name, len(foreign_structures_forbidden_ids), foreign_structures_forbidden_ids))
        sys.stdout.flush()

        # Requires role(s): access token
        corp_contracts_data = interface.get_esi_paged_data(
            "corporations/{}/contracts/".format(corporation_id))
        print("'{}' corporation has {} contracts\n".format(corporation_name, len(corp_contracts_data)))
        sys.stdout.flush()

        # Получение подробной информации о каждому из контракту в списке
        corp_contract_items_data = []
        corp_contract_items_len = 0
        corp_contract_items_not_found = []
        corp_contract_individual = []
        if len(corp_contracts_data) > 0:
            # Requires: access token
            for c in corp_contracts_data:
                # для удалённых контрактов нельзя загрузить items (см. ниже 404-ошибку), поэтому пропускаем запись
                if c["status"] == "deleted":
                    continue
                # в рамках отчёта accounting, нас интересует только набор контрактов, в которых продаются Ships
                # ищем любые контракты типа "обмен предметами"
                if c["type"] != "item_exchange":
                    continue
                # в рамках отчёта accounting нас интересуют только активные контракты
                if (c["status"] != "outstanding") and (c["status"] != "in_progress"):
                    continue
                # пропускаем контракты на продажу, которые выставили не мы
                # эту настройку лучше не трогать, т.к. во FRT например 12'000 контрактов, следовательно
                # это повлечёт загрузку 12'000 items и 12'000 issuers
                if c['issuer_corporation_id'] != corporation_id:
                    continue
                contract_id = c["contract_id"]
                # пропускаем контракты на продажу, которые выставлены не от имени корпорации, и доход от продажи
                # которых упадёт в кошелёк пилота, а не корпорации
                if not c['for_corporation']:
                    corp_contract_individual.append(contract_id)
                    continue
                try:
                    __contract_items = interface.get_esi_data(
                        "corporations/{}/contracts/{}/items/".format(corporation_id, contract_id),
                        fully_trust_cache=True)
                    corp_contract_items_len += len(__contract_items)
                    corp_contract_items_data.append({str(contract_id): __contract_items})
                except requests.exceptions.HTTPError as err:
                    status_code = err.response.status_code
                    if status_code == 404:  # это нормально, что часть доп.инфы по контрактам может быть не найдена!
                        corp_contract_items_not_found.append(contract_id)
                    else:
                        # print(sys.exc_info())
                        raise
                except:
                    print(sys.exc_info())
                    raise
                # Получение сведений о пилотах, вовлечённых в работу с контрактом
                issuer_id = c["issuer_id"]
                if str(issuer_id) not in various_characters_data:  # пилот м.б. быть в списке с dict=None
                    try:
                        # Public information about a character
                        issuer_data = interface.get_esi_data(
                            "characters/{}/".format(issuer_id),
                            fully_trust_cache=True)
                        various_characters_data.update({str(issuer_id): issuer_data})
                    except requests.exceptions.HTTPError as err:
                        status_code = err.response.status_code
                        if status_code == 404:  # 404 Client Error: Not Found ('Character has been deleted!')
                            various_characters_data.update({str(issuer_id): None})
                        else:
                            print(sys.exc_info())
                            raise
                    except:
                        print(sys.exc_info())
                        raise
                sys.stdout.flush()
        eve_esi_tools.dump_debug_into_file(argv_prms["workspace_cache_files_dir"], "corp_contract_items_data.{}".format(corporation_name), corp_contract_items_data)

        print("'{}' corporation has {} items in contracts\n".format(corporation_name, corp_contract_items_len))
        if len(corp_contract_items_not_found) > 0:
            print("'{}' corporation has {} contracts without details : {}\n".format(corporation_name, len(corp_contract_items_not_found), corp_contract_items_not_found))
        if corp_contract_individual:
            print("'{}' corporation has {} individual contracts : {}\n".format(corporation_name, len(corp_contract_individual), corp_contract_individual))
        sys.stdout.flush()

        # Построение дерева ассетов, с узлами в роли станций и систем, и листьями в роли хранящихся
        # элементов, в виде:
        # { location1: {items:[item1,item2,...],type_id,location_id},
        #   location2: {items:[item3],type_id} }
        corp_assets_tree = eve_esi_tools.get_assets_tree(corp_assets_data, foreign_structures_data, sde_inv_items, virtual_hierarchy_by_corpsag=False)
        eve_esi_tools.dump_debug_into_file(argv_prms["workspace_cache_files_dir"], "corp_assets_tree.{}".format(corporation_name), corp_assets_tree)

        # Requires role(s): Factory_Manager
        corp_industry_jobs_data = interface.get_esi_paged_data(
            "corporations/{}/industry/jobs/".format(corporation_id))
        print("'{}' corporation has {} industry jobs\n".format(corporation_name, len(corp_industry_jobs_data)))
        sys.stdout.flush()

        # Построение дерева имущества (сводная информация, учитывающая объёмы и ориентировочную стоимость asset-ов)
        print("\nBuilding {} accounting tree and stat...".format(corporation_name))
        sys.stdout.flush()
        corp_accounting_stat, corp_accounting_tree = __build_accounting(
            sde_type_ids,
            sde_inv_names,
            sde_inv_items,
            sde_market_groups,
            eve_market_prices_data,
            corp_ass_names_data,
            foreign_structures_data,
            foreign_structures_forbidden_ids,
            corp_assets_tree,
            corp_assets_data)
        eve_esi_tools.dump_debug_into_file(argv_prms["workspace_cache_files_dir"], "corp_accounting_stat.{}".format(corporation_name), corp_accounting_stat)
        eve_esi_tools.dump_debug_into_file(argv_prms["workspace_cache_files_dir"], "corp_accounting_tree.{}".format(corporation_name), corp_accounting_tree)
        corp_wallet_stat = __build_wallets_stat(corp_wallet_journal_data)
        eve_esi_tools.dump_debug_into_file(argv_prms["workspace_cache_files_dir"], "corp_wallet_stat.{}".format(corporation_name), corp_wallet_stat)
        corp_sell_contracts = __build_contracts_stat(
            sde_type_ids,
            sde_market_groups,
            corp_contracts_data,
            corp_contract_items_data,
            various_characters_data)
        eve_esi_tools.dump_debug_into_file(argv_prms["workspace_cache_files_dir"], "corp_sell_contracts.{}".format(corporation_name), corp_sell_contracts)
        corp_industry_jobs_stat = __build_industry_jobs_stat(
            sde_type_ids,
            sde_bp_materials,
            eve_market_prices_data,
            corp_industry_jobs_data)
        eve_esi_tools.dump_debug_into_file(argv_prms["workspace_cache_files_dir"], "corp_industry_jobs_stat.{}".format(corporation_name), corp_industry_jobs_stat)

        corps_accounting.update({str(corporation_id): {
            "corporation": corporation_name,
            "divisions": corp_divisions_data,
            "wallet": corp_wallets_data,
            "wallet_stat": corp_wallet_stat,
            "stat": corp_accounting_stat,
            "tree": corp_accounting_tree,
            "sell_contracts": corp_sell_contracts,
            "jobs_stat": corp_industry_jobs_stat
        }})

    eve_esi_tools.dump_debug_into_file(argv_prms["workspace_cache_files_dir"], "corps_accounting", corps_accounting)

    # Построение дерева asset-ов:
    print("\nBuilding accounting report...")
    sys.stdout.flush()
    render_html_accounting.dump_accounting_into_report(
        # путь, где будет сохранён отчёт
        argv_prms["workspace_cache_files_dir"],
        # sde данные, загруженные из .converted_xxx.json файлов
        sde_type_ids,
        sde_icon_ids,
        # данные, полученные в результате анализа и перекомпоновки входных списков
        corps_accounting)

    # Вывод в лог уведомления, что всё завершилось (для отслеживания с помощью tail)
    print("\nDone")
Example #2
0
def main():
    # работа с параметрами командной строки, получение настроек запуска программы, как то: работа в offline-режиме,
    # имя пилота ранее зарегистрированного и для которого имеется аутентификационный токен, регистрация нового и т.д.
    argv_prms = console_app.get_argv_prms()

    sde_inv_names = eve_sde_tools.read_converted(
        argv_prms["workspace_cache_files_dir"], "invNames")
    sde_inv_items = eve_sde_tools.read_converted(
        argv_prms["workspace_cache_files_dir"], "invItems")
    sde_inv_positions = eve_sde_tools.read_converted(
        argv_prms["workspace_cache_files_dir"], "invPositions")

    logist_data = []
    for pilot_name in argv_prms["character_names"]:
        # настройка Eve Online ESI Swagger interface
        auth = esi.EveESIAuth('{}/auth_cache'.format(
            argv_prms["workspace_cache_files_dir"]),
                              debug=True)
        client = esi.EveESIClient(
            auth,
            keep_alive=True,
            debug=argv_prms["verbose_mode"],
            logger=True,
            user_agent='Q.Industrialist v{ver}'.format(ver=__version__))
        interface = esi.EveOnlineInterface(
            client,
            q_industrialist_settings.g_client_scope,
            cache_dir='{}/esi_cache'.format(
                argv_prms["workspace_cache_files_dir"]),
            offline_mode=argv_prms["offline_mode"])

        authz = interface.authenticate(pilot_name)
        character_id = authz["character_id"]
        character_name = authz["character_name"]

        # Public information about a character
        character_data = interface.get_esi_data(
            "characters/{}/".format(character_id), fully_trust_cache=True)
        # Public information about a corporation
        corporation_data = interface.get_esi_data("corporations/{}/".format(
            character_data["corporation_id"]),
                                                  fully_trust_cache=True)

        corporation_id = character_data["corporation_id"]
        corporation_name = corporation_data["name"]
        print("\n{} is from '{}' corporation".format(character_name,
                                                     corporation_name))
        sys.stdout.flush()

        # Requires role(s): Director
        corp_assets_data = interface.get_esi_paged_data(
            "corporations/{}/assets/".format(corporation_id))
        print("\n'{}' corporation has {} assets".format(
            corporation_name, len(corp_assets_data)))
        sys.stdout.flush()

        # Получение названий контейнеров, станций, и т.п. - всё что переименовывается ingame
        corp_ass_named_ids = eve_esi_tools.get_assets_named_ids(
            corp_assets_data)
        # Requires role(s): Director
        corp_ass_names_data = interface.get_esi_piece_data(
            "corporations/{}/assets/names/".format(corporation_id),
            corp_ass_named_ids)
        print("\n'{}' corporation has {} custom asset's names".format(
            corporation_name, len(corp_ass_names_data)))
        sys.stdout.flush()
        del corp_ass_named_ids

        # Поиск тех станций, которые не принадлежат корпорации (на них имеется офис, но самой станции в ассетах нет)
        foreign_structures_data = {}
        foreign_structures_ids = eve_esi_tools.get_foreign_structures_ids(
            corp_assets_data)
        foreign_structures_forbidden_ids = []
        if len(foreign_structures_ids) > 0:
            # Requires: access token
            for structure_id in foreign_structures_ids:
                try:
                    universe_structure_data = interface.get_esi_data(
                        "universe/structures/{}/".format(structure_id),
                        fully_trust_cache=True)
                    foreign_structures_data.update(
                        {str(structure_id): universe_structure_data})
                except requests.exceptions.HTTPError as err:
                    status_code = err.response.status_code
                    if status_code == 403:  # это нормально, что часть структур со временем могут оказаться Forbidden
                        foreign_structures_forbidden_ids.append(structure_id)
                    else:
                        raise
                except:
                    print(sys.exc_info())
                    raise
        print("\n'{}' corporation has offices in {} foreign stations".format(
            corporation_name, len(foreign_structures_data)))
        if len(foreign_structures_forbidden_ids) > 0:
            print(
                "\n'{}' corporation has offices in {} forbidden stations : {}".
                format(corporation_name, len(foreign_structures_forbidden_ids),
                       foreign_structures_forbidden_ids))
        sys.stdout.flush()

        # Построение дерева ассетов, с узлами в роли станций и систем, и листьями в роли хранящихся
        # элементов, в виде:
        # { location1: {items:[item1,item2,...],type_id,location_id},
        #   location2: {items:[item3],type_id} }
        corp_assets_tree = eve_esi_tools.get_assets_tree(
            corp_assets_data, foreign_structures_data, sde_inv_items)
        eve_esi_tools.dump_debug_into_file(
            argv_prms["workspace_cache_files_dir"],
            "corp_assets_tree.{}".format(corporation_name), corp_assets_tree)

        logist_data.append({
            "corporation_ticker": corporation_data["ticker"],
            "corp_assets_tree": corp_assets_tree,
            "corp_assets_data": corp_assets_data,
        })

        del corp_assets_tree
        del corp_assets_data
        del foreign_structures_data

    # Фильтрация (вручную) ассетов, которые расположены на станках циносети
    corp_cynonetwork = {}
    for cn in q_logist_settings.g_cynonetworks:
        cn_route = cn["route"]
        jump_num = 1
        for location_id in cn_route:
            # если системы в цино сети повторяются, не гоняем искалочку зазря (повторно)
            if not (str(location_id) in corp_cynonetwork):
                datas = []
                found_tickers = []
                for corp_logist in logist_data:
                    data = get_cyno_solar_system_details(
                        location_id, corp_logist["corp_assets_tree"])
                    if data is None:
                        continue
                    datas.append(data)
                    datas[-1].update({
                        "corporation_ticker":
                        corp_logist["corporation_ticker"]
                    })
                    found_tickers.append(corp_logist["corporation_ticker"])
                # ---
                # signalling_level = 0 - normal, 1 - warning, 2 - danger, 3 - ошибка получения данных
                # оптимальный набор: 10 баджеров, 10 цин, 10'000 (по 950 на прожиг) озона
                #              плюс: 10 вентур, 10 цин, 10'000 (по 200 на прожиг) озона, 30 риг, 10 каргохолда
                # минимальный набор: 1 баджер, 1 вентурка, 2 цины, 1150 озона, 3 риги, 1 каргохолд
                if not datas:
                    # print('{} {}'.format(location_id, data))
                    system_id = None
                    loc_name = "NO-DATA!"
                    loc_id = location_id
                    if int(loc_id) < 1000000000000:
                        if str(loc_id) in sde_inv_names:
                            loc_name = sde_inv_names[str(loc_id)]
                            # print(loc_name)
                            if str(loc_id) in sde_inv_items:
                                root_item = sde_inv_items[str(loc_id)]
                                # print("root_item", root_item)
                                if root_item["typeID"] == 5:  # Solar System
                                    system_id = loc_id
                                    # print(" >>> >>> ", loc_name)
                                else:  # not Solar System (may be Station?)
                                    loc_id = root_item["locationID"]
                                    root_item = sde_inv_items[str(loc_id)]
                                    # print(" >>> ", loc_id, root_item)
                                    if root_item[
                                            "typeID"] == 5:  # Solar System
                                        system_id = loc_id
                                        loc_name = sde_inv_names[str(
                                            loc_id)]  # Solar System (name)
                                        # print(" >>> >>> ", loc_name)
                    data = {
                        "error":
                        "no data" if system_id is None else "no solar system",
                        "system_id": system_id,
                        "solar_system": loc_name,
                        "signalling_level": 3,
                        # -- используется, если 'error'='no solar system'
                        "badger": 0,
                        "venture": 0,
                        "liquid_ozone": 0,
                        "indus_cyno_gen": 0,
                        "exp_cargohold": 0,
                        "cargohold_rigs": 0,
                        "nitrogen_isotope": 0,
                        "hydrogen_isotope": 0,
                        "oxygen_isotope": 0,
                        "helium_isotope": 0
                    }
                else:
                    system_id = None
                    badger_num = 0
                    venture_num = 0
                    liquid_ozone_num = 0
                    indus_cyno_gen_num = 0
                    exp_cargohold_num = 0
                    cargohold_rigs_num = 0
                    nitrogen_isotope_num = 0
                    hydrogen_isotope_num = 0
                    oxygen_isotope_num = 0
                    helium_isotope_num = 0
                    # ---
                    for data in datas:
                        corporation_ticker = data["corporation_ticker"]
                        if system_id is None:
                            system_id = data["solar_system"]
                        badger_ids = data["badger"]
                        venture_ids = data["venture"]
                        liquid_ozone_ids = data["liquid_ozone"]
                        indus_cyno_gen_ids = data["indus_cyno_gen"]
                        exp_cargohold_ids = data["exp_cargohold"]
                        cargohold_rigs_ids = data["cargohold_rigs"]
                        nitrogen_isotope_ids = data["nitrogen_isotope"]
                        hydrogen_isotope_ids = data["hydrogen_isotope"]
                        oxygen_isotope_ids = data["oxygen_isotope"]
                        helium_isotope_ids = data["helium_isotope"]
                        # ---
                        corp_assets_data = []
                        for corp_logist in logist_data:
                            if corporation_ticker == corp_logist[
                                    "corporation_ticker"]:
                                corp_assets_data = corp_logist[
                                    "corp_assets_data"]
                                break
                        # ---
                        for a in corp_assets_data:
                            item_id = int(a["item_id"])
                            quantity = int(a["quantity"])
                            if not (badger_ids is
                                    None) and badger_ids.count(item_id) > 0:
                                badger_num = badger_num + quantity
                            elif not (venture_ids is
                                      None) and venture_ids.count(item_id) > 0:
                                venture_num = venture_num + quantity
                            elif not (
                                    liquid_ozone_ids is None
                            ) and liquid_ozone_ids.count(item_id) > 0:
                                liquid_ozone_num = liquid_ozone_num + quantity
                            elif not (
                                    indus_cyno_gen_ids is None
                            ) and indus_cyno_gen_ids.count(item_id) > 0:
                                indus_cyno_gen_num = indus_cyno_gen_num + quantity
                            elif not (
                                    exp_cargohold_ids is None
                            ) and exp_cargohold_ids.count(item_id) > 0:
                                exp_cargohold_num = exp_cargohold_num + quantity
                            elif not (
                                    cargohold_rigs_ids is None
                            ) and cargohold_rigs_ids.count(item_id) > 0:
                                cargohold_rigs_num = cargohold_rigs_num + quantity
                            elif not (
                                    nitrogen_isotope_ids is None
                            ) and nitrogen_isotope_ids.count(item_id) > 0:
                                nitrogen_isotope_num = nitrogen_isotope_num + quantity
                            elif not (
                                    hydrogen_isotope_ids is None
                            ) and hydrogen_isotope_ids.count(item_id) > 0:
                                hydrogen_isotope_num = hydrogen_isotope_num + quantity
                            elif not (
                                    oxygen_isotope_ids is None
                            ) and oxygen_isotope_ids.count(item_id) > 0:
                                oxygen_isotope_num = oxygen_isotope_num + quantity
                            elif not (
                                    helium_isotope_ids is None
                            ) and helium_isotope_ids.count(item_id) > 0:
                                helium_isotope_num = helium_isotope_num + quantity
                        # ---
                        del corp_assets_data
                    if system_id is None:
                        system_name = "NO-DATA!"
                        signalling_level = 3
                    else:
                        system_name = sde_inv_names[str(system_id)]
                        if (badger_num >= 10) and\
                           (venture_num >= 10) and\
                           (liquid_ozone_num >= 20000) and\
                           (indus_cyno_gen_num >= 20) and\
                           (exp_cargohold_num >= 10) and\
                           (cargohold_rigs_num >= 30):
                            signalling_level = 0
                        elif (badger_num >= 1) and \
                             (venture_num >= 1) and \
                             (liquid_ozone_num >= 1150) and \
                             (indus_cyno_gen_num >= 2) and \
                             (exp_cargohold_num >= 1) and \
                             (cargohold_rigs_num >= 3):
                            signalling_level = 1
                        else:
                            signalling_level = 2
                    # ---
                    data = {
                        "found_tickers": found_tickers,
                        "system_id": system_id,
                        "solar_system": system_name,
                        "badger": badger_num,
                        "venture": venture_num,
                        "liquid_ozone": liquid_ozone_num,
                        "indus_cyno_gen": indus_cyno_gen_num,
                        "exp_cargohold": exp_cargohold_num,
                        "cargohold_rigs": cargohold_rigs_num,
                        "nitrogen_isotope": nitrogen_isotope_num,
                        "hydrogen_isotope": hydrogen_isotope_num,
                        "oxygen_isotope": oxygen_isotope_num,
                        "helium_isotope": helium_isotope_num,
                        "signalling_level": signalling_level,
                    }
                    if system_id is None:
                        data.update({"error": "no solar system"})
                corp_cynonetwork.update({str(location_id): data})

                del datas
            jump_num = jump_num + 1
    eve_esi_tools.dump_debug_into_file(argv_prms["workspace_cache_files_dir"],
                                       "corp_cynonetwork", corp_cynonetwork)

    del logist_data
    del sde_inv_items
    del sde_inv_names

    print("\nBuilding cyno network report...")
    sys.stdout.flush()
    render_html_logist.dump_cynonetwork_into_report(
        # путь, где будет сохранён отчёт
        argv_prms["workspace_cache_files_dir"],
        # sde данные, загруженные из .converted_xxx.json файлов
        sde_inv_positions,
        # данные, полученные в результате анализа и перекомпоновки входных списков
        corp_cynonetwork)

    # Вывод в лог уведомления, что всё завершилось (для отслеживания с помощью tail)
    print("\nDone")
Example #3
0
def main():
    # работа с параметрами командной строки, получение настроек запуска программы, как то: работа в offline-режиме,
    # имя пилота ранее зарегистрированного и для которого имеется аутентификационный токен, регистрация нового и т.д.
    argv_prms = console_app.get_argv_prms()

    # настройка Eve Online ESI Swagger interface
    auth = esi.EveESIAuth('{}/auth_cache'.format(
        argv_prms["workspace_cache_files_dir"]),
                          debug=True)
    client = esi.EveESIClient(
        auth,
        keep_alive=True,
        debug=argv_prms["verbose_mode"],
        logger=True,
        user_agent='Q.Industrialist v{ver}'.format(ver=__version__))
    interface = esi.EveOnlineInterface(
        client,
        q_industrialist_settings.g_client_scope,
        cache_dir='{}/esi_cache'.format(
            argv_prms["workspace_cache_files_dir"]),
        offline_mode=argv_prms["offline_mode"])

    authz = interface.authenticate(argv_prms["character_names"][0])
    character_id = authz["character_id"]
    character_name = authz["character_name"]

    # Public information about a character
    character_data = interface.get_esi_data(
        "characters/{}/".format(character_id), fully_trust_cache=True)
    # Public information about a corporation
    corporation_data = interface.get_esi_data("corporations/{}/".format(
        character_data["corporation_id"]),
                                              fully_trust_cache=True)

    corporation_id = character_data["corporation_id"]
    corporation_name = corporation_data["name"]
    print("\n{} is from '{}' corporation".format(character_name,
                                                 corporation_name))
    sys.stdout.flush()

    sde_type_ids = eve_sde_tools.read_converted(
        argv_prms["workspace_cache_files_dir"], "typeIDs")
    sde_inv_names = eve_sde_tools.read_converted(
        argv_prms["workspace_cache_files_dir"], "invNames")
    sde_inv_items = eve_sde_tools.read_converted(
        argv_prms["workspace_cache_files_dir"], "invItems")
    sde_market_groups = eve_sde_tools.read_converted(
        argv_prms["workspace_cache_files_dir"], "marketGroups")

    # Requires role(s): Director
    corp_assets_data = interface.get_esi_paged_data(
        "corporations/{}/assets/".format(corporation_id))
    print("\n'{}' corporation has {} assets".format(corporation_name,
                                                    len(corp_assets_data)))
    sys.stdout.flush()

    # Получение названий контейнеров, станций, и т.п. - всё что переименовывается ingame
    corp_ass_named_ids = eve_esi_tools.get_assets_named_ids(corp_assets_data)
    # Requires role(s): Director
    corp_ass_names_data = interface.get_esi_piece_data(
        "corporations/{}/assets/names/".format(corporation_id),
        corp_ass_named_ids)
    print("\n'{}' corporation has {} custom asset's names".format(
        corporation_name, len(corp_ass_names_data)))
    sys.stdout.flush()
    del corp_ass_named_ids

    # Поиск тех станций, которые не принадлежат корпорации (на них имеется офис, но самой станции в ассетах нет)
    foreign_structures_data = {}
    foreign_structures_ids = eve_esi_tools.get_foreign_structures_ids(
        corp_assets_data)
    foreign_structures_forbidden_ids = []
    if len(foreign_structures_ids) > 0:
        # Requires: access token
        for structure_id in foreign_structures_ids:
            try:
                universe_structure_data = interface.get_esi_data(
                    "universe/structures/{}/".format(structure_id),
                    fully_trust_cache=True)
                foreign_structures_data.update(
                    {str(structure_id): universe_structure_data})
            except requests.exceptions.HTTPError as err:
                status_code = err.response.status_code
                if status_code == 403:  # это нормально, что часть структур со временем могут оказаться Forbidden
                    foreign_structures_forbidden_ids.append(structure_id)
                else:
                    raise
            except:
                print(sys.exc_info())
                raise
    print("\n'{}' corporation has offices in {} foreign stations".format(
        corporation_name, len(foreign_structures_data)))
    if len(foreign_structures_forbidden_ids) > 0:
        print("\n'{}' corporation has offices in {} forbidden stations : {}".
              format(corporation_name, len(foreign_structures_forbidden_ids),
                     foreign_structures_forbidden_ids))
    sys.stdout.flush()

    try:
        # Public information about market prices
        eve_market_prices_data = interface.get_esi_data("markets/prices/")
        print("\nEVE market has {} prices".format(
            len(eve_market_prices_data) if not (
                eve_market_prices_data is None) else 0))
        sys.stdout.flush()
    except requests.exceptions.HTTPError as err:
        status_code = err.response.status_code
        if status_code == 404:  # 2020.12.03 поломался доступ к ценам маркета (ССР-шники "внесли правки")
            eve_market_prices_data = []
        else:
            raise
    except:
        print(sys.exc_info())
        raise

    # # Public information with list of public structures
    # universe_structures_data = eve_esi_interface.get_esi_data(
    #     access_token,
    #     "universe/structures/")
    # print("\nFound {} public structures in universe".format(len(universe_structures_data)))
    # sys.stdout.flush()

    # Построение дерева ассетов, с узлави в роли станций и систем, и листьями в роли хранящихся
    # элементов, в виде:
    # { location1: {items:[item1,item2,...],type_id,location_id},
    #   location2: {items:[item3],type_id} }
    corp_assets_tree = eve_esi_tools.get_assets_tree(
        corp_assets_data,
        foreign_structures_data,
        sde_inv_items,
        virtual_hierarchy_by_corpsag=True)
    eve_esi_tools.dump_debug_into_file(argv_prms["workspace_cache_files_dir"],
                                       "corp_assets_tree", corp_assets_tree)

    # Построение дерева asset-ов:
    print("\nBuilding assets tree report...")
    sys.stdout.flush()
    render_html_assets.dump_assets_tree_into_report(
        # путь, где будет сохранён отчёт
        argv_prms["workspace_cache_files_dir"],
        # sde данные, загруженные из .converted_xxx.json файлов
        sde_type_ids,
        sde_inv_names,
        sde_inv_items,
        sde_market_groups,
        # esi данные, загруженные с серверов CCP
        corp_assets_data,
        corp_ass_names_data,
        foreign_structures_data,
        eve_market_prices_data,
        # данные, полученные в результате анализа и перекомпоновки входных списков
        corp_assets_tree)

    # Вывод в лог уведомления, что всё завершилось (для отслеживания с помощью tail)
    print("\nDone")
Example #4
0
def main():
    # работа с параметрами командной строки, получение настроек запуска программы, как то: работа в offline-режиме,
    # имя пилота ранее зарегистрированного и для которого имеется аутентификационный токен, регистрация нового и т.д.
    argv_prms = console_app.get_argv_prms()

    sde_type_ids = eve_sde_tools.read_converted(
        argv_prms["workspace_cache_files_dir"], "typeIDs")
    sde_inv_names = eve_sde_tools.read_converted(
        argv_prms["workspace_cache_files_dir"], "invNames")
    sde_inv_items = eve_sde_tools.read_converted(
        argv_prms["workspace_cache_files_dir"], "invItems")
    sde_market_groups = eve_sde_tools.read_converted(
        argv_prms["workspace_cache_files_dir"], "marketGroups")
    sde_bp_materials = eve_sde_tools.read_converted(
        argv_prms["workspace_cache_files_dir"], "blueprints")

    # удаление из списка чертежей тех, которые не published (надо соединить typeIDs и blueprints, отбросив часть)
    for t in [
            t for t in sde_type_ids if t in sde_bp_materials.keys()
            and sde_type_ids[t].get('published') == False
    ]:
        del sde_bp_materials[t]
    # индексация списка модулей и ресурсов, которые ИСПОЛЬЗУЮТСЯ в производстве
    materials_for_bps = set(
        eve_sde_tools.get_materials_for_blueprints(sde_bp_materials))
    research_materials_for_bps = set(
        eve_sde_tools.get_research_materials_for_blueprints(sde_bp_materials))
    # индексация списка продуктов, которые ПОЯВЛЯЮТСЯ в результате производства
    products_for_bps = set(
        eve_sde_tools.get_products_for_blueprints(sde_bp_materials,
                                                  activity="manufacturing"))
    reaction_products_for_bps = set(
        eve_sde_tools.get_products_for_blueprints(sde_bp_materials,
                                                  activity="reaction"))

    # подготовка списка контейнеров (их содержимого, которое будет исключено из плана производства)
    products_to_exclude: typing.List[typing.Tuple[typing.Tuple[str, str],
                                                  typing.List[int]]] = []
    for manuf_dict in [
            m for m in q_conveyor_settings.g_manufacturing
            if 'market_storage_to_exclude' in m
    ]:
        for ms2e in manuf_dict['market_storage_to_exclude']:
            products_to_exclude.append((ms2e, []))

    conveyor_data = []
    for pilot_name in argv_prms["character_names"]:
        # настройка Eve Online ESI Swagger interface
        auth = esi.EveESIAuth('{}/auth_cache'.format(
            argv_prms["workspace_cache_files_dir"]),
                              debug=True)
        client = esi.EveESIClient(
            auth,
            keep_alive=True,
            debug=argv_prms["verbose_mode"],
            logger=True,
            user_agent='Q.Industrialist v{ver}'.format(ver=__version__))
        interface = esi.EveOnlineInterface(
            client,
            q_industrialist_settings.g_client_scope,
            cache_dir='{}/esi_cache'.format(
                argv_prms["workspace_cache_files_dir"]),
            offline_mode=argv_prms["offline_mode"])

        authz = interface.authenticate(pilot_name)
        character_id = authz["character_id"]
        character_name = authz["character_name"]

        # Public information about a character
        character_data = interface.get_esi_data(
            "characters/{}/".format(character_id), fully_trust_cache=True)
        # Public information about a corporation
        corporation_data = interface.get_esi_data("corporations/{}/".format(
            character_data["corporation_id"]),
                                                  fully_trust_cache=True)

        corporation_id = character_data["corporation_id"]
        corporation_name = corporation_data["name"]
        print("\n{} is from '{}' corporation".format(character_name,
                                                     corporation_name))
        sys.stdout.flush()

        # Requires role(s): Director
        corp_assets_data = interface.get_esi_paged_data(
            "corporations/{}/assets/".format(corporation_id))
        print("\n'{}' corporation has {} assets".format(
            corporation_name, len(corp_assets_data)))
        sys.stdout.flush()

        # Requires role(s): Director
        corp_blueprints_data = interface.get_esi_paged_data(
            "corporations/{}/blueprints/".format(corporation_id))
        corp_blueprints_data_len = len(corp_blueprints_data)
        print("\n'{}' corporation has {} blueprints".format(
            corporation_name, corp_blueprints_data_len))
        sys.stdout.flush()

        # Requires role(s): Factory_Manager
        corp_industry_jobs_data = interface.get_esi_paged_data(
            "corporations/{}/industry/jobs/".format(corporation_id))
        print("\n'{}' corporation has {} industry jobs".format(
            corporation_name, len(corp_industry_jobs_data)))
        sys.stdout.flush()

        # Получение названий контейнеров, станций, и т.п. - всё что переименовывается ingame
        corp_ass_named_ids = eve_esi_tools.get_assets_named_ids(
            corp_assets_data)
        # Requires role(s): Director
        corp_ass_names_data = interface.get_esi_piece_data(
            "corporations/{}/assets/names/".format(corporation_id),
            corp_ass_named_ids)
        print("\n'{}' corporation has {} custom asset's names".format(
            corporation_name, len(corp_ass_names_data)))
        sys.stdout.flush()
        del corp_ass_named_ids

        # Построение иерархических списков БПО и БПЦ, хранящихся в корпоративных ангарах
        corp_bp_loc_data = eve_esi_tools.get_corp_bp_loc_data(
            corp_blueprints_data, corp_industry_jobs_data)
        eve_esi_tools.dump_debug_into_file(
            argv_prms["workspace_cache_files_dir"],
            "corp_bp_loc_data.{}".format(corporation_name), corp_bp_loc_data)

        del corp_blueprints_data

        # Построение списка модулей и ресуров, которые имеются в распоряжении корпорации и
        # которые предназначены для использования в чертежах
        corp_ass_loc_data = eve_esi_tools.get_corp_ass_loc_data(
            corp_assets_data, containers_filter=None)
        eve_esi_tools.dump_debug_into_file(
            argv_prms["workspace_cache_files_dir"],
            "corp_ass_loc_data.{}".format(corporation_name), corp_ass_loc_data)

        # Выявление предметов, которые хранятся в контейнерах корпорации, и которые следует исключить из
        # плана производства
        for p2e in [
                p for p in products_to_exclude if p[0][0] == corporation_name
        ]:
            market_overstock_loc_ids = [
                n["item_id"] for n in corp_ass_names_data
                if re.search(p2e[0][1], n['name'])
            ]
            for ass_loc in corp_ass_loc_data.values():
                for loc_id in market_overstock_loc_ids:
                    items: typing.Dict[str, int] = ass_loc.get(str(loc_id))
                    if items:
                        p2e[1].extend([int(itm) for itm in items.keys()])

        # Поиск тех станций, которые не принадлежат корпорации (на них имеется офис, но самой станции в ассетах нет)
        foreign_structures_data = {}
        foreign_structures_ids = eve_esi_tools.get_foreign_structures_ids(
            corp_assets_data)
        foreign_structures_forbidden_ids = []
        if len(foreign_structures_ids) > 0:
            # Requires: access token
            for structure_id in foreign_structures_ids:
                try:
                    universe_structure_data = interface.get_esi_data(
                        "universe/structures/{}/".format(structure_id),
                        fully_trust_cache=True)
                    foreign_structures_data.update(
                        {str(structure_id): universe_structure_data})
                except requests.exceptions.HTTPError as err:
                    status_code = err.response.status_code
                    if status_code == 403:  # это нормально, что часть структур со временем могут оказаться Forbidden
                        foreign_structures_forbidden_ids.append(structure_id)
                    else:
                        raise
                except:
                    print(sys.exc_info())
                    raise
        print("\n'{}' corporation has offices in {} foreign stations".format(
            corporation_name, len(foreign_structures_data)))
        if len(foreign_structures_forbidden_ids) > 0:
            print(
                "\n'{}' corporation has offices in {} forbidden stations : {}".
                format(corporation_name, len(foreign_structures_forbidden_ids),
                       foreign_structures_forbidden_ids))
        sys.stdout.flush()

        # Построение дерева ассетов, с узлави в роли станций и систем, и листьями в роли хранящихся
        # элементов, в виде:
        # { location1: {items:[item1,item2,...],type_id,location_id},
        #   location2: {items:[item3],type_id} }
        corp_assets_tree = eve_esi_tools.get_assets_tree(
            corp_assets_data,
            foreign_structures_data,
            sde_inv_items,
            virtual_hierarchy_by_corpsag=False)
        eve_esi_tools.dump_debug_into_file(
            argv_prms["workspace_cache_files_dir"],
            "corp_assets_tree.{}".format(corporation_name), corp_assets_tree)

        # Поиск контейнеров, которые участвуют в производстве
        corp_conveyour_entities = []
        for (__manuf_dict_num,
             __manuf_dict) in enumerate(q_conveyor_settings.g_manufacturing):
            # находим контейнеры по заданным названиям
            blueprint_loc_ids = []
            for tmplt in __manuf_dict["conveyor_container_names"]:
                blueprint_loc_ids.extend([
                    n["item_id"] for n in corp_ass_names_data
                    if re.search(tmplt, n['name'])
                ])
            # строим список названий контейнеров, содержимое которых исключается из плана производства (copy as is)
            market_storage_to_exclude: typing.List[typing.Tuple[
                str, str]] = __manuf_dict.get('market_storage_to_exclude')
            # кешируем признак того, что контейнеры являются стоком материалов
            same_stock_container = __manuf_dict.get("same_stock_container",
                                                    False)
            fixed_number_of_runs = __manuf_dict.get("fixed_number_of_runs",
                                                    None)
            manufacturing_activities = __manuf_dict.get(
                "manufacturing_activities", ["manufacturing"])
            # находим станцию, где расположены найденные контейнеры
            for id in blueprint_loc_ids:
                __loc_dict = eve_esi_tools.get_universe_location_by_item(
                    id, sde_inv_names, sde_inv_items, corp_assets_tree,
                    corp_ass_names_data, foreign_structures_data)
                if not ("station_id" in __loc_dict):
                    continue
                __station_id = __loc_dict["station_id"]
                __conveyor_entity = next(
                    (id for id in corp_conveyour_entities
                     if (id["station_id"] == __station_id) and (
                         id["num"] == __manuf_dict_num)), None)
                if __conveyor_entity is None:
                    __conveyor_entity = __loc_dict
                    __conveyor_entity.update({
                        "containers": [],
                        "stock": [],
                        "react_stock": [],
                        "exclude": [],
                        "num":
                        __manuf_dict_num,
                        'market_storage_to_exclude':
                        market_storage_to_exclude,  # впоследствии будет найден и заменён
                    })
                    corp_conveyour_entities.append(__conveyor_entity)
                    # на этой же станции находим контейнер со стоком материалов
                    if same_stock_container:
                        __conveyor_entity["stock"].append({
                            "id":
                            id,
                            "name":
                            next((n["name"] for n in corp_ass_names_data
                                  if n['item_id'] == id), None)
                        })
                    else:
                        for tmplt in __manuf_dict["stock_container_names"]:
                            __stock_ids = [
                                n["item_id"] for n in corp_ass_names_data
                                if re.search(tmplt, n['name'])
                            ]
                            for __stock_id in __stock_ids:
                                __stock_loc_dict = eve_esi_tools.get_universe_location_by_item(
                                    __stock_id, sde_inv_names, sde_inv_items,
                                    corp_assets_tree, corp_ass_names_data,
                                    foreign_structures_data)
                                if ("station_id" in __stock_loc_dict) and (
                                        __station_id
                                        == __stock_loc_dict["station_id"]):
                                    __conveyor_entity["stock"].append({
                                        "id":
                                        __stock_id,
                                        "name":
                                        next((n["name"]
                                              for n in corp_ass_names_data
                                              if n['item_id'] == __stock_id),
                                             None)
                                    })
                    # на этой же станции находим контейнеры, из которых нельзя доставать чертежи для производства материалов
                    for tmplt in __manuf_dict["exclude_container_names"]:
                        __exclude_ids = [
                            n["item_id"] for n in corp_ass_names_data
                            if re.search(tmplt, n['name'])
                        ]
                        for __exclude_id in __exclude_ids:
                            __stock_loc_dict = eve_esi_tools.get_universe_location_by_item(
                                __exclude_id, sde_inv_names, sde_inv_items,
                                corp_assets_tree, corp_ass_names_data,
                                foreign_structures_data)
                            if ("station_id" in __stock_loc_dict) and (
                                    __station_id
                                    == __stock_loc_dict["station_id"]):
                                __conveyor_entity["exclude"].append({
                                    "id":
                                    __exclude_id,
                                    "name":
                                    next((n["name"]
                                          for n in corp_ass_names_data
                                          if n['item_id'] == __exclude_id),
                                         None)
                                })
                    # на любой другой станции находим контейнер, в котором находится сток для нужд конвейера, но пока
                    # ещё на нужную станцию (например с Татары на Сотию)
                    for tmplt in __manuf_dict.get("reaction_stock_containers",
                                                  []):
                        rs_ids = [(n["item_id"], n['name'])
                                  for n in corp_ass_names_data
                                  if re.search(tmplt, n['name'])]
                        for (rs_id, rs_name) in rs_ids:
                            rs_loc_dict = eve_esi_tools.get_universe_location_by_item(
                                rs_id, sde_inv_names, sde_inv_items,
                                corp_assets_tree, corp_ass_names_data,
                                foreign_structures_data)
                            if "station_id" in rs_loc_dict:
                                __conveyor_entity["react_stock"].append({
                                    "id":
                                    rs_id,
                                    "name":
                                    rs_name,
                                    "loc":
                                    rs_loc_dict
                                })
                        del rs_ids
                # добавляем к текущей станции контейнер с чертежами
                # добаляем в свойства контейнера фиксированное кол-во запусков чертежей из настроек
                __conveyor_entity["containers"].append({
                    "id":
                    id,
                    "name":
                    next((n["name"]
                          for n in corp_ass_names_data if n['item_id'] == id),
                         None),
                    "fixed_number_of_runs":
                    fixed_number_of_runs,
                    "manufacturing_activities":
                    manufacturing_activities,
                })

        conveyor_data.append({
            "corporation_id": corporation_id,
            "corporation_name": corporation_name,
            "corp_conveyour_entities": corp_conveyour_entities,
            # esi данные, загруженные с серверов CCP
            "corp_industry_jobs_data": corp_industry_jobs_data,
            "corp_assets_data": corp_assets_data,
            "corp_bp_quantity": corp_blueprints_data_len,
            # данные, полученные в результате анализа и перекомпоновки входных списков
            "corp_ass_loc_data": corp_ass_loc_data,
            "corp_bp_loc_data": corp_bp_loc_data,
            "corp_assets_tree": corp_assets_tree,
        })
        del corp_conveyour_entities
        del corp_industry_jobs_data
        del corp_ass_names_data
        del corp_ass_loc_data
        del corp_bp_loc_data
        del corp_assets_tree

    # постобработка списка конвейеров (из списка удаляются корпорации без коробок контейнеров), поскольку не все
    # корпорации подключаемые к конвейеру спользуют его (например, торговая корпа в Jita имеет лишь
    # ящик с market оверстоком)
    conveyor_data = [c for c in conveyor_data if c['corp_conveyour_entities']]

    # после того, как информация по всем корпорациям была загружена, перекомпонуем список с названиями контейнеров
    # в новый список с идентификаторами продуктов, расчёты по которым следует пропустить
    for cc in conveyor_data:
        for c in [
                c for c in cc['corp_conveyour_entities']
                if 'market_storage_to_exclude' in c
        ]:
            if isinstance(c['market_storage_to_exclude'], list):
                p2e: typing.List[int] = []
                for ms2e in c['market_storage_to_exclude']:
                    for p in [
                            p[1] for p in products_to_exclude if p[0] == ms2e
                    ]:
                        p2e.extend(p)
                c.update({'products_to_exclude': p2e})
            del c['market_storage_to_exclude']
    del products_to_exclude

    # перечисляем станции и контейнеры, которые были найдены
    print('\nFound conveyor containters and station ids...')
    for cd in conveyor_data:
        print(' corporation = {}'.format(cd["corporation_name"]))
        for ce in cd["corp_conveyour_entities"]:
            print('   {} = {}'.format(ce["station_id"], ce["station"]))
            print('     containers with blueprints:')
            for cec in ce["containers"]:
                print('       {} = {}'.format(cec["id"], cec["name"]))
            print('     stock containers:')
            for ces in ce["stock"]:
                print('       {} = {}'.format(ces["id"], ces["name"]))
            if ce["react_stock"]:
                print('     reaction stock containers:')
                for cess in ce["react_stock"]:
                    print('       {} = {}'.format(cess["loc"]["station_id"],
                                                  cess["loc"]["station"]))
                    print('         {} = {}'.format(cess["id"], cess["name"]))
            if ce["containers"]:
                print('     exclude containers:')
                for cee in ce["exclude"]:
                    print('       {} = {}'.format(cee["id"], cee["name"]))
            if ce.get('products_to_exclude'):
                print('     market overstock:')
                for type_id in ce['products_to_exclude']:
                    print('       {} = {}'.format(
                        type_id,
                        eve_sde_tools.get_item_name_by_type_id(
                            sde_type_ids, type_id)))
    sys.stdout.flush()

    print("\nBuilding report...")
    sys.stdout.flush()

    del sde_inv_names
    del sde_inv_items

    render_html_conveyor.dump_conveyor_into_report(
        # путь, где будет сохранён отчёт
        argv_prms["workspace_cache_files_dir"],
        # sde данные, загруженные из .converted_xxx.json файлов
        sde_type_ids,
        sde_bp_materials,
        sde_market_groups,
        materials_for_bps,
        research_materials_for_bps,
        products_for_bps,
        reaction_products_for_bps,
        # настройки генерации отчёта
        # esi данные, загруженные с серверов CCP
        # данные, полученные в результате анализа и перекомпоновки входных списков
        conveyor_data)

    # Вывод в лог уведомления, что всё завершилось (для отслеживания с помощью tail)
    print("\nConveyor v{} done".format(__version__))
Example #5
0
def main():
    # работа с параметрами командной строки, получение настроек запуска программы, как то: работа в offline-режиме,
    # имя пилота ранее зарегистрированного и для которого имеется аутентификационный токен, регистрация нового и т.д.
    argv_prms = console_app.get_argv_prms()

    # настройка Eve Online ESI Swagger interface
    auth = esi.EveESIAuth('{}/auth_cache'.format(
        argv_prms["workspace_cache_files_dir"]),
                          debug=True)
    client = esi.EveESIClient(
        auth,
        keep_alive=True,
        debug=argv_prms["verbose_mode"],
        logger=True,
        user_agent='Q.Industrialist v{ver}'.format(ver=__version__))
    interface = esi.EveOnlineInterface(
        client,
        q_industrialist_settings.g_client_scope,
        cache_dir='{}/esi_cache'.format(
            argv_prms["workspace_cache_files_dir"]),
        offline_mode=argv_prms["offline_mode"])

    authz = interface.authenticate(argv_prms["character_names"][0])
    character_id = authz["character_id"]
    character_name = authz["character_name"]

    # Public information about a character
    character_data = interface.get_esi_data(
        "characters/{}/".format(character_id), fully_trust_cache=True)
    # Public information about a corporation
    corporation_data = interface.get_esi_data("corporations/{}/".format(
        character_data["corporation_id"]),
                                              fully_trust_cache=True)

    corporation_id = character_data["corporation_id"]
    corporation_name = corporation_data["name"]
    print("\n{} is from '{}' corporation".format(character_name,
                                                 corporation_name))
    sys.stdout.flush()

    sde_type_ids = eve_sde_tools.read_converted(
        argv_prms["workspace_cache_files_dir"], "typeIDs")
    sde_bp_materials = eve_sde_tools.read_converted(
        argv_prms["workspace_cache_files_dir"], "blueprints")
    sde_market_groups = eve_sde_tools.read_converted(
        argv_prms["workspace_cache_files_dir"], "marketGroups")
    sde_icon_ids = eve_sde_tools.read_converted(
        argv_prms["workspace_cache_files_dir"], "iconIDs")

    # удаление из списка чертежей тех, которые не published (надо соединить typeIDs и blueprints, отбросив часть)
    for t in [
            t for t in sde_type_ids if t in sde_bp_materials.keys()
            and sde_type_ids[t].get('published') == False
    ]:
        del sde_bp_materials[t]

    # Requires role(s): Director
    corp_assets_data = interface.get_esi_paged_data(
        "corporations/{}/assets/".format(corporation_id))
    print("\n'{}' corporation has {} assets".format(corporation_name,
                                                    len(corp_assets_data)))
    sys.stdout.flush()

    # Requires role(s): Director
    corp_blueprints_data = interface.get_esi_paged_data(
        "corporations/{}/blueprints/".format(corporation_id))
    print("\n'{}' corporation has {} blueprints".format(
        corporation_name, len(corp_blueprints_data)))
    sys.stdout.flush()

    # Построение дерева market-групп с элементами, в виде:
    # { group1: {items:[sub1,sub2,...]},
    #   group2: {items:[sub3],parent_id} }
    market_groups_tree = eve_sde_tools.get_market_groups_tree(
        sde_market_groups)
    eve_esi_tools.dump_debug_into_file(argv_prms["workspace_cache_files_dir"],
                                       "market_groups_tree",
                                       market_groups_tree)

    print("\nBuilding report...")
    sys.stdout.flush()

    found_blueprints = []
    glf = open('{dir}/corp_bpo.csv'.format(
        dir=argv_prms["workspace_cache_files_dir"]),
               "wt+",
               encoding='utf8')
    try:
        glf.write(
            'Blueprint\tBase Price\tMaterial Efficiency\tTime Efficiency\n')
        for a in corp_assets_data:
            if not (str(a["type_id"]) in sde_bp_materials):
                continue
            if ("is_blueprint_copy" in a) and a["is_blueprint_copy"]:
                continue
            item_id = a["item_id"]
            blueprint = None
            for b in corp_blueprints_data:
                if b["item_id"] == item_id:
                    blueprint = b
                    break
            if blueprint is None:
                continue
            type_id = sde_type_ids[str(a["type_id"])]
            glf.write('{nm}\t{prc}\t{me}\t{te}\n'.format(
                nm=type_id["name"]["en"],
                prc=type_id["basePrice"] if "basePrice" in type_id else "",
                me=blueprint["material_efficiency"],
                te=blueprint["time_efficiency"]))
            found_blueprints.append(int(a["type_id"]))
        glf.write('\nGenerated {}'.format(
            datetime.fromtimestamp(
                time.time(),
                g_local_timezone).strftime('%a, %d %b %Y %H:%M:%S %z')))
    finally:
        glf.close()

    glf = open('{dir}/corp_absent_bpo.csv'.format(
        dir=argv_prms["workspace_cache_files_dir"]),
               "wt+",
               encoding='utf8')
    try:
        glf.write(
            'Blueprint\tBase Price\tPresent\tManufacturing Impossible\tAbsent Materials\n'
        )
        bpo_keys = sde_bp_materials.keys()
        for tid in bpo_keys:
            type_id = int(tid)
            sde_type_id = sde_type_ids[str(type_id)]
            found = next((True for b in found_blueprints if b == type_id),
                         False)
            glf.write('{nm}\t{prc}\t{fnd}\t{impsbl}\t{absnt}\n'.format(
                nm=sde_type_id["name"]["en"],
                prc=sde_type_id["basePrice"]
                if "basePrice" in sde_type_id else "",
                fnd="yes" if found else "no",
                impsbl="yes" if not ("activities" in sde_bp_materials[tid])
                or not ("manufacturing" in sde_bp_materials[tid]["activities"])
                else "no",
                absnt="yes" if not ("activities" in sde_bp_materials[tid])
                or not ("manufacturing" in sde_bp_materials[tid]["activities"])
                or not ("materials" in sde_bp_materials[tid]["activities"]
                        ["manufacturing"]) else "no"))
        glf.write('\nGenerated {}'.format(
            datetime.fromtimestamp(
                time.time(),
                g_local_timezone).strftime('%a, %d %b %Y %H:%M:%S %z')))
    finally:
        glf.close()

    print("\nBuilding BPOs report...")
    sys.stdout.flush()
    render_html_bpos.dump_bpos_into_report(
        # путь, где будет сохранён отчёт
        argv_prms["workspace_cache_files_dir"],
        # sde данные, загруженные из .converted_xxx.json файлов
        sde_type_ids,
        sde_market_groups,
        sde_icon_ids,
        sde_bp_materials,
        # esi данные, загруженные с серверов CCP
        corp_assets_data,
        corp_blueprints_data,
        # данные, полученные в результате анализа и перекомпоновки входных списков
        market_groups_tree)

    # Вывод в лог уведомления, что всё завершилось (для отслеживания с помощью tail)
    print("\nDone")
def main():
    # работа с параметрами командной строки, получение настроек запуска программы, как то: работа в offline-режиме,
    # имя пилота ранее зарегистрированного и для которого имеется аутентификационный токен, регистрация нового и т.д.
    argv_prms = console_app.get_argv_prms()

    sde_type_ids = eve_sde_tools.read_converted(
        argv_prms["workspace_cache_files_dir"], "typeIDs")
    sde_inv_names = eve_sde_tools.read_converted(
        argv_prms["workspace_cache_files_dir"], "invNames")
    # sde_inv_items = eve_sde_tools.read_converted(argv_prms["workspace_cache_files_dir"], "invItems")
    sde_market_groups = eve_sde_tools.read_converted(
        argv_prms["workspace_cache_files_dir"], "marketGroups")
    sde_icon_ids = eve_sde_tools.read_converted(
        argv_prms["workspace_cache_files_dir"], "iconIDs")
    sde_bp_materials = eve_sde_tools.read_converted(
        argv_prms["workspace_cache_files_dir"], "blueprints")

    # удаление из списка чертежей тех, которые не published (надо соединить typeIDs и blueprints, отбросив часть)
    for t in [
            t for t in sde_type_ids if t in sde_bp_materials.keys()
            and sde_type_ids[t].get('published') == False
    ]:
        del sde_bp_materials[t]
    # построение списка продуктов, которые появляются в результате производства
    products_for_bps = set(
        eve_sde_tools.get_products_for_blueprints(sde_bp_materials))
    materials_for_bps = eve_sde_tools.get_materials_for_blueprints(
        sde_bp_materials)
    research_materials_for_bps = eve_sde_tools.get_research_materials_for_blueprints(
        sde_bp_materials)
    materials_for_bps.extend(research_materials_for_bps)
    materials_for_bps = set(materials_for_bps)
    del research_materials_for_bps

    pilot_name = argv_prms["character_names"][0]

    # настройка Eve Online ESI Swagger interface
    auth = esi.EveESIAuth('{}/auth_cache'.format(
        argv_prms["workspace_cache_files_dir"]),
                          debug=True)
    client = esi.EveESIClient(
        auth,
        keep_alive=True,
        debug=argv_prms["verbose_mode"],
        logger=True,
        user_agent='Q.Industrialist v{ver}'.format(ver=__version__))
    interface = esi.EveOnlineInterface(
        client,
        q_industrialist_settings.g_client_scope,
        cache_dir='{}/esi_cache'.format(
            argv_prms["workspace_cache_files_dir"]),
        offline_mode=argv_prms["offline_mode"])

    authz = interface.authenticate(pilot_name)
    character_id = authz["character_id"]
    character_name = authz["character_name"]

    # Public information about a character
    character_data = interface.get_esi_data(
        "characters/{}/".format(character_id), fully_trust_cache=True)
    # Public information about a corporation
    corporation_data = interface.get_esi_data("corporations/{}/".format(
        character_data["corporation_id"]),
                                              fully_trust_cache=True)

    # corporation_id = character_data["corporation_id"]
    corporation_name = corporation_data["name"]
    print("\n{} is from '{}' corporation".format(character_name,
                                                 corporation_name))
    sys.stdout.flush()

    market_regions = [
        (int(id), sde_inv_names[id], {}) for id in sde_inv_names
        if sde_inv_names[id] in q_market_analyzer_settings.g_regions
    ]

    for (region_id, region_name, region_details) in market_regions:
        # Requires: public access
        markets_region_orders = interface.get_esi_paged_data(
            "markets/{}/orders/".format(region_id))
        sys.stdout.flush()

        region_details.update({
            "orders": {
                "buy": 0,
                "sell": 0,
            },
        })

        region_systems = {}
        region_trade_hubs = {}
        region_market = {}
        for o in markets_region_orders:
            type_id: int = o["type_id"]

            # проверяем к какой группе товаров относится данный type_id, если это чертежи, книжки, шкурки - пропускаем
            market_chain = eve_sde_tools.get_market_groups_chain_by_type_id(
                sde_type_ids, sde_market_groups, type_id)
            if market_chain:
                if market_chain[0] in [
                        2,  # пропускаем Blueprints
                        1659,  # пропускаем Special Edition Assets
                        1396,  # пропускаем Apparel
                        1954,  # пропускаем Ship SKINs
                        150,  # пропускаем Skills
                ]:
                    continue
                semantic_market_group_id = market_chain[0] if len(
                    market_chain) == 1 else market_chain[1]
            else:
                semantic_market_group_id = 0  # нам что 0, что None - без разницы, группы для него нет

            # проверяем, и пропускаем те товары, которые нельзся произвести
            if q_market_analyzer_settings.g_skip_non_manufacturing_products:
                if type_id not in products_for_bps and type_id not in materials_for_bps:
                    continue

            system_id: str = o["system_id"]
            location_id: str = o["location_id"]

            system_dict = region_systems.get(system_id)
            if not system_dict:
                region_systems.update({
                    system_id: {
                        "name": sde_inv_names.get(str(system_id)),
                        "orders": {
                            "buy": 0,
                            "sell": 0
                        },
                        "market": {},
                    }
                })
                system_dict = region_systems.get(system_id)

            trade_hub_dict = region_trade_hubs.get(location_id)
            if not trade_hub_dict:
                region_trade_hubs.update({
                    location_id: {
                        "name": sde_inv_names.get(str(location_id)),
                        "system": system_id,
                        "orders": {
                            "buy": 0,
                            "sell": 0
                        },
                        "market": {},
                    }
                })
                trade_hub_dict = region_trade_hubs.get(location_id)

            region_market_dict = region_market.get(semantic_market_group_id)
            if not region_market_dict:
                region_market.update({
                    semantic_market_group_id: {
                        "orders": {
                            "buy": 0,
                            "sell": 0
                        },
                    }
                })
                region_market_dict = region_market.get(
                    semantic_market_group_id)

            system_market_dict = system_dict["market"].get(
                semantic_market_group_id)
            if not system_market_dict:
                system_dict["market"].update({
                    semantic_market_group_id: {
                        "orders": {
                            "buy": 0,
                            "sell": 0
                        },
                    }
                })
                system_market_dict = system_dict["market"].get(
                    semantic_market_group_id)

            trade_hub_market_dict = trade_hub_dict["market"].get(
                semantic_market_group_id)
            if not trade_hub_market_dict:
                trade_hub_dict["market"].update({
                    semantic_market_group_id: {
                        "orders": {
                            "buy": 0,
                            "sell": 0
                        },
                    }
                })
                trade_hub_market_dict = trade_hub_dict["market"].get(
                    semantic_market_group_id)
            """ debug
            if system_id == 30045352:
                print(
                    "{:>6} {:<50} {:>4} {:>11} {:>11} {:>11} {:>6} {}".
                    format(
                        type_id,
                        sde_type_ids.get(str(type_id), {"name":{"en":"?"}})["name"]["en"],
                        "buy" if o["is_buy_order"] else "sell",
                        o["range"],
                        o["price"],
                        o["volume_remain"],
                        semantic_market_group_id if semantic_market_group_id else "?",
                        sde_market_groups.get(str(semantic_market_group_id), {"nameID": {"en": "?"}})["nameID"]["en"]
                    ),
                    # o
                )
            """

            tag_order: str = "buy" if o["is_buy_order"] else "sell"
            region_details["orders"][tag_order] += 1
            system_dict["orders"][tag_order] += 1
            trade_hub_dict["orders"][tag_order] += 1
            region_market_dict["orders"][tag_order] += 1
            system_market_dict["orders"][tag_order] += 1
            trade_hub_market_dict["orders"][tag_order] += 1

        region_details.update({
            "systems": region_systems,
            "trade_hubs": region_trade_hubs,
            "market": region_market,
        })

        del region_market
        del region_trade_hubs
        del region_systems
        del markets_region_orders

    eve_esi_tools.dump_debug_into_file(argv_prms["workspace_cache_files_dir"],
                                       "market_regions", market_regions)

    render_html_market_analyzer.dump_market_analyzer_into_report(
        # путь, где будет сохранён отчёт
        argv_prms["workspace_cache_files_dir"],
        # sde данные, загруженные из .converted_xxx.json файлов
        sde_icon_ids,
        sde_market_groups,
        sde_inv_names,
        # данные, полученные в результате анализа и перекомпоновки входных списков
        market_regions)

    # Вывод в лог уведомления, что всё завершилось (для отслеживания с помощью tail)
    print("\nDone")
def main():
    # работа с параметрами командной строки, получение настроек запуска программы, как то: работа в offline-режиме,
    # имя пилота ранее зарегистрированного и для которого имеется аутентификационный токен, регистрация нового и т.д.
    argv_prms = console_app.get_argv_prms()

    various_characters_data = {}
    various_corporations_data = {}
    for pilot_name in argv_prms["character_names"]:
        # настройка Eve Online ESI Swagger interface
        auth = esi.EveESIAuth('{}/auth_cache'.format(
            argv_prms["workspace_cache_files_dir"]),
                              debug=True)
        client = esi.EveESIClient(
            auth,
            keep_alive=True,
            debug=argv_prms["verbose_mode"],
            logger=True,
            user_agent='Q.Industrialist v{ver}'.format(ver=__version__))
        interface = esi.EveOnlineInterface(
            client,
            q_industrialist_settings.g_client_scope,
            cache_dir='{}/esi_cache'.format(
                argv_prms["workspace_cache_files_dir"]),
            offline_mode=argv_prms["offline_mode"])

        authz = interface.authenticate(pilot_name)
        character_id = authz["character_id"]
        character_name = authz["character_name"]

        # Public information about a character
        character_data = interface.get_esi_data(
            "characters/{}/".format(character_id), fully_trust_cache=True)
        # Public information about a corporation
        corporation_data = interface.get_esi_data("corporations/{}/".format(
            character_data["corporation_id"]),
                                                  fully_trust_cache=True)

        corporation_id = character_data["corporation_id"]
        corporation_name = corporation_data["name"]
        print("\n{} is from '{}' corporation".format(character_name,
                                                     corporation_name))
        sys.stdout.flush()

        try:
            # Requires role(s): Director
            corp_shareholders_data = interface.get_esi_paged_data(
                "corporations/{}/shareholders/".format(corporation_id))
            print("'{}' corporation has {} shareholders\n".format(
                corporation_name, len(corp_shareholders_data)))
            sys.stdout.flush()
        except requests.exceptions.HTTPError as err:
            status_code = err.response.status_code
            if status_code == 500:  # 2021.01.28 поломался доступ к кошелькам, Internal Server Error
                corp_shareholders_data = []
            else:
                raise
        except:
            print(sys.exc_info())
            raise

        various_characters_data.update({str(character_id): character_data})
        various_corporations_data.update(
            {str(corporation_id): corporation_data})

        for shareholder in corp_shareholders_data:
            # Получение сведений о пилотах, имеющих акции корпорации
            corp_id = None
            if shareholder['shareholder_type'] == 'character':
                pilot_id = shareholder['shareholder_id']
                if str(
                        pilot_id
                ) in various_characters_data:  # пилот м.б. быть в списке с dict=None
                    __pilot_dict = various_characters_data.get(str(pilot_id))
                    if __pilot_dict:
                        corp_id = __pilot_dict.get("corporation_id")
                else:
                    try:
                        # Public information about a character
                        pilot_data = interface.get_esi_data(
                            "characters/{}/".format(pilot_id),
                            fully_trust_cache=True)
                        corp_id = pilot_data["corporation_id"]
                        various_characters_data.update(
                            {str(pilot_id): pilot_data})
                    except requests.exceptions.HTTPError as err:
                        status_code = err.response.status_code
                        if status_code == 404:  # 404 Client Error: Not Found ('Character has been deleted!')
                            various_characters_data.update(
                                {str(pilot_id): None})
                        else:
                            print(sys.exc_info())
                            raise
                    except:
                        print(sys.exc_info())
                        raise
                    sys.stdout.flush()
            elif shareholder['shareholder_type'] == 'corporation':
                corp_id = shareholder['shareholder_id']
            # Получение сведений о корпорациях, которым принадлежат акции, либо в которых состоят пилоты
            if corp_id:
                if str(corp_id) not in various_corporations_data:
                    # Public information about a character
                    corp_data = interface.get_esi_data(
                        "corporations/{}/".format(corp_id),
                        fully_trust_cache=True)
                    various_corporations_data.update({str(corp_id): corp_data})
            sys.stdout.flush()

        shareholders_data = {
            "corporation": corporation_data,
            "shareholders": corp_shareholders_data,
            "characters": various_characters_data,
            "corporations": various_corporations_data,
        }
        eve_esi_tools.dump_debug_into_file(
            argv_prms["workspace_cache_files_dir"],
            "corp_shareholders_data.{}".format(corporation_name),
            shareholders_data)

        # Построение дерева shareholders-ов:
        print("\nBuilding shareholders report...")
        sys.stdout.flush()
        render_html_shareholders.dump_shareholders_into_report(
            # путь, где будет сохранён отчёт
            argv_prms["workspace_cache_files_dir"],
            # данные, полученные в результате анализа и перекомпоновки входных списков
            shareholders_data)

    # Вывод в лог уведомления, что всё завершилось (для отслеживания с помощью tail)
    print("\nDone")
def main():
    # работа с параметрами командной строки, получение настроек запуска программы, как то: работа в offline-режиме,
    # имя пилота ранее зарегистрированного и для которого имеется аутентификационный токен, регистрация нового и т.д.
    argv_prms = console_app.get_argv_prms()

    sde_type_ids = eve_sde_tools.read_converted(
        argv_prms["workspace_cache_files_dir"], "typeIDs")
    sde_inv_names = eve_sde_tools.read_converted(
        argv_prms["workspace_cache_files_dir"], "invNames")
    sde_inv_items = eve_sde_tools.read_converted(
        argv_prms["workspace_cache_files_dir"], "invItems")
    sde_market_groups = eve_sde_tools.read_converted(
        argv_prms["workspace_cache_files_dir"], "marketGroups")

    corps_blueprints = {}
    eve_market_prices_data = None
    various_characters_data = []
    for pilot_name in argv_prms["character_names"]:
        # настройка Eve Online ESI Swagger interface
        auth = esi.EveESIAuth('{}/auth_cache'.format(
            argv_prms["workspace_cache_files_dir"]),
                              debug=True)
        client = esi.EveESIClient(
            auth,
            keep_alive=True,
            debug=argv_prms["verbose_mode"],
            logger=True,
            user_agent='Q.Industrialist v{ver}'.format(ver=__version__))
        interface = esi.EveOnlineInterface(
            client,
            q_industrialist_settings.g_client_scope,
            cache_dir='{}/esi_cache'.format(
                argv_prms["workspace_cache_files_dir"]),
            offline_mode=argv_prms["offline_mode"])

        authz = interface.authenticate(pilot_name)
        character_id = authz["character_id"]
        character_name = authz["character_name"]

        # Public information about a character
        character_data = interface.get_esi_data(
            "characters/{}/".format(character_id), fully_trust_cache=True)
        # Public information about a corporation
        corporation_data = interface.get_esi_data("corporations/{}/".format(
            character_data["corporation_id"]),
                                                  fully_trust_cache=True)

        corporation_id = character_data["corporation_id"]
        corporation_name = corporation_data["name"]
        print("\n{} is from '{}' corporation".format(character_name,
                                                     corporation_name))
        sys.stdout.flush()

        various_characters_data.append({str(corporation_id): character_data})

        if eve_market_prices_data is None:
            try:
                # Public information about market prices
                eve_market_prices_data = interface.get_esi_data(
                    "markets/prices/")
                print("\nEVE market has {} prices".format(
                    len(eve_market_prices_data) if not (
                        eve_market_prices_data is None) else 0))
                sys.stdout.flush()
            except requests.exceptions.HTTPError as err:
                status_code = err.response.status_code
                if status_code == 404:  # 2020.12.03 поломался доступ к ценам маркета (ССР-шники "внесли правки")
                    eve_market_prices_data = []
                else:
                    raise
            except:
                print(sys.exc_info())
                raise

        # Requires role(s): Director
        corp_assets_data = interface.get_esi_paged_data(
            "corporations/{}/assets/".format(corporation_id))
        print("\n'{}' corporation has {} assets".format(
            corporation_name, len(corp_assets_data)))
        sys.stdout.flush()

        # Requires role(s): Director
        corp_blueprints_data = interface.get_esi_paged_data(
            "corporations/{}/blueprints/".format(corporation_id))
        print("\n'{}' corporation has {} blueprints".format(
            corporation_name, len(corp_blueprints_data)))
        sys.stdout.flush()

        # Requires role(s): Factory_Manager
        corp_industry_jobs_data = interface.get_esi_paged_data(
            "corporations/{}/industry/jobs/".format(corporation_id))
        print("\n'{}' corporation has {} industry jobs".format(
            corporation_name, len(corp_industry_jobs_data)))
        sys.stdout.flush()

        # Получение названий контейнеров, станций, и т.п. - всё что переименовывается ingame
        corp_ass_named_ids = eve_esi_tools.get_assets_named_ids(
            corp_assets_data)
        # Requires role(s): Director
        corp_ass_names_data = interface.get_esi_piece_data(
            "corporations/{}/assets/names/".format(corporation_id),
            corp_ass_named_ids)
        print("\n'{}' corporation has {} custom asset's names".format(
            corporation_name, len(corp_ass_names_data)))
        sys.stdout.flush()
        del corp_ass_named_ids

        # Поиск тех станций, которые не принадлежат корпорации (на них имеется офис, но самой станции в ассетах нет)
        foreign_structures_data = {}
        foreign_structures_ids = eve_esi_tools.get_foreign_structures_ids(
            corp_assets_data)
        foreign_structures_forbidden_ids = []
        if len(foreign_structures_ids) > 0:
            # Requires: access token
            for structure_id in foreign_structures_ids:
                try:
                    universe_structure_data = interface.get_esi_data(
                        "universe/structures/{}/".format(structure_id),
                        fully_trust_cache=True)
                    foreign_structures_data.update(
                        {str(structure_id): universe_structure_data})
                except requests.exceptions.HTTPError as err:
                    status_code = err.response.status_code
                    if status_code == 403:  # это нормально, что часть структур со временем могут оказаться Forbidden
                        foreign_structures_forbidden_ids.append(structure_id)
                    else:
                        raise
                except:
                    print(sys.exc_info())
                    raise
        print("\n'{}' corporation has offices in {} foreign stations".format(
            corporation_name, len(foreign_structures_data)))
        if len(foreign_structures_forbidden_ids) > 0:
            print(
                "\n'{}' corporation has offices in {} forbidden stations : {}".
                format(corporation_name, len(foreign_structures_forbidden_ids),
                       foreign_structures_forbidden_ids))
        sys.stdout.flush()

        # Requires role(s): access token
        corp_contracts_data = interface.get_esi_paged_data(
            "corporations/{}/contracts/".format(corporation_id))
        print("\n'{}' corporation has {} contracts".format(
            corporation_name, len(corp_contracts_data)))
        sys.stdout.flush()

        # Получение подробной информации о каждому из контракту в списке
        corp_contract_items_data = []
        corp_contract_items_len = 0
        corp_contract_items_not_found = []
        if len(corp_contracts_data) > 0:
            # Requires: access token
            for c in corp_contracts_data:
                # для удалённых контрактов нельзя загрузить items (см. ниже 404-ошибку), поэтому пропускаем запись
                if c["status"] == "deleted":
                    continue
                # в рамках работы с чертежами, нас интересует только набор контрактов, в которых продаются чертежи
                # ищем публичные контракты типа "обмен предметами"
                if (c["availability"] != "public") or (c["type"] !=
                                                       "item_exchange"):
                    continue
                # пропускаем контракты на продажу, которые выставили не мы
                # эту настройку лучше не трогать, т.к. во FRT например 12'000 контрактов, следовательно
                # это повлечёт загрузку 12'000 items и 12'000 issuers
                if c['issuer_corporation_id'] != corporation_id:
                    continue
                contract_id = c["contract_id"]
                try:
                    __contract_items = interface.get_esi_data(
                        "corporations/{}/contracts/{}/items/".format(
                            corporation_id, contract_id),
                        fully_trust_cache=True)
                    corp_contract_items_len += len(__contract_items)
                    corp_contract_items_data.append(
                        {str(contract_id): __contract_items})
                except requests.exceptions.HTTPError as err:
                    status_code = err.response.status_code
                    if status_code == 404:  # это нормально, что часть доп.инфы по контрактам может быть не найдена!
                        corp_contract_items_not_found.append(contract_id)
                    else:
                        raise
                except:
                    print(sys.exc_info())
                    raise
                # Получение сведений о пилотах, вовлечённых в работу с контрактом
                issuer_id = c["issuer_id"]
                __issuer_dict = next(
                    (i for i in various_characters_data
                     if int(list(i.keys())[0]) == int(issuer_id)), None)
                if __issuer_dict is None:
                    # Public information about a character
                    issuer_data = interface.get_esi_data(
                        "characters/{}/".format(issuer_id),
                        fully_trust_cache=True)
                    various_characters_data.append(
                        {str(issuer_id): issuer_data})
                sys.stdout.flush()
        eve_esi_tools.dump_debug_into_file(
            argv_prms["workspace_cache_files_dir"],
            "corp_contract_items_data.{}".format(corporation_name),
            corp_contract_items_data)
        eve_esi_tools.dump_debug_into_file(
            argv_prms["workspace_cache_files_dir"], "various_characters_data",
            various_characters_data)  # сохраняем м.б. многократно

        print("\n'{}' corporation has {} items in contracts".format(
            corporation_name, corp_contract_items_len))
        if len(corp_contract_items_not_found) > 0:
            print("'{}' corporation has {} contracts without details : {}".
                  format(corporation_name, len(corp_contract_items_not_found),
                         corp_contract_items_not_found))
        sys.stdout.flush()

        # Построение дерева ассетов, с узлави в роли станций и систем, и листьями в роли хранящихся
        # элементов, в виде:
        # { location1: {items:[item1,item2,...],type_id,location_id},
        #   location2: {items:[item3],type_id} }
        corp_assets_tree = eve_esi_tools.get_assets_tree(
            corp_assets_data,
            foreign_structures_data,
            sde_inv_items,
            virtual_hierarchy_by_corpsag=False)
        eve_esi_tools.dump_debug_into_file(
            argv_prms["workspace_cache_files_dir"],
            "corp_assets_tree.{}".format(corporation_name), corp_assets_tree)

        # Построение дерева имущества (сводная информация, учитывающая объёмы и ориентировочную стоимость asset-ов)
        print("\nBuilding {} blueprints stat...".format(corporation_name))
        sys.stdout.flush()
        corp_blueprints, blueprints_locations = __build_blueprints(
            corp_blueprints_data, corp_industry_jobs_data,
            eve_market_prices_data, corp_contracts_data,
            corp_contract_items_data, various_characters_data, sde_type_ids,
            sde_inv_names, sde_inv_items, sde_market_groups, corp_assets_tree,
            corp_ass_names_data, foreign_structures_data)

        corp_blueprints.sort(key=lambda bp: bp["name"])

        corps_blueprints.update({
            str(corporation_id): {
                "corporation": corporation_name,
                "blueprints": corp_blueprints,
                "locations": blueprints_locations
            }
        })

    eve_esi_tools.dump_debug_into_file(argv_prms["workspace_cache_files_dir"],
                                       "corps_blueprints", corps_blueprints)

    print("\nBuilding blueprints reports...")
    sys.stdout.flush()

    render_html_blueprints.dump_blueprints_into_report(
        # путь, где будет сохранён отчёт
        argv_prms["workspace_cache_files_dir"],
        # данные, полученные в результате анализа и перекомпоновки входных списков
        corps_blueprints)

    # Вывод в лог уведомления, что всё завершилось (для отслеживания с помощью tail)
    print("\nDone")
Example #9
0
def main():
    qidb = __get_db_connection()
    try:
        module_settings = qidb.load_module_settings(g_module_default_settings,
                                                    g_module_default_types)
        db_monthly_jobs = qidb.select_all_rows(
            "SELECT wmj_quantity,wmj_eft,wmj_conveyor "
            "FROM workflow_monthly_jobs "
            "WHERE wmj_active;")
        db_factory_containers = qidb.select_all_rows(
            "SELECT wfc_id,wfc_name,wfc_active,wfc_disabled,wfc_station_num "
            "FROM workflow_factory_containers;")

        db_monthly_jobs = [{
            "eft": wmj[1],
            "quantity": wmj[0],
            "conveyor": bool(wmj[2])
        } for wmj in db_monthly_jobs]
        db_factory_containers = [{
            "id": wfc[0],
            "name": wfc[1],
            "active": wfc[2],
            "disabled": wfc[3],
            "station_num": wfc[4]
        } for wfc in db_factory_containers]

        # работа с параметрами командной строки, получение настроек запуска программы, как то: работа в offline-режиме,
        # имя пилота ранее зарегистрированного и для которого имеется аутентификационный токен, регистрация нового и т.д.
        argv_prms = console_app.get_argv_prms()

        # настройка Eve Online ESI Swagger interface
        auth = esi.EveESIAuth('{}/auth_cache'.format(
            argv_prms["workspace_cache_files_dir"]),
                              debug=True)
        client = esi.EveESIClient(
            auth,
            keep_alive=True,
            debug=argv_prms["verbose_mode"],
            logger=True,
            user_agent='Q.Industrialist v{ver}'.format(ver=__version__))
        interface = esi.EveOnlineInterface(
            client,
            q_industrialist_settings.g_client_scope,
            cache_dir='{}/esi_cache'.format(
                argv_prms["workspace_cache_files_dir"]),
            offline_mode=argv_prms["offline_mode"])

        authz = interface.authenticate(argv_prms["character_names"][0])
        character_id = authz["character_id"]
        character_name = authz["character_name"]

        sde_type_ids = eve_sde_tools.read_converted(
            argv_prms["workspace_cache_files_dir"], "typeIDs")
        sde_inv_names = eve_sde_tools.read_converted(
            argv_prms["workspace_cache_files_dir"], "invNames")
        sde_bp_materials = eve_sde_tools.read_converted(
            argv_prms["workspace_cache_files_dir"], "blueprints")
        sde_market_groups = eve_sde_tools.read_converted(
            argv_prms["workspace_cache_files_dir"], "marketGroups")
        sde_named_type_ids = eve_sde_tools.convert_sde_type_ids(sde_type_ids)

        # удаление из списка чертежей тех, которые не published (надо соединить typeIDs и blueprints, отбросив часть)
        for t in [
                t for t in sde_type_ids if t in sde_bp_materials.keys()
                and sde_type_ids[t].get('published') == False
        ]:
            del sde_bp_materials[t]

        # Public information about a character
        character_data = interface.get_esi_data(
            "characters/{}/".format(character_id), fully_trust_cache=True)
        # Public information about a corporation
        corporation_data = interface.get_esi_data("corporations/{}/".format(
            character_data["corporation_id"]),
                                                  fully_trust_cache=True)

        corporation_id = character_data["corporation_id"]
        corporation_name = corporation_data["name"]
        print("\n{} is from '{}' corporation".format(character_name,
                                                     corporation_name))
        sys.stdout.flush()

        # Requires role(s): Factory_Manager
        corp_industry_jobs_data = interface.get_esi_paged_data(
            "corporations/{}/industry/jobs/".format(corporation_id))
        print("\n'{}' corporation has {} industry jobs".format(
            corporation_name, len(corp_industry_jobs_data)))
        sys.stdout.flush()

        # строим данные для генерации отчёта
        corp_industry_stat = __build_industry(
            # настройки и подключение к БД
            qidb,
            module_settings,
            # sde данные, загруженные из .converted_xxx.json файлов
            sde_type_ids,
            sde_bp_materials,
            sde_market_groups,
            sde_named_type_ids,
            # esi данные, загруженные с серверов CCP
            corp_industry_jobs_data)
        eve_esi_tools.dump_debug_into_file(
            argv_prms["workspace_cache_files_dir"], "corp_industry_stat",
            corp_industry_stat)
    except:
        print(sys.exc_info())
        sys.exit(1)  # errno.h : EPERM=1 /* Operation not permitted */
    del qidb

    # вывод отчёта на экран
    print("\n'{}' corporation has {} new jobs since last update".format(
        corporation_name, corp_industry_stat["new_jobs_found"]))
    sys.stdout.flush()

    # для того, чтобы получить названия коробок и в каком ангаре они расположены, надо загрузить
    # данные по ассетам, т.к. только в этих данных можно учитывая иерархию пересчитать коробки
    # в нужном ангаре

    # Requires role(s): Director
    corp_assets_data = interface.get_esi_paged_data(
        "corporations/{}/assets/".format(corporation_id))
    print("\n'{}' corporation has {} assets".format(corporation_name,
                                                    len(corp_assets_data)))
    sys.stdout.flush()

    # Получение названий контейнеров, станций, и т.п. - всё что переименовывается ingame
    corp_ass_named_ids = eve_esi_tools.get_assets_named_ids(corp_assets_data)
    # Requires role(s): Director
    corp_ass_names_data = interface.get_esi_piece_data(
        "corporations/{}/assets/names/".format(corporation_id),
        corp_ass_named_ids)
    print("\n'{}' corporation has {} custom asset's names".format(
        corporation_name, len(corp_ass_names_data)))
    sys.stdout.flush()
    del corp_ass_named_ids

    # Поиск тех станций, которые не принадлежат корпорации (на них имеется офис, но самой станции в ассетах нет)
    foreign_structures_data = {}
    foreign_structures_ids = eve_esi_tools.get_foreign_structures_ids(
        corp_assets_data)
    foreign_structures_forbidden_ids = []
    if len(foreign_structures_ids) > 0:
        # Requires: access token
        for structure_id in foreign_structures_ids:
            try:
                universe_structure_data = interface.get_esi_data(
                    "universe/structures/{}/".format(structure_id),
                    fully_trust_cache=True)
                foreign_structures_data.update(
                    {str(structure_id): universe_structure_data})
            except requests.exceptions.HTTPError as err:
                status_code = err.response.status_code
                if status_code == 403:  # это нормально, что часть структур со временем могут оказаться Forbidden
                    foreign_structures_forbidden_ids.append(structure_id)
                else:
                    raise
            except:
                print(sys.exc_info())
                raise
    print("\n'{}' corporation has offices in {} foreign stations".format(
        corporation_name, len(foreign_structures_data)))
    if len(foreign_structures_forbidden_ids) > 0:
        print("\n'{}' corporation has offices in {} forbidden stations : {}".
              format(corporation_name, len(foreign_structures_forbidden_ids),
                     foreign_structures_forbidden_ids))
    sys.stdout.flush()

    factories_containers = __get_blueprints_containers(
        module_settings, sde_type_ids, sde_inv_names, corp_assets_data,
        foreign_structures_data, corp_ass_names_data)
    # обновление данных в БД (названия контейнеров, и первичное автозаполнение)
    for factory_containers in factories_containers:
        station_num = factory_containers["station_num"]
        __actualize_factory_containers(db_factory_containers,
                                       factory_containers["containers"],
                                       station_num)

        print(
            '\nFound factory station {} with containers in hangars...'.format(
                factory_containers["station_name"]))
        print('  {} = {}'.format(factory_containers["station_id"],
                                 factory_containers["station_name"]))
        print('  blueprint hangars = {}'.format(
            factory_containers["hangars_filter"]))
        print('  blueprint containers = {}'.format(
            len(factory_containers["containers"])))
        print('  database containers = {}'.format(
            len([
                dfc["id"] for dfc in db_factory_containers
                if dfc['station_num'] == station_num
            ])))
    sys.stdout.flush()

    # Requires role(s): Director
    corp_blueprints_data = interface.get_esi_paged_data(
        "corporations/{}/blueprints/".format(corporation_id))
    print("\n'{}' corporation has {} blueprints".format(
        corporation_name, len(corp_blueprints_data)))
    sys.stdout.flush()

    # формирование набора данных для построения отчёта
    corp_manufacturing_scheduler = __get_monthly_manufacturing_scheduler(
        # данные полученные из БД
        db_monthly_jobs,
        db_factory_containers,
        # sde данные загруженные из .converted_xxx.json файлов
        sde_type_ids,
        sde_named_type_ids,
        sde_bp_materials,
        sde_market_groups,
        # esi данные загруженные с серверов CCP
        corp_blueprints_data,
        corp_industry_jobs_data,
        # данные полученные в результате анализа и перекомпоновки входных списков
        factories_containers)
    eve_esi_tools.dump_debug_into_file(argv_prms["workspace_cache_files_dir"],
                                       "corp_manufacturing_scheduler",
                                       corp_manufacturing_scheduler)

    print('\nFound in {} stations...'.format(len(factories_containers)))
    print('  scheduled blueprints = {}'.format(
        len(corp_manufacturing_scheduler["scheduled_blueprints"])))
    print('  factory repository = {}'.format(
        len(corp_manufacturing_scheduler["factory_repository"])))
    print('  factory blueprints = {}'.format(
        len(corp_manufacturing_scheduler["factory_blueprints"])))
    sys.stdout.flush()

    print("\nBuilding workflow report...")
    sys.stdout.flush()

    render_html_workflow.dump_workflow_into_report(
        # путь, где будет сохранён отчёт
        argv_prms["workspace_cache_files_dir"],
        # sde данные, загруженные из .converted_xxx.json файлов
        sde_type_ids,
        sde_market_groups,
        # данные, полученные в результате анализа и перекомпоновки входных списков
        corp_manufacturing_scheduler)

    print("\nBuilding industry report...")
    sys.stdout.flush()

    render_html_industry.dump_industry_into_report(
        # путь, где будет сохранён отчёт
        argv_prms["workspace_cache_files_dir"],
        # sde данные, загруженные из .converted_xxx.json файлов
        sde_type_ids,
        # данные, полученные в результате анализа и перекомпоновки входных списков
        corp_industry_stat)

    # Вывод в лог уведомления, что всё завершилось (для отслеживания с помощью tail)
    print("\nDone")
Example #10
0
def main():
    try:
        # работа с параметрами командной строки, получение настроек запуска программы, как то: имена пилотов ранее
        # зарегистрированных и для которыйх имеется аутентификационные токены, регистрация нового и т.д.
        # настройка offline_mode игнорируется, скрипт всегда работает в --online режиме
        argv_prms = console_app.get_argv_prms()
    except:
        sys.exit(22)  # Unit errno.h : EINVAL=22 /* Invalid argument */

    # Вывод в лог уведомления, что всё завершилось (для отслеживания с помощью tail)
    print("\nStarting preload commonly used data...\n")

    try:
        eve_market_prices_data = None
        various_characters_data = {}
        various_corporations_data = {}
        markets_analyzer_first_time = True
        for pilot_name in argv_prms["character_names"]:
            # настройка Eve Online ESI Swagger interface
            auth = esi.EveESIAuth('{}/auth_cache'.format(
                argv_prms["workspace_cache_files_dir"]),
                                  debug=True)
            client = esi.EveESIClient(
                auth,
                keep_alive=True,
                debug=argv_prms["verbose_mode"],
                logger=True,
                user_agent='Q.Industrialist v{ver}'.format(ver=__version__))
            interface = esi.EveOnlineInterface(
                client,
                q_industrialist_settings.g_client_scope,
                cache_dir='{}/esi_cache'.format(
                    argv_prms["workspace_cache_files_dir"]),
                offline_mode=False
            )  # здесь обычно находится параметр argv_prms["offline_mode"]

            authz = interface.authenticate(pilot_name)
            character_id = authz["character_id"]
            character_name = authz["character_name"]

            # Public information about a character
            character_data = interface.get_esi_data(
                "characters/{}/".format(character_id), fully_trust_cache=True)
            # Public information about a corporation
            corporation_data = interface.get_esi_data(
                "corporations/{}/".format(character_data["corporation_id"]),
                fully_trust_cache=True)

            corporation_id = character_data["corporation_id"]
            corporation_name = corporation_data["name"]
            print("{} is from '{}' corporation\n".format(
                character_name, corporation_name))
            sys.stdout.flush()

            various_characters_data.update({str(character_id): character_data})
            various_corporations_data.update(
                {str(corporation_id): corporation_data})

            if eve_market_prices_data is None:
                try:
                    # Public information about market prices
                    eve_market_prices_data = interface.get_esi_data(
                        "markets/prices/")
                    print("\nEVE market has {} prices".format(
                        len(eve_market_prices_data) if not (
                            eve_market_prices_data is None) else 0))
                    sys.stdout.flush()
                except requests.exceptions.HTTPError as err:
                    status_code = err.response.status_code
                    if status_code == 404:  # 2020.12.03 поломался доступ к ценам маркета (ССР-шники "внесли правки")
                        eve_market_prices_data = []
                    else:
                        raise
                except:
                    print(sys.exc_info())
                    raise

            try:
                # Requires role(s): Accountant, Junior_Accountant
                corp_wallets_data = interface.get_esi_paged_data(
                    "corporations/{}/wallets/".format(corporation_id))
                print("'{}' corporation has {} wallet divisions\n".format(
                    corporation_name, len(corp_wallets_data)))
                sys.stdout.flush()
            except requests.exceptions.HTTPError as err:
                status_code = err.response.status_code
                if status_code == 500:  # 2021.01.28 поломался доступ к кошелькам, Internal Server Error
                    corp_wallets_data = []
                else:
                    raise
            except:
                print(sys.exc_info())
                raise

            # Requires role(s): Accountant, Junior_Accountant
            corp_wallet_journal_data = [
                None, None, None, None, None, None, None
            ]
            for w in corp_wallets_data:
                division = w["division"]
                try:
                    corp_wallet_journal_data[
                        division - 1] = interface.get_esi_paged_data(
                            "corporations/{}/wallets/{}/journal/".format(
                                corporation_id, division))
                    print("'{}' corporation has {} wallet#{} transactions\n".
                          format(corporation_name,
                                 len(corp_wallet_journal_data[division - 1]),
                                 division))
                    sys.stdout.flush()
                except requests.exceptions.HTTPError as err:
                    status_code = err.response.status_code
                    if status_code == 404:  # 2020.11.26 поломался доступ к журналу кошелька (ССР-шники "внесли правки")
                        corp_wallet_journal_data[division - 1] = None
                    elif status_code == 500:  # 2021.01.28 поломался доступ к кошелькам, Internal Server Error
                        corp_wallet_journal_data[division - 1] = None
                    else:
                        raise
                except:
                    print(sys.exc_info())
                    raise

            # Requires one of the following EVE corporation role(s): Director
            corp_divisions_data = interface.get_esi_data(
                "corporations/{}/divisions/".format(corporation_id),
                fully_trust_cache=True)
            print(
                "'{}' corporation has {} hangar and {} wallet names\n".format(
                    corporation_name,
                    len(corp_divisions_data["hangar"])
                    if "hangar" in corp_divisions_data else 0,
                    len(corp_divisions_data["wallet"])
                    if "wallet" in corp_divisions_data else 0))
            sys.stdout.flush()

            try:
                # Requires role(s): Director
                corp_shareholders_data = interface.get_esi_paged_data(
                    "corporations/{}/shareholders/".format(corporation_id))
                print("'{}' corporation has {} shareholders\n".format(
                    corporation_name, len(corp_shareholders_data)))
                sys.stdout.flush()
            except requests.exceptions.HTTPError as err:
                status_code = err.response.status_code
                if status_code == 500:  # 2021.01.28 поломался доступ к кошелькам, Internal Server Error
                    corp_shareholders_data = []
                else:
                    raise
            except:
                print(sys.exc_info())
                raise

            for shareholder in corp_shareholders_data:
                # Получение сведений о пилотах, имеющих акции корпорации
                corp_id = None
                if shareholder['shareholder_type'] == 'character':
                    pilot_id = shareholder['shareholder_id']
                    if str(
                            pilot_id
                    ) in various_characters_data:  # пилот м.б. быть в списке с dict=None
                        __pilot_dict = various_characters_data[str(pilot_id)]
                        if __pilot_dict:
                            corp_id = __pilot_dict.get("corporation_id")
                    else:
                        try:
                            # Public information about a character
                            pilot_data = interface.get_esi_data(
                                "characters/{}/".format(pilot_id),
                                fully_trust_cache=True)
                            corp_id = pilot_data["corporation_id"]
                            various_characters_data.update(
                                {str(pilot_id): pilot_data})
                        except requests.exceptions.HTTPError as err:
                            status_code = err.response.status_code
                            if status_code == 404:  # 404 Client Error: Not Found ('Character has been deleted!')
                                various_characters_data.update(
                                    {str(pilot_id): None})
                            else:
                                print(sys.exc_info())
                                raise
                        except:
                            print(sys.exc_info())
                            raise
                        sys.stdout.flush()
                elif shareholder['shareholder_type'] == 'corporation':
                    corp_id = shareholder['shareholder_id']
                # Получение сведений о корпорациях, которым принадлежат акции, либо в которых состоят пилоты
                if corp_id and (str(corp_id) not in various_corporations_data):
                    # Public information about a corporation
                    corp_data = interface.get_esi_data(
                        "corporations/{}/".format(corp_id),
                        fully_trust_cache=True)
                    various_corporations_data.update({str(corp_id): corp_data})
                sys.stdout.flush()

            # Requires role(s): Director
            corp_assets_data = interface.get_esi_paged_data(
                "corporations/{}/assets/".format(corporation_id))
            print("'{}' corporation has {} assets\n".format(
                corporation_name, len(corp_assets_data)))
            sys.stdout.flush()

            # Requires role(s): Director
            corp_blueprints_data = interface.get_esi_paged_data(
                "corporations/{}/blueprints/".format(corporation_id))
            print("'{}' corporation has {} blueprints\n".format(
                corporation_name, len(corp_blueprints_data)))
            sys.stdout.flush()

            # Requires role(s): Factory_Manager
            corp_industry_jobs_data = interface.get_esi_paged_data(
                "corporations/{}/industry/jobs/".format(corporation_id))
            print("'{}' corporation has {} industry jobs\n".format(
                corporation_name, len(corp_industry_jobs_data)))
            sys.stdout.flush()

            # # Requires role(s): Station_Manager
            # corp_structures_data = interface.get_esi_paged_data(
            #     "corporations/{}/structures/".format(corporation_id))
            # print("'{}' corporation has {} structures\n".format(corporation_name, len(corp_structures_data)))
            # sys.stdout.flush()

            # # Requires role(s): Director
            # corp_starbases_data = interface.get_esi_paged_data(
            #     "corporations/{}/starbases/".format(corporation_id))
            # print("'{}' corporation has {} starbases\n".format(corporation_name, len(corp_starbases_data)))
            # sys.stdout.flush()

            # # Requires role(s): Factory_Manager
            # corp_facilities_data = interface.get_esi_paged_data(
            #     "corporations/{}/facilities/".format(corporation_id))
            # print("'{}' corporation has {} facilities\n".format(corporation_name, len(corp_facilities_data)))
            # sys.stdout.flush()

            # # Requires role(s): Director
            # corp_customs_offices_data = interface.get_esi_paged_data(
            #     "corporations/{}/customs_offices/".format(corporation_id))
            # print("'{}' corporation has {} customs offices\n".format(corporation_name, len(corp_customs_offices_data)))
            # sys.stdout.flush()

            # Получение названий контейнеров, станций, и т.п. - всё что переименовывается ingame
            corp_ass_named_ids = eve_esi_tools.get_assets_named_ids(
                corp_assets_data)
            # Requires role(s): Director
            corp_ass_names_data = interface.get_esi_piece_data(
                "corporations/{}/assets/names/".format(corporation_id),
                corp_ass_named_ids)
            print("\n'{}' corporation has {} custom asset's names".format(
                corporation_name, len(corp_ass_names_data)))
            sys.stdout.flush()
            del corp_ass_named_ids

            # Поиск тех станций, которые не принадлежат корпорации (на них имеется офис, но самой станции в ассетах нет)
            foreign_structures_data = {}
            foreign_structures_ids = eve_esi_tools.get_foreign_structures_ids(
                corp_assets_data)
            foreign_structures_forbidden_ids = []
            if len(foreign_structures_ids) > 0:
                # Requires: access token
                for structure_id in foreign_structures_ids:
                    try:
                        universe_structure_data = interface.get_esi_data(
                            "universe/structures/{}/".format(structure_id),
                            fully_trust_cache=True)
                        foreign_structures_data.update(
                            {str(structure_id): universe_structure_data})
                    except requests.exceptions.HTTPError as err:
                        status_code = err.response.status_code
                        if status_code == 403:  # это нормально, что часть структур со временем могут оказаться Forbidden
                            foreign_structures_forbidden_ids.append(
                                structure_id)
                        else:
                            # print(sys.exc_info())
                            raise
                    except:
                        print(sys.exc_info())
                        raise
            print(
                "'{}' corporation has offices in {} foreign stations\n".format(
                    corporation_name, len(foreign_structures_data)))
            if len(foreign_structures_forbidden_ids) > 0:
                print(
                    "'{}' corporation has offices in {} forbidden stations : {}\n"
                    .format(corporation_name,
                            len(foreign_structures_forbidden_ids),
                            foreign_structures_forbidden_ids))
            sys.stdout.flush()

            # Requires role(s): access token
            corp_contracts_data = interface.get_esi_paged_data(
                "corporations/{}/contracts/".format(corporation_id))
            print("'{}' corporation has {} contracts\n".format(
                corporation_name, len(corp_contracts_data)))
            sys.stdout.flush()

            # Получение подробной информации о каждому из контракту в списке
            corp_contract_items_data = []
            corp_contract_items_len = 0
            corp_contract_items_not_found = []
            if len(corp_contracts_data) > 0:
                # Requires: access token
                for c in corp_contracts_data:
                    # для удалённых контрактов нельзя загрузить items (см. ниже 404-ошибку), поэтому пропускаем запись
                    if c["status"] == "deleted":
                        continue
                    # в рамках работы с чертежами, нас интересует только набор контрактов, в которых продаются чертежи
                    # ищем публичные контракты типа "обмен предметами"
                    if c["type"] != "item_exchange":
                        continue
                    # пропускаем контракты на продажу, которые выставили не мы
                    # эту настройку лучше не трогать, т.к. во FRT например 12'000 контрактов, следовательно
                    # это повлечёт загрузку 12'000 items и 12'000 issuers
                    if c['issuer_corporation_id'] != corporation_id:
                        continue
                    contract_id = c["contract_id"]
                    try:
                        __contract_items = interface.get_esi_data(
                            "corporations/{}/contracts/{}/items/".format(
                                corporation_id, contract_id),
                            fully_trust_cache=True)
                        corp_contract_items_len += len(__contract_items)
                        corp_contract_items_data.append(
                            {str(contract_id): __contract_items})
                    except requests.exceptions.HTTPError as err:
                        status_code = err.response.status_code
                        if status_code == 404:  # это нормально, что часть доп.инфы по контрактам может быть не найдена!
                            corp_contract_items_not_found.append(contract_id)
                        else:
                            # print(sys.exc_info())
                            raise
                    except:
                        print(sys.exc_info())
                        raise
                    # Получение сведений о пилотах, вовлечённых в работу с контрактом
                    issuer_id = c["issuer_id"]
                    if str(issuer_id) not in various_characters_data:
                        try:
                            # Public information about a character
                            issuer_data = interface.get_esi_data(
                                "characters/{}/".format(issuer_id),
                                fully_trust_cache=True)
                            various_characters_data.update(
                                {str(issuer_id): issuer_data})
                        except requests.exceptions.HTTPError as err:
                            status_code = err.response.status_code
                            if status_code == 404:  # 404 Client Error: Not Found ('Character has been deleted!')
                                various_characters_data.update(
                                    {str(issuer_id): None})
                            else:
                                print(sys.exc_info())
                                raise
                        except:
                            print(sys.exc_info())
                            raise
                    sys.stdout.flush()
            eve_esi_tools.dump_debug_into_file(
                argv_prms["workspace_cache_files_dir"],
                "corp_contract_items_data.{}".format(corporation_name),
                corp_contract_items_data)

            print("'{}' corporation has {} items in contracts\n".format(
                corporation_name, corp_contract_items_len))
            if len(corp_contract_items_not_found) > 0:
                print(
                    "'{}' corporation has {} contracts without details : {}\n".
                    format(corporation_name,
                           len(corp_contract_items_not_found),
                           corp_contract_items_not_found))
            sys.stdout.flush()

            # Requires: public access
            if markets_analyzer_first_time:
                markets_analyzer_first_time = False
                sde_inv_names = eve_sde_tools.read_converted(
                    argv_prms["workspace_cache_files_dir"], "invNames")
                market_regions = [(int(id), sde_inv_names[id])
                                  for id in sde_inv_names if sde_inv_names[id]
                                  in q_market_analyzer_settings.g_regions]
                del sde_inv_names
                try:
                    # Public information about market prices
                    for (region_id, region_name) in market_regions:
                        markets_region_orders = interface.get_esi_paged_data(
                            "markets/{}/orders/".format(region_id))
                        print("\n{} market has {} orders".format(
                            region_name,
                            len(markets_region_orders)
                            if markets_region_orders else 0))
                        sys.stdout.flush()
                        del markets_region_orders
                except requests.exceptions.HTTPError as err:
                    status_code = err.response.status_code
                    if status_code == 404:  # 2020.12.03 поломался доступ к ценам маркета (ССР-шники "внесли правки")
                        pass
                    else:
                        raise
                except:
                    print(sys.exc_info())
                    raise
                del market_regions

        eve_esi_tools.dump_debug_into_file(
            argv_prms["workspace_cache_files_dir"], "various_characters_data",
            various_characters_data)

        # Вывод в лог уведомления, что всё завершилось (для отслеживания с помощью tail)
        print("\nDone\n")
    except:
        print(sys.exc_info())
        sys.exit(1)  # errno.h : EPERM=1 /* Operation not permitted */
    sys.exit(0)  # code 0, all ok
Example #11
0
def main():
    qidb = __get_db_connection()
    try:
        db_regroup_stock = qidb.select_all_rows(
            "SELECT rs_quantity,rs_eft,rs_station,rs_container "
            "FROM regroup_stock "
            "WHERE rs_active;")

        db_regroup_stock = [{"eft": wmj[1], "q": wmj[0], "station": wmj[2], "container": wmj[3]} for wmj in db_regroup_stock]
    except:
        print(sys.exc_info())
        sys.exit(1)  # errno.h : EPERM=1 /* Operation not permitted */
    del qidb

    # работа с параметрами командной строки, получение настроек запуска программы, как то: работа в offline-режиме,
    # имя пилота ранее зарегистрированного и для которого имеется аутентификационный токен, регистрация нового и т.д.
    argv_prms = console_app.get_argv_prms()

    sde_type_ids = eve_sde_tools.read_converted(argv_prms["workspace_cache_files_dir"], "typeIDs")
    sde_inv_names = eve_sde_tools.read_converted(argv_prms["workspace_cache_files_dir"], "invNames")
    sde_market_groups = eve_sde_tools.read_converted(argv_prms["workspace_cache_files_dir"], "marketGroups")
    sde_named_type_ids = eve_sde_tools.convert_sde_type_ids(sde_type_ids)

    corp_regroup_stats = []
    for pilot_name in argv_prms["character_names"]:
        # настройка Eve Online ESI Swagger interface
        auth = esi.EveESIAuth(
            '{}/auth_cache'.format(argv_prms["workspace_cache_files_dir"]),
            debug=True)
        client = esi.EveESIClient(
            auth,
            keep_alive=True,
            debug=argv_prms["verbose_mode"],
            logger=True,
            user_agent='Q.Industrialist v{ver}'.format(ver=__version__))
        interface = esi.EveOnlineInterface(
            client,
            q_industrialist_settings.g_client_scope,
            cache_dir='{}/esi_cache'.format(argv_prms["workspace_cache_files_dir"]),
            offline_mode=argv_prms["offline_mode"])

        authz = interface.authenticate(pilot_name)
        character_id = authz["character_id"]
        character_name = authz["character_name"]

        # Public information about a character
        character_data = interface.get_esi_data(
            "characters/{}/".format(character_id),
            fully_trust_cache=True)
        # Public information about a corporation
        corporation_data = interface.get_esi_data(
            "corporations/{}/".format(character_data["corporation_id"]),
            fully_trust_cache=True)

        corporation_id = character_data["corporation_id"]
        corporation_name = corporation_data["name"]
        print("\n{} is from '{}' corporation".format(character_name, corporation_name))
        sys.stdout.flush()

        # для того, чтобы получить названия коробок и в каком ангаре они расположены, надо загрузить
        # данные по ассетам, т.к. только в этих данных можно учитывая иерархию пересчитать коробки
        # в нужном ангаре

        # Requires role(s): Director
        corp_assets_data = interface.get_esi_paged_data(
            "corporations/{}/assets/".format(corporation_id))
        print("\n'{}' corporation has {} assets".format(corporation_name, len(corp_assets_data)))
        sys.stdout.flush()

        # Получение названий контейнеров, станций, и т.п. - всё что переименовывается ingame
        corp_ass_named_ids = eve_esi_tools.get_assets_named_ids(corp_assets_data)
        # Requires role(s): Director
        corp_ass_names_data = interface.get_esi_piece_data(
            "corporations/{}/assets/names/".format(corporation_id),
            corp_ass_named_ids)
        print("\n'{}' corporation has {} custom asset's names".format(corporation_name, len(corp_ass_names_data)))
        sys.stdout.flush()
        del corp_ass_named_ids

        # Поиск тех станций, которые не принадлежат корпорации (на них имеется офис, но самой станции в ассетах нет)
        foreign_structures_data = {}
        foreign_structures_ids = eve_esi_tools.get_foreign_structures_ids(corp_assets_data)
        foreign_structures_forbidden_ids = []
        if len(foreign_structures_ids) > 0:
            # Requires: access token
            for structure_id in foreign_structures_ids:
                try:
                    universe_structure_data = interface.get_esi_data(
                        "universe/structures/{}/".format(structure_id),
                        fully_trust_cache=True)
                    foreign_structures_data.update({str(structure_id): universe_structure_data})
                except requests.exceptions.HTTPError as err:
                    status_code = err.response.status_code
                    if status_code == 403:  # это нормально, что часть структур со временем могут оказаться Forbidden
                        foreign_structures_forbidden_ids.append(structure_id)
                    else:
                        raise
                except:
                    print(sys.exc_info())
                    raise
        print(
            "\n'{}' corporation has offices in {} foreign stations".format(corporation_name, len(foreign_structures_data)))
        if len(foreign_structures_forbidden_ids) > 0:
            print("\n'{}' corporation has offices in {} forbidden stations : {}".format(corporation_name, len(
                foreign_structures_forbidden_ids), foreign_structures_forbidden_ids))
        sys.stdout.flush()

        # строим данные для генерации отчёта
        corp_regroup_stat = __build_regroup(
            # настройки из БД
            db_regroup_stock,
            # sde данные, загруженные из .converted_xxx.json файлов
            sde_type_ids,
            sde_inv_names,
            sde_market_groups,
            sde_named_type_ids,
            # esi данные, загруженные с серверов CCP
            corp_assets_data,
            foreign_structures_data,
            corp_ass_names_data)

        # обновление данных в БД (названия контейнеров, и первичное автозаполнение)
        for stock_containers in corp_regroup_stat["regroup_containers"]:
            cntnrs = stock_containers["containers"]
            print('\nFound station {} with containers...'.format(stock_containers["station_name"]))
            print('  {} = {}'.format(stock_containers["station_id"], stock_containers["station_name"]))
            print('  regroup containers = {}'.format([(c['id'], c['name']) for c in cntnrs]))
        sys.stdout.flush()

        eve_esi_tools.dump_debug_into_file(argv_prms["workspace_cache_files_dir"], "corp_regroup_stat.{}".format(corporation_name), corp_regroup_stat)

        corp_regroup_stat.update({"corporation_name": corporation_name})
        corp_regroup_stats.append(corp_regroup_stat)

    # освобождаем память от ненужных более списков
    del sde_inv_names
    del sde_named_type_ids

    print("\nBuilding regroup report...")
    sys.stdout.flush()

    render_html_regroup.dump_regroup_into_report(
        # путь, где будет сохранён отчёт
        argv_prms["workspace_cache_files_dir"],
        # sde данные, загруженные из .converted_xxx.json файлов
        sde_type_ids,
        sde_market_groups,
        # данные, полученные в результате анализа и перекомпоновки входных списков
        corp_regroup_stats
    )

    # Вывод в лог уведомления, что всё завершилось (для отслеживания с помощью tail)
    print("\nDone")