Add organizations v2 API and registry enrichment
All checks were successful
CI/CD Pipeline / Quality Gate (push) Successful in 26s
CI/CD Pipeline / Build and Push Images (push) Successful in 6s
CI/CD Pipeline / Internal Notify (push) Successful in 0s
CI/CD Pipeline / Deploy Dev in Dokploy (push) Successful in 1s

This commit is contained in:
2026-05-06 19:04:46 +02:00
parent f54aa4cb0b
commit 0f17ff6773
62 changed files with 10311 additions and 430 deletions

View File

@@ -0,0 +1,255 @@
from __future__ import annotations
from decimal import Decimal
from apps.parsers.clients.common.schemas import GenericParserItem
from apps.parsers.clients.trudvsem import TrudvsemClient
from apps.parsers.clients.vacancies import (
HHVacanciesClient,
SuperJobVacanciesClient,
VacanciesClient,
VacanciesClientError,
)
from apps.parsers.models import ParserLoadLog
from django.test import SimpleTestCase
from tests.utils import TestHTTPServer
class TrudvsemClientTest(SimpleTestCase):
def test_fetch_vacancies_by_company_inn_uses_company_endpoint(self):
with TestHTTPServer() as server:
server.add_json(
"/vacancies/company/inn/7701000001",
{
"results": {
"vacancies": [
{
"vacancy": {
"id": "trudvsem-1",
"company": {
"inn": "7701000001",
"ogrn": "1027700000001",
"name": "АО Реестр",
},
"job-name": "Инженер",
"salary": {"from": 100000},
}
}
]
}
},
)
client = TrudvsemClient(
base_url=server.base_url,
http_adapter=server.adapter,
)
records = client.fetch_vacancies(
company_inn="7701000001",
limit=100,
offset=0,
)
self.assertEqual(len(records), 1)
self.assertEqual(records[0].external_id, "trudvsem-1")
self.assertEqual(records[0].inn, "7701000001")
self.assertEqual(records[0].ogrn, "1027700000001")
class HHVacanciesClientTest(SimpleTestCase):
def test_fetch_vacancies_maps_hh_items_to_generic_records(self):
with TestHTTPServer() as server:
server.add_json(
"/vacancies",
{
"items": [
{
"id": "123",
"name": "Инженер",
"published_at": "2026-05-06T10:00:00+0300",
"salary": {"from": 120000, "to": 150000},
"employer": {"id": "77", "name": "АО Пример"},
"alternate_url": "https://hh.ru/vacancy/123",
"type": {"name": "Открытая"},
"archived": False,
}
]
},
)
client = HHVacanciesClient(
base_url=server.base_url,
http_adapter=server.adapter,
)
records = client.fetch_vacancies(limit=10, offset=0, text="Инженер")
self.assertEqual(len(records), 1)
record = records[0]
self.assertEqual(record.source, ParserLoadLog.Source.TRUDVSEM)
self.assertEqual(record.external_id, "hh:123")
self.assertEqual(record.title, "Инженер")
self.assertEqual(record.organisation_name, "АО Пример")
self.assertEqual(record.amount, Decimal("120000"))
self.assertEqual(record.url, "https://hh.ru/vacancy/123")
self.assertEqual(record.payload["vacancy_source"], "hh")
def test_fetch_vacancies_tolerates_unexpected_nested_shapes(self):
with TestHTTPServer() as server:
server.add_json(
"/vacancies",
{
"items": [
{
"id": "124",
"name": "Инженер",
"salary": "по договоренности",
"employer": "АО Пример",
"type": "open",
}
]
},
)
client = HHVacanciesClient(
base_url=server.base_url,
http_adapter=server.adapter,
)
records = client.fetch_vacancies(limit=10)
self.assertEqual(len(records), 1)
self.assertEqual(records[0].external_id, "hh:124")
self.assertEqual(records[0].organisation_name, "")
self.assertIsNone(records[0].amount)
class SuperJobVacanciesClientTest(SimpleTestCase):
def test_fetch_vacancies_maps_superjob_objects_to_generic_records(self):
with TestHTTPServer() as server:
server.add_json(
"/2.0/vacancies/",
{
"objects": [
{
"id": 456,
"id_client": 99,
"profession": "Технолог",
"firm_name": "ООО Пример",
"payment_from": 90000,
"payment_to": 130000,
"date_published": 1778064000,
"link": "https://www.superjob.ru/vakansii/456.html",
"is_archive": False,
}
],
"total": 1,
"more": False,
},
)
client = SuperJobVacanciesClient(
app_id="test-app-id",
base_url=server.base_url,
http_adapter=server.adapter,
)
records = client.fetch_vacancies(limit=10, offset=0, text="Технолог")
self.assertEqual(len(records), 1)
record = records[0]
self.assertEqual(record.source, ParserLoadLog.Source.TRUDVSEM)
self.assertEqual(record.external_id, "superjob:456")
self.assertEqual(record.title, "Технолог")
self.assertEqual(record.organisation_name, "ООО Пример")
self.assertEqual(record.amount, Decimal("90000"))
self.assertEqual(record.url, "https://www.superjob.ru/vakansii/456.html")
self.assertEqual(record.payload["vacancy_source"], "superjob")
class VacanciesClientTest(SimpleTestCase):
def test_fetch_vacancies_combines_enabled_sources(self):
class _Provider:
def __init__(self, source_name: str):
self.source_name = source_name
def fetch_vacancies(self, **kwargs):
return [
GenericParserItem(
source=ParserLoadLog.Source.TRUDVSEM,
external_id=f"{self.source_name}:1",
payload={"vacancy_source": self.source_name, "kwargs": kwargs},
)
]
client = VacanciesClient(
source_clients={
"trudvsem": _Provider("trudvsem"),
"hh": _Provider("hh"),
"superjob": _Provider("superjob"),
}
)
records = client.fetch_vacancies(limit=10, offset=5, text="инженер")
self.assertEqual(
[record.payload["vacancy_source"] for record in records],
["trudvsem", "hh", "superjob"],
)
def test_fetch_vacancies_skips_sources_without_company_inn_support(self):
class _Provider:
supports_company_inn = False
def fetch_vacancies(self, **kwargs):
return [
GenericParserItem(
source=ParserLoadLog.Source.TRUDVSEM,
external_id="unsupported:1",
)
]
class _InnProvider:
supports_company_inn = True
def fetch_vacancies(self, **kwargs):
return [
GenericParserItem(
source=ParserLoadLog.Source.TRUDVSEM,
external_id="trudvsem:1",
)
]
client = VacanciesClient(
source_clients={
"trudvsem": _InnProvider(),
"hh": _Provider(),
"superjob": _Provider(),
}
)
records = client.fetch_vacancies(company_inn="7700000000")
self.assertEqual([record.external_id for record in records], ["trudvsem:1"])
def test_fetch_vacancies_skips_unconfigured_optional_source_by_default(self):
class _Provider:
supports_company_inn = True
def fetch_vacancies(self, **kwargs):
return [
GenericParserItem(
source=ParserLoadLog.Source.TRUDVSEM,
external_id="trudvsem:1",
)
]
client = VacanciesClient(source_clients={"trudvsem": _Provider()})
records = client.fetch_vacancies()
self.assertEqual([record.external_id for record in records], ["trudvsem:1"])
def test_fetch_vacancies_requires_superjob_app_id_when_explicitly_selected(self):
client = VacanciesClient(sources=["superjob"], superjob_app_id="")
with self.assertRaises(VacanciesClientError):
client.fetch_vacancies()