fix(import): "fill my station fields" fills the station callsign too

STATION_CALLSIGN was the one field the option deliberately skipped, on the
grounds that stamping the active call could re-route a mixed-call log.

That protected nothing. The same option already writes this profile's grid,
rig, antenna, city and postal address onto every record it finds blank — it
has assumed "this log is mine" long before it reaches the callsign. And the
thing that actually keeps a multi-op log intact is that a record CARRYING a
station callsign is never touched, which has always been true and still is.
Withholding it only meant the option quietly failed on the one field an
operator goes and checks afterwards, leaving imported QSOs with no station
call at all — invisible in the ADIF they export, and unroutable for LoTW
and Club Log.

Counted and logged: "did it fill the callsign?" is the first question after
an import, and the log is where it gets answered.
This commit is contained in:
2026-08-18 11:08:45 +02:00
parent 628d1e8490
commit f0e00c63a3
3 changed files with 33 additions and 10 deletions
+27 -6
View File
@@ -3155,9 +3155,10 @@ func (a *App) applyStationDefaults(q *qso.QSO, includeIdentity bool) {
if err != nil {
return
}
// STATION_CALLSIGN drives upload routing, so only stamp it on NEW QSOs — on
// import backfill, stamping the active call onto a QSO that lacked one could
// misroute it in a mixed-call log.
// STATION_CALLSIGN drives upload routing, so it is filled only when the
// caller asks for identity — and only when the record has none. A QSO that
// already names its station keeps it, which is what stops a mixed-call log
// being re-routed; a QSO with the field blank has nothing to protect.
if includeIdentity && q.StationCallsign == "" {
q.StationCallsign = p.Callsign
}
@@ -6811,6 +6812,9 @@ func (a *App) ImportADIF(path string, dupMode string, applyCty bool, applyStatio
_ = a.clublog.EnsureLoaded()
}
clLoaded := a.clublog != nil && a.clublog.Loaded()
// Counted rather than assumed: "did it fill the callsign?" is the first
// question after an import, and the log is where it gets answered.
stationStamped := 0
if applyCty || applyStation {
im.Enrich = func(q *qso.QSO) {
if applyCty {
@@ -6822,9 +6826,23 @@ func (a *App) ImportADIF(path string, dupMode string, applyCty bool, applyStatio
// Unconditional: see fillDistance.
fillDistance(q)
if applyStation {
// Backfill empty MY_* descriptive fields from the active profile
// (identity fields left alone to keep mixed-call routing intact).
a.applyStationDefaults(q, false)
// Backfill every empty station field from the active profile,
// STATION_CALLSIGN included.
//
// It used to be the one field held back, on the grounds that
// stamping the active call could re-route a mixed-call log. That
// protected nothing: the same option already writes this profile's
// grid, rig, antenna and postal address onto every record it finds
// blank, so it has assumed "this log is mine" long before reaching
// the callsign — and a record that CARRIES a call is never touched,
// which is what actually keeps a multi-op log intact. Withholding it
// only meant the option quietly failed the one field an operator
// checks afterwards.
hadStation := strings.TrimSpace(q.StationCallsign) != ""
a.applyStationDefaults(q, true)
if !hadStation && strings.TrimSpace(q.StationCallsign) != "" {
stationStamped++
}
// Also stamp the default QSL/LoTW/eQSL confirmation statuses on
// any that are still empty (same defaults new QSOs get).
a.applyQSLDefaults(q)
@@ -6835,6 +6853,9 @@ func (a *App) ImportADIF(path string, dupMode string, applyCty bool, applyStatio
wruntime.EventsEmit(a.ctx, "import:progress", map[string]int{"processed": processed, "total": total})
}
res, err := im.ImportFile(a.ctx, path)
if stationStamped > 0 {
applog.Printf("import: STATION_CALLSIGN filled from the active profile on %d record(s) that carried none", stationStamped)
}
if err == nil && (res.Imported > 0 || res.Updated > 0) {
a.recomputeAwardRefsAsync() // materialise award_refs for the imported rows
}