package kfa import ( "encoding/json" "strconv" "strings" "time" ) func MapKfaDetailToEntity(detail KfaDetailResult) (*KfaProduct, []KfaProductActiveIngredient, []KfaProductPackaging) { now := time.Now() var displayName *string // Attempt to extract display_name safely if product template exists templateB := toJsonb(detail.ProductTemplate) if templateB != nil { var tpl struct { DisplayName string `json:"display_name"` } if err := json.Unmarshal(templateB, &tpl); err == nil && tpl.DisplayName != "" { displayName = &tpl.DisplayName } } if displayName == nil { displayName = &detail.Name } product := &KfaProduct{ KfaCode: detail.KfaCode, Name: detail.Name, DisplayName: displayName, TradeName: detail.NamaDagang, State: detail.State, IsGeneric: detail.Generik, DosageForm: toJsonb(detail.DosageForm), FarmalkesType: toJsonb(detail.FarmalkesType), Route: toJsonb(detail.RutePemberian), ControlledDrug: toJsonb(detail.ControlledDrug), Uom: toJsonb(detail.Uom), FixPrice: detail.FixPrice, HetPrice: detail.HetPrice, DosePerUnit: detail.DosePerUnit, NetWeight: detail.NetWeight, NetWeightUom: detail.NetWeightUomName, Volume: detail.Volume, VolumeUom: detail.VolumeUomName, ScoreTkdn: detail.ScoreTkdn, ScoreTkdnBmp: detail.ScoreTkdnBmp, ScoreBmp: detail.ScoreBmp, Rxterm: detail.Rxterm, Manufacturer: detail.Manufacturer, Registrar: detail.Registrar, Nie: detail.Nie, Hscode: detail.FarmalkesHscode, LkppCode: detail.KodeLkpp, IsLkppActive: detail.TayangLkpp, Description: detail.Description, Indication: detail.Indication, SideEffect: detail.SideEffect, Warning: detail.Warning, Image: detail.Image, DrugClassification: detail.KlasifikasiIzin, ManufacturingOrigin: detail.ProduksiBuatan, AtcInfo: buildAtcInfo(detail), Fornas: toJsonb(detail.Fornas), DosageUsage: toJsonb(detail.DosageUsage), Tags: toJsonb(detail.Tags), IdentifierIds: toJsonb(detail.IdentifierIds), ProductTemplate: templateB, Replacement: toJsonb(detail.Replacement), Ucum: toJsonb(detail.Ucum), CreatedAt: now, UpdatedAt: parseTime(detail.UpdatedAt, now), Active: &detail.Active, } var ingredients []KfaProductActiveIngredient for _, ing := range detail.ActiveIngredients { val, unit := parseStrength(ing.KekuatanZatAktif) ingredients = append(ingredients, KfaProductActiveIngredient{ ProductKfaCode: product.KfaCode, ProductDisplay: product.Name, SubstanceCode: ing.KfaCode, SubstanceName: ing.ZatAktif, StrengthValue: val, StrengthUnit: unit, StrengthText: ing.KekuatanZatAktif, State: ing.State, CreatedAt: now, UpdatedAt: parseTime(ing.UpdatedAt, now), Active: &ing.Active, }) } var packagings []KfaProductPackaging for _, pkg := range detail.PackagingIds { active := true packagings = append(packagings, KfaProductPackaging{ ProductKfaCode: product.KfaCode, ProductDisplay: product.Name, Code: pkg.KfaCode, Name: pkg.Name, Quantity: pkg.Qty, Unit: pkg.UomId, Price: pkg.PackPrice, State: "valid", CreatedAt: now, UpdatedAt: now, Active: &active, }) } return product, ingredients, packagings } func toJsonb(v interface{}) json.RawMessage { if v == nil { return nil } b, err := json.Marshal(v) if err != nil || string(b) == "null" { return nil } return b } func buildAtcInfo(d KfaDetailResult) json.RawMessage { m := map[string]interface{}{ "atc_ddd": d.AtcDdd, "atc_l1": d.AtcL1, "atc_l2": d.AtcL2, "atc_l3": d.AtcL3, "atc_l4": d.AtcL4, "atc_l5": d.AtcL5, } return toJsonb(m) } func parseStrength(text string) (*float64, string) { text = strings.TrimSpace(text) if text == "" { return nil, "" } parts := strings.Split(text, " ") if len(parts) == 0 { return nil, "" } val, err := strconv.ParseFloat(parts[0], 64) if err != nil { return nil, text } var unit string if len(parts) > 1 { unit = strings.Join(parts[1:], " ") } return &val, unit } func parseTime(t *string, defaultTime time.Time) time.Time { if t == nil || *t == "" { return defaultTime } parsed, err := time.Parse("2006-01-02 15:04:05", *t) if err != nil { return defaultTime } return parsed }