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

203 lines
8.4 KiB
Python

"""
WSP operation registry — single source of truth for SOAP call config.
Each operation declares:
- contract: SOAP contract (ISupplierWebService, IPubWebService, etc.)
- request_ns: XML namespace of the Request type
- date_fields: (start_field, end_field) — for window-based ops
- max_window_days: server-imposed max window
- extra_fields: static fields to inject (e.g. defaults)
- response_xpath: XPath to extract Items elements from the response
- parser: dotted module name of parser
- sink: 'announcements' (public) or 'beletage' (own)
"""
from __future__ import annotations
from dataclasses import dataclass, field
from typing import Optional
NS_INTEG = 'http://schemas.datacontract.org/2004/07/SICAP.Service.Integration'
NS_MODEL_BASE = 'http://schemas.datacontract.org/2004/07/SICAP.Supplier.Interface.Model'
NS_MODEL_CONTRACTS = NS_MODEL_BASE + '.Contracts'
# Endpoints
PROD_URL = 'https://e-licitatie.ro:8883/Pub'
DEMO_URL = 'http://demo.e-licitatie.ro:8884/Pub'
@dataclass
class WspOp:
name: str # operation name (matches SOAPAction tail)
contract: str # SOAP contract — 'ISupplierWebService'
request_ns: str = NS_MODEL_BASE
date_start_field: Optional[str] = None
date_end_field: Optional[str] = None
max_window_days: int = 7 # server max
page_size_inferred: int = 50 # confirmed empirically: server returns 50 items/page
items_cap: int = 1000 # if PageTotal == 1000, window may be truncated; auto-split
parser_module: str = '' # 'wsp.parsers.ca_notice'
sink: str = 'announcements' # 'announcements' | 'beletage_contracts' | 'beletage_invoices' | 'beletage_da' | 'beletage_catalog'
source_tag: str = '' # value for seap.announcements.source column
item_xpath: str = '' # XPath under <a:Items> to find each item element
@property
def soap_action(self) -> str:
return f'http://tempuri.org/{self.contract}/{self.name}'
# Public-data feeds (SU_*) — return all-Romania notices, not scoped to Beletage
PUBLIC_OPS: dict[str, WspOp] = {
'SU_CaNotices': WspOp(
name='SU_CaNotices',
contract='ISupplierWebService',
date_start_field='PublicationStartDate',
date_end_field='PublicationEndDate',
max_window_days=1, # high volume — must split per day
parser_module='wsp.parsers.ca_notice',
source_tag='wsp_canotice',
item_xpath='.//{http://schemas.datacontract.org/2004/07/SICAP.Supplier.Interface.Model.CANotice}CaNoticeBase',
),
'SU_CNotices': WspOp(
name='SU_CNotices',
contract='ISupplierWebService',
date_start_field='PublicationStartDate',
date_end_field='PublicationEndDate',
max_window_days=7,
parser_module='wsp.parsers.c_notice',
source_tag='wsp_cnotice',
item_xpath='.//{http://schemas.datacontract.org/2004/07/SICAP.Supplier.Interface.Model.CNotice}CNoticeBase',
),
'SU_PiNotices': WspOp(
name='SU_PiNotices',
contract='ISupplierWebService',
date_start_field='PublicationStartDate',
date_end_field='PublicationEndDate',
max_window_days=30,
parser_module='wsp.parsers.pi_notice',
source_tag='wsp_pinotice',
item_xpath='.//{http://schemas.datacontract.org/2004/07/SICAP.Supplier.Interface.Model.PINotice}PiNoticeBase',
),
'SU_RfqNotices': WspOp(
name='SU_RfqNotices',
contract='ISupplierWebService',
date_start_field='PublicationStartDate',
date_end_field='PublicationEndDate',
max_window_days=7,
parser_module='wsp.parsers.rfq_notice',
source_tag='wsp_rfq_notice',
item_xpath='.//{http://schemas.datacontract.org/2004/07/SICAP.Supplier.Interface.Model.RfqNotice}RfqNoticeBase',
),
'SU_RfqInvitations': WspOp(
name='SU_RfqInvitations',
contract='ISupplierWebService',
date_start_field='PublicationStartDate',
date_end_field='PublicationEndDate',
max_window_days=7,
parser_module='wsp.parsers.rfq_invitation',
source_tag='wsp_rfq_invitation',
item_xpath='.//{http://schemas.datacontract.org/2004/07/SICAP.Supplier.Interface.Model.RfqInvitation}RfqInvitationBase',
),
'SU_DCNotices': WspOp(
name='SU_DCNotices',
contract='ISupplierWebService',
date_start_field='PublicationStartDate',
date_end_field='PublicationEndDate',
max_window_days=30,
parser_module='wsp.parsers.dc_notice',
source_tag='wsp_dcnotice',
item_xpath='.//{http://schemas.datacontract.org/2004/07/SICAP.Supplier.Interface.Model.DCNotice}DCNoticeBase',
),
'SU_PCNotices': WspOp(
name='SU_PCNotices',
contract='ISupplierWebService',
date_start_field='PublicationStartDate',
date_end_field='PublicationEndDate',
max_window_days=30,
parser_module='wsp.parsers.pc_notice',
source_tag='wsp_pcnotice',
item_xpath='.//{http://schemas.datacontract.org/2004/07/SICAP.Supplier.Interface.Model.PCNotice}PCNoticeBase',
),
'SU_RdcNotices': WspOp(
name='SU_RdcNotices',
contract='ISupplierWebService',
date_start_field='PublicationStartDate',
date_end_field='PublicationEndDate',
max_window_days=30,
parser_module='wsp.parsers.rdc_notice',
source_tag='wsp_rdcnotice',
item_xpath='.//{http://schemas.datacontract.org/2004/07/SICAP.Supplier.Interface.Model.RDCNotice}RdcNoticeBase',
),
'SU_ENotices': WspOp(
name='SU_ENotices',
contract='ISupplierWebService',
date_start_field='PublicationStartDate',
date_end_field='PublicationEndDate',
max_window_days=30,
parser_module='wsp.parsers.e_notice',
source_tag='wsp_enotice',
item_xpath='.//{http://schemas.datacontract.org/2004/07/SICAP.Supplier.Interface.Model.ENotice}ENoticeBase',
),
'SU_EAProcedure': WspOp(
name='SU_EAProcedure',
contract='ISupplierWebService',
date_start_field='PublicationStartDate',
date_end_field='PublicationEndDate',
max_window_days=30,
parser_module='wsp.parsers.ea_procedure',
source_tag='wsp_eaprocedure',
item_xpath='.//{http://schemas.datacontract.org/2004/07/SICAP.Supplier.Interface.Model.EAProcedure}EAProcedureBase',
),
}
# Beletage-scoped (own data)
OWN_OPS: dict[str, WspOp] = {
'SuContracts': WspOp(
name='SuContracts',
contract='ISupplierWebService',
request_ns=NS_MODEL_CONTRACTS,
date_start_field='ContractStartDate',
date_end_field='ContractEndDate',
max_window_days=10,
parser_module='wsp.parsers.su_contract',
sink='beletage_contracts',
source_tag='wsp_beletage_contract',
item_xpath='.//{http://schemas.datacontract.org/2004/07/SICAP.Supplier.Interface.Model.Contracts}ContractItem',
),
'SuInvoices': WspOp(
name='SuInvoices',
contract='ISupplierWebService',
date_start_field='MinDate',
date_end_field='MaxDate',
max_window_days=10,
parser_module='wsp.parsers.su_invoice',
sink='beletage_invoices',
source_tag='wsp_beletage_invoice',
item_xpath='.//{http://schemas.datacontract.org/2004/07/SICAP.Supplier.Interface.Model}InvoiceItem',
),
'SuDirectAcquisitions': WspOp(
name='SuDirectAcquisitions',
contract='ISupplierWebService',
date_start_field='PublicationStartDate',
date_end_field='PublicationEndDate',
max_window_days=30,
parser_module='wsp.parsers.su_da',
sink='beletage_da',
source_tag='wsp_beletage_da',
item_xpath='.//{http://schemas.datacontract.org/2004/07/SICAP.Supplier.Interface.Model}SUDirectAcquisition',
),
'Catalog_ListItems': WspOp(
name='Catalog_ListItems',
contract='ISupplierWebService',
date_start_field='LastUpdateStart',
date_end_field='LastUpdateEnd',
max_window_days=365, # catalog is small, use wide window
parser_module='wsp.parsers.catalog',
sink='beletage_catalog',
source_tag='wsp_beletage_catalog',
item_xpath='.//{http://schemas.datacontract.org/2004/07/SICAP.Supplier.Interface.Model}CatalogListItem',
),
}
ALL_OPS: dict[str, WspOp] = {**PUBLIC_OPS, **OWN_OPS}