flamingo.me/flamingo-commerce/v3@v3.11.0/product/Readme.md (about)

     1  # Product Module
     2  
     3  * Provides product domain models and the related secondary ports
     4  * Provides controller for product detail view, including variant logic
     5  * Provides template functions for:
     6      * get a (filtered) list of products (e.g. for product teasers)
     7      * get product urls
     8      * get a specific product
     9  
    10  ## Domain Layer
    11  * A product is identified by a "MarketplaceCode"
    12  * There are different product types, each of them need to implement the `BasicProduct` interface.
    13  
    14  ### The product model
    15  ![Product Model](product_model.png)
    16  
    17  ## Details about Price fields
    18  
    19  ![Priceinfo Model](price_display.png)
    20  
    21  * The product has one main price (see PriceInfo Property) that stands for the value of that product.
    22  * The product has a maintained price in a certain currency - eventually different by channel or locale.
    23  * The price is either maintained as gross (B2C use cases) or net price (B2B use cases). How to interpret the price is up to the cart and view logic. 
    24      * Any logic depending on the gross/net knowledge should use the configuration under `commerce.product.priceIsGross`
    25  
    26  * the product might be currently discounted and has a discounted price (the discounted price is also either gross or net like the normal price)
    27  
    28  About Charges:
    29  * A Charge is a price that needs to be paid for that product. This is normally the product price.
    30  * But this concept allows to control "in what currency and type" a customer needs to pay the price of the product (See loyalty below)
    31  
    32  Loyalty prices:
    33  * The product might also have loyalty prices that allows to set a price in points, but also a minimum amount of points that need to be spent.
    34  * In cases where the customer needs to spend a certain amount of points, the Method "GetCharges()" will return the different charges. Again it is up for other modules to interpret if this is gross or net.
    35  
    36  ### Secondary Ports
    37  The module defines two secondary ports:
    38  
    39  * ProductService interface to receive products
    40  * SearchService interface, to search for product by any passed filter
    41  
    42  ### Product Types
    43  
    44  #### Simple Products
    45  Represents a simple product that can be purchased directly.
    46  
    47  #### ConfigurableProduct and ConfigurableProductWithActiveVariant
    48  Represents a product, that has several Variants. The configurable product cannot be sold directly.
    49  
    50  But from a "Configurable Product" you can get the Saleable Variants - this is a product with Type "ConfigurableProductWithActiveVariant"
    51  
    52  Here is an example illustrating this:
    53  
    54  ```go
    55     // ...
    56     // productService is the injected implementation of interface "ProductService"
    57     product, err := c.productService.Get(ctx, "id_of_a_configurable_product")
    58     if product.Type() == TYPECONFIGURABLE {
    59        // type assert ConfigurableProduct
    60        if configurableProduct, ok := product.(ConfigurableProduct); ok {
    61          variantProduct, err := configurableProduct.GetConfigurableWithActiveVariant("id_of_an_variant")
    62        }
    63     }
    64  ```
    65  
    66  ## Product Detail View
    67  
    68  The view gets the following Data passed:
    69  
    70  ```go
    71      // productViewData is used for product rendering
    72      productViewData struct {
    73          // simple / configurable / configurable_with_variant
    74          RenderContext    string
    75          Product          domain.BasicProduct
    76          VariantSelected  bool
    77          VariantSelection variantSelection
    78          BackURL          string
    79      }
    80  ```
    81  
    82  ## Template functions
    83  
    84  ### getProduct
    85  
    86  Returns the product or nil:
    87  `- var product = getProduct("marketplacecode")`
    88  
    89  
    90  ### getProductUrl
    91  
    92  Returns the correct url to the product:
    93  `getProductUrl(product)`
    94  
    95  The returned products urls slug will be
    96  
    97  * generated if the confuration `commerce.product.generateSlug` is set to true
    98  * use the configured attribute to fetch the utlSlug from the product data.
    99  
   100  ### findProducts
   101  
   102  findProducts is a template function that returns a search result to show products:
   103  
   104  * it will dynamically adjust the search request based on url parameters that match the given namespace
   105  * the template function requires 4 parameters:
   106  
   107      * `namespace`: A name of the findProduct call - it is used to check URL parameters with that namespace
   108      * `searchConfig`: A map with the following keys supported:
   109      
   110          * `query`: Optional - the search string that a "human" might have entered to filter the search
   111          * `pageSize`, `page`: Optional - set the page and the pageSize (for pagination)
   112          * `sortBy`, `sortDirection` (`A`/`D`): Optional - set the field that should be used to sort the search result
   113          
   114      * `keyValueFilters`: Optional - A map of key values that are used as additional keyValue Filters in the searchRequest
   115      * `filterConstrains`: Optional - A map that supports the following keys:
   116      
   117          * `blackList` or `whiteList` (if both given `whiteList` is preferred): This is a comma separated list of filter keys, that are evaluated during:
   118          
   119              * using url Parameters to set keyValueFilters - only allowed keys will be used
   120              * modifying the searchResult `FacetCollection` and remove disallowed facets
   121  
   122  See the following example:
   123  
   124  ```pug
   125  
   126    - 
   127      var searchResult1 = findProducts("list1",
   128                                      {"query":"","pageSize": "10","sortDirection":"A","sortBy":'name'},
   129                                      {"brand":"Hello Kitty"},
   130                                      {"whiteList":"brand,color,sortBy"})
   131  
   132    ul
   133      each product in searchResult1.products
   134        li Title: #{product.baseData.title} Retailer: #{product.baseData.retailerCode} Brand: #{product.baseData.attributes["brandCode"].value}
   135        
   136      - 
   137        var searchResult2 = findProducts("list2",
   138                                        {"query":"","pageSize": "10","sortDirection":"A","sortBy":'name'},
   139                                        {"brand":"Hello Kitty"},
   140                                        {"whiteList":"brand,color"})
   141    
   142      ul
   143        each product in searchResult2.products
   144          li Title: #{product.baseData.title} Retailer: #{product.baseData.retailerCode} Brand: #{product.baseData.attributes["brandCode"].value}
   145  ```
   146  
   147  It will show in the list1 10 products that match the brand "Hello Kitty".
   148  If you call the page that contains the call to that template function with urlparameters, the response can be dynamically modified.
   149  For example:
   150  
   151  `URL/?list1.brand=Apple&list2.color=black`
   152  
   153  will modify the result of the two lists accordingly - while
   154  
   155  `URL/?list2.notallowedkey=black`
   156  
   157  will not.
   158  
   159  
   160  ## FakeService
   161  
   162  With enabled fake services `domain.ProductService` and `domain.SearchService` are responding with preconfigured fake products on invocation.   
   163  
   164  ````yaml
   165  commerce: 
   166  	product: 
   167  		fakeservice: 
   168  			enabled: true # boolean: enables fake services
   169  			currency: "EUR" # string: currency for the fake services
   170  			jsonTestDataFolder: "testdata/products"
   171  			jsonTestDataLiveSearch: "testdata/livesearch/livesearch.json"
   172              jsonTestDataCategoryFacetItems: "testdata/facets/categoryFacetItems.json"
   173              defaultProducts: true
   174  ````
   175  
   176  The configuration option `jsonTestDataFolder` tells fakeservices to look for json files with product data in the defined folder. 
   177  Json files represent MarketPlaceCodes with their filename and `domain.BasicProduct` within the contents.
   178  You can find an example product under: `test/integrationtest/projecttest/tests/graphql/testdata/products/json_simple.json`
   179  
   180  The configuration option `jsonTestDataLiveSearch` provides a possibility to fake live search results separately. When you leave it
   181  empty, livesearch will just be redirected to normal search (without promotions and suggestions). The contents of the json file is a map
   182  of `search query => fake results`. The fake results must match the `fake.liveSearchData` struct and all mentioned marketplace codes must be available in the `jsonTestDataFolder`.
   183  
   184  The configuration option `jsonTestDataCategoryFacetItems` provides a possibility to fake the contents of the category facet individually. When you leave it
   185  empty, the default category facet items will be used. These can be found in `product/infrastructure/fake/testdata/categoryFacetItems.json` 
   186  which can be used as a reference for building your own file.
   187  
   188  The configuration option `defaultProducts` toggles the delivery of default test products. Json files will be still delivered.
   189  
   190  ### SearchService
   191  The fake service returns specific products if the query matches their marketplace code. This corresponds to the file name of the products in your project. There are also available default products with the marketplace codes:
   192  - fake_configurable
   193  - fake_configurable_with_active_variant
   194  - fake_simple
   195  - fake_simple_with_fixed_price
   196  - fake_simple_out_of_stock
   197  - fake_fixed_simple_without_discounts
   198  
   199  If you query the fake service with `no-results` no products are returned.
   200  In case no product with the given query is found and `no-results` is not used all preconfigured fake products are returned.
   201  
   202  ## Dependencies:
   203  * search package: the product.SearchService uses the search Result and Filter objects.