From cbe3cd3f6e7c9732c0c1e92cdb2218d6e55f550f Mon Sep 17 00:00:00 2001 From: Maciej Pienczyn Date: Fri, 20 Feb 2026 13:58:35 +0100 Subject: [PATCH] feat: complete KRS data import with all available fields MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Map remaining KRS API fields: registration date, company agreement date, duration, capital currency, OPP status, representation rules, shareholders (wspólnicy), and financial reports (sprawozdania finansowe). Co-Authored-By: Claude Opus 4.6 --- blueprints/admin/routes_membership.py | 117 +++++++++++++++++++++++++- 1 file changed, 116 insertions(+), 1 deletion(-) diff --git a/blueprints/admin/routes_membership.py b/blueprints/admin/routes_membership.py index 77817ed..1b394db 100644 --- a/blueprints/admin/routes_membership.py +++ b/blueprints/admin/routes_membership.py @@ -17,7 +17,7 @@ from . import bp from database import ( SessionLocal, MembershipApplication, CompanyDataRequest, Company, Category, User, UserNotification, Person, CompanyPerson, CompanyPKD, - SystemRole, UserCompany + CompanyFinancialReport, SystemRole, UserCompany ) from krs_api_service import get_company_from_krs from utils.decorators import role_required @@ -25,6 +25,21 @@ from utils.decorators import role_required logger = logging.getLogger(__name__) +def _parse_krs_date(date_str): + """Parse KRS date format 'DD.MM.YYYY' to Python date. Returns None on failure.""" + if not date_str: + return None + # Extract first date-like pattern (handles "25.10.2011 R. - ASESOR..." format) + import re as _re + match = _re.search(r'(\d{2})\.(\d{2})\.(\d{4})', date_str) + if match: + try: + return date(int(match.group(3)), int(match.group(2)), int(match.group(1))) + except ValueError: + return None + return None + + def _generate_slug(name): """Generate URL-safe slug from company name.""" slug = re.sub(r'[^\w\s-]', '', name.lower()) @@ -124,6 +139,35 @@ def _enrich_company_from_krs(company, db): kapital = data_dict.get('kapital', {}) if kapital.get('zakladowy'): company.capital_amount = kapital['zakladowy'] + if kapital.get('waluta'): + company.capital_currency = kapital['waluta'] + + # Representation rules + if data_dict.get('sposob_reprezentacji'): + company.krs_representation_rules = data_dict['sposob_reprezentacji'] + + # Registration date + daty = data_dict.get('daty', {}) + if daty.get('rejestracji'): + parsed = _parse_krs_date(daty['rejestracji']) + if parsed: + company.krs_registration_date = parsed + + # Company agreement (umowa spółki) + umowa = data_dict.get('umowa_spolki', {}) + if umowa.get('data_umowy'): + parsed = _parse_krs_date(umowa['data_umowy']) + if parsed: + company.krs_company_agreement_date = parsed + if umowa.get('czas_trwania'): + company.krs_duration = umowa['czas_trwania'] + + # OPP status + if 'czy_opp' in data_dict: + company.is_opp = bool(data_dict['czy_opp']) + + # Last audit timestamp + company.krs_last_audit_at = datetime.now() # Primary PKD on Company model pkd_list = data_dict.get('przedmiot_dzialalnosci', []) @@ -191,6 +235,77 @@ def _enrich_company_from_krs(company, db): ) db.add(cpkd) + # Import shareholders (wspólnicy) + for wspolnik in data_dict.get('wspolnicy', []): + nazwisko = wspolnik.get('nazwisko', '') + imiona = wspolnik.get('imiona', wspolnik.get('imie', '')) + + if not nazwisko: + continue + + person = db.query(Person).filter( + Person.nazwisko == nazwisko, + Person.imiona == imiona + ).first() + + if not person: + person = Person(nazwisko=nazwisko, imiona=imiona) + db.add(person) + db.flush() + + existing = db.query(CompanyPerson).filter( + CompanyPerson.company_id == company.id, + CompanyPerson.person_id == person.id, + CompanyPerson.role_category == 'wspolnik' + ).first() + + if not existing: + cp = CompanyPerson( + company_id=company.id, + person_id=person.id, + role=wspolnik.get('funkcja', 'WSPÓLNIK'), + role_category='wspolnik', + shares_count=wspolnik.get('liczba_udzialow'), + shares_value=wspolnik.get('wartosc_udzialow'), + source='ekrs.ms.gov.pl', + fetched_at=datetime.now() + ) + db.add(cp) + + # Import financial reports (sprawozdania finansowe) + for sf in data_dict.get('sprawozdania_finansowe', []): + za_okres = sf.get('za_okres', '') + data_zlozenia = sf.get('data_zlozenia', '') + + period_start = None + period_end = None + if ' - ' in za_okres: + parts = za_okres.split(' - ') + period_start = _parse_krs_date(parts[0].strip()) + period_end = _parse_krs_date(parts[1].strip()) + + filed = _parse_krs_date(data_zlozenia) + + if not period_start and not period_end: + continue + + existing = db.query(CompanyFinancialReport).filter( + CompanyFinancialReport.company_id == company.id, + CompanyFinancialReport.period_start == period_start, + CompanyFinancialReport.period_end == period_end + ).first() + + if not existing: + cfr = CompanyFinancialReport( + company_id=company.id, + period_start=period_start, + period_end=period_end, + filed_at=filed, + report_type='annual', + source='ekrs' + ) + db.add(cfr) + logger.info(f"Enriched company {company.id} with KRS data") return True