package com.gzzn.omms.msgexchange.codec import com.fasterxml.jackson.annotation.JsonIgnoreProperties import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlText import com.gzzn.omms.msgexchange.domain.flight.ScheduleRecord /** Stable payload boundary used by processing. It is deliberately not an XML model. */ data class FlopPayload( val flid: String, val scalars: Map = emptyMap(), val collections: Map>> = emptyMap(), ) data class ScheduleBody( val recsDeclared: Int, val records: List, ) /** * 只保留在 wire/domain、尚未映射到持久化明细的集合键(`[G-SRVT-VIPF]`)。 * * 它们不参与合并、不进快照、不落库;保留的目的是不让入站事实在解码层被静默抹平,并让真实 * 流量里的出现情况可观测——决定"缺席是否等于删除"的 `Q2` 需要真实报文才能定案。 */ private val UNPERSISTED_COLLECTION_KEYS: Set = setOf("SRVT", "VIPF") /** * 一条解码载荷里各未落库集合命中的**记录数**(`[G-SRVT-VIPF]`)。 * * 按记录计(一条记录带该段即算 1),不按段内元素计;只返回命中项。载荷类型不在 * [ScheduleBody] / [FlopPayload] 之内时返回空——调用方不得据此改变处理结果。 */ fun unpersistedCollectionHits(body: Any?): Map { val perRecord = when (body) { is ScheduleBody -> body.records.map { it.collections } is FlopPayload -> listOf(body.collections) else -> return emptyMap() } if (perRecord.isEmpty()) return emptyMap() return UNPERSISTED_COLLECTION_KEYS .mapNotNull { key -> perRecord.count { key in it }.takeIf { it > 0 }?.let { key to it } } .toMap() } /** * Wire DTOs for SIS in docs/legacy/SIS_AODB_RMS-V0.1.md. * SIS permits a subsystem to ignore standard fields it does not use; those fields are * therefore ignored here, while fields used by the state model are explicitly annotated. */ @JsonIgnoreProperties(ignoreUnknown = true) @JacksonXmlRootElement(localName = "MSG") data class SisMessageXml( @param:JacksonXmlProperty(localName = "META") val meta: SisMetaXml? = null, @param:JacksonXmlProperty(localName = "SCHD") val schd: SchdXml? = null, @param:JacksonXmlProperty(localName = "FLOP") val flop: FlightRecordXml? = null, ) @JsonIgnoreProperties(ignoreUnknown = true) data class SisMetaXml( @param:JacksonXmlProperty(localName = "SNDR") val sndr: String? = null, @param:JacksonXmlProperty(localName = "SEQN") val seqn: Long? = null, @param:JacksonXmlProperty(localName = "DTTM") val dttm: Long? = null, @param:JacksonXmlProperty(localName = "TYPE") val type: String? = null, @param:JacksonXmlProperty(localName = "STYP") val styp: String? = null, ) @JsonIgnoreProperties(ignoreUnknown = true) data class SchdXml( @param:JacksonXmlProperty(localName = "RECS") val recs: Int? = null, @param:JacksonXmlElementWrapper(useWrapping = false) @param:JacksonXmlProperty(localName = "FLTR") val fltr: List = emptyList(), ) @JsonIgnoreProperties(ignoreUnknown = true) data class FlightRecordXml( @param:JacksonXmlProperty(localName = "FLID") val flid: String? = null, @param:JacksonXmlProperty(localName = "FDEL") val fdel: FdelXml? = null, @param:JacksonXmlProperty(localName = "ALCD") val alcd: String? = null, @param:JacksonXmlProperty(localName = "ALSC") val alsc: String? = null, @param:JacksonXmlProperty(localName = "FLNO") val flno: String? = null, @param:JacksonXmlProperty(localName = "MVIN") val mvin: String? = null, @param:JacksonXmlProperty(localName = "SODT") val sodt: String? = null, @param:JacksonXmlProperty(localName = "FLTY") val flty: String? = null, @param:JacksonXmlProperty(localName = "FLIN") val flin: String? = null, @param:JacksonXmlProperty(localName = "ACFT") val acft: String? = null, @param:JacksonXmlProperty(localName = "RENO") val reno: String? = null, @param:JacksonXmlProperty(localName = "TAOP") val taop: String? = null, @param:JacksonXmlProperty(localName = "TAFL") val tafl: String? = null, @param:JacksonXmlProperty(localName = "TAID") val taid: String? = null, @param:JacksonXmlProperty(localName = "TRML") val trml: String? = null, @param:JacksonXmlProperty(localName = "MAXP") val maxp: String? = null, @param:JacksonXmlProperty(localName = "CSOP") val csop: String? = null, @param:JacksonXmlProperty(localName = "CSFT") val csft: String? = null, @param:JacksonXmlProperty(localName = "MAID") val maid: String? = null, @param:JacksonXmlProperty(localName = "ESTT") val estt: String? = null, @param:JacksonXmlProperty(localName = "ACTT") val actt: String? = null, @param:JacksonXmlProperty(localName = "STND") val stnd: String? = null, @param:JacksonXmlProperty(localName = "PHAG") val phag: String? = null, @param:JacksonXmlProperty(localName = "CNCL") val cncl: String? = null, @param:JacksonXmlProperty(localName = "REMC") val remc: String? = null, @param:JacksonXmlProperty(localName = "BOTM") val botm: String? = null, @param:JacksonXmlProperty(localName = "LACL") val lacl: String? = null, @param:JacksonXmlProperty(localName = "FINT") val fint: String? = null, @param:JacksonXmlProperty(localName = "APPT") val appt: String? = null, @param:JacksonXmlProperty(localName = "EGSR") val egsr: String? = null, @param:JacksonXmlProperty(localName = "EGST") val egst: String? = null, @param:JacksonXmlProperty(localName = "FHAG") val fhag: String? = null, @param:JacksonXmlProperty(localName = "MHAG") val mhag: String? = null, @param:JacksonXmlProperty(localName = "VIPP") val vipp: String? = null, @param:JacksonXmlProperty(localName = "VIPR") val vipr: String? = null, @param:JacksonXmlProperty(localName = "LBNO") val lbno: String? = null, @param:JacksonXmlProperty(localName = "LBWT") val lbwt: String? = null, @param:JacksonXmlProperty(localName = "PAXC") val paxc: String? = null, @param:JacksonXmlProperty(localName = "EXSC") val exsc: String? = null, @param:JacksonXmlProperty(localName = "EXSR") val exsr: String? = null, @param:JacksonXmlProperty(localName = "FTSS") val ftss: String? = null, @param:JacksonXmlProperty(localName = "PEDT") val pedt: String? = null, @param:JacksonXmlProperty(localName = "NAAT") val naat: String? = null, @param:JacksonXmlProperty(localName = "NEAT") val neat: String? = null, @param:JacksonXmlProperty(localName = "PADT") val padt: String? = null, @param:JacksonXmlElementWrapper(useWrapping = false) @param:JacksonXmlProperty(localName = "GTDT") val gtdt: List = emptyList(), @param:JacksonXmlElementWrapper(useWrapping = false) @param:JacksonXmlProperty(localName = "CKDT") val ckdt: List = emptyList(), @param:JacksonXmlElementWrapper(useWrapping = false) @param:JacksonXmlProperty(localName = "CLDT") val cldt: List = emptyList(), @param:JacksonXmlElementWrapper(useWrapping = false) @param:JacksonXmlProperty(localName = "PSDT") val psdt: List = emptyList(), @param:JacksonXmlElementWrapper(useWrapping = false) @param:JacksonXmlProperty(localName = "CHDT") val chdt: List = emptyList(), @param:JacksonXmlElementWrapper(useWrapping = false) @param:JacksonXmlProperty(localName = "DELY") val dely: List = emptyList(), @param:JacksonXmlElementWrapper(useWrapping = false) @param:JacksonXmlProperty(localName = "ABTM") val abtm: List = emptyList(), @param:JacksonXmlElementWrapper(useWrapping = false) @param:JacksonXmlProperty(localName = "CHOT") val chot: List = emptyList(), @param:JacksonXmlElementWrapper(useWrapping = false) @param:JacksonXmlProperty(localName = "ROUT") val rout: List = emptyList(), @param:JacksonXmlElementWrapper(useWrapping = false) @param:JacksonXmlProperty(localName = "ERUT") val erut: List = emptyList(), // SRVT/VIPF 用可空表达"段是否出现":null = 未出现;出现即为列表(空元素得到一行空行)。 // 两者都不落明细表、不参与合并,清空语义待 `Q2`(`[G-SRVT-VIPF]`)。 @param:JacksonXmlElementWrapper(useWrapping = false) @param:JacksonXmlProperty(localName = "SRVT") val srvt: List? = null, @param:JacksonXmlElementWrapper(useWrapping = false) @param:JacksonXmlProperty(localName = "VIPF") val vipf: List? = null, ) @JsonIgnoreProperties(ignoreUnknown = true) class FdelXml @JsonIgnoreProperties(ignoreUnknown = true) data class GtdtXml( @param:JacksonXmlProperty(isAttribute = true, localName = "GTNO") val gtno: String? = null, @param:JacksonXmlProperty(localName = "GATE") val gate: String? = null, @param:JacksonXmlProperty(localName = "PGOT") val pgot: String? = null, @param:JacksonXmlProperty(localName = "PGCT") val pgct: String? = null, @param:JacksonXmlProperty(localName = "GOTM") val gotm: String? = null, @param:JacksonXmlProperty(localName = "GCTM") val gctm: String? = null, @param:JacksonXmlProperty(localName = "GTYP") val gtyp: String? = null, ) @JsonIgnoreProperties(ignoreUnknown = true) data class CkdtXml( @param:JacksonXmlProperty(isAttribute = true, localName = "CKNO") val ckno: String? = null, @param:JacksonXmlProperty(localName = "CHKC") val chkc: String? = null, @param:JacksonXmlProperty(localName = "CCLS") val ccls: String? = null, @param:JacksonXmlProperty(localName = "PCOT") val pcot: String? = null, @param:JacksonXmlProperty(localName = "PCCT") val pcct: String? = null, @param:JacksonXmlProperty(localName = "COTM") val cotm: String? = null, @param:JacksonXmlProperty(localName = "CCTM") val cctm: String? = null, @param:JacksonXmlProperty(localName = "CTYP") val ctyp: String? = null, ) @JsonIgnoreProperties(ignoreUnknown = true) data class CldtXml( @param:JacksonXmlProperty(isAttribute = true, localName = "CLNO") val clno: String? = null, @param:JacksonXmlProperty(localName = "BELT") val belt: String? = null, @param:JacksonXmlProperty(localName = "BCLS") val bcls: String? = null, @param:JacksonXmlProperty(localName = "PCOT") val pcot: String? = null, @param:JacksonXmlProperty(localName = "PCCT") val pcct: String? = null, @param:JacksonXmlProperty(localName = "FBAG") val fbag: String? = null, @param:JacksonXmlProperty(localName = "LBAG") val lbag: String? = null, @param:JacksonXmlProperty(localName = "BTYP") val btyp: String? = null, ) @JsonIgnoreProperties(ignoreUnknown = true) data class PsdtXml( @param:JacksonXmlProperty(isAttribute = true, localName = "PSNO") val psno: String? = null, @param:JacksonXmlProperty(localName = "PSST") val psst: String? = null, @param:JacksonXmlProperty(localName = "STST") val stst: String? = null, @param:JacksonXmlProperty(localName = "STET") val stet: String? = null, ) @JsonIgnoreProperties(ignoreUnknown = true) data class ChdtXml( @param:JacksonXmlProperty(isAttribute = true, localName = "CHNO") val chno: String? = null, @param:JacksonXmlProperty(localName = "CHUT") val chut: String? = null, // SIS 的 CHDT 类字段固定为 CCLS/CTYP(implementation.md「动态运行事件」);曾误绑 CHCLS/CHTYP @param:JacksonXmlProperty(localName = "CCLS") val ccls: String? = null, @param:JacksonXmlProperty(localName = "PCBT") val pcbt: String? = null, @param:JacksonXmlProperty(localName = "PCET") val pcet: String? = null, @param:JacksonXmlProperty(localName = "CBTM") val cbtm: String? = null, @param:JacksonXmlProperty(localName = "CETM") val cetm: String? = null, @param:JacksonXmlProperty(localName = "CTYP") val ctyp: String? = null, ) @JsonIgnoreProperties(ignoreUnknown = true) data class DelyXml( @param:JacksonXmlProperty(isAttribute = true, localName = "CODE") val code: String? = null, @param:JacksonXmlProperty(isAttribute = true, localName = "STRT") val strt: String? = null, @param:JacksonXmlProperty(isAttribute = true, localName = "DURA") val dura: String? = null, ) { @field:JacksonXmlText var text: String? = null } @JsonIgnoreProperties(ignoreUnknown = true) data class AbtmXml( @param:JacksonXmlProperty(isAttribute = true, localName = "ASNO") val asno: String? = null, @param:JacksonXmlProperty(localName = "ABDG") val abdg: String? = null, @param:JacksonXmlProperty(localName = "ABOP") val abop: String? = null, @param:JacksonXmlProperty(localName = "AOTM") val aotm: String? = null, ) @JsonIgnoreProperties(ignoreUnknown = true) data class ChotXml( @param:JacksonXmlProperty(isAttribute = true, localName = "CSNO") val csno: String? = null, @param:JacksonXmlProperty(localName = "CHID") val chid: String? = null, @param:JacksonXmlProperty(localName = "CHST") val chst: String? = null, @param:JacksonXmlProperty(localName = "CHTM") val chtm: String? = null, ) @JsonIgnoreProperties(ignoreUnknown = true) data class RoutXml( @param:JacksonXmlProperty(isAttribute = true, localName = "RTNO") val rtno: String? = null, @param:JacksonXmlProperty(localName = "APCD") val apcd: String? = null, @param:JacksonXmlProperty(localName = "SCAT") val scat: String? = null, @param:JacksonXmlProperty(localName = "SCDT") val scdt: String? = null, ) /** * SIS `SRVT`/`SERVICEDATA`(SCHD)与 `OPT_SERVICEDATA`(FLOP):一次服务明细,可重复出现。 * * 字段形态以 `docs/legacy/unisysaodbsis.xsd` 为准。`OPER` 是元素属性,SIS 正文未记载其值域; * `SANR`/`SARR` 只出现在 FLOP 的 `OPT_SERVICEDATA`。协议未给序号属性,故没有源序号。 */ @JsonIgnoreProperties(ignoreUnknown = true) data class SrvtXml( @param:JacksonXmlProperty(isAttribute = true, localName = "OPER") val oper: String? = null, @param:JacksonXmlProperty(localName = "SRTC") val srtc: String? = null, @param:JacksonXmlProperty(localName = "SRQT") val srqt: String? = null, @param:JacksonXmlProperty(localName = "SRST") val srst: String? = null, @param:JacksonXmlProperty(localName = "SRET") val sret: String? = null, @param:JacksonXmlProperty(localName = "SRPR") val srpr: String? = null, @param:JacksonXmlProperty(localName = "SANR") val sanr: String? = null, @param:JacksonXmlProperty(localName = "SARR") val sarr: String? = null, ) /** * SIS `VIPF`/`VIPDATA`(SCHD)与 `OPT_VIPDATA`(FLOP):一位 VIP,可重复出现。 * * `VIPT` 按 XSD 至多一个;SIS 正文"每个 VIP 重复"的说法与之冲突,形态以 XSD 为准。 */ @JsonIgnoreProperties(ignoreUnknown = true) data class VipfXml( @param:JacksonXmlProperty(isAttribute = true, localName = "OPER") val oper: String? = null, @param:JacksonXmlProperty(localName = "VPCD") val vpcd: String? = null, @param:JacksonXmlProperty(localName = "VFES") val vfes: String? = null, @param:JacksonXmlProperty(localName = "VIPT") val vipt: ViptXml? = null, ) /** SIS `VIPT`/`VIPTXNDATA`:VIP 关联的服务交易明细,嵌套在 [VipfXml] 内。 */ @JsonIgnoreProperties(ignoreUnknown = true) data class ViptXml( @param:JacksonXmlProperty(isAttribute = true, localName = "OPER") val oper: String? = null, @param:JacksonXmlProperty(localName = "VSCD") val vscd: String? = null, @param:JacksonXmlProperty(localName = "VTQY") val vtqy: String? = null, @param:JacksonXmlProperty(localName = "VTST") val vtst: String? = null, @param:JacksonXmlProperty(localName = "VTET") val vtet: String? = null, )