flamingo.me/flamingo-commerce/v3@v3.11.0/order/domain/orderDecorator.go (about) 1 package domain 2 3 import ( 4 "context" 5 "sort" 6 7 "flamingo.me/flamingo-commerce/v3/product/domain" 8 "flamingo.me/flamingo/v3/framework/flamingo" 9 ) 10 11 type ( 12 // OrderDecoratorInterface defines the interface of the order decorator 13 OrderDecoratorInterface interface { 14 Create(context.Context, *Order) *DecoratedOrder 15 } 16 17 // OrderDecorator struct defines the order decorator 18 OrderDecorator struct { 19 ProductService domain.ProductService `inject:""` 20 Logger flamingo.Logger `inject:""` 21 } 22 23 // DecoratedOrder struct 24 DecoratedOrder struct { 25 Order *Order 26 DecoratedItems []*DecoratedOrderItem 27 } 28 29 // DecoratedOrderItem struct 30 DecoratedOrderItem struct { 31 Item *OrderItem 32 Product domain.BasicProduct 33 } 34 35 // GroupedDecoratedOrder struct 36 GroupedDecoratedOrder struct { 37 Order *DecoratedOrder 38 Groups []*GroupedDecoratedOrderItems 39 } 40 41 // GroupedDecoratedOrderItems struct 42 GroupedDecoratedOrderItems struct { 43 DecoratedItems []*DecoratedOrderItem 44 Group string 45 } 46 ) 47 48 // check interface implementation 49 var _ OrderDecoratorInterface = (*OrderDecorator)(nil) 50 51 // Create creates a new decorated order 52 func (rd *OrderDecorator) Create(ctx context.Context, order *Order) *DecoratedOrder { 53 result := &DecoratedOrder{Order: order} 54 result.DecoratedItems = rd.createDecoratedItems(ctx, order.OrderItems) 55 56 return result 57 } 58 59 func (rd *OrderDecorator) createDecoratedItems(ctx context.Context, items []*OrderItem) []*DecoratedOrderItem { 60 result := make([]*DecoratedOrderItem, len(items)) 61 for i, item := range items { 62 result[i] = rd.createDecoratedItem(ctx, item) 63 } 64 65 return result 66 } 67 68 func (rd *OrderDecorator) createDecoratedItem(ctx context.Context, item *OrderItem) *DecoratedOrderItem { 69 result := &DecoratedOrderItem{ 70 Item: item, 71 } 72 73 product, err := rd.ProductService.Get(ctx, item.MarketplaceCode) 74 switch { 75 case err != nil: 76 rd.Logger.WithContext(ctx).Error("order.decorator - no product for item", err) 77 // fallback to return something the frontend still could use 78 product = rd.createFallbackProduct(item) 79 case product.Type() == domain.TypeConfigurable && item.VariantMarketplaceCode != "": 80 configurable, ok := product.(domain.ConfigurableProduct) 81 if !ok { 82 // not a usable configrable 83 break 84 } 85 86 variant, err := configurable.GetConfigurableWithActiveVariant(item.VariantMarketplaceCode) 87 if err == nil { 88 product = variant 89 } else { 90 product = rd.createFallbackProduct(item) 91 } 92 } 93 result.Product = product 94 95 return result 96 } 97 98 func (rd *OrderDecorator) createFallbackProduct(item *OrderItem) *domain.SimpleProduct { 99 return &domain.SimpleProduct{ 100 BasicProductData: domain.BasicProductData{ 101 Title: item.Name, 102 }, 103 Saleable: domain.Saleable{ 104 IsSaleable: false, 105 }, 106 } 107 } 108 109 // IsConfigurable - checks if current order item is a configurable product 110 func (doi DecoratedOrderItem) IsConfigurable() bool { 111 return doi.Product.Type() == domain.TypeConfigurableWithActiveVariant 112 } 113 114 // GetVariant getter 115 func (doi DecoratedOrderItem) GetVariant() (*domain.Variant, error) { 116 return doi.Product.(domain.ConfigurableProductWithActiveVariant).Variant(doi.Item.VariantMarketplaceCode) 117 } 118 119 // GetDisplayTitle getter 120 func (doi DecoratedOrderItem) GetDisplayTitle() string { 121 if doi.IsConfigurable() { 122 variant, e := doi.GetVariant() 123 if e != nil { 124 return "Error Getting Variant" 125 } 126 return variant.Title 127 } 128 return doi.Product.BaseData().Title 129 } 130 131 // GetDisplayMarketplaceCode getter 132 func (doi DecoratedOrderItem) GetDisplayMarketplaceCode() string { 133 if doi.IsConfigurable() { 134 variant, e := doi.GetVariant() 135 if e != nil { 136 return "Error Getting Variant" 137 } 138 return variant.MarketPlaceCode 139 } 140 return doi.Product.BaseData().MarketPlaceCode 141 } 142 143 // GetVariantsVariationAttributes gets the decorated order item variant attributes 144 func (doi DecoratedOrderItem) GetVariantsVariationAttributes() domain.Attributes { 145 attributes := domain.Attributes{} 146 if doi.IsConfigurable() { 147 variant, _ := doi.GetVariant() 148 149 for _, attributeName := range doi.Product.(domain.ConfigurableProductWithActiveVariant).VariantVariationAttributes { 150 attributes[attributeName] = variant.BaseData().Attributes[attributeName] 151 } 152 } 153 return attributes 154 } 155 156 // GetVariantsVariationAttributeCodes gets the decorated order item variant variation attributes 157 func (doi DecoratedOrderItem) GetVariantsVariationAttributeCodes() []string { 158 if doi.Product.Type() == domain.TypeConfigurableWithActiveVariant { 159 return doi.Product.(domain.ConfigurableProductWithActiveVariant).VariantVariationAttributes 160 } 161 return nil 162 } 163 164 // GetGroupedBy groups the decorated order into a *GroupedDecoratedOrder 165 func (rd *DecoratedOrder) GetGroupedBy(group string, sortGroup bool) *GroupedDecoratedOrder { 166 result := &GroupedDecoratedOrder{ 167 Order: rd, 168 } 169 groupedItemsCollection := make(map[string]*GroupedDecoratedOrderItems) 170 var groupedItemKeys []string 171 172 var groupKey string 173 for _, item := range rd.DecoratedItems { 174 switch group { 175 case "retailer_code": 176 groupKey = item.Product.BaseData().RetailerCode 177 default: 178 groupKey = "default" 179 } 180 181 if _, ok := groupedItemsCollection[groupKey]; !ok { 182 groupedItemsCollection[groupKey] = &GroupedDecoratedOrderItems{ 183 Group: groupKey, 184 } 185 186 groupedItemKeys = append(groupedItemKeys, groupKey) 187 } 188 189 groupedItemsEntry := groupedItemsCollection[groupKey] 190 groupedItemsEntry.DecoratedItems = append(groupedItemsEntry.DecoratedItems, item) 191 } 192 193 if sortGroup { 194 sort.Strings(groupedItemKeys) 195 } 196 197 groups := make([]*GroupedDecoratedOrderItems, len(groupedItemKeys)) 198 for i, key := range groupedItemKeys { 199 groupedItemsEntry := groupedItemsCollection[key] 200 groups[i] = groupedItemsEntry 201 } 202 result.Groups = groups 203 204 return result 205 } 206 207 // GetSourceIds collects the source ids of the items of the group 208 func (i *GroupedDecoratedOrderItems) GetSourceIds() []string { 209 // the group has at least one group in there 210 sourceIds := make(map[string]bool, 1) 211 result := make([]string, 1) 212 for _, item := range i.DecoratedItems { 213 sourceID := item.Item.SourceID 214 if _, ok := sourceIds[sourceID]; ok { 215 continue 216 } 217 218 sourceIds[sourceID] = true 219 result = append(result, sourceID) 220 } 221 222 return result 223 }