Files
contracts/testgen/pools.py
T

114 lines
6.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
pools.py — Пулы данных для генератора тестовых документов.
Схема Опуса: 10 компаний, пул из ~12 услуг, цены ±20% от базовых,
вариативность дат, номеров, названий.
Все данные основаны на реальных файлах из примеры_договоров_для_ИИ/.
"""
import random
# ── Компании ─────────────────────────────────────────────────
COMPANIES = [
{"prefix": "XXX001", "legal": 'ЗАО "XXX001"', "dir": "Генерального директора"},
{"prefix": "XXX002", "legal": 'ООО "XXX002"', "dir": "Генерального директора"},
{"prefix": "XXX003", "legal": 'АО "XXX003"', "dir": "Директора"},
{"prefix": "XXX004", "legal": 'ПАО "XXX004"', "dir": "Генерального директора"},
{"prefix": "XXX005", "legal": 'ООО "XXX005"', "dir": "Директора"},
{"prefix": "XXX006", "legal": 'ЗАО "XXX006"', "dir": "Генерального директора"},
{"prefix": "XXX007", "legal": 'АО "XXX007"', "dir": "Директора"},
{"prefix": "XXX008", "legal": 'ООО "XXX008"', "dir": "Генерального директора"},
{"prefix": "XXX009", "legal": 'ИП "XXX009"', "dir": "Индивидуального предпринимателя"},
{"prefix": "XXX010", "legal": 'ПАО "XXX010"', "dir": "Генерального директора"},
# Кириллический edge (уже есть в примерах)
{"prefix": "ХХХ002", "legal": 'ООО "ХХХ002"', "dir": "Генерального директора"},
]
PROVIDER = 'ООО "НУБЕС"'
PROVIDER_DIR = "Генерального директора Степаненко В.И."
CITY = "г. Москва"
ADDRESS = "115404, г. Москва, 1-я Стекольная 7с5"
# ── Номера договоров ─────────────────────────────────────────
# Базовые номера из примеров + вариации
BASE_NUMBERS = ["03700", "01200", "01300", "04100", "05200", "06800", "07400", "08100", "09900", "10500"]
def contract_number(company_idx, variant=0):
"""Сгенерировать номер договора: БАЗА[_суффикс]."""
base = BASE_NUMBERS[company_idx % len(BASE_NUMBERS)]
if variant > 0:
return f"{base}_{variant}"
return base
# ── Даты ─────────────────────────────────────────────────────
def random_date(base_year=2025, base_month=12, spread_months=7):
"""Случайная дата ±spread_months от базовой. Возвращает DD.MM.YYYY."""
import datetime
base = datetime.date(base_year, base_month, 1)
offset = random.randint(0, spread_months * 30)
d = base + datetime.timedelta(days=offset)
return d.strftime("%d.%m.%Y")
# ── Пул услуг и базовых цен (из реальных файлов) ────────────
# (наименование, базовая_цена, мин_объём, макс_объём, категория)
# категория: 'rack' | 'power' | 'network' | 'cloud' | 'ip' | 'cross'
SERVICES = [
("Аренда стойко-места", 213905.44, 1, 5, "rack"),
("Аренда PDU: 3Ф 32А вертикальный", 2511.17, 1, 5, "power"),
("Организация L2 канала без резерва, в составе:\n Скорость порта: 1 Гбит/с", 11016.36, 1, 3, "network"),
("Организация L2 канала без резерва, в составе:\n Скорость порта: 10 Гбит/с", 28300.00, 1, 2, "network"),
("Next Generation Cloud (Intel 3.0 ГГц), в составе:\n Количество vCPU: 8, RAM: 32 ГБ", 76704.00, 1, 3, "cloud"),
("Next Generation Cloud (AMD 4.0 ГГц), в составе:\n Количество vCPU: 4, RAM: 16 ГБ", 123823.00, 1, 2, "cloud"),
("Аренда IPv4 адреса /32", 157.28, 1, 16, "ip"),
("Аренда IPv4 подсети /30", 629.10, 1, 4, "ip"),
("Организация cross-connect: ВОЛС, 2×SMF", 4192.40, 1, 5, "cross"),
("Организация cross-connect: UTP", 840.94, 1, 5, "cross"),
("Интернет без защиты от DDoS, в составе:\n Полоса Интернет: 100 Мбит/с", 7015.00, 1, 3, "network"),
("Аренда порта без резерва, в составе:\n Скорость порта: 1 Гбит/с", 1525.00, 1, 3, "network"),
("Аренда публичной подсети (Длина префикса: /30 — 1 IPv4 адрес)", 589.66, 1, 4, "ip"),
]
# ── Функции вариативности ────────────────────────────────────
def vary_price(base, pct=0.20):
"""Случайное изменение цены ±pct, округление до копеек."""
factor = 1.0 + random.uniform(-pct, pct)
return round(base * factor, 2)
def vary_qty(min_q, max_q):
return random.randint(min_q, max_q)
def format_price(p):
"""Формат цены с пробелами-разделителями: 213 905,44."""
s = f"{p:,.2f}"
# 213,905.44 → 213 905,44
return s.replace(",", " ").replace(".", ",").replace(" ", " ")
def pick_services(count=5, with_prices=True):
"""Выбрать случайный набор услуг. Возвращает [(name, price, qty, sum), ...]."""
selected = random.sample(SERVICES, min(count, len(SERVICES)))
result = []
total = 0.0
for i, (name, base_price, min_q, max_q, cat) in enumerate(selected, 1):
price = vary_price(base_price) if with_prices else base_price
qty = vary_qty(min_q, max_q)
s = round(price * qty, 2)
total += s
result.append({
"num": i,
"name": name,
"price": price,
"price_str": format_price(price),
"qty": qty,
"sum": s,
"sum_str": format_price(s),
"cat": cat,
})
return result, round(total, 2), format_price(round(total, 2))