Some checks are pending
NordaBiz Tests / Unit & Integration Tests (push) Waiting to run
NordaBiz Tests / E2E Tests (Playwright) (push) Blocked by required conditions
NordaBiz Tests / Smoke Tests (Production) (push) Blocked by required conditions
NordaBiz Tests / Send Failure Notification (push) Blocked by required conditions
Replace ~20 remaining is_admin references across backend, templates and scripts with proper SystemRole checks. Column is_admin stays as deprecated (synced by set_role()) until DB migration removes it. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
643 lines
26 KiB
Python
643 lines
26 KiB
Python
"""
|
|
Membership Routes
|
|
==================
|
|
|
|
Routes for membership application wizard and status tracking.
|
|
"""
|
|
|
|
import logging
|
|
from datetime import datetime
|
|
|
|
from flask import render_template, request, redirect, url_for, flash, jsonify
|
|
from flask_login import login_required, current_user
|
|
from sqlalchemy.orm.attributes import flag_modified
|
|
|
|
from . import bp
|
|
from database import SessionLocal, MembershipApplication, CompanyDataRequest, Company, UserNotification, User, SystemRole
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
# ============================================================
|
|
# APPLICATION WIZARD
|
|
# ============================================================
|
|
|
|
@bp.route('/apply')
|
|
@login_required
|
|
def apply():
|
|
"""
|
|
Membership application wizard - multi-step form.
|
|
"""
|
|
db = SessionLocal()
|
|
try:
|
|
# Check if user already has a company
|
|
if current_user.company_id:
|
|
flash('Masz już przypisaną firmę. Nie możesz składać nowej deklaracji.', 'warning')
|
|
return redirect(url_for('index'))
|
|
|
|
# Check for existing draft or pending application
|
|
existing = db.query(MembershipApplication).filter(
|
|
MembershipApplication.user_id == current_user.id,
|
|
MembershipApplication.status.in_(['draft', 'submitted', 'under_review', 'pending_user_approval', 'changes_requested'])
|
|
).first()
|
|
|
|
if existing:
|
|
# If pending user approval, redirect to review page
|
|
if existing.status == 'pending_user_approval':
|
|
flash('Administrator zaproponował zmiany do Twojej deklaracji. Przejrzyj je i zaakceptuj lub odrzuć.', 'info')
|
|
return redirect(url_for('membership.review_changes', app_id=existing.id))
|
|
# If already submitted, redirect to status page
|
|
if existing.status in ['submitted', 'under_review']:
|
|
flash('Masz już wysłaną deklarację oczekującą na rozpatrzenie.', 'info')
|
|
return redirect(url_for('membership.status'))
|
|
# Otherwise continue editing
|
|
return redirect(url_for('membership.apply_step', step=1))
|
|
|
|
# Create new draft
|
|
application = MembershipApplication(
|
|
user_id=current_user.id,
|
|
company_name='',
|
|
nip='',
|
|
email=current_user.email or '',
|
|
status='draft'
|
|
)
|
|
db.add(application)
|
|
db.commit()
|
|
|
|
return redirect(url_for('membership.apply_step', step=1))
|
|
finally:
|
|
db.close()
|
|
|
|
|
|
@bp.route('/apply/step/<int:step>', methods=['GET', 'POST'])
|
|
@login_required
|
|
def apply_step(step):
|
|
"""
|
|
Handle specific step of the application wizard.
|
|
Step 1: Company data (from registry)
|
|
Step 2: Additional info
|
|
Step 3: Sections and declaration
|
|
"""
|
|
if step not in [1, 2, 3]:
|
|
return redirect(url_for('membership.apply_step', step=1))
|
|
|
|
db = SessionLocal()
|
|
try:
|
|
# Get current application
|
|
application = db.query(MembershipApplication).filter(
|
|
MembershipApplication.user_id == current_user.id,
|
|
MembershipApplication.status.in_(['draft', 'changes_requested'])
|
|
).first()
|
|
|
|
if not application:
|
|
# Check if user has submitted application
|
|
submitted = db.query(MembershipApplication).filter(
|
|
MembershipApplication.user_id == current_user.id,
|
|
MembershipApplication.status.in_(['submitted', 'under_review'])
|
|
).first()
|
|
if submitted:
|
|
flash('Twoja deklaracja oczekuje na rozpatrzenie.', 'info')
|
|
return redirect(url_for('membership.status'))
|
|
|
|
# No application at all - redirect to start
|
|
flash('Nie znaleziono aktywnej deklaracji.', 'error')
|
|
return redirect(url_for('membership.status'))
|
|
|
|
if request.method == 'POST':
|
|
action = request.form.get('action', 'save')
|
|
|
|
if step == 1:
|
|
# Save step 1 data
|
|
application.company_name = request.form.get('company_name', '').strip()
|
|
application.nip = request.form.get('nip', '').strip().replace('-', '').replace(' ', '')
|
|
application.address_postal_code = request.form.get('address_postal_code', '').strip()
|
|
application.address_city = request.form.get('address_city', '').strip()
|
|
application.address_street = request.form.get('address_street', '').strip()
|
|
application.address_number = request.form.get('address_number', '').strip()
|
|
application.delegate_1 = request.form.get('delegate_1', '').strip()
|
|
application.delegate_2 = request.form.get('delegate_2', '').strip()
|
|
application.delegate_3 = request.form.get('delegate_3', '').strip()
|
|
application.krs_number = request.form.get('krs_number', '').strip()
|
|
application.regon = request.form.get('regon', '').strip()
|
|
application.registry_source = request.form.get('registry_source', 'manual')
|
|
|
|
elif step == 2:
|
|
# Save step 2 data
|
|
application.website = request.form.get('website', '').strip()
|
|
application.email = request.form.get('email', '').strip()
|
|
application.phone = request.form.get('phone', '').strip()
|
|
application.short_name = request.form.get('short_name', '').strip()
|
|
application.description = request.form.get('description', '').strip()
|
|
|
|
founded_date = request.form.get('founded_date', '').strip()
|
|
if founded_date:
|
|
try:
|
|
application.founded_date = datetime.strptime(founded_date, '%Y-%m-%d').date()
|
|
except ValueError:
|
|
pass
|
|
|
|
employee_count = request.form.get('employee_count', '').strip()
|
|
if employee_count:
|
|
try:
|
|
application.employee_count = int(employee_count)
|
|
except ValueError:
|
|
pass
|
|
|
|
application.show_employee_count = request.form.get('show_employee_count') == 'on'
|
|
application.annual_revenue = request.form.get('annual_revenue', '').strip()
|
|
|
|
# Related companies (JSON array)
|
|
related = []
|
|
for i in range(1, 6):
|
|
company = request.form.get(f'related_company_{i}', '').strip()
|
|
if company:
|
|
related.append(company)
|
|
application.related_companies = related if related else None
|
|
|
|
elif step == 3:
|
|
# Save step 3 data
|
|
sections = request.form.getlist('sections')
|
|
application.sections = sections if sections else []
|
|
application.sections_other = request.form.get('sections_other', '').strip()
|
|
application.business_type = request.form.get('business_type', 'sp_z_oo')
|
|
application.business_type_other = request.form.get('business_type_other', '').strip()
|
|
|
|
# GDPR consents
|
|
application.consent_email = request.form.get('consent_email') == 'on'
|
|
application.consent_email_address = request.form.get('consent_email_address', '').strip()
|
|
application.consent_sms = request.form.get('consent_sms') == 'on'
|
|
application.consent_sms_phone = request.form.get('consent_sms_phone', '').strip()
|
|
|
|
# Declaration
|
|
application.declaration_accepted = request.form.get('declaration_accepted') == 'on'
|
|
if application.declaration_accepted:
|
|
application.declaration_accepted_at = datetime.now()
|
|
application.declaration_ip_address = request.remote_addr
|
|
|
|
application.updated_at = datetime.now()
|
|
db.commit()
|
|
|
|
if action == 'next':
|
|
if step < 3:
|
|
return redirect(url_for('membership.apply_step', step=step + 1))
|
|
else:
|
|
# Final validation before submit
|
|
errors = validate_application(application)
|
|
if errors:
|
|
for error in errors:
|
|
flash(error, 'error')
|
|
return redirect(url_for('membership.apply_step', step=3))
|
|
|
|
# Submit application
|
|
application.status = 'submitted'
|
|
application.submitted_at = datetime.now()
|
|
db.commit()
|
|
|
|
# Wyślij notyfikacje do administratorów i kierowników biura
|
|
try:
|
|
admin_users = db.query(User).filter(
|
|
User.system_role.in_([SystemRole.ADMIN.value, SystemRole.OFFICE_MANAGER.value])
|
|
).all()
|
|
|
|
for admin in admin_users:
|
|
notification = UserNotification(
|
|
user_id=admin.id,
|
|
title='Nowa deklaracja członkowska',
|
|
message=f'{current_user.name or current_user.email} złożył/a deklarację członkowską dla firmy "{application.company_name}".',
|
|
notification_type='alert',
|
|
related_type='membership_application',
|
|
related_id=application.id,
|
|
action_url=url_for('admin.membership_detail', app_id=application.id)
|
|
)
|
|
db.add(notification)
|
|
|
|
db.commit()
|
|
logger.info(f"Notifications sent to {len(admin_users)} admins for membership application {application.id}")
|
|
except Exception as e:
|
|
logger.error(f"Failed to send notifications for membership application: {e}")
|
|
# Nie przerywaj flow - deklaracja już została wysłana
|
|
|
|
flash('Deklaracja została wysłana do rozpatrzenia!', 'success')
|
|
logger.info(f"Membership application submitted: user={current_user.id}, app={application.id}")
|
|
return redirect(url_for('membership.status'))
|
|
|
|
elif action == 'prev' and step > 1:
|
|
return redirect(url_for('membership.apply_step', step=step - 1))
|
|
else:
|
|
flash('Zapisano zmiany.', 'success')
|
|
return redirect(url_for('membership.apply_step', step=step))
|
|
|
|
# GET - render step
|
|
return render_template(
|
|
'membership/apply.html',
|
|
application=application,
|
|
step=step,
|
|
section_choices=MembershipApplication.SECTION_CHOICES,
|
|
business_type_choices=MembershipApplication.BUSINESS_TYPE_CHOICES
|
|
)
|
|
finally:
|
|
db.close()
|
|
|
|
|
|
def validate_application(app):
|
|
"""Validate application before submission."""
|
|
errors = []
|
|
|
|
if not app.company_name:
|
|
errors.append('Nazwa firmy jest wymagana.')
|
|
if not app.nip or len(app.nip) != 10:
|
|
errors.append('NIP jest wymagany (10 cyfr).')
|
|
if not app.email:
|
|
errors.append('Email jest wymagany.')
|
|
if not app.delegate_1:
|
|
errors.append('Przynajmniej jeden delegat jest wymagany.')
|
|
if not app.sections:
|
|
errors.append('Wybierz przynajmniej jedną sekcję tematyczną.')
|
|
if not app.consent_email:
|
|
errors.append('Zgoda na kontakt email jest wymagana.')
|
|
if not app.declaration_accepted:
|
|
errors.append('Musisz zaakceptować oświadczenie.')
|
|
|
|
return errors
|
|
|
|
|
|
# ============================================================
|
|
# APPLICATION STATUS
|
|
# ============================================================
|
|
|
|
@bp.route('/status')
|
|
@login_required
|
|
def status():
|
|
"""
|
|
Show current application status.
|
|
"""
|
|
db = SessionLocal()
|
|
try:
|
|
applications = db.query(MembershipApplication).filter(
|
|
MembershipApplication.user_id == current_user.id
|
|
).order_by(MembershipApplication.created_at.desc()).all()
|
|
|
|
return render_template('membership/status.html', applications=applications)
|
|
finally:
|
|
db.close()
|
|
|
|
|
|
# ============================================================
|
|
# PROPOSED CHANGES REVIEW (User approval workflow)
|
|
# ============================================================
|
|
|
|
@bp.route('/review-changes/<int:app_id>')
|
|
@login_required
|
|
def review_changes(app_id):
|
|
"""
|
|
Page for user to review proposed changes from admin.
|
|
"""
|
|
db = SessionLocal()
|
|
try:
|
|
application = db.query(MembershipApplication).get(app_id)
|
|
|
|
if not application:
|
|
flash('Nie znaleziono deklaracji.', 'error')
|
|
return redirect(url_for('membership.status'))
|
|
|
|
# Verify ownership
|
|
if application.user_id != current_user.id:
|
|
flash('Brak dostępu do tej deklaracji.', 'error')
|
|
return redirect(url_for('membership.status'))
|
|
|
|
# Check status
|
|
if application.status != 'pending_user_approval':
|
|
flash('Ta deklaracja nie wymaga przeglądu zmian.', 'info')
|
|
return redirect(url_for('membership.status'))
|
|
|
|
# Get reviewer info (person who proposed changes)
|
|
reviewer = None
|
|
if application.proposed_changes_by_id:
|
|
reviewer = db.query(User).get(application.proposed_changes_by_id)
|
|
|
|
return render_template(
|
|
'membership/review_changes.html',
|
|
application=application,
|
|
reviewer=reviewer
|
|
)
|
|
finally:
|
|
db.close()
|
|
|
|
|
|
@bp.route('/review-changes/<int:app_id>/accept', methods=['POST'])
|
|
@login_required
|
|
def accept_changes(app_id):
|
|
"""
|
|
User accepts proposed changes from admin.
|
|
Changes are applied and application returns to under_review.
|
|
"""
|
|
db = SessionLocal()
|
|
try:
|
|
application = db.query(MembershipApplication).get(app_id)
|
|
|
|
if not application:
|
|
return jsonify({'success': False, 'error': 'Nie znaleziono deklaracji'}), 404
|
|
|
|
if application.user_id != current_user.id:
|
|
return jsonify({'success': False, 'error': 'Brak dostępu'}), 403
|
|
|
|
if application.status != 'pending_user_approval':
|
|
return jsonify({
|
|
'success': False,
|
|
'error': 'Ta deklaracja nie oczekuje na akceptację zmian'
|
|
}), 400
|
|
|
|
proposed = application.proposed_changes or {}
|
|
|
|
# Get proposer info for history
|
|
proposer = db.query(User).get(application.proposed_changes_by_id) if application.proposed_changes_by_id else None
|
|
proposer_name = proposer.name if proposer else 'Biuro Izby NORDA'
|
|
|
|
# Apply all proposed changes
|
|
applied_fields = []
|
|
changes_summary = []
|
|
for field_name, change in proposed.items():
|
|
new_value = change.get('new')
|
|
if new_value is not None:
|
|
if field_name == 'founded_date':
|
|
try:
|
|
setattr(application, field_name, datetime.strptime(new_value, '%Y-%m-%d').date())
|
|
except (ValueError, TypeError):
|
|
setattr(application, field_name, None)
|
|
else:
|
|
setattr(application, field_name, new_value)
|
|
applied_fields.append(field_name)
|
|
changes_summary.append(f"{change.get('label', field_name)}: {change.get('old', '-')} → {new_value}")
|
|
|
|
# Record user acceptance
|
|
application.user_changes_accepted_at = datetime.now()
|
|
application.user_changes_action = 'accepted'
|
|
|
|
# Add to workflow history
|
|
history = application.workflow_history or []
|
|
history.append({
|
|
'event': 'user_accepted_changes',
|
|
'timestamp': datetime.now().isoformat(),
|
|
'user_id': current_user.id,
|
|
'user_name': current_user.name or current_user.email,
|
|
'details': {
|
|
'proposed_by': proposer_name,
|
|
'proposed_at': application.proposed_changes_at.isoformat() if application.proposed_changes_at else None,
|
|
'changes_applied': changes_summary,
|
|
'comment': application.proposed_changes_comment
|
|
}
|
|
})
|
|
application.workflow_history = list(history) # Create new list for SQLAlchemy change detection
|
|
flag_modified(application, 'workflow_history')
|
|
|
|
# Update status - back to under_review for final approval
|
|
application.status = 'under_review'
|
|
application.updated_at = datetime.now()
|
|
|
|
# Keep proposed_changes_by_id for reference but clear the rest
|
|
application.proposed_changes = None
|
|
application.proposed_changes_at = None
|
|
application.proposed_changes_comment = None
|
|
|
|
# Create notification for admins
|
|
admins = db.query(User).filter(User.role == 'ADMIN').all()
|
|
for admin in admins:
|
|
notification = UserNotification(
|
|
user_id=admin.id,
|
|
title='Użytkownik zaakceptował zmiany',
|
|
message=f'Użytkownik {current_user.name or current_user.email} zaakceptował proponowane zmiany dla firmy "{application.company_name}". Deklaracja oczekuje na ostateczne zatwierdzenie.',
|
|
notification_type='alert',
|
|
related_type='membership_application',
|
|
related_id=app_id,
|
|
action_url=f'/admin/membership/{app_id}'
|
|
)
|
|
db.add(notification)
|
|
|
|
db.commit()
|
|
|
|
logger.info(
|
|
f"User {current_user.id} accepted proposed changes for application {app_id}. "
|
|
f"Applied fields: {applied_fields}"
|
|
)
|
|
|
|
return jsonify({
|
|
'success': True,
|
|
'applied_fields': applied_fields,
|
|
'message': 'Zmiany zostały zaakceptowane. Twoja deklaracja wróciła do rozpatrzenia.'
|
|
})
|
|
except Exception as e:
|
|
db.rollback()
|
|
logger.error(f"Error accepting changes for application {app_id}: {e}")
|
|
return jsonify({'success': False, 'error': str(e)}), 500
|
|
finally:
|
|
db.close()
|
|
|
|
|
|
@bp.route('/review-changes/<int:app_id>/reject', methods=['POST'])
|
|
@login_required
|
|
def reject_changes(app_id):
|
|
"""
|
|
User rejects proposed changes from admin.
|
|
Application returns to under_review with original data.
|
|
"""
|
|
db = SessionLocal()
|
|
try:
|
|
application = db.query(MembershipApplication).get(app_id)
|
|
|
|
if not application:
|
|
return jsonify({'success': False, 'error': 'Nie znaleziono deklaracji'}), 404
|
|
|
|
if application.user_id != current_user.id:
|
|
return jsonify({'success': False, 'error': 'Brak dostępu'}), 403
|
|
|
|
if application.status != 'pending_user_approval':
|
|
return jsonify({
|
|
'success': False,
|
|
'error': 'Ta deklaracja nie oczekuje na akceptację zmian'
|
|
}), 400
|
|
|
|
data = request.get_json() or {}
|
|
user_comment = data.get('comment', '').strip()
|
|
|
|
# Get proposer info for history
|
|
proposer = db.query(User).get(application.proposed_changes_by_id) if application.proposed_changes_by_id else None
|
|
proposer_name = proposer.name if proposer else 'Biuro Izby NORDA'
|
|
|
|
# Record user rejection
|
|
application.user_changes_accepted_at = datetime.now()
|
|
application.user_changes_action = 'rejected'
|
|
|
|
# Add to workflow history
|
|
history = application.workflow_history or []
|
|
history.append({
|
|
'event': 'user_rejected_changes',
|
|
'timestamp': datetime.now().isoformat(),
|
|
'user_id': current_user.id,
|
|
'user_name': current_user.name or current_user.email,
|
|
'details': {
|
|
'proposed_by': proposer_name,
|
|
'proposed_at': application.proposed_changes_at.isoformat() if application.proposed_changes_at else None,
|
|
'user_comment': user_comment,
|
|
'original_comment': application.proposed_changes_comment
|
|
}
|
|
})
|
|
application.workflow_history = list(history) # Create new list for SQLAlchemy change detection
|
|
flag_modified(application, 'workflow_history')
|
|
|
|
# Clear proposed changes - keep original data
|
|
application.proposed_changes = None
|
|
application.proposed_changes_at = None
|
|
application.proposed_changes_by_id = None
|
|
application.proposed_changes_comment = None
|
|
|
|
# Add user's rejection reason to review_comment
|
|
if user_comment:
|
|
existing_comment = application.review_comment or ''
|
|
application.review_comment = f"{existing_comment}\n\n[Użytkownik odrzucił propozycje zmian: {user_comment}]".strip()
|
|
|
|
# Back to under_review with original data
|
|
application.status = 'under_review'
|
|
application.updated_at = datetime.now()
|
|
|
|
# Create notification for admins
|
|
admins = db.query(User).filter(User.role == 'ADMIN').all()
|
|
for admin in admins:
|
|
notification = UserNotification(
|
|
user_id=admin.id,
|
|
title='Użytkownik odrzucił zmiany',
|
|
message=f'Użytkownik {current_user.name or current_user.email} odrzucił proponowane zmiany dla firmy "{application.company_name}".{" Powód: " + user_comment if user_comment else ""} Deklaracja wraca do rozpatrzenia z oryginalnymi danymi.',
|
|
notification_type='alert',
|
|
related_type='membership_application',
|
|
related_id=app_id,
|
|
action_url=f'/admin/membership/{app_id}'
|
|
)
|
|
db.add(notification)
|
|
|
|
db.commit()
|
|
|
|
logger.info(
|
|
f"User {current_user.id} rejected proposed changes for application {app_id}. "
|
|
f"Reason: {user_comment or 'brak'}"
|
|
)
|
|
|
|
return jsonify({
|
|
'success': True,
|
|
'message': 'Odrzuciłeś proponowane zmiany. Twoja deklaracja zachowuje oryginalne dane.'
|
|
})
|
|
except Exception as e:
|
|
db.rollback()
|
|
logger.error(f"Error rejecting changes for application {app_id}: {e}")
|
|
return jsonify({'success': False, 'error': str(e)}), 500
|
|
finally:
|
|
db.close()
|
|
|
|
|
|
# ============================================================
|
|
# COMPANY DATA REQUEST (Modal-based)
|
|
# ============================================================
|
|
|
|
@bp.route('/data-request', methods=['GET', 'POST'])
|
|
@login_required
|
|
def data_request():
|
|
"""
|
|
Handle company data update request.
|
|
For users with a company but missing NIP/data.
|
|
"""
|
|
if not current_user.company_id:
|
|
flash('Nie masz przypisanej firmy.', 'warning')
|
|
return redirect(url_for('membership.apply'))
|
|
|
|
db = SessionLocal()
|
|
try:
|
|
company = db.query(Company).get(current_user.company_id)
|
|
if not company:
|
|
flash('Firma nie została znaleziona.', 'error')
|
|
return redirect(url_for('index'))
|
|
|
|
# Check for pending request
|
|
pending = db.query(CompanyDataRequest).filter(
|
|
CompanyDataRequest.user_id == current_user.id,
|
|
CompanyDataRequest.company_id == company.id,
|
|
CompanyDataRequest.status == 'pending'
|
|
).first()
|
|
|
|
if request.method == 'POST':
|
|
if pending:
|
|
flash('Masz już oczekujące zgłoszenie.', 'warning')
|
|
return redirect(url_for('membership.data_request'))
|
|
|
|
nip = request.form.get('nip', '').strip().replace('-', '').replace(' ', '')
|
|
if not nip or len(nip) != 10:
|
|
flash('NIP musi mieć 10 cyfr.', 'error')
|
|
return redirect(url_for('membership.data_request'))
|
|
|
|
# Create request
|
|
data_request = CompanyDataRequest(
|
|
request_type='update_data',
|
|
user_id=current_user.id,
|
|
company_id=company.id,
|
|
nip=nip,
|
|
user_note=request.form.get('user_note', '').strip()
|
|
)
|
|
|
|
# Try to fetch registry data
|
|
fetched = fetch_registry_data(nip)
|
|
if fetched:
|
|
data_request.registry_source = fetched.get('source')
|
|
data_request.fetched_data = fetched
|
|
|
|
db.add(data_request)
|
|
db.commit()
|
|
|
|
flash('Zgłoszenie zostało wysłane do rozpatrzenia.', 'success')
|
|
logger.info(f"Company data request created: user={current_user.id}, company={company.id}")
|
|
return redirect(url_for('index'))
|
|
|
|
return render_template(
|
|
'membership/data_request.html',
|
|
company=company,
|
|
pending_request=pending
|
|
)
|
|
finally:
|
|
db.close()
|
|
|
|
|
|
def fetch_registry_data(nip):
|
|
"""
|
|
Fetch company data from KRS/CEIDG registries.
|
|
Returns dict with source and data, or None if not found.
|
|
"""
|
|
try:
|
|
# Try KRS first
|
|
from krs_api_service import krs_api_service
|
|
krs_data = krs_api_service.search_by_nip(nip)
|
|
if krs_data:
|
|
return {
|
|
'source': 'KRS',
|
|
'name': krs_data.get('nazwa'),
|
|
'krs': krs_data.get('krs'),
|
|
'regon': krs_data.get('regon'),
|
|
'address': krs_data.get('adres'),
|
|
'founding_date': krs_data.get('data_rejestracji'),
|
|
'raw': krs_data
|
|
}
|
|
except Exception as e:
|
|
logger.warning(f"KRS lookup failed for NIP {nip}: {e}")
|
|
|
|
try:
|
|
# Try CEIDG
|
|
from ceidg_api_service import fetch_ceidg_by_nip
|
|
ceidg_data = fetch_ceidg_by_nip(nip)
|
|
if ceidg_data:
|
|
return {
|
|
'source': 'CEIDG',
|
|
'name': ceidg_data.get('firma'),
|
|
'regon': ceidg_data.get('regon'),
|
|
'address': ceidg_data.get('adres'),
|
|
'raw': ceidg_data
|
|
}
|
|
except Exception as e:
|
|
logger.warning(f"CEIDG lookup failed for NIP {nip}: {e}")
|
|
|
|
return None
|