flamingo.me/flamingo-commerce/v3@v3.11.0/product/infrastructure/fake/productservice.go (about)

     1  package fake
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"math/big"
     7  	"math/rand"
     8  	"os"
     9  	"sort"
    10  	"strconv"
    11  	"strings"
    12  	"time"
    13  
    14  	"flamingo.me/flamingo/v3/framework/web"
    15  
    16  	"flamingo.me/flamingo/v3/framework/flamingo"
    17  
    18  	priceDomain "flamingo.me/flamingo-commerce/v3/price/domain"
    19  	"flamingo.me/flamingo-commerce/v3/product/domain"
    20  )
    21  
    22  var (
    23  	brands = []string{
    24  		"Apple",
    25  		"Bose",
    26  		"Dior",
    27  		"Hugo Boss",
    28  	}
    29  
    30  	inflightLoyaltyAmount = 500.0
    31  	hdLoyaltyAmount       = 600.0
    32  )
    33  
    34  // ProductService is just mocking stuff
    35  type ProductService struct {
    36  	currencyCode           string
    37  	testDataFiles          map[string]string
    38  	logger                 flamingo.Logger
    39  	deliverDefaultProducts bool
    40  	deliveryCodes          []string
    41  }
    42  
    43  // Inject dependencies
    44  func (ps *ProductService) Inject(logger flamingo.Logger,
    45  	c *struct {
    46  		CurrencyCode            string   `inject:"config:commerce.product.fakeservice.currency,optional"`
    47  		TestDataFolder          string   `inject:"config:commerce.product.fakeservice.jsonTestDataFolder,optional"`
    48  		DeliveryDefaultProducts bool     `inject:"config:commerce.product.fakeservice.defaultProducts,optional"`
    49  		DeliveryCodes           []string `inject:"config:commerce.product.fakeservice.deliveryCodes,optional"`
    50  	},
    51  ) *ProductService {
    52  	ps.logger = logger
    53  	if c != nil {
    54  		ps.currencyCode = c.CurrencyCode
    55  		if len(c.TestDataFolder) > 0 {
    56  			ps.testDataFiles = registerTestData(c.TestDataFolder, ps.logger)
    57  		}
    58  
    59  		ps.deliverDefaultProducts = c.DeliveryDefaultProducts
    60  		ps.deliveryCodes = c.DeliveryCodes
    61  	}
    62  
    63  	return ps
    64  }
    65  
    66  // Get returns a product struct
    67  func (ps *ProductService) Get(_ context.Context, marketplaceCode string) (domain.BasicProduct, error) {
    68  	switch marketplaceCode {
    69  	case "fake_configurable":
    70  		return ps.getFakeConfigurableWithVariants(marketplaceCode), nil
    71  
    72  	case "fake_configurable_with_active_variant":
    73  		return ps.getFakeConfigurableWithActiveVariant(marketplaceCode), nil
    74  
    75  	case "fake_simple":
    76  		return ps.FakeSimple(marketplaceCode, false, false, false, true, false), nil
    77  
    78  	case "fake_simple_with_fixed_price":
    79  		return ps.FakeSimple(marketplaceCode, false, false, false, true, true), nil
    80  
    81  	case "fake_fixed_simple_without_discounts":
    82  		return ps.FakeSimple(marketplaceCode, false, false, false, false, true), nil
    83  
    84  	case "fake_simple_out_of_stock":
    85  		return ps.FakeSimple(marketplaceCode, false, false, true, true, false), nil
    86  	case "fake_bundle":
    87  		return ps.FakeBundle(marketplaceCode, false, false, true, true, false), nil
    88  	default:
    89  		jsonProduct, err := ps.getProductFromJSON(marketplaceCode)
    90  		if err != nil {
    91  			if _, isProductNotFoundError := err.(domain.ProductNotFound); !isProductNotFoundError {
    92  				return nil, err
    93  			}
    94  		} else {
    95  			return jsonProduct, nil
    96  		}
    97  	}
    98  
    99  	marketPlaceCodes := ps.GetMarketPlaceCodes()
   100  	return nil, domain.ProductNotFound{
   101  		MarketplaceCode: "Code " + marketplaceCode + " Not implemented in FAKE: Only following codes should be used" + strings.Join(marketPlaceCodes, ", "),
   102  	}
   103  }
   104  
   105  // FakeSimple generates a simple fake product
   106  func (ps *ProductService) FakeSimple(marketplaceCode string, isNew bool, isExclusive bool, isOutOfStock bool, isDiscounted bool, hasFixedPrice bool) domain.SimpleProduct {
   107  	product := domain.SimpleProduct{}
   108  	product.Title = "TypeSimple product"
   109  	ps.addBasicData(&product.BasicProductData)
   110  
   111  	product.Saleable = domain.Saleable{
   112  		IsSaleable:   true,
   113  		SaleableTo:   time.Now().Add(time.Hour * time.Duration(1)),
   114  		SaleableFrom: time.Now().Add(time.Hour * time.Duration(-1)),
   115  		ActiveLoyaltyPrice: &domain.LoyaltyPriceInfo{
   116  			Type:    "AwesomeLoyaltyProgram",
   117  			Default: priceDomain.NewFromFloat(inflightLoyaltyAmount, "BonusPoints"),
   118  		},
   119  		LoyaltyPrices: []domain.LoyaltyPriceInfo{
   120  			{
   121  				Type:    "AwesomeLoyaltyProgram",
   122  				Default: priceDomain.NewFromFloat(inflightLoyaltyAmount, "BonusPoints"),
   123  				Context: domain.PriceContext{DeliveryCode: "inflight"},
   124  			},
   125  			{
   126  				Type:    "AwesomeLoyaltyProgram",
   127  				Default: priceDomain.NewFromFloat(hdLoyaltyAmount, "BonusPoints"),
   128  				Context: domain.PriceContext{DeliveryCode: "delivery____domestichome"},
   129  			},
   130  		},
   131  		LoyaltyEarnings: []domain.LoyaltyEarningInfo{
   132  			{
   133  				Type:    "AwesomeLoyaltyProgram",
   134  				Default: priceDomain.NewFromFloat(23.23, "BonusPoints"),
   135  			},
   136  		},
   137  	}
   138  
   139  	discountedPrice := 0.0
   140  	if isDiscounted {
   141  		discountedPrice = 10.49 + float64(rand.Intn(10))
   142  		if hasFixedPrice {
   143  			discountedPrice = 10.49
   144  		}
   145  	}
   146  
   147  	defaultPrice := 20.99 + float64(rand.Intn(10))
   148  	if hasFixedPrice {
   149  		defaultPrice = 20.99
   150  	}
   151  
   152  	product.ActivePrice = ps.getPrice(defaultPrice, discountedPrice)
   153  	product.MarketPlaceCode = marketplaceCode
   154  
   155  	product.CreatedAt = time.Date(2019, 6, 29, 00, 00, 00, 00, time.UTC)
   156  	product.UpdatedAt = time.Date(2019, 7, 29, 12, 00, 00, 00, time.UTC)
   157  	product.VisibleFrom = time.Date(2019, 7, 29, 12, 00, 00, 00, time.UTC)
   158  	product.VisibleTo = time.Now().Add(time.Hour * time.Duration(10))
   159  
   160  	product.Teaser = domain.TeaserData{
   161  		ShortDescription: product.ShortDescription,
   162  		ShortTitle:       product.Title,
   163  		URLSlug:          product.BaseData().Attributes["urlSlug"].Value(),
   164  		Media:            product.Media,
   165  		MarketPlaceCode:  product.MarketPlaceCode,
   166  		TeaserPrice: domain.PriceInfo{
   167  			Default: priceDomain.NewFromFloat(9.99, "SD").GetPayable(),
   168  		},
   169  		TeaserLoyaltyPriceInfo: &domain.LoyaltyPriceInfo{
   170  			Type:    "AwesomeLoyaltyProgram",
   171  			Default: priceDomain.NewFromFloat(500, "BonusPoints"),
   172  		},
   173  		TeaserLoyaltyEarningInfo: &domain.LoyaltyEarningInfo{
   174  			Type:    "AwesomeLoyaltyProgram",
   175  			Default: priceDomain.NewFromFloat(23.23, "BonusPoints"),
   176  		},
   177  		Badges: product.Badges,
   178  	}
   179  
   180  	if isNew {
   181  		product.BasicProductData.IsNew = true
   182  	}
   183  
   184  	if isExclusive {
   185  		product.Attributes["exclusiveProduct"] = domain.Attribute{
   186  			RawValue: "30002654_yes",
   187  			Code:     "exclusiveProduct",
   188  		}
   189  	}
   190  
   191  	product.Stock = ps.getStock(true, domain.StockLevelInStock, 999)
   192  
   193  	if isOutOfStock {
   194  		product.Stock = ps.getStock(false, domain.StockLevelOutOfStock, 0)
   195  	}
   196  
   197  	return product
   198  }
   199  
   200  func (ps *ProductService) getStock(inStock bool, level string, amount int) []domain.Stock {
   201  	stock := make([]domain.Stock, 0)
   202  
   203  	for _, code := range ps.deliveryCodes {
   204  		stock = append(stock, domain.Stock{
   205  			Amount:       amount,
   206  			InStock:      inStock,
   207  			Level:        level,
   208  			DeliveryCode: code,
   209  		})
   210  	}
   211  
   212  	return stock
   213  }
   214  
   215  // GetMarketPlaceCodes returns list of available marketplace codes which are supported by this fakeservice
   216  func (ps *ProductService) GetMarketPlaceCodes() []string {
   217  	if !ps.deliverDefaultProducts {
   218  		return ps.jsonProductCodes()
   219  	}
   220  
   221  	marketPlaceCodes := []string{
   222  		"fake_configurable",
   223  		"fake_configurable_with_active_variant",
   224  		"fake_simple",
   225  		"fake_simple_with_fixed_price",
   226  		"fake_simple_out_of_stock",
   227  		"fake_fixed_simple_without_discounts",
   228  	}
   229  
   230  	return append(marketPlaceCodes, ps.jsonProductCodes()...)
   231  }
   232  
   233  func (ps *ProductService) getFakeConfigurable(marketplaceCode string) domain.ConfigurableProduct {
   234  	product := domain.ConfigurableProduct{}
   235  	product.Title = "TypeConfigurable product"
   236  	ps.addBasicData(&product.BasicProductData)
   237  	product.MarketPlaceCode = marketplaceCode
   238  	product.Identifier = marketplaceCode + "_identifier"
   239  	product.Teaser.TeaserPrice = ps.getPrice(30.99+float64(rand.Intn(10)), 20.49+float64(rand.Intn(10)))
   240  	product.Teaser.Badges = product.Badges
   241  	product.VariantVariationAttributes = []string{"color", "size"}
   242  	product.VariantVariationAttributesSorting = map[string][]string{
   243  		"size":  {"M", "L"},
   244  		"color": {"red", "white", "black"},
   245  	}
   246  
   247  	return product
   248  }
   249  
   250  func (ps *ProductService) getFakeConfigurableWithVariants(marketplaceCode string) domain.ConfigurableProduct {
   251  	product := ps.getFakeConfigurable(marketplaceCode)
   252  	product.RetailerCode = "retailer"
   253  
   254  	variants := []struct {
   255  		marketplaceCode string
   256  		title           string
   257  		attributes      domain.Attributes
   258  		stock           []domain.Stock
   259  		badges          []domain.Badge
   260  	}{
   261  		{"shirt-red-s", "Shirt Red S", domain.Attributes{
   262  			"size":                  domain.Attribute{RawValue: "S", Code: "size", CodeLabel: "Size", Label: "S"},
   263  			"manufacturerColor":     domain.Attribute{RawValue: "red", Code: "manufacturerColor", CodeLabel: "Manufacturer Color", Label: "Red"},
   264  			"manufacturerColorCode": domain.Attribute{RawValue: "#ff0000", Code: "manufacturerColorCode", CodeLabel: "Manufacturer Color Code", Label: "BloodRed"}},
   265  			ps.getStock(true, domain.StockLevelInStock, 999),
   266  			[]domain.Badge{{Code: "new", Label: "New"}},
   267  		},
   268  		{"shirt-white-s", "Shirt White S", domain.Attributes{
   269  			"size":                  domain.Attribute{RawValue: "S", Code: "size", CodeLabel: "Size", Label: "S"},
   270  			"manufacturerColor":     domain.Attribute{RawValue: "white", Code: "manufacturerColor", CodeLabel: "Manufacturer Color", Label: "White"},
   271  			"manufacturerColorCode": domain.Attribute{RawValue: "#ffffff", Code: "manufacturerColorCode", CodeLabel: "Manufacturer Color Code", Label: "SnowWhite"}},
   272  			ps.getStock(true, domain.StockLevelInStock, 999),
   273  			nil,
   274  		},
   275  		{"shirt-white-m", "Shirt White M", domain.Attributes{
   276  			"size":  domain.Attribute{RawValue: "M", Code: "size", CodeLabel: "Size", Label: "M"},
   277  			"color": domain.Attribute{RawValue: "white", Code: "color", CodeLabel: "Color", Label: "White"}},
   278  			ps.getStock(true, domain.StockLevelInStock, 999),
   279  			nil,
   280  		},
   281  		{"shirt-black-m", "Shirt Black M", domain.Attributes{
   282  			"size":                  domain.Attribute{RawValue: "M", Code: "size", CodeLabel: "Size", Label: "M"},
   283  			"manufacturerColor":     domain.Attribute{RawValue: "blue", Code: "manufacturerColor", CodeLabel: "Manufacturer Color", Label: "Blue"},
   284  			"manufacturerColorCode": domain.Attribute{RawValue: "#0000ff", Code: "manufacturerColorCode", CodeLabel: "Manufacturer Color Code", Label: "SkyBlue"}},
   285  			ps.getStock(true, domain.StockLevelInStock, 999),
   286  			nil,
   287  		},
   288  		{"shirt-black-l", "Shirt Black L", domain.Attributes{
   289  			"size":  domain.Attribute{RawValue: "L", Code: "size", CodeLabel: "Size", Label: "L"},
   290  			"color": domain.Attribute{RawValue: "black", Code: "color", CodeLabel: "Color", Label: "Black"}},
   291  			ps.getStock(true, domain.StockLevelInStock, 999),
   292  			nil,
   293  		},
   294  		{"shirt-red-l", "Shirt Red L", domain.Attributes{
   295  			"size":  domain.Attribute{RawValue: "L", Code: "size", CodeLabel: "Size", Label: "L"},
   296  			"color": domain.Attribute{RawValue: "red", Code: "color", CodeLabel: "Color", Label: "Red"}},
   297  			ps.getStock(false, domain.StockLevelOutOfStock, 0),
   298  			nil,
   299  		},
   300  		{"shirt-red-m", "Shirt Red M", domain.Attributes{
   301  			"size":  domain.Attribute{RawValue: "M", Code: "size", CodeLabel: "Size", Label: "M"},
   302  			"color": domain.Attribute{RawValue: "red", Code: "color", CodeLabel: "Color", Label: "Red"}},
   303  			ps.getStock(false, domain.StockLevelOutOfStock, 0),
   304  			nil,
   305  		},
   306  	}
   307  
   308  	for _, variant := range variants {
   309  		simpleVariant := ps.fakeVariant(variant.marketplaceCode)
   310  		simpleVariant.Title = variant.title
   311  
   312  		for key, attr := range variant.attributes {
   313  			simpleVariant.Attributes[key] = attr
   314  			simpleVariant.BasicProductData.Attributes[key] = attr
   315  		}
   316  
   317  		simpleVariant.Stock = variant.stock
   318  
   319  		// Give new images for variants with custom colors
   320  		if simpleVariant.Attributes.HasAttribute("manufacturerColorCode") {
   321  			manufacturerColorCode := simpleVariant.Attributes["manufacturerColorCode"].Value()
   322  			manufacturerColorCode = strings.TrimPrefix(manufacturerColorCode, "#")
   323  			image := domain.Media{Type: "image-external", Reference: "http://dummyimage.com/1024x768/000/" + manufacturerColorCode, Usage: "detail"}
   324  			simpleVariant.Media[0] = image
   325  			product.Media = []domain.Media{image}
   326  			product.Teaser.Media = []domain.Media{image}
   327  		}
   328  		simpleVariant.Badges = variant.badges
   329  
   330  		product.Variants = append(product.Variants, simpleVariant)
   331  	}
   332  
   333  	return product
   334  }
   335  
   336  func (ps *ProductService) getFakeConfigurableWithActiveVariant(marketplaceCode string) domain.ConfigurableProductWithActiveVariant {
   337  	configurable := ps.getFakeConfigurableWithVariants(marketplaceCode)
   338  	product := domain.ConfigurableProductWithActiveVariant{
   339  		Identifier:                        configurable.Identifier,
   340  		BasicProductData:                  configurable.BasicProductData,
   341  		Teaser:                            configurable.Teaser,
   342  		VariantVariationAttributes:        configurable.VariantVariationAttributes,
   343  		VariantVariationAttributesSorting: configurable.VariantVariationAttributesSorting,
   344  		Variants:                          configurable.Variants,
   345  		ActiveVariant:                     configurable.Variants[4], // shirt-black-l
   346  	}
   347  
   348  	product.Teaser.TeaserPrice = product.ActiveVariant.ActivePrice
   349  
   350  	return product
   351  }
   352  
   353  func (ps *ProductService) fakeVariant(marketplaceCode string) domain.Variant {
   354  	var simpleVariant domain.Variant
   355  	simpleVariant.Attributes = make(map[string]domain.Attribute)
   356  
   357  	ps.addBasicData(&simpleVariant.BasicProductData)
   358  
   359  	simpleVariant.ActivePrice = ps.getPrice(30.99+float64(rand.Intn(10)), 20.49+float64(rand.Intn(10)))
   360  	simpleVariant.MarketPlaceCode = marketplaceCode
   361  	simpleVariant.IsSaleable = true
   362  
   363  	return simpleVariant
   364  }
   365  
   366  func (ps *ProductService) addBasicData(product *domain.BasicProductData) {
   367  	product.ShortDescription = "Short Description"
   368  	product.Description = "Description"
   369  	product.Keywords = []string{"keywords"}
   370  
   371  	product.Media = append(product.Media, domain.Media{Type: "image-external", Reference: "http://dummyimage.com/1024x768/000/fff", Usage: "detail"})
   372  	product.Media = append(product.Media, domain.Media{Type: "image-external", Reference: "http://dummyimage.com/200x200/000/fff", Usage: "list"})
   373  
   374  	brand := brands[rand.Intn(len(brands))]
   375  	brandValue := web.URLTitle(brand)
   376  	product.Attributes = domain.Attributes{
   377  		"brandCode":        domain.Attribute{Code: "brandCode", Label: brand, RawValue: brandValue},
   378  		"brandName":        domain.Attribute{Code: "brandName", Label: brand, RawValue: brandValue},
   379  		"collectionOption": domain.Attribute{Code: "collectionOption", Label: "Collection option", RawValue: []interface{}{"departure", "arrival"}},
   380  		"urlSlug":          domain.Attribute{Code: "urlSlug", Label: "product-slug", RawValue: "product-slug"},
   381  	}
   382  
   383  	product.RetailerCode = "retailer"
   384  	product.RetailerName = "Test Retailer"
   385  	product.RetailerSku = "12345sku"
   386  
   387  	categoryTeaser1 := domain.CategoryTeaser{
   388  		Path: "Testproducts",
   389  		Name: "Testproducts",
   390  		Code: "testproducts",
   391  	}
   392  	categoryTeaser2 := domain.CategoryTeaser{
   393  		Path: "Testproducts/Fake/Configurable",
   394  		Name: "Configurable",
   395  		Code: "configurable",
   396  	}
   397  	badges := []domain.Badge{
   398  		{
   399  			Code:  "new",
   400  			Label: "New",
   401  		},
   402  	}
   403  	product.Categories = append(product.Categories, categoryTeaser1)
   404  	product.Categories = append(product.Categories, categoryTeaser2)
   405  	product.MainCategory = categoryTeaser1
   406  	product.Badges = badges
   407  }
   408  
   409  func (ps *ProductService) getPrice(defaultP float64, discounted float64) domain.PriceInfo {
   410  	defaultP, _ = strconv.ParseFloat(fmt.Sprintf("%.2f", defaultP), 64)
   411  	discounted, _ = strconv.ParseFloat(fmt.Sprintf("%.2f", discounted), 64)
   412  
   413  	var price domain.PriceInfo
   414  	currency := "EUR"
   415  	if ps.currencyCode != "" {
   416  		currency = ps.currencyCode
   417  	}
   418  
   419  	price.Default = priceDomain.NewFromFloat(defaultP, currency).GetPayable()
   420  	if discounted > 0 {
   421  		price.Discounted = priceDomain.NewFromFloat(discounted, currency).GetPayable()
   422  		price.DiscountText = "Super test campaign"
   423  		price.IsDiscounted = true
   424  	}
   425  	price.ActiveBase = *big.NewFloat(1)
   426  	price.ActiveBaseAmount = *big.NewFloat(10)
   427  	price.ActiveBaseUnit = "ml"
   428  	return price
   429  }
   430  
   431  func (ps *ProductService) getProductFromJSON(code string) (domain.BasicProduct, error) {
   432  	file, ok := ps.testDataFiles[code]
   433  
   434  	if !ok {
   435  		return nil, &domain.ProductNotFound{MarketplaceCode: code}
   436  	}
   437  
   438  	jsonBytes, err := os.ReadFile(file)
   439  	if err != nil {
   440  		return nil, err
   441  	}
   442  
   443  	return unmarshalJSONProduct(jsonBytes)
   444  }
   445  
   446  // jsonProductCodes returns an ordered list of the json product codes
   447  func (ps *ProductService) jsonProductCodes() []string {
   448  	keys := make([]string, 0, len(ps.testDataFiles))
   449  	for k := range ps.testDataFiles {
   450  		keys = append(keys, k)
   451  	}
   452  	sort.Strings(keys)
   453  	return keys
   454  }
   455  
   456  // FakeBundle generates a bundle fake product
   457  func (ps *ProductService) FakeBundle(marketplaceCode string, isNew bool, isExclusive bool, isOutOfStock bool, isDiscounted bool, hasFixedPrice bool) domain.BundleProduct {
   458  	product := domain.BundleProduct{}
   459  	product.Title = "TypeBundle product"
   460  	ps.addBasicData(&product.BasicProductData)
   461  
   462  	product.Saleable = domain.Saleable{
   463  		IsSaleable:   true,
   464  		SaleableTo:   time.Now().Add(time.Hour * time.Duration(1)),
   465  		SaleableFrom: time.Now().Add(time.Hour * time.Duration(-1)),
   466  		ActiveLoyaltyPrice: &domain.LoyaltyPriceInfo{
   467  			Type:    "AwesomeLoyaltyProgram",
   468  			Default: priceDomain.NewFromFloat(inflightLoyaltyAmount, "BonusPoints"),
   469  		},
   470  		LoyaltyPrices: []domain.LoyaltyPriceInfo{
   471  			{
   472  				Type:    "AwesomeLoyaltyProgram",
   473  				Default: priceDomain.NewFromFloat(inflightLoyaltyAmount, "BonusPoints"),
   474  				Context: domain.PriceContext{DeliveryCode: "inflight"},
   475  			},
   476  			{
   477  				Type:    "AwesomeLoyaltyProgram",
   478  				Default: priceDomain.NewFromFloat(hdLoyaltyAmount, "BonusPoints"),
   479  				Context: domain.PriceContext{DeliveryCode: "delivery____domestichome"},
   480  			},
   481  		},
   482  		LoyaltyEarnings: []domain.LoyaltyEarningInfo{
   483  			{
   484  				Type:    "AwesomeLoyaltyProgram",
   485  				Default: priceDomain.NewFromFloat(23.23, "BonusPoints"),
   486  			},
   487  		},
   488  	}
   489  
   490  	discountedPrice := 0.0
   491  	if isDiscounted {
   492  		discountedPrice = 10.49 + float64(rand.Intn(10))
   493  		if hasFixedPrice {
   494  			discountedPrice = 10.49
   495  		}
   496  	}
   497  
   498  	defaultPrice := 21.37 + float64(rand.Intn(10))
   499  	if hasFixedPrice {
   500  		defaultPrice = 20.99
   501  	}
   502  
   503  	product.ActivePrice = ps.getPrice(defaultPrice, discountedPrice)
   504  	product.MarketPlaceCode = marketplaceCode
   505  
   506  	product.CreatedAt = time.Date(2019, 6, 29, 00, 00, 00, 00, time.UTC)
   507  	product.UpdatedAt = time.Date(2019, 7, 29, 12, 00, 00, 00, time.UTC)
   508  	product.VisibleFrom = time.Date(2019, 7, 29, 12, 00, 00, 00, time.UTC)
   509  	product.VisibleTo = time.Now().Add(time.Hour * time.Duration(10))
   510  
   511  	product.Teaser = domain.TeaserData{
   512  		ShortDescription: product.ShortDescription,
   513  		ShortTitle:       product.Title,
   514  		URLSlug:          product.BaseData().Attributes["urlSlug"].Value(),
   515  		Media:            product.Media,
   516  		MarketPlaceCode:  product.MarketPlaceCode,
   517  		TeaserPrice: domain.PriceInfo{
   518  			Default: priceDomain.NewFromFloat(9.99, "SD").GetPayable(),
   519  		},
   520  		TeaserLoyaltyPriceInfo: &domain.LoyaltyPriceInfo{
   521  			Type:    "AwesomeLoyaltyProgram",
   522  			Default: priceDomain.NewFromFloat(500, "BonusPoints"),
   523  		},
   524  		TeaserLoyaltyEarningInfo: &domain.LoyaltyEarningInfo{
   525  			Type:    "AwesomeLoyaltyProgram",
   526  			Default: priceDomain.NewFromFloat(23.23, "BonusPoints"),
   527  		},
   528  		Badges: product.Badges,
   529  	}
   530  
   531  	if isNew {
   532  		product.BasicProductData.IsNew = true
   533  	}
   534  
   535  	if isExclusive {
   536  		product.Attributes["exclusiveProduct"] = domain.Attribute{
   537  			RawValue: "30002654_yes",
   538  			Code:     "exclusiveProduct",
   539  		}
   540  	}
   541  
   542  	product.Stock = ps.getStock(true, domain.StockLevelInStock, 999)
   543  
   544  	if isOutOfStock {
   545  		product.Stock = ps.getStock(false, domain.StockLevelOutOfStock, 0)
   546  	}
   547  
   548  	product.Choices = []domain.Choice{
   549  		{
   550  			Identifier: "identifier1",
   551  			Required:   true,
   552  			Label:      "first choice",
   553  			Options: []domain.Option{
   554  				{
   555  					MinQty:  1,
   556  					MaxQty:  1,
   557  					Product: ps.FakeSimple("simple_option1", false, false, false, true, true),
   558  				},
   559  				{
   560  					MinQty:  1,
   561  					MaxQty:  1,
   562  					Product: ps.FakeSimple("simple_option2", false, false, false, true, true),
   563  				},
   564  			},
   565  		},
   566  		{
   567  			Identifier: "identifier2",
   568  			Required:   true,
   569  			Label:      "second choice",
   570  			Options: []domain.Option{
   571  				{
   572  					MinQty:  1,
   573  					MaxQty:  1,
   574  					Product: ps.getFakeConfigurableWithVariants("configurable_option1"),
   575  				},
   576  				{
   577  					MinQty:  1,
   578  					MaxQty:  1,
   579  					Product: ps.getFakeConfigurableWithVariants("configurable_option2"),
   580  				},
   581  			},
   582  		},
   583  	}
   584  
   585  	return product
   586  }