diff --git a/controllers/ImportController.go b/controllers/ImportController.go index b5a602a..f6f0809 100644 --- a/controllers/ImportController.go +++ b/controllers/ImportController.go @@ -61,8 +61,12 @@ func StartImport(w http.ResponseWriter, route *http.Request) { } //get categories from mysql on main thread - mainCategories = gm.GetMainCategories(baza) + mainCategories, err = gm.GetMainCategories(baza) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } famAndSellerWG.Add(3) //get attribute families from mysql go func() { @@ -215,12 +219,12 @@ func getCats(db *gorm.DB, catIDs []int) ([]gm.Category, string, error) { var keywords string if errCat := db.Preload("Translations", "locale=?", "tm").Find(&categories, catIDs).Error; errCat != nil { - //log.Println(errCat) + log.Println(errCat) return categories, keywords, errCat } for _, cat := range categories { - log.Println(cat) + //log.Println(cat) if len(cat.Translations) > 0 && cat.Translations[0].MetaKeywords != "" { translation := cat.Translations[0] @@ -289,11 +293,11 @@ func ImportProduct(product models.Product, db *gorm.DB) error { Images: productImages, } - if len(product.ColorVariants) > 0 { + if len(*product.ColorVariants) > 0 { iproduct.SuperAttributes = append(iproduct.SuperAttributes, AttributesMap["color"]) } - if len(product.SizeVariants) > 0 { + if len(*product.SizeVariants) > 0 { iproduct.SuperAttributes = append(iproduct.SuperAttributes, AttributesMap["size"]) } @@ -323,10 +327,10 @@ func ImportProduct(product models.Product, db *gorm.DB) error { return errProductMainFlat } - if len(product.ColorVariants) > 0 { - product.ColorVariants = append([]models.Product{product}, product.ColorVariants...) + if len(*product.ColorVariants) > 0 { + *product.ColorVariants = append([]models.Product{product}, *product.ColorVariants...) - for colorIndex, colorVariant := range product.ColorVariants { + for colorIndex, colorVariant := range *product.ColorVariants { weight, _ := strconv.ParseFloat(colorVariant.Weight, 64) var description string for _, desc := range colorVariant.Descriptions { @@ -335,9 +339,9 @@ func ImportProduct(product models.Product, db *gorm.DB) error { colorOption := gm.GetAttributeOption(&tx, AttributesMap["color"].ID, colorVariant.Color) - if len(colorVariant.SizeVariants) > 0 { + if len(*colorVariant.SizeVariants) > 0 { - for index, sizeVariant := range colorVariant.SizeVariants { + for index, sizeVariant := range *colorVariant.SizeVariants { savePoint := "Size" + strconv.Itoa(colorIndex) + "sp" + strconv.Itoa(index) @@ -516,11 +520,11 @@ func ImportProduct(product models.Product, db *gorm.DB) error { return tx.Rollback().Error } - } else if len(product.SizeVariants) > 0 { + } else if len(*product.SizeVariants) > 0 { weight, _ := strconv.ParseFloat(product.Weight, 64) colorOption := gm.GetAttributeOption(&tx, AttributesMap["color"].ID, product.Color) - for index, sizeVariant := range product.SizeVariants { + for index, sizeVariant := range *product.SizeVariants { sizeSavePoint := "size" + strconv.Itoa(index) tx.SavePoint(sizeSavePoint) @@ -792,7 +796,7 @@ func prepearAttributesWithFlat(data *models.Product) ([]gm.ProductAttributeValue Price: 0, } - if len(data.ColorVariants) == 0 && len(data.SizeVariants) == 0 { + if len(*data.ColorVariants) == 0 && len(*data.SizeVariants) == 0 { if data.Price.OriginalPrice.Value > data.Price.DiscountedPrice.Value { productAttributeValues = append(productAttributeValues, []gm.ProductAttributeValue{ @@ -822,7 +826,7 @@ func UpdateProduct(product models.Product, db *gorm.DB, productFlat gm.ProductFl minPrice := 0.0 maxPrice := 0.0 - if len(product.ColorVariants) == 0 && len(product.SizeVariants) == 0 { + if len(*product.ColorVariants) == 0 && len(*product.SizeVariants) == 0 { if product.Price.OriginalPrice.Value > product.Price.DiscountedPrice.Value { //productAttributeValues = append(productAttributeValues, []gm.ProductAttributeValue{ @@ -869,15 +873,15 @@ func UpdateProduct(product models.Product, db *gorm.DB, productFlat gm.ProductFl } } } - } else if len(product.ColorVariants) > 0 { + } else if len(*product.ColorVariants) > 0 { //todo update configurable product - product.ColorVariants = append(product.ColorVariants, product) + *product.ColorVariants = append(*product.ColorVariants, product) //tx := db.Begin() - for _, colorVariant := range product.ColorVariants { + for _, colorVariant := range *product.ColorVariants { - if len(colorVariant.SizeVariants) > 0 { + if len(*colorVariant.SizeVariants) > 0 { - for _, sizeVariant := range colorVariant.SizeVariants { + for _, sizeVariant := range *colorVariant.SizeVariants { sku := fmt.Sprintf("%s-%s-%d-col-size", colorVariant.ProductGroupID, colorVariant.ProductNumber, sizeVariant.ItemNumber) var variantFlat gm.ProductFlat @@ -992,9 +996,9 @@ func UpdateProduct(product models.Product, db *gorm.DB, productFlat gm.ProductFl productFlat.MinPrice = minPrice productFlat.MaxPrice = maxPrice - } else if len(product.SizeVariants) > 0 { + } else if len(*product.SizeVariants) > 0 { - for _, sizeVariant := range product.SizeVariants { + for _, sizeVariant := range *product.SizeVariants { sku := fmt.Sprintf("%s-%s-%d-size", product.ProductGroupID, product.ProductNumber, sizeVariant.ItemNumber) var variantFlat gm.ProductFlat err := db.Where("sku=?", sku).First(&variantFlat).Error diff --git a/controllers/ImportV2.go b/controllers/ImportV2.go index b0b429f..1713c0a 100644 --- a/controllers/ImportV2.go +++ b/controllers/ImportV2.go @@ -1 +1,50 @@ package controller + +import ( + "db_service/repositories" + "encoding/json" + "fmt" + "log" + "math/big" + "net/http" + "sync/atomic" + "time" +) + +func StartProductImport(w http.ResponseWriter, _ *http.Request) { + if !atomic.CompareAndSwapUint32(&locker, stateUnlocked, stateLocked) { + w.WriteHeader(http.StatusTooManyRequests) + err := json.NewEncoder(w).Encode(map[string]string{ + "msg": "Product import in progress!", + }) + + log.Println(err) + + return + } + defer atomic.StoreUint32(&locker, stateUnlocked) + start := time.Now() + + r := new(big.Int) + fmt.Println("start import", r.Binomial(1000, 10)) + + importRepo, err := repositories.ImporterInstance() + + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + //wait until initialization data is loaded to memory + importRepo.ImportWGroup.Wait() + + if err = importRepo.Start().Error; err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + importRepo.ImportWGroup.Wait() + + elapsed := time.Since(start) + log.Printf("end import took %s", elapsed) + http.Error(w, fmt.Sprintf("end import took %s", elapsed), http.StatusOK) +} diff --git a/gorm_models/category.go b/gorm_models/category.go index 0468c68..4d0866d 100644 --- a/gorm_models/category.go +++ b/gorm_models/category.go @@ -24,14 +24,25 @@ type Category struct { Translations []CategoryTranslation } -func GetMainCategories(db *gorm.DB) []Category { +func GetMainCategories(db *gorm.DB) ([]Category, error) { var categories []Category err := db.Model(&Category{}).Preload("Translations").Find(&categories, "status=1 AND parent_id=1 AND display_mode!='promotion'").Error if err != nil { log.Println(err.Error()) - + return nil, err } - return categories + return categories, nil +} + +func GetCatKeywords(db *gorm.DB, catIDs []int) ([]Category, error) { + var categories []Category + + if errCat := db.Preload("Translations", "locale=?", "tm").Find(&categories, catIDs).Error; errCat != nil { + log.Println(errCat) + return categories, errCat + } + + return categories, nil } diff --git a/gorm_models/family.go b/gorm_models/family.go index 82f971d..d698c2d 100644 --- a/gorm_models/family.go +++ b/gorm_models/family.go @@ -68,3 +68,16 @@ func GetAttributeOption(db *gorm.DB, attrbuteID uint, value string) AttributeOpt } return option } + +func GetAttrOptions(db *gorm.DB, attrbuteID uint) ([]AttributeOption, error) { + + var options []AttributeOption + + err := db.Find(&options, AttributeOption{AttributeID: attrbuteID}).Error + + if err != nil { + log.Println(err.Error()) + } + + return options, err +} diff --git a/main.go b/main.go index 5b1069b..57e821f 100644 --- a/main.go +++ b/main.go @@ -46,7 +46,8 @@ func InitCouchDbServer() error { func main() { route := mux.NewRouter() - route.HandleFunc("/init-importer", controller.StartImport) + //route.HandleFunc("/init-importer", controller.StartImport) + route.HandleFunc("/init-importer", controller.StartProductImport) route.HandleFunc("/parse-link", controller.ParseLink) err := http.ListenAndServe(os.Getenv("port"), route) diff --git a/models/product.go b/models/product.go index 5d2d9f6..d537e85 100644 --- a/models/product.go +++ b/models/product.go @@ -7,7 +7,7 @@ type Product struct { Cinsiyet string `json:"cinsiyet"` Color string `json:"color"` ColorVariantCount int `json:"color_variant_count"` - ColorVariants []Product `json:"color_variants"` + ColorVariants *[]Product `json:"color_variants"` Description string `json:"description"` IsSellable bool `json:"sellable"` FavoriteCount int `json:"favorite_count"` @@ -23,7 +23,7 @@ type Product struct { ProductGroupID string `json:"product_group_id"` ProductNumber string `json:"product_number"` ShortDescription string `json:"short_description"` - SizeVariants []Variant `json:"size_variants"` + SizeVariants *[]Variant `json:"size_variants"` Sku string `json:"sku"` Stock interface{} `json:"stock"` URLKey string `json:"url_key"` diff --git a/repositories/ImportRepository.go b/repositories/ImportRepository.go index 5fa74dd..e8aa9d2 100644 --- a/repositories/ImportRepository.go +++ b/repositories/ImportRepository.go @@ -2,15 +2,253 @@ package repositories import ( gm "db_service/gorm_models" + "db_service/models" + helper "db_service/pkg" + "encoding/json" + "fmt" + "gorm.io/driver/mysql" "gorm.io/gorm" + "log" + "os" + "sync" ) type Importer struct { mainCategories []gm.Category baza *gorm.DB families []gm.AttributeFamily + sellers map[string]gm.MarketplaceSeller + AttributesMap map[string]gm.Attribute + Error error + ImportWGroup sync.WaitGroup + ColorOptions map[string]gm.AttributeOption + SexOptions map[string]gm.AttributeOption } -func ImporterInstance() Importer { - return Importer{} +func ImporterInstance() (instance *Importer, err error) { + + db, err := gorm.Open(mysql.Open(os.Getenv("database_url")), &gorm.Config{SkipDefaultTransaction: true}) + + if err != nil { + log.Println(err) + return nil, err + } + + instance = &Importer{baza: db} + + instance.ImportWGroup.Add(4) + + //load main categories to memory + go func(db *gorm.DB) { + defer instance.ImportWGroup.Done() + instance.mainCategories, instance.Error = gm.GetMainCategories(db) + }(db) + + //load families to memory + go func() { + defer instance.ImportWGroup.Done() + instance.families, instance.Error = gm.GetFamilies(db) + }() + + //load attributes to memory + go func() { + defer instance.ImportWGroup.Done() + + if attributes, err := gm.GetAttributes(db); err != nil { + instance.Error = err + return + } else { + instance.AttributesMap = make(map[string]gm.Attribute, len(attributes)) + + for _, attribute := range attributes { + instance.AttributesMap[attribute.Code] = attribute + } + } + + if colorOptions, err := gm.GetAttrOptions(db, instance.AttributesMap["color"].ID); err != nil { + instance.Error = err + return + } else { + instance.ColorOptions = make(map[string]gm.AttributeOption, len(colorOptions)) + + for _, option := range colorOptions { + instance.ColorOptions[option.AdminName] = option + } + } + + if sexOPtions, err := gm.GetAttrOptions(db, instance.AttributesMap["cinsiyet"].ID); err != nil { + instance.Error = err + return + } else { + instance.SexOptions = make(map[string]gm.AttributeOption, len(sexOPtions)) + + for _, option := range sexOPtions { + instance.SexOptions[option.AdminName] = option + } + } + + }() + + //load sellers to memory + go func() { + defer instance.ImportWGroup.Done() + + var vendors, err = gm.GetSellers(db) + + if err != nil { + instance.Error = err + return + } + //init sellers map + instance.sellers = make(map[string]gm.MarketplaceSeller, len(vendors)) + + for _, vendor := range vendors { + instance.sellers[vendor.Url] = vendor + } + }() + + if instance.Error != nil { + log.Println(instance.Error) + return nil, instance.Error + } + + return instance, nil +} + +func (importer *Importer) Start() (instance *Importer) { + //init wait group to main categories length + importer.ImportWGroup.Add(len(importer.mainCategories)) + //start gorutines for each main category + for _, element := range importer.mainCategories { + + slug := element.Translations[0].Slug + + go importer.categoryRoutine("ty_db_" + slug) + } + + return importer +} + +func (importer *Importer) categoryRoutine(dbName string) { + defer importer.ImportWGroup.Done() + + if dbExists := helper.CheckDBExists(os.Getenv("couch_db_source") + dbName); dbExists { + + totalDocCount := getTotalDocumentCount(dbName) + skip := 0 + limit := 200 + totalImport := 0 + for skip < totalDocCount { + + var response models.BagistoModelResponse + + url := fmt.Sprintf("%s%s/_all_docs?include_docs=true&limit=%v&skip=%v", os.Getenv("couch_db_source"), dbName, limit, skip) + + fmt.Println(url) + + skip += limit + + body, err := helper.SendRequest("GET", url, nil, "") + + if err != nil { + fmt.Println(err.Error()) + continue + } + + if err = json.Unmarshal(body, &response); err != nil { + log.Println(err.Error()) + continue + } + + //iterate 100 row products + for _, element := range response.Rows { + + if err := importer.ImportProduct(element.Doc).Error; err != nil { + log.Println(err) + } else { + totalImport++ + } + } + + log.Printf("%s total imported documents count %d \n", dbName, totalImport) + } + } else { + log.Println(dbName + "+doesnt exist") + } + +} + +func getTotalDocumentCount(db string) int { + + var response models.DBDocCountResponse + + url := os.Getenv("couch_db_source") + db + + body, err := helper.SendRequest("GET", url, nil, "") + + if err != nil { + log.Println(err.Error()) + return 0 + } + + err = json.Unmarshal(body, &response) + if err != nil { + log.Println(err.Error()) + return 0 + } + + return response.DocCount +} + +func (importer *Importer) ImportProduct(product models.Product) (instance *Importer) { + + productRepo := InitProductRepo(&product, importer.GetColorOption(product.Color), importer.GetSexOption(product.Cinsiyet)) + var categories []gm.Category + + if categories, importer.Error = gm.GetCatKeywords(importer.baza, product.Categories); importer.Error != nil { + log.Println("ERR0 Categories" + importer.Error.Error()) + return importer + } + + productRepo.SetCategories(categories) + + if productRepo.Brand, importer.Error = gm.FindOrCreateBrand(importer.baza, product.Brand, productRepo.Categories); importer.Error != nil { + log.Println("ERR BRAND" + importer.Error.Error()) + return importer + } + + //BEGIN TRANSACTION + //tx := *importer.baza.Begin() + + return importer +} + +func (importer *Importer) GetColorOption(optionName string) gm.AttributeOption { + if optionName == "" { + return gm.AttributeOption{} + } + + if option, ok := importer.ColorOptions[optionName]; ok { + return option + } else { + option := gm.GetAttributeOption(importer.baza, importer.AttributesMap["color"].ID, optionName) + + importer.ColorOptions[optionName] = option + return option + } +} + +func (importer *Importer) GetSexOption(optionName string) gm.AttributeOption { + if optionName == "" { + return gm.AttributeOption{} + } + + if option, ok := importer.ColorOptions[optionName]; ok { + return option + } else { + option := gm.GetAttributeOption(importer.baza, importer.AttributesMap["cinsiyet"].ID, optionName) + + importer.SexOptions[optionName] = option + return option + } } diff --git a/repositories/ProductRepository.go b/repositories/ProductRepository.go new file mode 100644 index 0000000..70ce223 --- /dev/null +++ b/repositories/ProductRepository.go @@ -0,0 +1,251 @@ +package repositories + +import ( + gm "db_service/gorm_models" + "db_service/models" + "math" + "strconv" +) + +type ProductRepo struct { + Categories []gm.Category + Brand gm.Brand + Weight float64 + Description string + Keywords string + Data *models.Product + Error error + ColorOption gm.AttributeOption + SexOption gm.AttributeOption +} + +func InitProductRepo(data *models.Product, color, sex gm.AttributeOption) *ProductRepo { + + weight, wError := strconv.ParseFloat(data.Weight, 64) + + if wError != nil || weight == 0 { + weight = 0.5 + } + + var description string + + for _, desc := range data.Descriptions { + description += "
" + desc.Description + "
" + } + + instance := &ProductRepo{ + Weight: weight, + Description: description, + Data: data, + ColorOption: color, + SexOption: sex, + } + + return instance +} + +func (pr *ProductRepo) SetCategories(categories []gm.Category) { + pr.Categories = categories + pr.Keywords = pr.Data.Brand + + for _, cat := range categories { + //log.Println(cat) + if len(cat.Translations) > 0 && cat.Translations[0].MetaKeywords != "" { + translation := cat.Translations[0] + + pr.Keywords += "," + translation.MetaKeywords + } + } +} + +func (pr *ProductRepo) makeProduct(imp *Importer) gm.Product { + var famID uint = 1 + + if len(imp.families) > 0 { //todo make real fam function + famID = imp.families[0].ID + } + + product := gm.Product{ + Sku: pr.Data.ProductNumber, + Type: "simple", + AttributeFamilyID: famID, + BrandID: pr.Brand.ID, + Categories: pr.Categories, + AttributeValues: pr.getProductAttributes(imp.AttributesMap, pr.Data), + } + + if pr.Data.SizeVariants != nil && len(*pr.Data.SizeVariants) > 0 { + product.Type = "configurable" + product.SuperAttributes = []gm.Attribute{imp.AttributesMap["size"]} + } else { + price := pr.Data.Price + + if price.OriginalPrice.Value > price.DiscountedPrice.Value { + product.AttributeValues = append(product.AttributeValues, []gm.ProductAttributeValue{ + {AttributeID: imp.AttributesMap["price"].ID, FloatValue: price.OriginalPrice.Value}, + {AttributeID: imp.AttributesMap["special_price"].ID, FloatValue: price.DiscountedPrice.Value}, + }...) + } else { + product.AttributeValues = append(product.AttributeValues, gm.ProductAttributeValue{ + AttributeID: imp.AttributesMap["price"].ID, FloatValue: price.DiscountedPrice.Value, + }) + } + } + + for _, element := range pr.Data.Images { + product.Images = append(product.Images, gm.ProductImage{Type: "cdn", Path: element}) + } + + return product +} + +func (pr *ProductRepo) makeVariant(parentID, famID uint) gm.Product { + + //todo + product := gm.Product{ + Sku: pr.Data.ProductNumber, + Type: "simple", + AttributeFamilyID: famID, + BrandID: pr.Brand.ID, + Categories: pr.Categories, + ParentID: parentID, + } + + return product +} + +func (pr *ProductRepo) makeProductFlat(im *Importer) gm.ProductFlat { + + flat := gm.ProductFlat{ + + Status: true, + VisibleIndividually: true, + Name: pr.Data.Name, + Sku: pr.Data.ProductGroupID, + //ProductNumber: pr.Data.ProductNumber, + Description: pr.Description, + //UrlKey: pr.Data.ProductGroupID, + Weight: pr.Weight, + FavoritesCount: uint(pr.Data.FavoriteCount), + MaxPrice: 0, + MinPrice: 0, + Price: 0, + } + + if pr.Data.Color != "" { + flat.Color = int(im.GetColorOption(pr.Data.Color).ID) + flat.ColorLabel = pr.Data.Color + } + + if pr.Data.SizeVariants != nil && len(*pr.Data.SizeVariants) > 0 { + + for _, variant := range *pr.Data.SizeVariants { + price := variant.Price + + if flat.MinPrice == 0 || flat.MinPrice > price.DiscountedPrice.Value { + flat.MaxPrice = price.DiscountedPrice.Value + } + + maxPrice := math.Max(price.OriginalPrice.Value, price.DiscountedPrice.Value) + if flat.MaxPrice == 0 || flat.MaxPrice < maxPrice { + flat.MaxPrice = maxPrice + } + } + + } else { + flat.MinPrice = pr.Data.Price.DiscountedPrice.Value + flat.MaxPrice = math.Max(pr.Data.Price.OriginalPrice.Value, pr.Data.Price.DiscountedPrice.Value) + flat.Price = flat.MaxPrice + + if flat.MinPrice < flat.MaxPrice { + flat.SpecialPrice = flat.MinPrice + } + + } + + return flat +} + +func (pr *ProductRepo) makeVariantFlat(variant models.Variant, SizID int) gm.ProductFlat { + + maxPRice := math.Max(variant.Price.OriginalPrice.Value, variant.Price.DiscountedPrice.Value) + + flat := gm.ProductFlat{ + Status: true, + Name: pr.Data.Name, + Sku: pr.Data.ProductGroupID, + ProductNumber: pr.Data.ProductNumber, + Weight: pr.Weight, + FavoritesCount: uint(pr.Data.FavoriteCount), + SizeLabel: variant.AttributeValue, + Size: SizID, + MaxPrice: maxPRice, + MinPrice: variant.Price.DiscountedPrice.Value, + Price: maxPRice, + } + + if flat.MaxPrice > flat.MinPrice { + flat.SpecialPrice = flat.MinPrice + } + + if pr.Data.Color != "" { + flat.Color = int(pr.ColorOption.ID) + flat.ColorLabel = pr.Data.Color + } + + return flat +} + +func (pr *ProductRepo) getProductAttributes(AttributesMap map[string]gm.Attribute, product *models.Product) []gm.ProductAttributeValue { + attributes := []gm.ProductAttributeValue{ + {AttributeID: AttributesMap["source"].ID, TextValue: product.URLKey}, + {AttributeID: AttributesMap["favoritesCount"].ID, IntegerValue: product.FavoriteCount}, + {AttributeID: AttributesMap["sku"].ID, TextValue: product.ProductNumber}, + {AttributeID: AttributesMap["name"].ID, TextValue: product.Name, Channel: "default", Locale: "tm"}, + {AttributeID: AttributesMap["weight"].ID, TextValue: product.Weight}, + {AttributeID: AttributesMap["status"].ID, BooleanValue: true}, + {AttributeID: AttributesMap["visible_individually"].ID, BooleanValue: true}, + {AttributeID: AttributesMap["description"].ID, TextValue: pr.Description, Channel: "default", Locale: "tm"}, + {AttributeID: AttributesMap["meta_keywords"].ID, TextValue: pr.Keywords, Channel: "default", Locale: "tm"}, + } + + if product.Color != "" { + attributes = append(attributes, gm.ProductAttributeValue{AttributeID: AttributesMap["color"].ID, IntegerValue: int(pr.ColorOption.ID)}) + } + + if product.Cinsiyet != "" { + attributes = append(attributes, gm.ProductAttributeValue{AttributeID: AttributesMap["cinsiyet"].ID, IntegerValue: int(pr.SexOption.ID)}) + } + + return attributes +} + +func (pr *ProductRepo) getVariantAttributes(AttributesMap map[string]gm.Attribute, product *models.Variant, SizID int) []gm.ProductAttributeValue { + + price := math.Max(product.Price.OriginalPrice.Value, product.Price.DiscountedPrice.Value) + + attributes := []gm.ProductAttributeValue{ + {AttributeID: AttributesMap["source"].ID, TextValue: pr.Data.URLKey}, + {AttributeID: AttributesMap["sku"].ID, TextValue: string(rune(product.ItemNumber))}, //todo unique + {AttributeID: AttributesMap["product_number"].ID, TextValue: string(rune(product.ItemNumber))}, //todo unique + {AttributeID: AttributesMap["name"].ID, TextValue: pr.Data.Name, Channel: "default", Locale: "tm"}, + {AttributeID: AttributesMap["weight"].ID, TextValue: pr.Data.Weight}, + {AttributeID: AttributesMap["status"].ID, BooleanValue: true}, + {AttributeID: AttributesMap["size"].ID, IntegerValue: SizID}, + {AttributeID: AttributesMap["price"].ID, FloatValue: price}, + } + + if pr.Data.Color != "" { + attributes = append(attributes, gm.ProductAttributeValue{AttributeID: AttributesMap["color"].ID, IntegerValue: int(pr.ColorOption.ID)}) + } + + if pr.Data.Cinsiyet != "" { + attributes = append(attributes, gm.ProductAttributeValue{AttributeID: AttributesMap["cinsiyet"].ID, IntegerValue: int(pr.SexOption.ID)}) + } + + if product.Price.OriginalPrice.Value > product.Price.DiscountedPrice.Value { + attributes = append(attributes, gm.ProductAttributeValue{AttributeID: AttributesMap["special_price"].ID, FloatValue: product.Price.DiscountedPrice.Value}) + } + + return attributes +}