Базовые понятия Planiqum ¶
Иерархии ¶
Иерархии в Planiqum представляют собой древовидные структуры данных, которые используются для организации и группировки информации. Каждая иерархия имеет:
- Тип (Type) - определяет назначение иерархии (например, планирование, горизонт)
- Уровни (Level) - определяют структуру иерархии (например, DPU, месяц)
- Элементы (Item) - конкретные значения на каждом уровне (например, DPU1, январь)
Пример создания иерархии¶
# Создание типа иерархии
planning_type = Type.objects.create(
key='planning',
shortname='Planning',
description='Planning Hierarchy Type'
)
# Создание уровня иерархии
dpu_level = HierarchyLevel.objects.create(
type=planning_type,
key='dpu',
shortname='dpu',
description='Demand Planning Unit'
)
# Создание элементов иерархии
dpu_item = HierarchyItem.objects.create(
level=dpu_level,
shortname='DPU1',
description='Demand Planning Unit 1'
)
Пример инициализации через seed (hierarchy.yaml):
- model: hierarchy.type
fields:
key: planning
shortname: Планирование
- model: hierarchy.level
fields:
type: [planning]
key: dpu
shortname: Объект планирования спроса
description: ...
# и т.д. для всех уровней
Пример наполнения элементов (data/hierarchy/dpu.csv):
key,shortname,description
DPU1,Объект 1,Описание 1
DPU2,Объект 2,Описание 2
Работа с API¶
- Получить список иерархий:
GET /core/hierarchy/api/types/ - Получить список уровней:
GET /core/hierarchy/api/levels/ - Получить список элементов:
GET /core/hierarchy/api/items/
Подробнее: Работа с API Planiqum
Параметры ¶
Параметры - это контейнеры для хранения данных. Каждый параметр:
- Имеет уникальный ключ и название
- Связан с определенными измерениями
- Содержит одну или несколько мер
- Имеет свою таблицу фактов в базе данных
Пример создания параметра¶
parameter = Parameter.objects.create(
key='parameter1',
shortname='Parameter 1',
description='Parameter 1 Description'
)
# Добавление измерений
parameter.dimensions.add(dpu_dimension, month_dimension)
# Создание меры
measure = ParameterMeasure.objects.create(
parameter=parameter,
type=MEASURE_TYPES_ENUM.FLOAT,
shortname='Qty Measure 1',
description='Qty Measure 1 Description',
key='qty1'
)
# Синхронизация параметра для создания таблицы фактов
parameter.sync()
> **Подробнее:** См. [Синхронизация параметров (для разработчиков)](parameters/sync.md) — технические детали реализации.
Пример инициализации через seed (parameters.yaml):
- model: parameters.dimension
fields:
key: dpu
hierarchy_level: [dpu]
shortname: Объект планирования спроса
- model: parameters.parameter
fields:
key: demand_plan
app_name: demand
shortname: План продаж
dimensions:
- [dpu]
- [horizon__week]
# и т.д. для всех параметров и мер
Работа с API¶
- Получить список параметров:
GET /core/parameters/api/parameters/ - Создать параметр:
POST /core/parameters/api/parameters/
Измерения ¶
Измерения (Dimensions) связывают параметры с иерархиями. Каждое измерение:
- Связано с определенным уровнем иерархии
- Используется для организации данных в таблице фактов
- Имеет уникальный ключ и название
Пример создания измерения¶
dimension = ParameterDimension.objects.create(
key='dpu',
shortname='DPU',
description='Demand Planning Unit Dimension',
hierarchy_level=dpu_level
)
Пример инициализации через seed (parameters.yaml):
- model: parameters.dimension
fields:
key: dpu
hierarchy_level: [dpu]
shortname: Объект планирования спроса
Работа с API¶
- Получить список измерений:
GET /core/parameters/api/dimensions/ - Создать измерение:
POST /core/parameters/api/dimensions/
Меры ¶
Меры (Measures) определяют типы данных, которые могут храниться в параметре. Каждая мера:
- Имеет тип данных (FLOAT, INTEGER и т.д.)
- Имеет уникальный ключ в рамках параметра
- Представлена колонкой в таблице фактов
- Может иметь дополнительные настройки (единицы измерения, валюта и т.д.)
Пример создания меры¶
measure = ParameterMeasure.objects.create(
parameter=parameter,
type=MEASURE_TYPES_ENUM.FLOAT,
shortname='Quantity',
description='Quantity Measure',
key='qty'
)
Пример инициализации через seed (parameters.yaml):
- model: parameters.measure
fields:
key: demand_plan__qty
parameter: [demand_plan]
shortname: Кол-во
Работа с API¶
- Получить список мер:
GET /core/parameters/api/measures/ - Создать меру:
POST /core/parameters/api/measures/
Таблицы фактов ¶
Каждый параметр имеет свою таблицу фактов в базе данных, которая:
- Создается автоматически при синхронизации параметра
- Содержит колонки для каждого измерения (dim_{key})
- Содержит колонки для каждой меры (m_{key})
- Может содержать дополнительные служебные колонки
Пример структуры таблицы фактов¶
CREATE TABLE fact_parameter1 (
dim_dpu INTEGER,
dim_month INTEGER,
m_qty1 FLOAT,
PRIMARY KEY (dim_dpu, dim_month)
);
Пример наполнения фактов (data/facts.csv):
parameter_key,level_dpu,level_month,qty
sales,DPU1,2024-01,100
sales,DPU1,2024-02,120
Работа с API¶
- Получить данные фактов:
GET /core/parameters/api/facts/ - Загрузить данные:
POST /core/parameters/api/facts/
Единицы измерения (UOM) и Валюты (Currency)¶
Общие понятия¶
- UOM (единицы измерения) — позволяют хранить и отображать значения в разных физических единицах (кг, шт, паллеты и т.д.).
- Currency (валюты) — позволяют хранить и отображать значения в разных денежных единицах (RUR, kRUR, mlnRUR и т.д.).
Модели и их поля¶
-
Модель
UOM(единицы измерения):class UOM(models.Model): code = models.CharField(max_length=10) # Код единицы измерения (например, "kg", "pcs") name = models.CharField(max_length=255) # Название единицы измерения description = models.TextField(blank=True) # Описание is_active = models.BooleanField(default=True) # Активна ли единица измерения created_at = models.DateTimeField(auto_now_add=True) # Дата создания updated_at = models.DateTimeField(auto_now=True) # Дата обновления -
Модель
Currency(валюты):class Currency(models.Model): code = models.CharField(max_length=10) # Код валюты (например, "RUR", "USD") name = models.CharField(max_length=255) # Название валюты factor = models.DecimalField(max_digits=20, decimal_places=10) # Коэффициент конвертации is_active = models.BooleanField(default=True) # Активна ли валюта created_at = models.DateTimeField(auto_now_add=True) # Дата создания updated_at = models.DateTimeField(auto_now=True) # Дата обновления -
Модель
ConversionFactor(коэффициенты конвертации):class ConversionFactor(models.Model): element = models.ForeignKey(Element, on_delete=models.CASCADE) # Элемент иерархии uom = models.ForeignKey(UOM, on_delete=models.CASCADE) # Единица измерения factor = models.DecimalField(max_digits=20, decimal_places=10) # Коэффициент конвертации created_at = models.DateTimeField(auto_now_add=True) # Дата создания updated_at = models.DateTimeField(auto_now=True) # Дата обновления
Примеры использования¶
-
Создание единиц измерения:
# Создание единиц измерения kg = UOM.objects.create( code='kg', name='Килограмм', description='Единица измерения массы' ) ton = UOM.objects.create( code='ton', name='Тонна', description='Единица измерения массы (1000 кг)' ) -
Создание валют:
# Создание валют rur = Currency.objects.create( code='RUR', name='Рубль', factor=1.0 # Базовая валюта ) krur = Currency.objects.create( code='kRUR', name='Тысяча рублей', factor=0.001 # 1 RUR = 0.001 kRUR ) -
Создание коэффициентов конвертации:
# Создание коэффициентов конвертации для элемента иерархии ConversionFactor.objects.create( element=dpu_item, uom=kg, factor=1.0 # Базовая единица измерения ) ConversionFactor.objects.create( element=dpu_item, uom=ton, factor=0.001 # 1 кг = 0.001 тонн ) -
Использование в параметрах:
# Создание параметра с поддержкой единиц измерения parameter = Parameter.objects.create( key='production', shortname='Производство', description='Параметр производства' ) # Добавление измерения с поддержкой единиц измерения dpu_level.use_conversion_factors = True dpu_level.save() dimension = ParameterDimension.objects.create( parameter=parameter, hierarchy_level=dpu_level, key='dpu' ) # Создание меры с поддержкой валют measure = ParameterMeasure.objects.create( parameter=parameter, type=MEASURE_TYPES_ENUM.FLOAT, shortname='Количество', description='Количество продукции', key='qty', supports_currency=True )
Особенности работы¶
- Порядок конвертации:
- Сначала применяется конвертация единиц измерения (UOM)
-
Затем применяется конвертация валют (Currency)
-
Коэффициенты конвертации:
- Для валют: коэффициент берется из модели
Currency -
Для UOM: коэффициент берется из модели
ConversionFactorдля конкретного элемента иерархии -
Обработка ошибок:
- Если указана валюта для меры без поддержки валют, возвращается ошибка
- Если указана единица измерения для уровня без поддержки UOM, возвращается ошибка
- Если не найден коэффициент конвертации, возвращается ошибка
Уровни (Level) и поле is_hidden¶
- Поле
is_hiddenопределяет, скрыт ли уровень для обычных пользователей. - Только пользователи с разрешением
view_hidden_levelsвидят скрытые уровни и полеis_hiddenв ответе API. - Обычные пользователи не видят скрытые уровни и не получают поле
is_hiddenв выдаче.
Пример работы с is_hidden через API¶
Для пользователя с разрешением:
[
{ "id": 1, "shortname": "Видимый уровень", "is_hidden": false },
{ "id": 2, "shortname": "Скрытый уровень", "is_hidden": true }
]
Для обычного пользователя:
[
{ "id": 1, "shortname": "Видимый уровень" }
]
Подробная инструкция по работе с API: dev/api_usage.md
Важные моменты¶
- При работе с иерархиями важно правильно определить типы и уровни, так как они определяют структуру данных
- Параметры должны быть синхронизированы после создания или изменения их структуры
- Ключи мер в таблице фактов формируются как
m_{measure.key} - Ключи измерений в таблице фактов формируются как
dim_{dimension.key} - При работе с API ID меры всегда передается в виде строки
- Порядок измерений в ответе API может отличаться от порядка в таблице фактов
Работа с API: формирование URL-адресов¶
В проекте Planiqum используется многоуровневая маршрутизация для построения путей к API. Это важно учитывать при интеграции, написании тестов и разработке новых приложений.
Как формируется путь к endpoint¶
- В корневом urls.py проекта:
path("core/", include("planiqum.core.urls")), - В urls.py ядра:
path("hierarchy/", include("planiqum.core.hierarchy.urls")), - В urls.py приложения (например, hierarchy):
path("api/", include(router.urls)), # router.register(r"levels", ...)
В результате, путь к endpoint для уровней будет:
/core/hierarchy/api/levels/
Аналогично формируются пути для других сущностей: - /core/hierarchy/api/items/ - /core/hierarchy/api/types/ - и т.д.
Важно: При написании тестов и интеграции с API всегда учитывайте все уровни вложенности в urls.py.
Примеры запросов¶
Получить список уровней:
GET /core/hierarchy/api/levels/
Получить список элементов:
GET /core/hierarchy/api/items/
Советы¶
- Если endpoint не найден (404), проверьте структуру urls.py на всех уровнях.
- Для DRF ViewSet-ов используйте router и обращайтесь по соответствующим путям.
Константы ключей стандартных уровней иерархии¶
Для избежания хардкода и унификации работы с уровнями иерархий в проекте используются константы, определённые в horizons.models:
from planiqum.core.horizons.models import (
HORIZON_DAY_LEVEL_KEY,
HORIZON_WEEK_LEVEL_KEY,
HORIZON_MONTH_LEVEL_KEY,
HORIZON_YEAR_LEVEL_KEY,
HORIZON_QUARTER_LEVEL_KEY,
HORIZON_HALF_YEAR_LEVEL_KEY,
)
HORIZON_DAY_LEVEL_KEY = "horizon__day"HORIZON_WEEK_LEVEL_KEY = "horizon__week"HORIZON_MONTH_LEVEL_KEY = "horizon__month"HORIZON_YEAR_LEVEL_KEY = "horizon__year"HORIZON_QUARTER_LEVEL_KEY = "horizon__quarter"HORIZON_HALF_YEAR_LEVEL_KEY = "horizon__half_year"
Используйте эти константы при фильтрации, создании измерений, параметров и другой логике, связанной с уровнями иерархии.