Про дані Prozorro.Sale

АТ “Прозорро.Продажі” оперує двома інстансами системи електронних аукціонів: ЦБД-1 та нова ЦБД. В різних інстансах в різний час відбувались аукціони  по різних напрямках роботи. Під напрямком мається на увазі групування аукціонів за типом процедури продажу. Наприклад, земельні торги або лоти малої приватизації. Також існує відключений інстанс ЦБД-2 (архівована). Всі обʼєкти з архівованого інстансу були перенесені на ЦБД-2 нову. У звʼязку з архівацією сутностей ЦБД-2, відбулось приведення структури даних до вигляду, що використовується у новій ЦБД-2.

Основною одиницею даних є процедура аукціону (procedure) - структура, що зберігає в собі:

  • весь перебіг подій одного аукціону від оголошення до остаточного завершення
  • інформацію про об’єкт продажу (item) 
  • інформацію про ставки учасників (bid)
  • інформацію про фінальну ціну (award)
  • інформацію про укладений договір (contract)

Різні типи процедур мають різну структуру даних і бізнес-процеси. Назви частини полів у ЦБД-1 та новій ЦБД відрізняються.

Адреси ЦБД

ЦБД-1

https://public.api.ea.openprocurement.org/api/2/auctions

​​https://public.api.registry.ea.openprocurement.net/api/0.1/assets

ЦБД-2 (ендпоінт виведено з користування)

https://public.api.ea2.openprocurement.net/api/2/auctions

ЦБД-нова [версія]

№1: https://dgf-procedure.prozorro.sale/api

№2: https://procedure.prozorro.sale/api 

Отримання даних

ЦБД-1:

  1. Робимо запит по відповідному ендпоінту
  2. У відповідь отримуємо:
    1. перелік зі 100 ID процедур
    2. посилання на сторінку з наступними 100 ID процедур 
  3. Підставляючи в кінці адреси кожен з отриманих ID і у відповідь отримуємо дані кожної з процедур (наприклад, https://public.api.ea.openprocurement.org/api/2/auctions/8076e2654e2b4865a1b1fd7839e120b4)
  4. Переходимо на сторінку з наступними 100 ID процедур, отриманими на кроці 2.b (перехід за посиланням з uri)

ЦБД-нова:

  1. Переходимо за посиланням https://procedure.prozorro.sale/api/search/byDateModified/2021-01-01?limit=100 - це ендпоінт пошуку по даті зміни, запущений з 1.01.2021 з максимально доступним лімітом (100 записів)
  2. Отримуємо і забираємо повні дані 100 найстаріших процедур
  3. З отриманого сету процедур обираємо ту, що була змінена останньою, беремо значення dateModified для цієї процедури, додаємо до нього одну мілісекунду
  4. Підставляємо отримане значення в посилання з п.1 замість 2021-01-01, таким чином отримуємо наступні 100 процедур (наприклад, https://procedure.prozorro.sale/api/search/byDateModified/2021-01-04T14:15:31.763000Z?limit=100)


import os
import time
import logging
from datetime import datetime, timedelta, timezone

import requests
import pymongo
from dotenv import load_dotenv

load_dotenv()

# Налаштування
MONGO_URI = os.getenv("MONGO_URI", "mongodb://localhost:27017/")
DB_NAME = os.getenv("DB_NAME", "testdb")
COLLECTION_NAME = os.getenv("COLLECTION_NAME", "cbd3_procedures")
BASE_URL = "https://procedure.prozorro.sale/api/search/byDateModified/"
START_DATE = "2021-10-01T00:00:00.000001Z"
LIMIT = 100
REQUEST_TIMEOUT = 30
NO_PROGRESS_LIMIT = 5 # скільки разів підряд можна "не просунутись", перш ніж зупинитись

logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s")
logger = logging.getLogger(__name__)

client = pymongo.MongoClient(MONGO_URI)
db = client[DB_NAME]
collection = db[COLLECTION_NAME]

def parse_z(dt_str: str) -> datetime:
# "2025-05-07T17:25:32.907000Z" -> aware datetime UTC
if dt_str.endswith("Z"):
dt_str = dt_str[:-1]
return datetime.fromisoformat(dt_str).replace(tzinfo=timezone.utc)

def to_z(dt: datetime) -> str:
return dt.astimezone(timezone.utc).isoformat().replace("+00:00", "Z")

def fetch_and_store_data():
date_modified = parse_z(START_DATE)
no_progress_streak = 0
last_url = None

try:
while True:
url = f"{BASE_URL}{to_z(date_modified)}?limit={LIMIT}"
if url == last_url:
no_progress_streak += 1
logger.warning(f"Same URL encountered again ({no_progress_streak}/{NO_PROGRESS_LIMIT}).")
if no_progress_streak >= NO_PROGRESS_LIMIT:
logger.info("No progress guard triggered. Stopping.")
break
else:
no_progress_streak = 0

last_url = url
logger.info(f"Fetching data from: {url}")

try:
resp = requests.get(url, timeout=REQUEST_TIMEOUT)
resp.raise_for_status()
except requests.RequestException as e:
logger.error(f"Request failed: {e}")
break

data = resp.json()

# Порожній або не список — фініш
if not isinstance(data, list) or not data:
logger.info("No more data to fetch. Stopping execution.")
break

# Записуємо/оновлюємо
inserted_count = 0
for item in data:
res = collection.update_one(
{"_id": item["_id"]},
{"$set": item},
upsert=True
)
if res.upserted_id:
inserted_count += 1

logger.info(f"Inserted {inserted_count} new records into MongoDB.")

# Вираховуємо наступний курсор
# Беремо максимальний dateModified з поточної порції
try:
max_date_str = max(obj["dateModified"] for obj in data)
batch_max = parse_z(max_date_str)
except (KeyError, ValueError, TypeError) as e:
logger.error(f"Bad dateModified in response: {e}. Stopping.")
break

next_cursor = max(date_modified, batch_max) + timedelta(microseconds=1)

if next_cursor <= date_modified:
# safety (по ідеї не має спрацьовувати, але лишимо)
no_progress_streak += 1
logger.warning(f"Cursor did not advance (streak {no_progress_streak}/{NO_PROGRESS_LIMIT}).")
if no_progress_streak >= NO_PROGRESS_LIMIT:
logger.info("No progress guard triggered. Stopping.")
break
else:
date_modified = next_cursor
logger.info(f"Next dateModified: {to_z(date_modified)}")

time.sleep(1) # не душимо API
finally:
client.close()

if __name__ == "__main__":
fetch_and_store_data()

Напрями роботи і параметри процедур

Перелік документації по Напрямкам

Зв’язок у Малій приватизації

Приклад стосується ситуації з успішним завершенням приватизації після проведення голландського аукціону після 2х неуспішних англійських аукціонів

#

Об’єкт ЦБД (посилання на обʼєкт)

Зв’язок з пов’язаними об’єктами

1

Об’єкт малої приватизації (реєстр активів)

У моделі relatedEntities є інформація про інформаційне повідомлення, процедури та контрактинг

Інформаційне повідомлення

"type": "announcement",
"_id": "636a1e3fa578bab6c5a503d2",
"objectId": "JAS001-UA-20221108-79790",
"url": "/api/jobber/announcements/jas/636a1e3fa578bab6c5a503d2"

Процедури

"type": "procedure",
"_id": "636cc140b1dfdb8d6a127b79",
"objectId": "SPE001-UA-20221110-77372",
"url": "/api/procedures/636cc140b1dfdb8d6a127b79"

"type": "procedure",
"_id": "6388eba1b2f2c4213d8dc7d7",
"objectId": "SPE001-UA-20221201-56940",
"url": "/api/procedures/6388eba1b2f2c4213d8dc7d7"

"type": "procedure",
"_id": "63961aa41e2baa39a1c7b4d6",
"objectId": "SPD001-UA-20221211-09375",
"url": "/api/procedures/63961aa41e2baa39a1c7b4d6"

Приватизація шляхом викупу

{
"type": "redemption",
"_id": "6920578986a2e00b85d46895",
"objectId": "JRS001-UA-20251121-27082",
"url": "/api/jobber/redemption/jrs/6920578986a2e00b85d46895"
},

Контрактинг

{
"type": "execution",
"_id": "6922fa898cbe832ce875825b",
"objectId": "RES001-UA-20251123-69523",
"url": "/api/registry/executions/6922fa898cbe832ce875825b"
}


2

Інформаційне повідомлення (лот)

У моделі relatedEntities є інформація про об'єкт, з якого було створене інформаційне повідомлення

"relatedEntities": [
	{
		"type": "asset",
		"_id": "6849896fc676880cb7804db3",
		"objectId": "RAS001-UA-20250611-57359",
		"archiveId": "69551665f72d0d83696a815e",
		"url": "/api/registry/assets/6849896fc676880cb7804db3"
	}
],

У моделі producedEntities відображається інформація щодо процедур та контрактингу

"producedEntities": [
	{
		"type": "procedure",
		"_id": "693d37f6a825f3c00e30c374",
		"objectId": "SPE001-UA-20251213-32470",
		"url": "/api/procedures/693d37f6a825f3c00e30c374"
	},
	{
		"type": "execution",
		"_id": "694e8dbd81a94ad9892a9837",
		"objectId": "RES001-UA-20251226-67063",
		"url": "/api/registry/executions/694e8dbd81a94ad9892a9837"
	}
],


3

Англійський аукціон

  1. Зв'язок з інформаційним повідомоеннням та об'єктом переліку через relatedEntities
    1. "type": "asset",
      "_id": "63690dfa9a64799b1865a103",
      "objectId": "RAS001-UA-20221107-02409",
      "url": "/api/registry/assets/63690dfa9a64799b1865a103"
    2. "type": "announcement",
      "_id": "636a1e3fa578bab6c5a503d2",
      "objectId": "JAS001-UA-20221108-79790",
      "url": "/api/jobber/announcements/jas/636a1e3fa578bab6c5a503d2"

4

Англійський аукціон -50%

  1. Зв'язок з інформаційним повідомленнням та об'єктом переліку через relatedEntities
    1. "type": "asset",
      "_id": "63690dfa9a64799b1865a103",
      "objectId": "RAS001-UA-20221107-02409",
      "url": "/api/registry/assets/63690dfa9a64799b1865a103"
    2. "type": "announcement",
      "_id": "636a1e3fa578bab6c5a503d2",
      "objectId": "JAS001-UA-20221108-79790",
      "url": "/api/jobber/announcements/jas/636a1e3fa578bab6c5a503d2"
  2. Зв'язок з попереднім аукціоном
    1. "previousAuctionId": "SPE001-UA-20221110-77372"

5

Голландський аукціон

  1. Зв'язок з інформаційним повідолменнням та об'єктом переліку через relatedEntities
    1. "type": "asset",
      "_id": "63690dfa9a64799b1865a103",
      "objectId": "RAS001-UA-20221107-02409",
      "url": "/api/registry/assets/63690dfa9a64799b1865a103"
    2. "type": "announcement",
      "_id": "636a1e3fa578bab6c5a503d2",
      "objectId": "JAS001-UA-20221108-79790",
      "url": "/api/jobber/announcements/jas/636a1e3fa578bab6c5a503d2"
  2. Зв'язок з попереднім аукціоном
    1. "previousAuctionId": "SPE001-UA-20221201-56940"

6

Об’єкт “контракт” у модулі контрактингу

  1. Зв'язок з іншими сутностями малої приватизації через relatedEntities 
    1. об'єкт переліку
      "type": "asset",
      "_id": "63690dfa9a64799b1865a103",
      "objectId": "RAS001-UA-20221107-02409",
      "url": "/api/registry/assets/63690dfa9a64799b1865a103"
    2. інформаціне повідомлення
      "type": "announcement",
      "_id": "636a1e3fa578bab6c5a503d2",
      "objectId": "JAS001-UA-20221108-79790",
      "url": "/api/jobber/announcements/jas/636a1e3fa578bab6c5a503d2"
    3. Остання процедура в ланцюжку
      "type": "procedure",
      "_id": "63961aa41e2baa39a1c7b4d6",
      "objectId": "SPD001-UA-20221211-09375",
      "url": "/api/procedures/63961aa41e2baa39a1c7b4d6"

Зв’язок обʼєктів у Оренді державного і комунального майна

Існує звʼязок на рівні "child - parent" для об'єктів, які задіяні в напрямку Оренди.




1Обʼєкт реєстру Оренди (registry)

В JSON відсутня інформація про Аукціони (procedure), Дії (action) та Запити (lease_request) повʼязані з конкретним Обʼєктом реєстру оренди

Приклад

2Процедура Оренди державного і комунального майна

В Процедурі можна побачити ID Обʼєкта Оренди, до якого створена Процедура в рядках

"registryObjectId": "RGL001-UA-20210120-44798",
"registryId": "6007f7e32b861d45c3e79c96",

Приклад

3Дія (action)

В обʼєкті action можна побачити до якого Обʼєкта реєстру Оренди було створено Дію:

"relatedEntity": [
	{
		"id": "6682aa481182d660e419acd8",
		"entity_type": "registry"
	}
]

Приклад

4Заявка (lease_request)

В обʼєкті lease_request можна побачити до якого Обʼєкта реєстру Оренди було створено Заявку:

"relatedObjectId": "6437b40c93f1fc621ad67df7"

Приклад

Статуси

В усіх джерелах поле status

Бізнес назва

ЦБД-1

ЦБД-нова

Прийняття заяв на участь

active.tendering

active_tendering

Період редагування

-

active_rectification

Аукціон

active.auction

active_auction

Очікується опублікування протоколу

active.qualification

active_qualification

Очікується підписання договору

active.awarded

active_awarded

Очікується оплата

pending.payment

pending_payment

Очікується рішення про викуп

pending.admission

pending_admission

Аукціон завершено. Договір підписано

complete

complete

Аукціон відмінено

cancelled

cancelled

Аукціон не відбувся

unsuccessful

unsuccessful

Період уточнень

active.enquiry

active_enquiry

Анонімізація даних на час військового стану

На час військового стану запроваджена можливість анонімізувати дані у публічно доступних ендпоїнтах. Передбачено два рівні анонімізації: часткова (medium) та повна (hight). Ідентифікувати сутності ЦБД для яких застосована анонімізація можна по  значенню параметру _protected=true. За рівень анонімізації відповідає _protect_level. Повний доступ зберігається у організатора процедури та учасників процедури

Часткова анонімізація передбачає приховання всієї інформації про учасиків процедури та протоколу процедури. Приклад процедури з частковою анонімізацією: https://procedure.prozorro.sale/api/procedures/62ea4c490174727332f8b0d1

Повна анонімізація, додатково до інформації що прихована у сежах часткової анонімізації, приховує дані про організатора та інформацію про об'єкт. Приклад об'єкту переліку оренди: https://procedure.prozorro.sale/api/registry/objects/5f9fb808aa56594a84909f65

Після завершення військового стану всі анонімізовані дані стануть загальнодоступними.

Архів ЦБД-2

З метою уніфікації моделі даних та збільшення ефективністі роботи з даними, усі сутності ЦБД-2 старої приведені до вигляду відповідних сутностей ЦБД-2 нова, та мігровані на ЦБД-2 нову.

Для мігрованих обʼєктів процедур додано поле sellingMethod, яке було відсутнє на ЦБД-2. Змігровані процедури можна ідентифікувати по префіксу legacy

Для процедур збережений ідентифікатор auctionId без змін. Машиночитний ідентифікатор перенесли у поле legacyId

Процедури ЦБД-2 були розподілені за наступними напрямками:

Назва нового sellingMethod ЦБД-нова

Аналог sellingMethod ЦБД-нова

legacySmallPrivatization-english

smallPrivatization-english

legacySmallPrivatization-dutch

smallPrivatization-dutch

legacyBasicSell-english

basicSell-english

legacyBasicSell-dutch

basicSell-dutch

legacyLegitimatePropertyLease-english

legitimatePropertyLease-english

legacyLegitimatePropertyLease-dutch

legitimatePropertyLease-dutch

legacyRegulationsPropertyLease-english

regulationsPropertyLease-english

legacyRegulationsPropertyLease-dutch

regulationsPropertyLease-dutch

legacyBankRuptcy-english

bankRuptcy-english

legacyBankRuptcy-dutch

bankRuptcy-dutch

legacyTimber-english

timber-english

legacyRailwayCargo-english

railwayCargo-english

legacyRailwayCargo-dutch

railwayCargo-dutch

legacySubsoil-english

subsoil-english

legacySubsoil-dutch

subsoil-dutch

legacyLandRental-infinity

landRental-english

legacyCommercialSell-english

commercialSell-english

legacyCommercialSell-dutch

commercialSell-dutch

legacyCommercialPropertyLease-english

commercialPropertyLease-english

legacyCommercialPropertyLease-dutch

commercialPropertyLease-dutch


Приклади змігрованих сутностей:

legacySmallPrivatization-english
legacySmallPrivatization-dutch
legacyBasicSell-english
legacyBasicSell-dutch
legacyLegitimatePropertyLease-english
legacyLegitimatePropertyLease-dutch
legacyRegulationsPropertyLease-english
legacyRegulationsPropertyLease-dutch
legacyBankRuptcy-english
legacyBankRuptcy-dutch
legacyTimber-english
legacyRailwayCargo-english
legacyRailwayCargo-dutch
legacySubsoil-english
legacySubsoil-dutch
legacyLandRental-infinity
legacyCommercialSell-english
legacyCommercialSell-dutch
legacyCommercialPropertyLease-english
legacyCommercialPropertyLease-dutch

legacy_asset
legacy_announcement
redemption-legacy
legacy_execution

Інформація щодо міграції обʼєктів для Майданчиків ТУТ

АРІ-документація

ЦБД-1

http://dgf.api-docs.openprocurement.org/uk/latest/ 

ЦБД-2 (АРХІВОВАНО)

http://dgf.api-docs.ea2.openprocurement.io/en/latest/

http://lease.api-docs.ea2.openprocurement.io/en/latest

http://appraisal-insider.api-docs.ea2.openprocurement.io/en/latest/

ЦБД-2 (оновлена)

№1: https://dgf-procedure.prozorro.sale/api/doc

№2: https://procedure.prozorro.sale/api/doc 

Технічні завдання

ЦБД-1

https://docs.google.com/document/d/1dKg81cEvc_BZtXg-esvhrLvtKcobpgn1MRLYeNAh0ZA 

https://confluence-sale.prozorro.org/pages/viewpage.action?pageId=42730023 

ЦБД-2 (АРХІВОВАНО)

https://docs.google.com/document/d/1GBfFp6CrXtXgcCUbooiemyx_WcxNhaRraQXpYEYCE68 

https://confluence-sale.prozorro.org/pages/viewpage.action?pageId=42729635

ЦБД-нова

ТЗ: Procedure (Сервіс процедур)

Також зі структурою даних для різних процедур можна знайомитись у Swagger: https://procedure-staging.prozorro.sale/api/doc



  • No labels