v1.0.178: генератор тестовых файлов (схема Опуса). 61 файл: 10 контрактов × (договор+спека v1+v2+допники) + ошибки + ZIP + дубликаты. Комментарий в каждом файле.
This commit is contained in:
@@ -0,0 +1,113 @@
|
||||
"""
|
||||
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))
|
||||
Reference in New Issue
Block a user