624 lines
18 KiB
Go
624 lines
18 KiB
Go
package importer
|
|
|
|
import (
|
|
"bamort/database"
|
|
"bamort/models"
|
|
"bytes"
|
|
"compress/gzip"
|
|
"fmt"
|
|
"time"
|
|
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
// ImportResult represents the result of a character import operation
|
|
type ImportResult struct {
|
|
CharacterID uint `json:"character_id"`
|
|
ImportID uint `json:"import_id"`
|
|
AdapterID string `json:"adapter_id"`
|
|
Warnings []ValidationWarning `json:"warnings"`
|
|
CreatedItems map[string]int `json:"created_items"` // {"skills": 3, "spells": 1}
|
|
Status string `json:"status"`
|
|
}
|
|
|
|
// ImportCharacter imports a character with full transaction safety
|
|
// This implements the transaction-wrapped import logic from Phase 1
|
|
func ImportCharacter(char *CharacterImport, userID uint, adapterID string, originalData []byte) (*ImportResult, error) {
|
|
tx := database.DB.Begin()
|
|
defer func() {
|
|
if r := recover(); r != nil {
|
|
tx.Rollback()
|
|
}
|
|
}()
|
|
|
|
result := &ImportResult{
|
|
AdapterID: adapterID,
|
|
CreatedItems: make(map[string]int),
|
|
Status: "in_progress",
|
|
}
|
|
|
|
// Default game system (CharacterImport doesn't include game system field)
|
|
// TODO: Add game system to CharacterImport or detect from adapter metadata
|
|
gameSystem := "Midgard5"
|
|
|
|
// 1. Create ImportHistory record (failed status initially)
|
|
history := &ImportHistory{
|
|
UserID: userID,
|
|
AdapterID: adapterID,
|
|
SourceFormat: adapterID, // Can be refined based on adapter metadata
|
|
SourceFilename: fmt.Sprintf("%s_import_%d.json", char.Name, time.Now().Unix()),
|
|
BmrtVersion: "1.0",
|
|
ImportedAt: time.Now(),
|
|
Status: "in_progress",
|
|
}
|
|
|
|
// Compress original data
|
|
if originalData != nil {
|
|
compressed, err := compressData(originalData)
|
|
if err != nil {
|
|
tx.Rollback()
|
|
return nil, fmt.Errorf("failed to compress source data: %w", err)
|
|
}
|
|
history.SourceSnapshot = compressed
|
|
}
|
|
|
|
if err := tx.Create(history).Error; err != nil {
|
|
tx.Rollback()
|
|
return nil, fmt.Errorf("failed to create import history: %w", err)
|
|
}
|
|
|
|
result.ImportID = history.ID
|
|
|
|
// 2. Reconcile master data and track created items
|
|
createdCounts := make(map[string]int)
|
|
|
|
// Reconcile skills
|
|
for _, skill := range char.Fertigkeiten {
|
|
_, matchType, err := reconcileSkillWithTx(tx, skill, history.ID, gameSystem)
|
|
if err != nil {
|
|
history.Status = "failed"
|
|
history.ErrorLog = fmt.Sprintf("Failed to reconcile skill %s: %v", skill.Name, err)
|
|
tx.Save(history)
|
|
tx.Rollback()
|
|
return nil, fmt.Errorf("failed to reconcile skill: %w", err)
|
|
}
|
|
if matchType == "created_personal" {
|
|
createdCounts["skills"]++
|
|
}
|
|
}
|
|
|
|
// Reconcile spells
|
|
for _, spell := range char.Zauber {
|
|
_, matchType, err := reconcileSpellWithTx(tx, spell, history.ID, gameSystem)
|
|
if err != nil {
|
|
history.Status = "failed"
|
|
history.ErrorLog = fmt.Sprintf("Failed to reconcile spell %s: %v", spell.Name, err)
|
|
tx.Save(history)
|
|
tx.Rollback()
|
|
return nil, fmt.Errorf("failed to reconcile spell: %w", err)
|
|
}
|
|
if matchType == "created_personal" {
|
|
createdCounts["spells"]++
|
|
}
|
|
}
|
|
|
|
// Reconcile weapon skills
|
|
for _, ws := range char.Waffenfertigkeiten {
|
|
_, matchType, err := reconcileWeaponSkillWithTx(tx, ws, history.ID, gameSystem)
|
|
if err != nil {
|
|
history.Status = "failed"
|
|
history.ErrorLog = fmt.Sprintf("Failed to reconcile weapon skill %s: %v", ws.Name, err)
|
|
tx.Save(history)
|
|
tx.Rollback()
|
|
return nil, fmt.Errorf("failed to reconcile weapon skill: %w", err)
|
|
}
|
|
if matchType == "created_personal" {
|
|
createdCounts["weapon_skills"]++
|
|
}
|
|
}
|
|
|
|
// Reconcile weapons
|
|
for _, weapon := range char.Waffen {
|
|
_, matchType, err := reconcileWeaponWithTx(tx, weapon, history.ID, gameSystem)
|
|
if err != nil {
|
|
history.Status = "failed"
|
|
history.ErrorLog = fmt.Sprintf("Failed to reconcile weapon %s: %v", weapon.Name, err)
|
|
tx.Save(history)
|
|
tx.Rollback()
|
|
return nil, fmt.Errorf("failed to reconcile weapon: %w", err)
|
|
}
|
|
if matchType == "created_personal" {
|
|
createdCounts["weapons"]++
|
|
}
|
|
}
|
|
|
|
// Reconcile equipment
|
|
for _, eq := range char.Ausruestung {
|
|
_, matchType, err := reconcileEquipmentWithTx(tx, eq, history.ID, gameSystem)
|
|
if err != nil {
|
|
history.Status = "failed"
|
|
history.ErrorLog = fmt.Sprintf("Failed to reconcile equipment %s: %v", eq.Name, err)
|
|
tx.Save(history)
|
|
tx.Rollback()
|
|
return nil, fmt.Errorf("failed to reconcile equipment: %w", err)
|
|
}
|
|
if matchType == "created_personal" {
|
|
createdCounts["equipment"]++
|
|
}
|
|
}
|
|
|
|
// Reconcile containers
|
|
for _, container := range char.Behaeltnisse {
|
|
_, matchType, err := reconcileContainerWithTx(tx, container, history.ID, gameSystem)
|
|
if err != nil {
|
|
history.Status = "failed"
|
|
history.ErrorLog = fmt.Sprintf("Failed to reconcile container %s: %v", container.Name, err)
|
|
tx.Save(history)
|
|
tx.Rollback()
|
|
return nil, fmt.Errorf("failed to reconcile container: %w", err)
|
|
}
|
|
if matchType == "created_personal" {
|
|
createdCounts["containers"]++
|
|
}
|
|
}
|
|
|
|
result.CreatedItems = createdCounts
|
|
|
|
// 3. Create models.Char
|
|
// TODO: Implement CreateCharacterFromImport helper
|
|
// For now, create a minimal character record
|
|
newChar := &models.Char{
|
|
Rasse: char.Rasse,
|
|
Typ: char.Typ,
|
|
Alter: char.Alter,
|
|
Anrede: char.Anrede,
|
|
Grad: char.Grad,
|
|
Groesse: char.Groesse,
|
|
Gewicht: char.Gewicht,
|
|
Glaube: char.Glaube,
|
|
Hand: char.Hand,
|
|
UserID: userID,
|
|
ImportedFromAdapter: &adapterID,
|
|
ImportedAt: &history.ImportedAt,
|
|
}
|
|
|
|
// Set the name through BamortBase (inherited)
|
|
newChar.BamortBase.Name = char.Name
|
|
|
|
if err := tx.Create(newChar).Error; err != nil {
|
|
history.Status = "failed"
|
|
history.ErrorLog = fmt.Sprintf("Failed to create character: %v", err)
|
|
tx.Save(history)
|
|
tx.Rollback()
|
|
return nil, fmt.Errorf("failed to create character: %w", err)
|
|
}
|
|
|
|
// Create attributes as separate records
|
|
attributes := []models.Eigenschaft{
|
|
{CharacterID: newChar.ID, UserID: userID, Name: "St", Value: char.Eigenschaften.St},
|
|
{CharacterID: newChar.ID, UserID: userID, Name: "Gs", Value: char.Eigenschaften.Gs},
|
|
{CharacterID: newChar.ID, UserID: userID, Name: "Gw", Value: char.Eigenschaften.Gw},
|
|
{CharacterID: newChar.ID, UserID: userID, Name: "Ko", Value: char.Eigenschaften.Ko},
|
|
{CharacterID: newChar.ID, UserID: userID, Name: "In", Value: char.Eigenschaften.In},
|
|
{CharacterID: newChar.ID, UserID: userID, Name: "Zt", Value: char.Eigenschaften.Zt},
|
|
{CharacterID: newChar.ID, UserID: userID, Name: "Au", Value: char.Eigenschaften.Au},
|
|
{CharacterID: newChar.ID, UserID: userID, Name: "Pa", Value: char.Eigenschaften.Pa},
|
|
{CharacterID: newChar.ID, UserID: userID, Name: "Wk", Value: char.Eigenschaften.Wk},
|
|
}
|
|
|
|
for _, attr := range attributes {
|
|
if err := tx.Create(&attr).Error; err != nil {
|
|
history.Status = "failed"
|
|
history.ErrorLog = fmt.Sprintf("Failed to create attribute %s: %v", attr.Name, err)
|
|
tx.Save(history)
|
|
tx.Rollback()
|
|
return nil, fmt.Errorf("failed to create attribute: %w", err)
|
|
}
|
|
}
|
|
|
|
// Create LP, AP, B records
|
|
lp := &models.Lp{
|
|
CharacterID: newChar.ID,
|
|
Max: char.Lp.Max,
|
|
Value: char.Lp.Value,
|
|
}
|
|
if err := tx.Create(lp).Error; err != nil {
|
|
history.Status = "failed"
|
|
history.ErrorLog = fmt.Sprintf("Failed to create LP: %v", err)
|
|
tx.Save(history)
|
|
tx.Rollback()
|
|
return nil, fmt.Errorf("failed to create LP: %w", err)
|
|
}
|
|
|
|
ap := &models.Ap{
|
|
CharacterID: newChar.ID,
|
|
Max: char.Ap.Max,
|
|
Value: char.Ap.Value,
|
|
}
|
|
if err := tx.Create(ap).Error; err != nil {
|
|
history.Status = "failed"
|
|
history.ErrorLog = fmt.Sprintf("Failed to create AP: %v", err)
|
|
tx.Save(history)
|
|
tx.Rollback()
|
|
return nil, fmt.Errorf("failed to create AP: %w", err)
|
|
}
|
|
|
|
b := &models.B{
|
|
CharacterID: newChar.ID,
|
|
Max: char.B.Max,
|
|
Value: char.B.Value,
|
|
}
|
|
if err := tx.Create(b).Error; err != nil {
|
|
history.Status = "failed"
|
|
history.ErrorLog = fmt.Sprintf("Failed to create B: %v", err)
|
|
tx.Save(history)
|
|
tx.Rollback()
|
|
return nil, fmt.Errorf("failed to create B: %w", err)
|
|
}
|
|
|
|
// Create XP record
|
|
xp := &models.Erfahrungsschatz{
|
|
BamortCharTrait: models.BamortCharTrait{
|
|
CharacterID: newChar.ID,
|
|
UserID: userID,
|
|
},
|
|
EP: char.Erfahrungsschatz.Value,
|
|
}
|
|
if err := tx.Create(xp).Error; err != nil {
|
|
history.Status = "failed"
|
|
history.ErrorLog = fmt.Sprintf("Failed to create XP: %v", err)
|
|
tx.Save(history)
|
|
tx.Rollback()
|
|
return nil, fmt.Errorf("failed to create XP: %w", err)
|
|
}
|
|
|
|
// Create Bennies record
|
|
bennies := &models.Bennies{
|
|
BamortCharTrait: models.BamortCharTrait{
|
|
CharacterID: newChar.ID,
|
|
UserID: userID,
|
|
},
|
|
Gg: char.Bennies.Gg,
|
|
Gp: char.Bennies.Gp,
|
|
Sg: char.Bennies.Sg,
|
|
}
|
|
if err := tx.Create(bennies).Error; err != nil {
|
|
history.Status = "failed"
|
|
history.ErrorLog = fmt.Sprintf("Failed to create bennies: %v", err)
|
|
tx.Save(history)
|
|
tx.Rollback()
|
|
return nil, fmt.Errorf("failed to create bennies: %w", err)
|
|
}
|
|
|
|
result.CharacterID = newChar.ID
|
|
|
|
// 4. Update ImportHistory (success status)
|
|
history.CharacterID = &newChar.ID
|
|
history.Status = "success"
|
|
if err := tx.Save(history).Error; err != nil {
|
|
tx.Rollback()
|
|
return nil, fmt.Errorf("failed to update import history: %w", err)
|
|
}
|
|
|
|
// Commit transaction
|
|
if err := tx.Commit().Error; err != nil {
|
|
// Transaction commit failed - try to keep ImportHistory with failed status
|
|
// This is best-effort since we're outside the transaction now
|
|
database.DB.Model(&ImportHistory{}).
|
|
Where("id = ?", history.ID).
|
|
Updates(map[string]interface{}{
|
|
"status": "failed",
|
|
"error_log": fmt.Sprintf("Transaction commit failed: %v", err),
|
|
})
|
|
return nil, err
|
|
}
|
|
|
|
result.Status = "success"
|
|
return result, nil
|
|
}
|
|
|
|
// compressData compresses data using gzip
|
|
func compressData(data []byte) ([]byte, error) {
|
|
var buf bytes.Buffer
|
|
gzipWriter := gzip.NewWriter(&buf)
|
|
|
|
if _, err := gzipWriter.Write(data); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if err := gzipWriter.Close(); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return buf.Bytes(), nil
|
|
}
|
|
|
|
// decompressData decompresses gzip data
|
|
func decompressData(data []byte) ([]byte, error) {
|
|
reader, err := gzip.NewReader(bytes.NewReader(data))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer reader.Close()
|
|
|
|
var buf bytes.Buffer
|
|
if _, err := buf.ReadFrom(reader); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return buf.Bytes(), nil
|
|
}
|
|
|
|
// Transaction-aware reconciliation helpers that use the provided transaction instead of database.DB
|
|
|
|
func reconcileSkillWithTx(tx *gorm.DB, skill Fertigkeit, importHistoryID uint, gameSystem string) (*models.Skill, string, error) {
|
|
gs := models.GetGameSystem(0, gameSystem)
|
|
if gs == nil {
|
|
return nil, "", fmt.Errorf("game system not found: %s (required for master data reconciliation)", gameSystem)
|
|
}
|
|
|
|
var existing models.Skill
|
|
err := tx.Where("name = ? AND game_system = ?", skill.Name, gs.Name).First(&existing).Error
|
|
|
|
if err == nil {
|
|
// Exact match found
|
|
if importHistoryID > 0 {
|
|
logMasterDataImportWithTx(tx, importHistoryID, "skill", existing.ID, skill.Name, "exact")
|
|
}
|
|
return &existing, "exact", nil
|
|
}
|
|
|
|
if err != gorm.ErrRecordNotFound {
|
|
return nil, "", fmt.Errorf("failed to query skill: %w", err)
|
|
}
|
|
|
|
// Create new personal item
|
|
newSkill := &models.Skill{
|
|
Name: skill.Name,
|
|
GameSystem: gs.Name,
|
|
GameSystemId: gs.ID,
|
|
Beschreibung: skill.Beschreibung,
|
|
Initialwert: skill.Fertigkeitswert,
|
|
Quelle: skill.Quelle,
|
|
Bonuseigenschaft: "check",
|
|
Improvable: true,
|
|
PersonalItem: true,
|
|
SourceID: 1,
|
|
}
|
|
|
|
if err := tx.Create(newSkill).Error; err != nil {
|
|
return nil, "", fmt.Errorf("failed to create skill: %w", err)
|
|
}
|
|
|
|
if importHistoryID > 0 {
|
|
logMasterDataImportWithTx(tx, importHistoryID, "skill", newSkill.ID, skill.Name, "created_personal")
|
|
}
|
|
|
|
return newSkill, "created_personal", nil
|
|
}
|
|
|
|
func reconcileSpellWithTx(tx *gorm.DB, spell Zauber, importHistoryID uint, gameSystem string) (*models.Spell, string, error) {
|
|
gs := models.GetGameSystem(0, gameSystem)
|
|
if gs == nil {
|
|
return nil, "", fmt.Errorf("game system not found: %s (required for master data reconciliation)", gameSystem)
|
|
}
|
|
|
|
var existing models.Spell
|
|
err := tx.Where("name = ? AND game_system = ?", spell.Name, gs.Name).First(&existing).Error
|
|
|
|
if err == nil {
|
|
if importHistoryID > 0 {
|
|
logMasterDataImportWithTx(tx, importHistoryID, "spell", existing.ID, spell.Name, "exact")
|
|
}
|
|
return &existing, "exact", nil
|
|
}
|
|
|
|
if err != gorm.ErrRecordNotFound {
|
|
return nil, "", fmt.Errorf("failed to query spell: %w", err)
|
|
}
|
|
|
|
newSpell := &models.Spell{
|
|
Name: spell.Name,
|
|
GameSystem: gs.Name,
|
|
GameSystemId: gs.ID,
|
|
Beschreibung: spell.Beschreibung,
|
|
Quelle: spell.Quelle,
|
|
PersonalItem: true,
|
|
SourceID: 1,
|
|
}
|
|
|
|
if err := tx.Create(newSpell).Error; err != nil {
|
|
return nil, "", fmt.Errorf("failed to create spell: %w", err)
|
|
}
|
|
|
|
if importHistoryID > 0 {
|
|
logMasterDataImportWithTx(tx, importHistoryID, "spell", newSpell.ID, spell.Name, "created_personal")
|
|
}
|
|
|
|
return newSpell, "created_personal", nil
|
|
}
|
|
|
|
func reconcileWeaponSkillWithTx(tx *gorm.DB, ws Waffenfertigkeit, importHistoryID uint, gameSystem string) (*models.WeaponSkill, string, error) {
|
|
gs := models.GetGameSystem(0, gameSystem)
|
|
if gs == nil {
|
|
return nil, "", fmt.Errorf("game system not found: %s (required for master data reconciliation)", gameSystem)
|
|
}
|
|
|
|
var existing models.WeaponSkill
|
|
err := tx.Where("name = ? AND game_system = ?", ws.Name, gs.Name).First(&existing).Error
|
|
|
|
if err == nil {
|
|
if importHistoryID > 0 {
|
|
logMasterDataImportWithTx(tx, importHistoryID, "weapon_skill", existing.ID, ws.Name, "exact")
|
|
}
|
|
return &existing, "exact", nil
|
|
}
|
|
|
|
if err != gorm.ErrRecordNotFound {
|
|
return nil, "", fmt.Errorf("failed to query weapon skill: %w", err)
|
|
}
|
|
|
|
newWS := &models.WeaponSkill{
|
|
Skill: models.Skill{
|
|
Name: ws.Name,
|
|
GameSystem: gs.Name,
|
|
GameSystemId: gs.ID,
|
|
Beschreibung: ws.Beschreibung,
|
|
Quelle: ws.Quelle,
|
|
Bonuseigenschaft: "check",
|
|
Improvable: true,
|
|
PersonalItem: true,
|
|
SourceID: 1,
|
|
},
|
|
}
|
|
|
|
if err := tx.Create(newWS).Error; err != nil {
|
|
return nil, "", fmt.Errorf("failed to create weapon skill: %w", err)
|
|
}
|
|
|
|
if importHistoryID > 0 {
|
|
logMasterDataImportWithTx(tx, importHistoryID, "weapon_skill", newWS.ID, ws.Name, "created_personal")
|
|
}
|
|
|
|
return newWS, "created_personal", nil
|
|
}
|
|
|
|
func reconcileWeaponWithTx(tx *gorm.DB, weapon Waffe, importHistoryID uint, gameSystem string) (*models.Weapon, string, error) {
|
|
gs := models.GetGameSystem(0, gameSystem)
|
|
if gs == nil {
|
|
return nil, "", fmt.Errorf("game system not found: %s (required for master data reconciliation)", gameSystem)
|
|
}
|
|
|
|
var existing models.Weapon
|
|
err := tx.Where("name = ? AND game_system = ?", weapon.Name, gs.Name).First(&existing).Error
|
|
|
|
if err == nil {
|
|
if importHistoryID > 0 {
|
|
logMasterDataImportWithTx(tx, importHistoryID, "weapon", existing.ID, weapon.Name, "exact")
|
|
}
|
|
return &existing, "exact", nil
|
|
}
|
|
|
|
if err != gorm.ErrRecordNotFound {
|
|
return nil, "", fmt.Errorf("failed to query weapon: %w", err)
|
|
}
|
|
|
|
newWeapon := &models.Weapon{
|
|
Equipment: models.Equipment{
|
|
Name: weapon.Name,
|
|
GameSystem: gs.Name,
|
|
GameSystemId: gs.ID,
|
|
Beschreibung: weapon.Beschreibung,
|
|
PersonalItem: true,
|
|
SourceID: 1,
|
|
},
|
|
}
|
|
|
|
if err := tx.Create(newWeapon).Error; err != nil {
|
|
return nil, "", fmt.Errorf("failed to create weapon: %w", err)
|
|
}
|
|
|
|
if importHistoryID > 0 {
|
|
logMasterDataImportWithTx(tx, importHistoryID, "weapon", newWeapon.ID, weapon.Name, "created_personal")
|
|
}
|
|
|
|
return newWeapon, "created_personal", nil
|
|
}
|
|
|
|
func reconcileEquipmentWithTx(tx *gorm.DB, eq Ausruestung, importHistoryID uint, gameSystem string) (*models.Equipment, string, error) {
|
|
gs := models.GetGameSystem(0, gameSystem)
|
|
if gs == nil {
|
|
return nil, "", fmt.Errorf("game system not found: %s (required for master data reconciliation)", gameSystem)
|
|
}
|
|
|
|
var existing models.Equipment
|
|
err := tx.Where("name = ? AND game_system = ?", eq.Name, gs.Name).First(&existing).Error
|
|
|
|
if err == nil {
|
|
if importHistoryID > 0 {
|
|
logMasterDataImportWithTx(tx, importHistoryID, "equipment", existing.ID, eq.Name, "exact")
|
|
}
|
|
return &existing, "exact", nil
|
|
}
|
|
|
|
if err != gorm.ErrRecordNotFound {
|
|
return nil, "", fmt.Errorf("failed to query equipment: %w", err)
|
|
}
|
|
|
|
newEq := &models.Equipment{
|
|
Name: eq.Name,
|
|
GameSystem: gs.Name,
|
|
GameSystemId: gs.ID,
|
|
Beschreibung: eq.Beschreibung,
|
|
PersonalItem: true,
|
|
SourceID: 1,
|
|
}
|
|
|
|
if err := tx.Create(newEq).Error; err != nil {
|
|
return nil, "", fmt.Errorf("failed to create equipment: %w", err)
|
|
}
|
|
|
|
if importHistoryID > 0 {
|
|
logMasterDataImportWithTx(tx, importHistoryID, "equipment", newEq.ID, eq.Name, "created_personal")
|
|
}
|
|
|
|
return newEq, "created_personal", nil
|
|
}
|
|
|
|
func reconcileContainerWithTx(tx *gorm.DB, container Behaeltniss, importHistoryID uint, gameSystem string) (*models.Container, string, error) {
|
|
gs := models.GetGameSystem(0, gameSystem)
|
|
if gs == nil {
|
|
return nil, "", fmt.Errorf("game system not found: %s (required for master data reconciliation)", gameSystem)
|
|
}
|
|
|
|
var existing models.Container
|
|
err := tx.Where("name = ? AND game_system = ?", container.Name, gs.Name).First(&existing).Error
|
|
|
|
if err == nil {
|
|
if importHistoryID > 0 {
|
|
logMasterDataImportWithTx(tx, importHistoryID, "container", existing.ID, container.Name, "exact")
|
|
}
|
|
return &existing, "exact", nil
|
|
}
|
|
|
|
if err != gorm.ErrRecordNotFound {
|
|
return nil, "", fmt.Errorf("failed to query container: %w", err)
|
|
}
|
|
|
|
newContainer := &models.Container{
|
|
Equipment: models.Equipment{
|
|
Name: container.Name,
|
|
GameSystem: gs.Name,
|
|
GameSystemId: gs.ID,
|
|
Beschreibung: container.Beschreibung,
|
|
PersonalItem: true,
|
|
SourceID: 1,
|
|
},
|
|
}
|
|
|
|
if err := tx.Create(newContainer).Error; err != nil {
|
|
return nil, "", fmt.Errorf("failed to create container: %w", err)
|
|
}
|
|
|
|
if importHistoryID > 0 {
|
|
logMasterDataImportWithTx(tx, importHistoryID, "container", newContainer.ID, container.Name, "created_personal")
|
|
}
|
|
|
|
return newContainer, "created_personal", nil
|
|
}
|
|
|
|
func logMasterDataImportWithTx(tx *gorm.DB, importHistoryID uint, itemType string, itemID uint, externalName string, matchType string) {
|
|
log := &MasterDataImport{
|
|
ImportHistoryID: importHistoryID,
|
|
ItemType: itemType,
|
|
ItemID: itemID,
|
|
ExternalName: externalName,
|
|
MatchType: matchType,
|
|
CreatedAt: time.Now(),
|
|
}
|
|
|
|
if err := tx.Create(log).Error; err != nil {
|
|
fmt.Printf("Warning: Failed to log master data import: %v\n", err)
|
|
}
|
|
}
|