New test TestCalculateSkillImproveCostNewSystem in chain of learning system

Updated learning_skill_category_difficulties to match rule set
removed SkillImprovementCost replaced by SkillImprovementCost2
This commit is contained in:
2026-02-01 13:21:16 +01:00
parent 3297c408d2
commit 39659bcb3e
20 changed files with 8095 additions and 90 deletions
+113
View File
@@ -368,3 +368,116 @@ func TestCalculateSpellLearnCostNewSystem(t *testing.T) {
})
}
}
// ToDo: add more test cases for other classes dificulties and higher TEs
func TestCalculateSkillImproveCostNewSystem(t *testing.T) {
// Ensure DB is initialized so GetImprovementCost can run without nil DB
database.SetupTestDB()
defer database.ResetTestDB()
tests := []struct {
name string
request gsmaster.LernCostRequest
skillInfo models.SkillLearningInfo
targetLevel int
requiredTE int
requiredEP int
requiredGold int
availablePP int
availableGold int
}{
{
name: "Base cost calculation without rewards",
request: gsmaster.LernCostRequest{},
skillInfo: models.SkillLearningInfo{
SkillName: "Schwimmen",
CategoryName: "Körper",
DifficultyName: "leicht",
ClassCode: "Bb",
EPPerTE: 10,
LearnCost: 1,
},
requiredTE: 1,
requiredEP: 10,
requiredGold: 200,
targetLevel: 13,
availablePP: 0,
availableGold: 0,
}, {
name: "applies PP reduction",
request: gsmaster.LernCostRequest{},
skillInfo: models.SkillLearningInfo{
SkillName: "Schwimmen",
CategoryName: "Körper",
DifficultyName: "leicht",
ClassCode: "Bb",
EPPerTE: 10,
LearnCost: 1,
},
requiredTE: 0,
requiredEP: 0,
requiredGold: 0,
targetLevel: 13,
availablePP: 1,
availableGold: 0,
},
{
name: "converts gold up to half EP",
request: gsmaster.LernCostRequest{},
skillInfo: models.SkillLearningInfo{
SkillName: "Schwimmen",
CategoryName: "Körper",
DifficultyName: "leicht",
ClassCode: "Bb",
EPPerTE: 10,
},
requiredTE: 1,
requiredEP: 5,
targetLevel: 13,
availablePP: 0,
availableGold: 50,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
remainingPP := tt.availablePP
remainingGold := tt.availableGold
result := gsmaster.SkillCostResultNew{
CharacterClass: tt.skillInfo.ClassCode,
SkillName: tt.skillInfo.SkillName,
Category: tt.skillInfo.CategoryName,
Difficulty: tt.skillInfo.DifficultyName,
TargetLevel: tt.targetLevel,
}
err := CalculateSkillImproveCostNewSystem(&tt.request, &result, tt.targetLevel, &remainingPP, &remainingGold, &tt.skillInfo)
assert.NoError(t, err)
// Base EP before gold conversion is computed from post-PP LE
baseEP := tt.skillInfo.EPPerTE * result.LE
originalTrain := result.LE + result.PPUsed
assert.Greater(t, originalTrain, 0, "should have positive training cost")
assert.Equal(t, tt.availablePP-result.PPUsed, remainingPP, "PP tracking should be consistent")
assert.Equal(t, tt.availableGold-result.GoldUsed, remainingGold, "Gold tracking should match usage")
if tt.availablePP > 0 {
assert.Equal(t, tt.availablePP-remainingPP, result.PPUsed, "PP used should reduce remaining PP")
assert.Equal(t, baseEP, result.EP, "No gold in this case; EP equals base")
assert.Equal(t, tt.skillInfo.EPPerTE*result.LE, result.EP)
} else {
expectedGoldUsed := tt.availableGold
halfEPCap := (baseEP / 2) * 10
if expectedGoldUsed > halfEPCap {
expectedGoldUsed = halfEPCap
}
assert.Equal(t, expectedGoldUsed, result.GoldUsed)
assert.Equal(t, baseEP-expectedGoldUsed/10, result.EP)
assert.Equal(t, tt.availableGold-expectedGoldUsed, remainingGold)
}
})
}
}
+31 -23
View File
@@ -1254,30 +1254,37 @@ func ImportSpellLevelLECosts(inputDir string) error {
// ExportSkillImprovementCosts exports all skill improvement costs to a JSON file
func ExportSkillImprovementCosts(outputDir string) error {
var costs []models.SkillImprovementCost
if err := database.DB.Preload("SkillCategoryDifficulty.Skill").
Preload("SkillCategoryDifficulty.SkillCategory").
Preload("SkillCategoryDifficulty.SkillDifficulty").
Find(&costs).Error; err != nil {
var costs []models.SkillImprovementCost2
if err := database.DB.Find(&costs).Error; err != nil {
return fmt.Errorf("failed to fetch skill improvement costs: %w", err)
}
exportable := make([]ExportableSkillImprovementCost, 0, len(costs))
for _, cost := range costs {
// Skip records with incomplete relationships
if cost.SkillCategoryDifficulty.Skill.Name == "" ||
cost.SkillCategoryDifficulty.SkillCategory.Name == "" ||
cost.SkillCategoryDifficulty.SkillDifficulty.Name == "" {
var lc models.SkillCategory
if err := database.DB.First(&lc, cost.CategoryID).Error; err != nil {
continue
}
var ld models.SkillDifficulty
if err := database.DB.First(&ld, cost.DifficultyID).Error; err != nil {
continue
}
var scd models.SkillCategoryDifficulty
if err := database.DB.Where("skill_category = ? AND skill_difficulty = ?", lc.Name, ld.Name).First(&scd).Error; err != nil {
continue
}
var skill models.Skill
if err := database.DB.First(&skill, scd.SkillID).Error; err != nil {
continue
}
exportable = append(exportable, ExportableSkillImprovementCost{
SkillName: cost.SkillCategoryDifficulty.Skill.Name,
SkillSystem: cost.SkillCategoryDifficulty.Skill.GameSystem,
CategoryName: cost.SkillCategoryDifficulty.SkillCategory.Name,
CategorySystem: cost.SkillCategoryDifficulty.SkillCategory.GameSystem,
DifficultyName: cost.SkillCategoryDifficulty.SkillDifficulty.Name,
DifficultySystem: cost.SkillCategoryDifficulty.SkillDifficulty.GameSystem,
SkillName: skill.Name,
SkillSystem: skill.GameSystem,
CategoryName: lc.Name,
CategorySystem: lc.GameSystem,
DifficultyName: ld.Name,
DifficultySystem: ld.GameSystem,
CurrentLevel: cost.CurrentLevel,
TERequired: cost.TERequired,
})
@@ -1325,16 +1332,17 @@ func ImportSkillImprovementCosts(inputDir string) error {
exp.SkillName, exp.CategoryName, exp.DifficultyName, err)
}
// Find or create SkillImprovementCost
var cost models.SkillImprovementCost
result := database.DB.Where("skill_category_difficulty_id = ? AND current_level = ?",
scd.ID, exp.CurrentLevel).First(&cost)
// Find or create SkillImprovementCost2 using category/difficulty IDs
var cost models.SkillImprovementCost2
result := database.DB.Where("skill_category_id = ? AND skill_difficulty_id = ? AND current_level = ?",
categoryID, difficultyID, exp.CurrentLevel).First(&cost)
if result.Error == gorm.ErrRecordNotFound {
cost = models.SkillImprovementCost{
SkillCategoryDifficultyID: scd.ID,
CurrentLevel: exp.CurrentLevel,
TERequired: exp.TERequired,
cost = models.SkillImprovementCost2{
CategoryID: categoryID,
DifficultyID: difficultyID,
CurrentLevel: exp.CurrentLevel,
TERequired: exp.TERequired,
}
if err := database.DB.Create(&cost).Error; err != nil {
return fmt.Errorf("failed to create skill improvement cost: %w", err)
+33 -23
View File
@@ -13,30 +13,39 @@ import (
// ExportSkillImprovementCosts exports all skill improvement costs to a JSON file
func ExportSkillImprovementCosts(outputDir string) error {
var costs []models.SkillImprovementCost
if err := database.DB.Preload("SkillCategoryDifficulty.Skill").
Preload("SkillCategoryDifficulty.SkillCategory").
Preload("SkillCategoryDifficulty.SkillDifficulty").
Find(&costs).Error; err != nil {
var costs []models.SkillImprovementCost2
if err := database.DB.Find(&costs).Error; err != nil {
return fmt.Errorf("failed to fetch skill improvement costs: %w", err)
}
exportable := make([]ExportableSkillImprovementCost, 0, len(costs))
for _, cost := range costs {
// Skip records with incomplete relationships
if cost.SkillCategoryDifficulty.Skill.Name == "" ||
cost.SkillCategoryDifficulty.SkillCategory.Name == "" ||
cost.SkillCategoryDifficulty.SkillDifficulty.Name == "" {
// Resolve category and difficulty names
var lc models.SkillCategory
if err := database.DB.First(&lc, cost.CategoryID).Error; err != nil {
continue
}
var ld models.SkillDifficulty
if err := database.DB.First(&ld, cost.DifficultyID).Error; err != nil {
continue
}
// Find skill via learning_skill_category_difficulties
var scd models.SkillCategoryDifficulty
if err := database.DB.Where("skill_category = ? AND skill_difficulty = ?", lc.Name, ld.Name).First(&scd).Error; err != nil {
continue
}
var skill models.Skill
if err := database.DB.First(&skill, scd.SkillID).Error; err != nil {
continue
}
exportable = append(exportable, ExportableSkillImprovementCost{
SkillName: cost.SkillCategoryDifficulty.Skill.Name,
SkillSystem: cost.SkillCategoryDifficulty.Skill.GameSystem,
CategoryName: cost.SkillCategoryDifficulty.SkillCategory.Name,
CategorySystem: cost.SkillCategoryDifficulty.SkillCategory.GameSystem,
DifficultyName: cost.SkillCategoryDifficulty.SkillDifficulty.Name,
DifficultySystem: cost.SkillCategoryDifficulty.SkillDifficulty.GameSystem,
SkillName: skill.Name,
SkillSystem: skill.GameSystem,
CategoryName: lc.Name,
CategorySystem: lc.GameSystem,
DifficultyName: ld.Name,
DifficultySystem: ld.GameSystem,
CurrentLevel: cost.CurrentLevel,
TERequired: cost.TERequired,
})
@@ -84,16 +93,17 @@ func ImportSkillImprovementCosts(inputDir string) error {
exp.SkillName, exp.CategoryName, exp.DifficultyName, err)
}
// Find or create SkillImprovementCost
var cost models.SkillImprovementCost
result := database.DB.Where("skill_category_difficulty_id = ? AND current_level = ?",
scd.ID, exp.CurrentLevel).First(&cost)
// Find or create SkillImprovementCost2 using category/difficulty IDs
var cost models.SkillImprovementCost2
result := database.DB.Where("skill_category_id = ? AND skill_difficulty_id = ? AND current_level = ?",
categoryID, difficultyID, exp.CurrentLevel).First(&cost)
if result.Error == gorm.ErrRecordNotFound {
cost = models.SkillImprovementCost{
SkillCategoryDifficultyID: scd.ID,
CurrentLevel: exp.CurrentLevel,
TERequired: exp.TERequired,
cost = models.SkillImprovementCost2{
CategoryID: categoryID,
DifficultyID: difficultyID,
CurrentLevel: exp.CurrentLevel,
TERequired: exp.TERequired,
}
if err := database.DB.Create(&cost).Error; err != nil {
return fmt.Errorf("failed to create skill improvement cost: %w", err)
+9 -8
View File
@@ -893,11 +893,12 @@ func TestExportImportSkillImprovementCosts(t *testing.T) {
t.Fatalf("Failed to query SkillCategoryDifficulty: %v", err)
}
// Create SkillImprovementCost
improvementCost := models.SkillImprovementCost{
SkillCategoryDifficultyID: scd.ID,
CurrentLevel: 15, // Use unique level to avoid conflicts
TERequired: 5,
// Create SkillImprovementCost2 (new model)
improvementCost := models.SkillImprovementCost2{
CategoryID: category.ID,
DifficultyID: difficulty.ID,
CurrentLevel: 15, // Use unique level to avoid conflicts
TERequired: 5,
}
database.DB.Create(&improvementCost)
@@ -923,10 +924,10 @@ func TestExportImportSkillImprovementCosts(t *testing.T) {
t.Fatalf("ImportSkillImprovementCosts failed: %v", err)
}
var imported models.SkillImprovementCost
result := database.DB.Where("skill_category_difficulty_id = ? AND current_level = ?", scd.ID, 15).First(&imported)
var imported models.SkillImprovementCost2
result := database.DB.Where("skill_category_id = ? AND skill_difficulty_id = ? AND current_level = ?", category.ID, difficulty.ID, 15).First(&imported)
if result.Error != nil {
t.Fatalf("SkillImprovementCost not found after import: %v", result.Error)
t.Fatalf("SkillImprovementCost2 not found after import: %v", result.Error)
}
// Should be restored to original value from export
@@ -291,7 +291,7 @@ func CreateLearningCostsTables() error {
&models.ClassSpellSchoolEPCost{},
&models.SpellLevelLECost{},
&models.SkillCategoryDifficulty{},
&models.SkillImprovementCost{},
&models.SkillImprovementCost2{},
}
// Erstelle oder migriere alle Tabellen
+26 -8
View File
@@ -5,6 +5,8 @@ import (
"bamort/models"
"fmt"
"log"
"gorm.io/gorm"
)
// MigrateLearningCostsToDatabase überträgt die Daten aus learningCostsData in die Datenbank
@@ -473,16 +475,32 @@ func migrateSkillImprovementCosts() error {
// Für jeden Level in TrainCosts
for level, teCost := range data.TrainCosts {
improvementCost := models.SkillImprovementCost{
SkillCategoryDifficultyID: categoryDifficulty.ID,
CurrentLevel: level,
TERequired: teCost,
var improvementCost models.SkillImprovementCost2
err := database.DB.Where(
"skill_category_id = ? AND skill_difficulty_id = ? AND current_level = ?",
skillCategory.ID, skillDifficulty.ID, level,
).First(&improvementCost).Error
if err == gorm.ErrRecordNotFound {
improvementCost = models.SkillImprovementCost2{
CategoryID: skillCategory.ID,
DifficultyID: skillDifficulty.ID,
CurrentLevel: level,
TERequired: teCost,
}
if err := improvementCost.Create(); err != nil {
return fmt.Errorf("failed to create improvement cost for %s level %d: %w", skillName, level, err)
}
} else if err != nil {
return fmt.Errorf("failed to query improvement cost for %s level %d: %w", skillName, level, err)
} else {
improvementCost.TERequired = teCost
if err := database.DB.Save(&improvementCost).Error; err != nil {
return fmt.Errorf("failed to update improvement cost for %s level %d: %w", skillName, level, err)
}
}
if err := improvementCost.Create(); err != nil {
return fmt.Errorf("failed to create improvement cost for %s level %d: %w", skillName, level, err)
}
log.Printf("Created improvement cost: %s - %s - %s Level %d = %d TE",
log.Printf("Upserted improvement cost: %s - %s - %s Level %d = %d TE",
skillName, categoryName, difficultyName, level, teCost)
}
}
+8 -7
View File
@@ -248,7 +248,7 @@ func copyMariaDBToSQLite(mariaDB, sqliteDB *gorm.DB) error {
&models.SpellLevelLECost{},
&models.SkillCategoryDifficulty{},
&models.WeaponSkillCategoryDifficulty{},
&models.SkillImprovementCost{},
&models.SkillImprovementCost2{},
&models.ClassCategoryLearningPoints{},
&models.ClassSpellPoints{},
&models.ClassTypicalSkill{},
@@ -368,10 +368,11 @@ func copyTableData(sourceDB, targetDB *gorm.DB, model interface{}) error {
}
// Batch in SQLite einfügen
// Use Save() instead of Create() to avoid GORM applying default values to zero values (e.g., false for booleans)
// Use Save() with SkipHooks to preserve raw values and avoid callbacks that rely on global DB state
db := targetDB.Session(&gorm.Session{SkipHooks: true})
for i := 0; i < recordsVal.Len(); i++ {
record := recordsVal.Index(i).Addr().Interface()
if err := targetDB.Save(record).Error; err != nil {
if err := db.Save(record).Error; err != nil {
logger.Error("Fehler beim Speichern von Datensatz in Batch %d für %s: %s", batchNum, tableName, err.Error())
return err
}
@@ -770,7 +771,7 @@ func copySQLiteToMariaDB(sqliteDB, mariaDB *gorm.DB) error {
&models.SpellLevelLECost{},
&models.SkillCategoryDifficulty{}, // Jetzt nach Skills
&models.WeaponSkillCategoryDifficulty{},
&models.SkillImprovementCost{},
&models.SkillImprovementCost2{},
&models.ClassCategoryLearningPoints{},
&models.ClassSpellPoints{},
&models.ClassTypicalSkill{},
@@ -923,8 +924,8 @@ func copyTableDataReverse(sourceDB, targetDB *gorm.DB, model interface{}) error
return fmt.Errorf("failed to read batch from source: %w", err)
}
records = batch
case *models.SkillImprovementCost:
var batch []models.SkillImprovementCost
case *models.SkillImprovementCost2:
var batch []models.SkillImprovementCost2
if err := sourceDB.Limit(batchSize).Offset(offset).Find(&batch).Error; err != nil {
return fmt.Errorf("failed to read batch from source: %w", err)
}
@@ -1162,7 +1163,7 @@ func clearMariaDBData(db *gorm.DB) error {
&models.Char{},
// Learning Costs System - Abhängige Tabellen (vor Skills/Spells löschen)
&models.SkillImprovementCost{},
&models.SkillImprovementCost2{},
&models.WeaponSkillCategoryDifficulty{},
&models.SkillCategoryDifficulty{},
&models.SpellLevelLECost{},
+4 -4
View File
@@ -32,7 +32,7 @@ func TestTableListCompleteness(t *testing.T) {
"*models.SpellLevelLECost": true,
"*models.SkillCategoryDifficulty": true,
"*models.WeaponSkillCategoryDifficulty": true,
"*models.SkillImprovementCost": true,
"*models.SkillImprovementCost2": true,
// GSMaster Base Data
"*models.Skill": true,
@@ -88,7 +88,7 @@ func TestTableListCompleteness(t *testing.T) {
&models.SpellLevelLECost{},
&models.SkillCategoryDifficulty{},
&models.WeaponSkillCategoryDifficulty{},
&models.SkillImprovementCost{},
&models.SkillImprovementCost2{},
&models.Skill{},
&models.WeaponSkill{},
&models.Spell{},
@@ -301,8 +301,8 @@ func getModelTypeName(model interface{}) string {
return "*models.SkillCategoryDifficulty"
case *models.WeaponSkillCategoryDifficulty:
return "*models.WeaponSkillCategoryDifficulty"
case *models.SkillImprovementCost:
return "*models.SkillImprovementCost"
case *models.SkillImprovementCost2:
return "*models.SkillImprovementCost2"
case *models.Skill:
return "*models.Skill"
case *models.WeaponSkill:
+1 -1
View File
@@ -180,12 +180,12 @@ func learningMigrateStructure(db ...*gorm.DB) error {
&SpellLevelLECost{},
&SkillCategoryDifficulty{},
&WeaponSkillCategoryDifficulty{},
&SkillImprovementCost{},
&ClassCategoryLearningPoints{},
&ClassSpellPoints{},
&ClassTypicalSkill{},
&ClassTypicalSpell{},
&AuditLogEntry{},
&SkillImprovementCost2{},
)
if err != nil {
return err
+1 -1
View File
@@ -306,7 +306,7 @@ func TestLearningMigrateStructure_VerifyStructures(t *testing.T) {
&ClassSpellSchoolEPCost{},
&SpellLevelLECost{},
&SkillCategoryDifficulty{},
&SkillImprovementCost{},
&SkillImprovementCost2{},
&AuditLogEntry{},
}
+37 -8
View File
@@ -132,6 +132,7 @@ type WeaponSkillCategoryDifficulty struct {
SCategory string `gorm:"column:skill_category;size:25;not null;index;default:Waffen" json:"skillCategory"`
}
/*
// SkillImprovementCost definiert TE-Kosten für Verbesserungen basierend auf Kategorie, Schwierigkeit und aktuellem Wert
type SkillImprovementCost struct {
ID uint `gorm:"primaryKey" json:"id"`
@@ -139,6 +140,17 @@ type SkillImprovementCost struct {
CurrentLevel int `gorm:"not null;index" json:"current_level"` // Aktueller Fertigkeitswert
TERequired int `gorm:"not null" json:"te_required"` // Benötigte Trainingseinheiten
SkillCategoryDifficulty SkillCategoryDifficulty `gorm:"foreignKey:SkillCategoryDifficultyID;constraint:OnUpdate:CASCADE,OnDelete:CASCADE" json:"skill_category_difficulty"`
CategoryID uint `gorm:"column:skill_category_id;not null;index;default:1" json:"skillCategoryId"` // SkillCategoryID
DifficultyID uint `gorm:"column:skill_difficulty_id;not null;index;default:1" json:"skillDifficultyId"` // SkillDifficultyID
}
*/
// SkillImprovementCost definiert TE-Kosten für Verbesserungen basierend auf Kategorie, Schwierigkeit und aktuellem Wert
type SkillImprovementCost2 struct {
ID uint `gorm:"primaryKey" json:"id"`
CurrentLevel int `gorm:"not null;index" json:"current_level"` // Aktueller Fertigkeitswert
TERequired int `gorm:"not null" json:"te_required"` // Benötigte Trainingseinheiten
CategoryID uint `gorm:"column:skill_category_id;not null;index;default:1" json:"skillCategoryId"` // SkillCategoryID
DifficultyID uint `gorm:"column:skill_difficulty_id;not null;index;default:1" json:"skillDifficultyId"` // SkillDifficultyID
}
// Für komplexere Queries: View oder Helper-Strukturen
@@ -151,7 +163,7 @@ type SkillLearningInfo struct {
CategoryName string `json:"category_name"`
DifficultyID uint `json:"difficulty_id"`
DifficultyName string `json:"difficulty_name"`
LearnCost int `json:"learn_cost"` // LE-Kosten für das Erlernen
LearnCost int `json:"learn_cost"` // LE-Kosten / TE-Kosten für das Erlernen
CharacterClassID uint `json:"character_class_id"`
ClassCode string `json:"class_code"`
ClassName string `json:"class_name"`
@@ -233,9 +245,15 @@ func (WeaponSkillCategoryDifficulty) TableName() string {
return "learning_weaponskill_category_difficulties"
}
/*
func (SkillImprovementCost) TableName() string {
return "learning_skill_improvement_costs"
}
*/
func (SkillImprovementCost2) TableName() string {
return "skill_improvement_cost2"
}
func (sllc *SpellLevelLECost) ensureGameSystem() {
gs := GetGameSystem(sllc.GameSystemId, sllc.GameSystem)
@@ -476,9 +494,15 @@ func (wscd *WeaponSkillCategoryDifficulty) Create() error {
return database.DB.Create(wscd).Error
}
/*
func (sic *SkillImprovementCost) Create() error {
return database.DB.Create(sic).Error
}
*/
func (sic *SkillImprovementCost2) Create() error {
return database.DB.Create(sic).Error
}
// Komplexere Query-Methoden
@@ -630,15 +654,20 @@ func GetSpellLearningInfoNewSystem(spellName string, classCode string) (*SpellLe
// GetImprovementCost holt die Verbesserungskosten für eine Fertigkeit
func GetImprovementCost(skillName string, categoryName string, difficultyName string, currentLevel int) (int, error) {
var result SkillImprovementCost
var result SkillImprovementCost2
err := database.DB.Raw(`
SELECT sic.te_required
FROM learning_skill_improvement_costs sic
JOIN learning_skill_category_difficulties scd ON sic.skill_category_difficulty_id = scd.id
JOIN gsm_skills s ON scd.skill_id = s.id
WHERE s.name = ? AND scd.skill_category = ? AND scd.skill_difficulty = ? AND sic.current_level = ?
`, skillName, categoryName, difficultyName, currentLevel).Scan(&result).Error
SELECT sic.te_required
FROM skill_improvement_cost2 sic
JOIN learning_skill_categories lc ON lc.id = sic.skill_category_id
JOIN learning_skill_difficulties ld ON ld.id = sic.skill_difficulty_id
JOIN learning_skill_category_difficulties scd ON scd.skill_category = lc.name AND scd.skill_difficulty = ld.name
JOIN gsm_skills s ON scd.skill_id = s.id
WHERE s.name = ?
AND lc.name = ?
AND ld.name = ?
AND sic.current_level = ?
`, skillName, categoryName, difficultyName, currentLevel).Scan(&result).Error
if err != nil {
return 0, err
+1 -1
View File
@@ -989,7 +989,7 @@ func TestLearningCostsWorkflow_CompleteDataValidation(t *testing.T) {
assert.Equal(t, "leicht", skillInfo.DifficultyName)
assert.Equal(t, "Bb", skillInfo.ClassCode)
assert.Equal(t, 10, skillInfo.EPPerTE, "EP per TE should match the class/category cost")
assert.Equal(t, 5, skillInfo.LearnCost, "Learn cost should be 5 for leicht difficulty")
assert.Equal(t, 1, skillInfo.LearnCost, "Learn cost should be 5 for leicht difficulty")
// 3. Verify active source codes include expected values
sourceCodes, err := GetActiveSourceCodes()
+1 -1
View File
@@ -64,7 +64,7 @@ type DatabaseExport struct {
ClassSpellSchoolEPCosts []models.ClassSpellSchoolEPCost `json:"learning_class_spell_school_ep_costs"`
SpellLevelLECosts []models.SpellLevelLECost `json:"learning_spell_level_le_costs"`
SkillCategoryDifficulties []models.SkillCategoryDifficulty `json:"learning_skill_category_difficulties"`
SkillImprovementCosts []models.SkillImprovementCost `json:"learning_skill_improvement_costs"`
SkillImprovementCosts []models.SkillImprovementCost2 `json:"learning_skill_improvement_costs"`
AuditLogEntries []models.AuditLogEntry `json:"audit_log_entries"`
}
+1 -1
View File
@@ -80,7 +80,7 @@ func TestImportDatabaseHandler_Success(t *testing.T) {
assert.Equal(t, "Database imported successfully", response["message"])
assert.Greater(t, response["record_count"], float64(0))
assert.Equal(t, response["record_count"], exportResult)
assert.Equal(t, float64(exportResult.RecordCount), response["record_count"])
}
func TestImportDatabaseHandler_MissingFilepath(t *testing.T) {
+3 -3
View File
@@ -31,7 +31,7 @@ type LearningDataExport struct {
ClassSpellSchoolEPCosts []models.ClassSpellSchoolEPCost `json:"class_spell_school_ep_costs"`
SpellLevelLECosts []models.SpellLevelLECost `json:"spell_level_le_costs"`
SkillCategoryDifficulties []models.SkillCategoryDifficulty `json:"skill_category_difficulties"`
SkillImprovementCosts []models.SkillImprovementCost `json:"skill_improvement_costs"`
SkillImprovementCosts []models.SkillImprovementCost2 `json:"skill_improvement_costs"`
}
// ExportCharacter exports a complete character with all related data
@@ -177,7 +177,7 @@ func ExportCharacter(characterID uint) (*CharacterExport, error) {
ClassSpellSchoolEPCosts: make([]models.ClassSpellSchoolEPCost, 0),
SpellLevelLECosts: make([]models.SpellLevelLECost, 0),
SkillCategoryDifficulties: make([]models.SkillCategoryDifficulty, 0),
SkillImprovementCosts: make([]models.SkillImprovementCost, 0),
SkillImprovementCosts: make([]models.SkillImprovementCost2, 0),
}
database.DB.Find(&export.LearningData.Sources)
@@ -189,7 +189,7 @@ func ExportCharacter(characterID uint) (*CharacterExport, error) {
database.DB.Preload("CharacterClass").Preload("SpellSchool").Find(&export.LearningData.ClassSpellSchoolEPCosts)
database.DB.Find(&export.LearningData.SpellLevelLECosts)
database.DB.Preload("Skill").Preload("SkillCategory").Preload("SkillDifficulty").Find(&export.LearningData.SkillCategoryDifficulties)
database.DB.Preload("SkillCategoryDifficulty").Find(&export.LearningData.SkillImprovementCosts)
database.DB.Find(&export.LearningData.SkillImprovementCosts)
// Load audit log entries
export.AuditLogEntries = make([]models.AuditLogEntry, 0)
+5
View File
@@ -170,6 +170,11 @@ func importOrUpdateSkill(tx *gorm.DB, skill *models.Skill) error {
skill.SourceID = 1
}
// Ensure game system fields are populated so queries match existing records
gs := models.GetGameSystem(skill.GameSystemId, skill.GameSystem)
skill.GameSystem = gs.Name
skill.GameSystemId = gs.ID
var existing models.Skill
err := tx.Where("name = ? AND game_system = ?", skill.Name, skill.GameSystem).First(&existing).Error