up
This commit is contained in:
@@ -94,7 +94,8 @@ const (
|
||||
|
||||
keyAwardDefs = "awards.defs" // JSON array of award definitions (editable)
|
||||
keyAwardRefsUpdated = "awards.refs.updated." // + CODE → last list-update timestamp
|
||||
keyAwardRefsSeeded = "awards.refs.seeded" // "1" once built-in lists were seeded
|
||||
keyAwardRefsSeeded = "awards.refs.seeded" // built-in reference-list seed version
|
||||
keyAwardDefsFixed = "awards.defs.fixed" // built-in award def correction version
|
||||
|
||||
keyClublogCtyEnabled = "clublog.cty_exceptions" // "1" → apply ClubLog exceptions
|
||||
|
||||
@@ -1072,6 +1073,7 @@ func (a *App) AddQSO(q qso.QSO) (int64, error) {
|
||||
a.applyStationDefaults(&q)
|
||||
a.applyDXCCNumber(&q)
|
||||
a.applyClublogException(&q, false) // override entity for date-ranged DXpeditions
|
||||
a.refineDistrictZones(&q) // W6 → CQ3/ITU6 for zone-split countries
|
||||
a.applyQSLDefaults(&q)
|
||||
// Fill the contacted operator's e-mail from the (cached) lookup so the
|
||||
// recording can be auto-sent. Cheap: the entry already looked the call up.
|
||||
@@ -1141,6 +1143,11 @@ func (a *App) ComputeStationInfo(callsign, grid string) StationInfoComputed {
|
||||
out.Lat = m.Lat
|
||||
out.Lon = m.Lon
|
||||
out.DXCC = dxcc.EntityDXCC(m.Entity.Name)
|
||||
// Refine zones by call district (W6 → CQ3/ITU6) so the entry strip
|
||||
// shows what will be logged.
|
||||
if cqz, ituz, ok := dxcc.ZoneByCallDistrict(out.DXCC, callsign); ok {
|
||||
out.CQZ, out.ITUZ = cqz, ituz
|
||||
}
|
||||
}
|
||||
}
|
||||
// Grid wins on lat/lon — it's user-set, finer than the DXCC centroid.
|
||||
@@ -1167,6 +1174,20 @@ func (a *App) applyDXCCNumber(q *qso.QSO) {
|
||||
}
|
||||
}
|
||||
|
||||
// refineDistrictZones sets the CQ/ITU zone from the call district for
|
||||
// zone-split countries (USA, Australia), so every entry point — manual,
|
||||
// UDP, import, re-stamp, award scan — agrees on W6 = CQ3/ITU6 instead of the
|
||||
// coarse per-entity default. Call AFTER the DXCC is finalised.
|
||||
func (a *App) refineDistrictZones(q *qso.QSO) {
|
||||
if q.DXCC == nil {
|
||||
return
|
||||
}
|
||||
if cqz, ituz, ok := dxcc.ZoneByCallDistrict(*q.DXCC, q.Callsign); ok {
|
||||
zc, zi := cqz, ituz
|
||||
q.CQZ, q.ITUZ = &zc, &zi
|
||||
}
|
||||
}
|
||||
|
||||
// applyStationDefaults fills any empty MY_* / station field on q with the
|
||||
// currently-active profile's values. Multi-profile support means a user
|
||||
// can be /P with a different callsign + grid + SOTA ref than home — the
|
||||
@@ -1354,12 +1375,31 @@ func (a *App) migrateAwardDefs() {
|
||||
return
|
||||
}
|
||||
migrated, changed := award.Migrate(defs)
|
||||
// Version-gated correction of the built-in awards' Validate sources, which
|
||||
// an earlier version wrongly set equal to Confirm (so VALIDATED == CONFIRMED
|
||||
// even for paper-QSL-only entities). Re-apply the canonical Confirm/Validate
|
||||
// from Defaults to protected/built-in awards once.
|
||||
const defsFixVersion = "2"
|
||||
if v, _ := a.settings.Get(a.ctx, keyAwardDefsFixed); v != defsFixVersion {
|
||||
byCode := map[string]award.Def{}
|
||||
for _, d := range award.Defaults() {
|
||||
byCode[strings.ToUpper(d.Code)] = d
|
||||
}
|
||||
for i := range migrated {
|
||||
if d, ok := byCode[strings.ToUpper(migrated[i].Code)]; ok && (migrated[i].Builtin || migrated[i].Protected) {
|
||||
migrated[i].Confirm = d.Confirm
|
||||
migrated[i].Validate = d.Validate
|
||||
changed = true
|
||||
}
|
||||
}
|
||||
_ = a.settings.Set(a.ctx, keyAwardDefsFixed, defsFixVersion)
|
||||
}
|
||||
if !changed {
|
||||
return
|
||||
}
|
||||
if b, err := json.Marshal(migrated); err == nil {
|
||||
_ = a.settings.Set(a.ctx, keyAwardDefs, string(b))
|
||||
applog.Printf("awards: migrated %d legacy definitions to the new model", len(migrated))
|
||||
applog.Printf("awards: migrated/fixed %d definitions", len(migrated))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1716,6 +1756,10 @@ func (a *App) enrichQSOForAwards(q *qso.QSO) {
|
||||
q.DXCC = &n
|
||||
}
|
||||
}
|
||||
// Zone-split countries (USA, Australia): the per-entity default zone is too
|
||||
// coarse (W6 = CQ5 instead of 3). Apply the call-district rule so awards
|
||||
// (WAZ / WITUZ) match Log4OM. This OVERRIDES a stored entity-default zone.
|
||||
a.refineDistrictZones(q)
|
||||
}
|
||||
|
||||
// awardBandPlan maps a frequency (Hz) to its ADIF band. Used to recover the
|
||||
@@ -1932,25 +1976,37 @@ func (a *App) HasBuiltinReferences(code string) bool {
|
||||
return ok
|
||||
}
|
||||
|
||||
// seedBuiltinReferences populates the reference lists of built-in awards on
|
||||
// first run (idempotent: only seeds an award that currently has none, and only
|
||||
// once overall, tracked by a settings flag so a user who clears a list is not
|
||||
// overruled on the next launch).
|
||||
// builtinRefsVersion is bumped whenever the built-in reference data changes
|
||||
// (e.g. the West Malaysia 155→299 fix) so existing installs re-seed the
|
||||
// derived lists. Bump this after correcting BuiltinRefs / the DXCC name table.
|
||||
const builtinRefsVersion = "2"
|
||||
|
||||
// seedBuiltinReferences populates the reference lists of built-in awards.
|
||||
// - First run (no version stored): seed only awards that have NO references
|
||||
// yet, so an online-loaded list (POTA…) or a user list isn't clobbered.
|
||||
// - Version bump (stored != current): RE-SEED the derived built-in lists
|
||||
// (DXCC, WAZ, WAC, WAS, DDFM) to push data corrections to existing installs.
|
||||
// These lists are canonical, not user-maintained, so overwriting is safe.
|
||||
func (a *App) seedBuiltinReferences() {
|
||||
if a.awardRefs == nil || a.settings == nil {
|
||||
return
|
||||
}
|
||||
if done, _ := a.settings.Get(a.ctx, keyAwardRefsSeeded); done == "1" {
|
||||
ver, _ := a.settings.Get(a.ctx, keyAwardRefsSeeded)
|
||||
if ver == builtinRefsVersion {
|
||||
return
|
||||
}
|
||||
firstRun := ver == "" || ver == "1" // "1" was the old boolean flag
|
||||
if ver == "1" {
|
||||
firstRun = false // already seeded once → treat as a version upgrade
|
||||
}
|
||||
counts, err := a.awardRefs.Counts(a.ctx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for _, d := range a.awardDefs() {
|
||||
code := strings.ToUpper(d.Code)
|
||||
if counts[code] > 0 {
|
||||
continue
|
||||
if firstRun && counts[code] > 0 {
|
||||
continue // don't overwrite an existing list on a fresh install
|
||||
}
|
||||
if refs, ok := awardref.BuiltinRefs(code); ok {
|
||||
if n, err := a.awardRefs.ReplaceAll(a.ctx, code, refs); err == nil {
|
||||
@@ -1958,7 +2014,7 @@ func (a *App) seedBuiltinReferences() {
|
||||
}
|
||||
}
|
||||
}
|
||||
_ = a.settings.Set(a.ctx, keyAwardRefsSeeded, "1")
|
||||
_ = a.settings.Set(a.ctx, keyAwardRefsSeeded, builtinRefsVersion)
|
||||
}
|
||||
|
||||
// ImportAwardReferencesText parses pasted lines or CSV into references and
|
||||
@@ -4100,6 +4156,9 @@ func (a *App) enrichContactedFromCtyForce(q *qso.QSO) bool {
|
||||
v := m.ITUZone
|
||||
q.ITUZ = &v
|
||||
}
|
||||
// Zone-split countries (USA, Australia): refine the per-entity default zone
|
||||
// to the call-district zone (W6 → CQ3/ITU6), matching Log4OM/DXKeeper.
|
||||
a.refineDistrictZones(q)
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -4469,6 +4528,7 @@ func (a *App) LogUDPLoggedADIF(adifText string) (int64, error) {
|
||||
// fields (or what the lookup gave us) always win.
|
||||
a.applyDXCCNumber(&q)
|
||||
a.applyClublogException(&q, false) // date-ranged DXpedition override
|
||||
a.refineDistrictZones(&q) // W6 → CQ3/ITU6 for zone-split countries
|
||||
a.applyQSLDefaults(&q)
|
||||
|
||||
// ── Dedup ──
|
||||
|
||||
Reference in New Issue
Block a user