""" 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 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}