fix(qsl): separate the QSL manager from the routing method (#16)

QSL_VIA is the manager. QSL_SENT_VIA and QSL_RCVD_VIA are the ADIF "QSL Via"
enumeration — B bureau, D direct, E electronic, M manager (import-only) —
and say how a card travelled. OpsLog had one column for all three:

  - the import folded QSL_SENT_VIA into QSL_VIA whenever QSL_VIA was empty,
    which is exactly a Log4OM export (it defaults QSL_SENT_VIA to E), so
    OE6CLD saw "E" everywhere OpsLog shows the manager;
  - QSL_RCVD_VIA was listed in adifPromoted with no column behind it, so it
    was not stored, not kept among the extras, and not exported — dropped
    outright on import;
  - neither was ever written on export, so an import followed by an export
    destroyed both;
  - and OpsLog polluted the field itself: the QSL Manager panel wrote
    "Bureau" / "Direct" / "Electronic", in full words, into QSL_VIA.

Two columns added (migration 0027), carried through the five places a
promoted ADIF field has to touch, with round-trip tests pinning the reported
case. The QSL panel now offers Bureau / Direct / Electronic for each
direction and stores the enumeration; the manager field is labelled as the
manager and holds only that. M is kept when a file gives it and never
written back out.

Existing logs hold a mixture of the two in one column. The repair is offered,
not performed: the count is shown once per log with a plain question, and a
"no" is remembered. It moves only where QSL_SENT_VIA is still empty, and only
values that normalise to the enumeration — a manager is a callsign and can
never be one of those six words, which a test pins against real manager calls.
This commit is contained in:
2026-08-14 11:50:25 +02:00
parent 30143b01bf
commit 4e88bdfaa7
20 changed files with 542 additions and 35 deletions
+6
View File
@@ -176,6 +176,8 @@ export function DiscoverFlexRadios():Promise<Array<cat.FlexRadio>>;
export function DismissAwardUpdate(arg1:string):Promise<void>;
export function DismissQSLViaRepair():Promise<void>;
export function DownloadAllReferenceLists():Promise<string>;
export function DownloadAndApplyUpdate(arg1:string):Promise<void>;
@@ -808,6 +810,8 @@ export function QSLSetDefaultTemplate(arg1:number):Promise<void>;
export function QSLStylePresets():Promise<Array<main.QSLPresetInfo>>;
export function QSLViaRepairStatus():Promise<main.QSLViaRepairStatus>;
export function QSOAudioBegin():Promise<boolean>;
export function QSOAudioCancel():Promise<void>;
@@ -846,6 +850,8 @@ export function RenameLogbook(arg1:string):Promise<void>;
export function RenderEQSL(arg1:number,arg2:number):Promise<string>;
export function RepairQSLVia():Promise<main.QSLViaRepairResult>;
export function ReplaceAwardReferences(arg1:string,arg2:Array<awardref.Ref>):Promise<number>;
export function ReportLiveActivity(arg1:number,arg2:string,arg3:string):Promise<void>;
+12
View File
@@ -294,6 +294,10 @@ export function DismissAwardUpdate(arg1) {
return window['go']['main']['App']['DismissAwardUpdate'](arg1);
}
export function DismissQSLViaRepair() {
return window['go']['main']['App']['DismissQSLViaRepair']();
}
export function DownloadAllReferenceLists() {
return window['go']['main']['App']['DownloadAllReferenceLists']();
}
@@ -1558,6 +1562,10 @@ export function QSLStylePresets() {
return window['go']['main']['App']['QSLStylePresets']();
}
export function QSLViaRepairStatus() {
return window['go']['main']['App']['QSLViaRepairStatus']();
}
export function QSOAudioBegin() {
return window['go']['main']['App']['QSOAudioBegin']();
}
@@ -1634,6 +1642,10 @@ export function RenderEQSL(arg1, arg2) {
return window['go']['main']['App']['RenderEQSL'](arg1, arg2);
}
export function RepairQSLVia() {
return window['go']['main']['App']['RepairQSLVia']();
}
export function ReplaceAwardReferences(arg1, arg2) {
return window['go']['main']['App']['ReplaceAwardReferences'](arg1, arg2);
}
+30
View File
@@ -2859,6 +2859,32 @@ export namespace main {
this.updated_at = source["updated_at"];
}
}
export class QSLViaRepairResult {
moved: number;
static createFrom(source: any = {}) {
return new QSLViaRepairResult(source);
}
constructor(source: any = {}) {
if ('string' === typeof source) source = JSON.parse(source);
this.moved = source["moved"];
}
}
export class QSLViaRepairStatus {
affected: number;
asked: boolean;
static createFrom(source: any = {}) {
return new QSLViaRepairStatus(source);
}
constructor(source: any = {}) {
if ('string' === typeof source) source = JSON.parse(source);
this.affected = source["affected"];
this.asked = source["asked"];
}
}
export class QSOAwardRef {
code: string;
ref: string;
@@ -4330,6 +4356,8 @@ export namespace qso {
qsl_sent_date?: string;
qsl_rcvd_date?: string;
qsl_via?: string;
qsl_sent_via?: string;
qsl_rcvd_via?: string;
qsl_msg?: string;
qslmsg_rcvd?: string;
lotw_sent?: string;
@@ -4469,6 +4497,8 @@ export namespace qso {
this.qsl_sent_date = source["qsl_sent_date"];
this.qsl_rcvd_date = source["qsl_rcvd_date"];
this.qsl_via = source["qsl_via"];
this.qsl_sent_via = source["qsl_sent_via"];
this.qsl_rcvd_via = source["qsl_rcvd_via"];
this.qsl_msg = source["qsl_msg"];
this.qslmsg_rcvd = source["qslmsg_rcvd"];
this.lotw_sent = source["lotw_sent"];