376 lines
9.4 KiB
Go
376 lines
9.4 KiB
Go
package repositories
|
|
|
|
import (
|
|
"db_service/models"
|
|
helper "db_service/pkg"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"net/http"
|
|
"reflect"
|
|
"regexp"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
type LinkParser struct {
|
|
link string
|
|
}
|
|
|
|
func NewLinkParser(link string) LinkParser {
|
|
return LinkParser{link: link}
|
|
}
|
|
|
|
func (l LinkParser) ParseLink() (models.TrendyolProductDetailModel, error) {
|
|
|
|
helper.Info("link: ", l.link)
|
|
|
|
productId := ""
|
|
|
|
if isShortLink(l.link) {
|
|
productId = getProductIdFromShortLink(l.link)
|
|
} else {
|
|
productId = getProductIdFromLink(l.link)
|
|
}
|
|
|
|
if len(productId) == 0 {
|
|
parseErr := errors.New("can not parse product id")
|
|
helper.Error(parseErr)
|
|
return models.TrendyolProductDetailModel{}, parseErr
|
|
}
|
|
|
|
helper.Info("productId: ", productId)
|
|
|
|
return GetProductDetails(productId)
|
|
}
|
|
|
|
func getProductIdFromShortLink(shortLink string) string {
|
|
|
|
var productId string
|
|
|
|
client, _ := helper.NewHttpClient()
|
|
req, err := http.NewRequest("GET", shortLink, nil)
|
|
req.Proto = "HTTP/2.0"
|
|
if err != nil {
|
|
helper.Error(err)
|
|
return ""
|
|
}
|
|
|
|
q := req.URL.Query()
|
|
req.URL.RawQuery = q.Encode()
|
|
req.Header.Set("Connection", "close")
|
|
req = req.WithContext(req.Context())
|
|
req.Close = true
|
|
client.CloseIdleConnections()
|
|
|
|
response, err := client.Do(req)
|
|
if err != nil {
|
|
helper.Error(err)
|
|
return productId
|
|
}
|
|
|
|
defer response.Body.Close()
|
|
|
|
url := response.Request.URL.Path
|
|
|
|
helper.Info("link url: ", url)
|
|
|
|
productId = getProductIdFromLink(url)
|
|
|
|
helper.Info("productId: ", productId)
|
|
|
|
return productId
|
|
}
|
|
|
|
func getProductIdFromLink(link string) string {
|
|
var productId string
|
|
|
|
if strings.Contains(link, "?") {
|
|
link = strings.Split(link, "?")[0]
|
|
}
|
|
|
|
strArr := strings.Split(link, "-")
|
|
productId = strArr[len(strArr)-1]
|
|
|
|
return productId
|
|
}
|
|
|
|
func isShortLink(link string) bool {
|
|
return !strings.Contains(link, "trendyol.com")
|
|
}
|
|
|
|
// GetProductDetails return JSON object. Merges color option
|
|
func GetProductDetails(productId string) (models.TrendyolProductDetailModel, error) {
|
|
|
|
var response models.TrendyolProductDetailResponse
|
|
productDetailModel := models.TrendyolProductDetailModel{}
|
|
|
|
// set linearVariants false to get variants
|
|
url := "https://public.trendyol.com/discovery-web-productgw-service/api/productDetail/" + productId + "?storefrontId=1&culture=tr-TR&linearVariants=false"
|
|
|
|
body, err := helper.SendRequest("GET", url, nil, "")
|
|
|
|
if err != nil {
|
|
return productDetailModel, err
|
|
}
|
|
|
|
err = json.Unmarshal(body, &response)
|
|
|
|
if err != nil {
|
|
helper.Error(err)
|
|
return productDetailModel, err
|
|
}
|
|
|
|
productDetailModel = response.Result
|
|
|
|
return productDetailModel, nil
|
|
}
|
|
|
|
// getProductDetailWithOptions returns JSON with variants
|
|
func (l LinkParser) GetProductDetailWithOptions(productId, productGroupId int) (models.Product, error) {
|
|
|
|
primaryProductDetail, err := GetProductDetails(strconv.Itoa(productId))
|
|
|
|
if err != nil {
|
|
return models.Product{}, err
|
|
}
|
|
|
|
productDetailJSON := CreateJSONFromModel(primaryProductDetail)
|
|
|
|
if productDetailJSON != nil {
|
|
colorVariants, err := GetProductColorVariants(productGroupId)
|
|
|
|
var colorVariantsJson []map[string]interface{}
|
|
|
|
if err != nil {
|
|
return models.Product{}, err
|
|
}
|
|
|
|
// get the color variant products
|
|
for _, slicingAttribute := range colorVariants.Result.SlicingAttributes {
|
|
for _, attribute := range slicingAttribute.Attributes {
|
|
for _, content := range attribute.Contents {
|
|
// Don't fetch primary product again.
|
|
if content.ID != primaryProductDetail.ID {
|
|
productVariantDetail, errGPD := GetProductDetails(strconv.Itoa(content.ID))
|
|
if errGPD == nil {
|
|
productVariantJSON := CreateJSONFromModel(productVariantDetail)
|
|
if productVariantJSON != nil {
|
|
colorVariantsJson = append(colorVariantsJson, productVariantJSON)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// Color variant count
|
|
if len(slicingAttribute.Attributes) > 0 {
|
|
productDetailJSON["color_variant_count"] = len(slicingAttribute.Attributes)
|
|
productDetailJSON["color_variants"] = colorVariantsJson
|
|
}
|
|
}
|
|
}
|
|
|
|
jsonString, _ := json.Marshal(productDetailJSON)
|
|
|
|
// convert json to struct
|
|
converted := models.Product{}
|
|
json.Unmarshal(jsonString, &converted)
|
|
|
|
return converted, nil
|
|
}
|
|
|
|
// getProductColorVariants returns color options of product
|
|
func GetProductColorVariants(productGroupId int) (models.TrendyolProductVariantsResponse, error) {
|
|
|
|
url := "https://public.trendyol.com/discovery-web-productgw-service/api/productGroup/" + strconv.Itoa(productGroupId) + "?storefrontId=1&culture=tr-TR"
|
|
|
|
var response models.TrendyolProductVariantsResponse
|
|
|
|
body, err := helper.SendRequest("GET", url, nil, "")
|
|
|
|
if err != nil {
|
|
return response, err
|
|
}
|
|
|
|
err = json.Unmarshal(body, &response)
|
|
|
|
if err != nil {
|
|
helper.Error(err)
|
|
return response, err
|
|
}
|
|
|
|
return response, nil
|
|
}
|
|
|
|
// createJSONFromModel creates json from [trendyol.TrendyolProductDetailModel] and returns
|
|
func CreateJSONFromModel(model models.TrendyolProductDetailModel) map[string]interface{} {
|
|
|
|
json := map[string]interface{}{}
|
|
|
|
// get weight from categories (Stored in helper array (RAM))
|
|
weight := helper.GetCategoryWeight(model.Category.BeautifiedName)
|
|
productGroupId := strconv.Itoa(model.ProductGroupID)
|
|
|
|
json["_id"] = productGroupId
|
|
json["product_group_id"] = productGroupId
|
|
json["vendor"] = "trendyol"
|
|
json["sku"] = "p-" + strconv.Itoa(model.ID)
|
|
json["product_number"] = strconv.Itoa(model.ID)
|
|
json["product_code"] = model.ProductCode
|
|
json["name"] = model.Name
|
|
json["sellable"] = model.IsSellable
|
|
json["favorite_count"] = model.FavoriteCount
|
|
json["weight"] = weight
|
|
json["name_with_product_code"] = model.NameWithProductCode
|
|
json["url_key"] = "https://www.trendyol.com" + model.URL
|
|
json["images"] = model.Images
|
|
json["brand"] = model.Brand.Name
|
|
json["cinsiyet"] = model.Gender.Name
|
|
//json["description"] = model.Description
|
|
json["descriptions"] = model.ContentDescriptions
|
|
//json["short_description"] = model.Description
|
|
// nested structure
|
|
json["price"] = make(map[string]interface{})
|
|
json["price"].(map[string]interface{})["originalPrice"] = model.Price.OriginalPrice
|
|
json["price"].(map[string]interface{})["sellingPrice"] = model.Price.SellingPrice
|
|
json["price"].(map[string]interface{})["discountedPrice"] = model.Price.DiscountedPrice
|
|
|
|
attrLen := len(model.Attributes)
|
|
|
|
if attrLen != 0 {
|
|
for i := 0; i < attrLen; i++ {
|
|
attribute := model.Attributes[i]
|
|
if attribute.Key.Name == "Renk" {
|
|
json["color"] = attribute.Value.Name
|
|
}
|
|
}
|
|
}
|
|
|
|
// set categories with value 1
|
|
json["categories"] = []int{1}
|
|
|
|
attributes := make([]map[string]string, 0)
|
|
for _, attr := range model.Attributes {
|
|
var re = regexp.MustCompile(`/[^A-Z0-9]/ig`)
|
|
keyStr := re.ReplaceAllString(attr.Key.Name, `_`)
|
|
key := strings.ToLower(keyStr)
|
|
attribute := map[string]string{
|
|
key: attr.Value.Name,
|
|
}
|
|
|
|
attributes = append(attributes, attribute)
|
|
}
|
|
|
|
json["attributes"] = attributes
|
|
|
|
var variants []models.Variant
|
|
|
|
// if show variants, then it is configurable product.
|
|
if model.ShowVariants {
|
|
|
|
for i := 0; i < len(model.Variants); i++ {
|
|
variant := model.Variants[i]
|
|
|
|
if variant.Sellable {
|
|
stockType := reflect.TypeOf(variant.Stock)
|
|
|
|
if stockType == nil {
|
|
variants = append(variants, variant)
|
|
} else {
|
|
// scrape is via link parse
|
|
// we need to parse other variants
|
|
|
|
// convert stock to int
|
|
stock, ok := variant.Stock.(float64)
|
|
|
|
if ok {
|
|
if stock > 0 {
|
|
variants = append(variants, variant)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
for i := 0; i < len(model.AllVariants); i++ {
|
|
singleVariant := model.AllVariants[i]
|
|
|
|
// get the first variant for attribute info
|
|
fv := variants[0]
|
|
|
|
variant := models.Variant{
|
|
AttributeID: fv.AttributeID, //
|
|
AttributeName: fv.AttributeName, // Sample: "Beden"
|
|
AttributeType: fv.AttributeType, // Sample: "Size"
|
|
AttributeValue: singleVariant.Value,
|
|
Price: models.Price{
|
|
ProfitMargin: 0,
|
|
DiscountedPrice: struct {
|
|
Text string "json:\"text\""
|
|
Value float64 "json:\"value\""
|
|
}{
|
|
Text: fmt.Sprintf("%f", singleVariant.Price),
|
|
Value: singleVariant.Price,
|
|
},
|
|
SellingPrice: struct {
|
|
Text string "json:\"text\""
|
|
Value float64 "json:\"value\""
|
|
}{
|
|
Text: fmt.Sprintf("%f", singleVariant.Price),
|
|
Value: singleVariant.Price,
|
|
},
|
|
OriginalPrice: struct {
|
|
Text string "json:\"text\""
|
|
Value float64 "json:\"value\""
|
|
}{
|
|
Text: fmt.Sprintf("%f", singleVariant.Price),
|
|
Value: singleVariant.Price,
|
|
},
|
|
Currency: singleVariant.Currency,
|
|
},
|
|
ItemNumber: singleVariant.ItemNumber,
|
|
Sellable: singleVariant.InStock,
|
|
}
|
|
|
|
exists := helper.IsVariantsAdded(variants, variant.ItemNumber)
|
|
|
|
if !exists {
|
|
variants = append(variants, variant)
|
|
}
|
|
}
|
|
|
|
for i := 0; i < len(model.AlternativeVariants); i++ {
|
|
alternativeVariant := model.AlternativeVariants[i]
|
|
|
|
if len(variants) > 0 {
|
|
|
|
// get the first variant for attribute info
|
|
fv := variants[0]
|
|
|
|
variant := models.Variant{
|
|
AttributeID: fv.AttributeID, //
|
|
AttributeName: fv.AttributeName, // Sample: "Beden"
|
|
AttributeType: fv.AttributeType, // Sample: "Size"
|
|
AttributeValue: alternativeVariant.AttributeValue,
|
|
Price: alternativeVariant.Price,
|
|
ItemNumber: alternativeVariant.ItemNumber,
|
|
Sellable: alternativeVariant.Quantity > 0,
|
|
}
|
|
exists := helper.IsVariantsAdded(variants, variant.ItemNumber)
|
|
|
|
if !exists {
|
|
variants = append(variants, variant)
|
|
}
|
|
}
|
|
}
|
|
|
|
json["size_variants"] = variants
|
|
}
|
|
|
|
if model.ShowVariants && len(variants) == 0 {
|
|
return nil
|
|
}
|
|
|
|
return json
|
|
}
|