Files
msgexchange-v2/src/main/kotlin/com/gzzn/omms/msgexchange/codec/SisMessageBody.kt
T
windyboyandCursor 02b0b2f189 feat(flight): UNMAPPED_FIELD、SRVT/VIPF 明细与白名单内未映射留档(ACM2-89/99/100)
V5 迁移;集合段出现才写;白名单 7 类内未落态写入 UNMAPPED_FIELD,不扩白名单。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-21 15:54:55 +08:00

320 lines
17 KiB
Kotlin
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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
import com.gzzn.omms.msgexchange.domain.flight.UnmappedFieldEntry
/** Stable payload boundary used by processing. It is deliberately not an XML model. */
data class FlopPayload(
val flid: String,
val scalars: Map<String, String> = emptyMap(),
val collections: Map<String, List<Map<String, String>>> = emptyMap(),
val unmapped: List<UnmappedFieldEntry> = emptyList(),
)
data class ScheduleBody(
val recsDeclared: Int,
val records: List<ScheduleRecord>,
)
/**
* `SRVT`/`VIPF` 集合键(`[G-SRVT-VIPF]`):用于入站出现次数指标;明细落库见 `FLIGHT_SRVT`/`FLIGHT_VIPF`
* 不参与合并层与 Redis 快照。
*/
private val UNPERSISTED_COLLECTION_KEYS: Set<String> = setOf("SRVT", "VIPF")
/**
* 一条解码载荷里各未落库集合命中的**记录数**`[G-SRVT-VIPF]`)。
*
* 按记录计(一条记录带该段即算 1),不按段内元素计;只返回命中项。载荷类型不在
* [ScheduleBody] / [FlopPayload] 之内时返回空——调用方不得据此改变处理结果。
*/
fun unpersistedCollectionHits(body: Any?): Map<String, Int> {
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,
@param:JacksonXmlProperty(localName = "EROR") val eror: ErorXml? = null,
@param:JacksonXmlProperty(localName = "RQFD") val rqfd: RqfdXml? = null,
@param:JacksonXmlProperty(localName = "RQRD") val rqrd: RqrdXml? = null,
)
@JsonIgnoreProperties(ignoreUnknown = true)
data class ErorXml(
@param:JacksonXmlProperty(localName = "SEQS") val seqs: Long? = null,
@param:JacksonXmlProperty(localName = "TYPS") val typs: String? = null,
@param:JacksonXmlProperty(localName = "STYS") val stys: String? = null,
@param:JacksonXmlProperty(localName = "ETEX") val etex: String? = null,
)
/** 出站 RQFD 空体占位(C-4 全量不带 STDB/STDE)。 */
@JsonIgnoreProperties(ignoreUnknown = true)
class RqfdXml
@JsonIgnoreProperties(ignoreUnknown = true)
data class RqrdXml(
@param:JacksonXmlProperty(localName = "RTYP") val rtyp: String? = null,
)
@JsonIgnoreProperties(ignoreUnknown = true)
@JacksonXmlRootElement(localName = "MSG")
data class SisOutboundMessageXml(
@param:JacksonXmlProperty(localName = "META") val meta: SisMetaXml,
@param:JacksonXmlProperty(localName = "RQFD") val rqfd: RqfdXml? = null,
@param:JacksonXmlProperty(localName = "RQRD") val rqrd: RqrdXml? = 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<FlightRecordXml> = 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<GtdtXml> = emptyList(),
@param:JacksonXmlElementWrapper(useWrapping = false) @param:JacksonXmlProperty(localName = "CKDT") val ckdt: List<CkdtXml> = emptyList(),
@param:JacksonXmlElementWrapper(useWrapping = false) @param:JacksonXmlProperty(localName = "CLDT") val cldt: List<CldtXml> = emptyList(),
@param:JacksonXmlElementWrapper(useWrapping = false) @param:JacksonXmlProperty(localName = "PSDT") val psdt: List<PsdtXml> = emptyList(),
@param:JacksonXmlElementWrapper(useWrapping = false) @param:JacksonXmlProperty(localName = "CHDT") val chdt: List<ChdtXml> = emptyList(),
@param:JacksonXmlElementWrapper(useWrapping = false) @param:JacksonXmlProperty(localName = "DELY") val dely: List<DelyXml> = emptyList(),
@param:JacksonXmlElementWrapper(useWrapping = false) @param:JacksonXmlProperty(localName = "ABTM") val abtm: List<AbtmXml> = emptyList(),
@param:JacksonXmlElementWrapper(useWrapping = false) @param:JacksonXmlProperty(localName = "CHOT") val chot: List<ChotXml> = emptyList(),
@param:JacksonXmlElementWrapper(useWrapping = false) @param:JacksonXmlProperty(localName = "ROUT") val rout: List<RoutXml> = emptyList(),
@param:JacksonXmlElementWrapper(useWrapping = false) @param:JacksonXmlProperty(localName = "ERUT") val erut: List<RoutXml> = emptyList(),
// SRVT/VIPF 用可空表达"段是否出现":null = 未出现;出现即为列表(空元素得到一行空行)。
// 明细表见 `G-SRVT-VIPF`;缺席是否清除待 `Q2`,现行默认不删已有行。
@param:JacksonXmlElementWrapper(useWrapping = false) @param:JacksonXmlProperty(localName = "SRVT") val srvt: List<SrvtXml>? = null,
@param:JacksonXmlElementWrapper(useWrapping = false) @param:JacksonXmlProperty(localName = "VIPF") val vipf: List<VipfXml>? = null,
@param:JacksonXmlProperty(localName = "FDIV") val fdiv: FdivXml? = null,
@param:JacksonXmlProperty(localName = "FRET") val fret: FretXml? = null,
)
@JsonIgnoreProperties(ignoreUnknown = true)
data class FdivXml(
@param:JacksonXmlProperty(isAttribute = true, localName = "DDES") val ddes: String? = null,
@param:JacksonXmlProperty(isAttribute = true, localName = "DDIR") val ddir: String? = null,
) {
@field:JacksonXmlText
var text: String? = null
}
@JsonIgnoreProperties(ignoreUnknown = true)
data class FretXml(
@param:JacksonXmlProperty(isAttribute = true, localName = "REID") val reid: String? = null,
) {
@field:JacksonXmlText
var text: String? = 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/CTYPimplementation.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,
)