Files
Claude VM a6c03a091e initial: split from gov-agreg — vreau.digital standalone platform
Moved from gov-agreg/src/pages/achizitii/* to root (drop prefix).
- 22 pages migrated, 127 files total
- All internal links: /achizitii/X → /X (176 occurrences fixed)
- AchizitiiLayout subnav rewritten: /X paths, top-right link to vreaudigital.ro hub
- BaseLayout new (vreau.digital branding, OG tags, site URL)
- astro.config.mjs: site https://vreau.digital, server output (was static)
- docker-compose: port 5096 (vreaudigital is 5095), container vreau-digital
- deploy.sh: paths /opt/vreau-digital, log /var/log/vreau-digital-deploy.log

Backend shared with gov-agreg:
- PostgreSQL satra (same schemas: seap, firms, anaf, anre, ...)
- Photon, Martin tiles
- Infisical /vreaudigital path (DATABASE_URL etc. shared)

build: PASS (npx astro check 0 errors, npm run build 5s vite + 10s server)
2026-05-13 00:10:32 +03:00

154 lines
5.6 KiB
Python

#!/usr/bin/env python3
"""
Minimal SEAP WSP connectivity test.
SEAP_ENV=prod -> https://e-licitatie.ro:8883/pub (mTLS, requires
credentials/client.crt + client.key extracted from p12)
SEAP_ENV=demo -> http://demo.e-licitatie.ro:8884/pub (no TLS)
SEAP_OP=<name> -> SuContracts (default), CANotices, PINotices, SU_CaNotices
Extract cert+key on demand (do NOT commit):
source ~/Code/claude-dotfiles/load-infisical-path.sh /seap
cd credentials
openssl pkcs12 -in 50076FB3826FADA540ACFB19.p12 -clcerts -nokeys \\
-passin env:SEAP_CERT_KEY > client.crt
openssl pkcs12 -in 50076FB3826FADA540ACFB19.p12 -nocerts -nodes \\
-passin env:SEAP_CERT_KEY > client.key
chmod 600 client.{crt,key}
"""
import os
import sys
from lxml import etree
from zeep import Client, Settings
from zeep.plugins import HistoryPlugin
from zeep.transports import Transport
DEMO_WSDL = 'http://demo.e-licitatie.ro:8884/pub?wsdl'
LOCAL_WSDL = os.path.join(os.path.dirname(__file__), 'wsdl', 'pub.wsdl')
SICAP_NS = 'http://schemas.datacontract.org/2004/07/SICAP.Service.Integration'
TEMPURI_NS = 'http://tempuri.org/'
def build_credentials_header(user: str, password: str) -> etree._Element:
cred = etree.Element('{%s}SeapUserCredentials' % TEMPURI_NS, nsmap={
None: TEMPURI_NS,
'i': 'http://www.w3.org/2001/XMLSchema-instance',
})
pw = etree.SubElement(cred, '{%s}Password' % SICAP_NS, nsmap={None: SICAP_NS})
pw.text = password
un = etree.SubElement(cred, '{%s}Username' % SICAP_NS, nsmap={None: SICAP_NS})
un.text = user
return cred
def main():
user = os.environ.get('SEAP_USER')
pw = os.environ.get('SEAP_PASS')
if not user or not pw:
print('ERROR: SEAP_USER / SEAP_PASS not in env', file=sys.stderr)
sys.exit(2)
wsdl_source = LOCAL_WSDL if os.path.exists(LOCAL_WSDL) else DEMO_WSDL
use_prod = os.environ.get('SEAP_ENV') == 'prod'
endpoint = 'https://e-licitatie.ro:8883/pub' if use_prod else 'http://demo.e-licitatie.ro:8884/pub'
print(f'WSDL: {wsdl_source}')
print(f'Endpoint: {endpoint}')
history = HistoryPlugin()
settings = Settings(strict=False, xml_huge_tree=True, raw_response=False)
import requests as _req
session = _req.Session()
if use_prod:
cred_dir = os.path.join(os.path.dirname(__file__), 'credentials')
session.cert = (os.path.join(cred_dir, 'client.crt'),
os.path.join(cred_dir, 'client.key'))
transport = Transport(timeout=30, session=session)
client = Client(wsdl_source, settings=settings, transport=transport,
plugins=[history])
service = client.create_service(
'{http://tempuri.org/}IPubServiceEndpoint',
endpoint,
)
cred_header = build_credentials_header(user, pw)
operation = os.environ.get('SEAP_OP', 'SuContracts')
requests = {
'SuContracts': {
'PageIndex': 1,
'ContractStartDate': '2024-01-01T00:00:00',
'ContractEndDate': '2026-05-05T00:00:00',
},
'CANotices': {
'PageIndex': 1,
'PublicationStartDate': '2026-04-01T00:00:00',
'PublicationEndDate': '2026-05-05T00:00:00',
},
'PINotices': {
'PageIndex': 1,
'PublicationStartDate': '2026-04-01T00:00:00',
'PublicationEndDate': '2026-05-05T00:00:00',
},
'SU_CaNotices': {
'PageIndex': 1,
'PublicationStartDate': '2026-04-01T00:00:00',
'PublicationEndDate': '2026-05-05T00:00:00',
},
}
print(f'\n--- Calling {operation} ---')
try:
result = getattr(service, operation)(
request=requests[operation],
_soapheaders=[cred_header],
)
except Exception as e:
print(f'SOAP fault / error: {type(e).__name__}: {e}')
if history.last_sent is not None:
print('\n--- Last sent envelope (truncated) ---')
sent = etree.tostring(history.last_sent['envelope'], pretty_print=True).decode()
# redact password
sent = sent.replace(pw, '<REDACTED>')
print(sent[:2000])
if history.last_received is not None:
print('\n--- Last received envelope (truncated) ---')
print(etree.tostring(history.last_received['envelope'],
pretty_print=True).decode()[:2000])
sys.exit(1)
if history.last_sent is not None:
sent = etree.tostring(history.last_sent['envelope'], pretty_print=True).decode()
sent = sent.replace(pw, '<REDACTED>')
print('\n--- Sent envelope ---')
print(sent)
if history.last_received is not None:
recv = etree.tostring(history.last_received['envelope'], pretty_print=True).decode()
print('\n--- Received envelope (first 3000 chars) ---')
print(recv[:3000])
print('\n--- Result ---')
print(f'Status: {getattr(result, "Status", "?")}')
print(f'Description: {getattr(result, "Description", None)}')
print(f'PageIndex: {getattr(result, "PageIndex", "?")}')
print(f'PageTotal: {getattr(result, "PageTotal", "?")}')
items = getattr(result, 'Items', None)
if items is not None:
for child_field in ('ContractItem', 'CANoticeItem', 'PINoticeItem',
'NoticeItem', 'Item'):
sub = getattr(items, child_field, None)
if sub:
print(f'Items count ({child_field}): {len(sub)}')
print(f'First item fields: {list(sub[0].__values__.keys())[:15]}')
break
else:
print('Items present but unknown shape')
if __name__ == '__main__':
main()