flamingo.me/flamingo-commerce/v3@v3.11.0/checkout/module.go (about)

     1  package checkout
     2  
     3  import (
     4  	"flamingo.me/dingo"
     5  	"github.com/go-playground/form/v4"
     6  
     7  	"flamingo.me/flamingo/v3/core/healthcheck/domain/healthcheck"
     8  	"flamingo.me/flamingo/v3/framework/flamingo"
     9  	"flamingo.me/flamingo/v3/framework/web"
    10  	flamingographql "flamingo.me/graphql"
    11  
    12  	"flamingo.me/flamingo-commerce/v3/checkout/infrastructure/contextstore"
    13  	"flamingo.me/flamingo-commerce/v3/checkout/interfaces/graphql/dto"
    14  	"flamingo.me/flamingo-commerce/v3/payment"
    15  
    16  	"flamingo.me/flamingo-commerce/v3/cart"
    17  	"flamingo.me/flamingo-commerce/v3/checkout/application/placeorder"
    18  	"flamingo.me/flamingo-commerce/v3/checkout/domain/placeorder/process"
    19  	"flamingo.me/flamingo-commerce/v3/checkout/domain/placeorder/states"
    20  	"flamingo.me/flamingo-commerce/v3/checkout/infrastructure/locker"
    21  	"flamingo.me/flamingo-commerce/v3/checkout/interfaces/controller"
    22  	"flamingo.me/flamingo-commerce/v3/checkout/interfaces/graphql"
    23  )
    24  
    25  type (
    26  	// Module registers our checkout module
    27  	Module struct {
    28  		PlaceOrderLockType     string `inject:"config:commerce.checkout.placeorder.lock.type"`
    29  		PlaceOrderContextStore string `inject:"config:commerce.checkout.placeorder.contextstore.type"`
    30  	}
    31  )
    32  
    33  // Configure module
    34  func (m *Module) Configure(injector *dingo.Injector) {
    35  	injector.Bind((*form.Decoder)(nil)).ToProvider(form.NewDecoder).AsEagerSingleton()
    36  
    37  	if m.PlaceOrderLockType == "redis" {
    38  		injector.Bind(new(locker.Redis)).ToProvider(locker.NewRedis).In(dingo.Singleton)
    39  		injector.Bind(new(placeorder.TryLocker)).To(new(locker.Redis))
    40  		injector.BindMap(new(healthcheck.Status), "placeorder.locker.redis").To(new(locker.Redis))
    41  	} else {
    42  		injector.Bind(new(placeorder.TryLocker)).ToProvider(locker.NewMemory).In(dingo.Singleton)
    43  	}
    44  
    45  	if m.PlaceOrderContextStore == "redis" {
    46  		injector.Bind(new(contextstore.Redis)).In(dingo.Singleton)
    47  		injector.Bind(new(process.ContextStore)).To(new(contextstore.Redis))
    48  		injector.BindMap(new(healthcheck.Status), "placeorder.contextstore.redis").To(new(contextstore.Redis))
    49  	} else {
    50  		injector.Bind(new(process.ContextStore)).To(new(contextstore.Memory)).In(dingo.Singleton)
    51  	}
    52  
    53  	injector.Bind(new(process.PaymentValidatorFunc)).ToInstance(placeorder.PaymentValidator)
    54  
    55  	injector.Bind(new(process.State)).AnnotatedWith("startState").To(states.New{})
    56  	injector.Bind(new(process.State)).AnnotatedWith("failedState").To(states.Failed{})
    57  	injector.BindMap(new(process.State), new(states.New).Name()).To(states.New{})
    58  	injector.BindMap(new(process.State), new(states.PrepareCart).Name()).To(states.PrepareCart{})
    59  	injector.BindMap(new(process.State), new(states.ValidateCart).Name()).To(states.ValidateCart{})
    60  	injector.BindMap(new(process.State), new(states.ValidatePaymentSelection).Name()).To(states.ValidatePaymentSelection{})
    61  	injector.BindMap(new(process.State), new(states.CreatePayment).Name()).To(states.CreatePayment{})
    62  	injector.BindMap(new(process.State), new(states.CompleteCart).Name()).To(states.CompleteCart{})
    63  	injector.BindMap(new(process.State), new(states.CompletePayment).Name()).To(states.CompletePayment{})
    64  	injector.BindMap(new(process.State), new(states.PlaceOrder).Name()).To(states.PlaceOrder{})
    65  	injector.BindMap(new(process.State), new(states.ValidatePayment).Name()).To(states.ValidatePayment{})
    66  	injector.BindMap(new(process.State), new(states.WaitForCustomer).Name()).To(states.WaitForCustomer{})
    67  	injector.BindMap(new(process.State), new(states.Success).Name()).To(states.Success{})
    68  	injector.BindMap(new(process.State), new(states.Failed).Name()).To(states.Failed{})
    69  	injector.BindMap(new(process.State), new(states.ShowIframe).Name()).To(states.ShowIframe{})
    70  	injector.BindMap(new(process.State), new(states.ShowHTML).Name()).To(states.ShowHTML{})
    71  	injector.BindMap(new(process.State), new(states.ShowWalletPayment).Name()).To(states.ShowWalletPayment{})
    72  	injector.BindMap(new(process.State), new(states.Redirect).Name()).To(states.Redirect{})
    73  	injector.BindMap(new(process.State), new(states.PostRedirect).Name()).To(states.PostRedirect{})
    74  	injector.BindMap(new(process.State), new(states.TriggerClientSDK).Name()).To(states.TriggerClientSDK{})
    75  
    76  	// bind internal states to graphQL states
    77  	injector.BindMap(new(dto.State), new(states.New).Name()).To(dto.Wait{})
    78  	injector.BindMap(new(dto.State), new(states.PrepareCart).Name()).To(dto.Wait{})
    79  	injector.BindMap(new(dto.State), new(states.ValidateCart).Name()).To(dto.Wait{})
    80  	injector.BindMap(new(dto.State), new(states.ValidatePaymentSelection).Name()).To(dto.Wait{})
    81  	injector.BindMap(new(dto.State), new(states.CreatePayment).Name()).To(dto.Wait{})
    82  	injector.BindMap(new(dto.State), new(states.CompleteCart).Name()).To(dto.Wait{})
    83  	injector.BindMap(new(dto.State), new(states.CompletePayment).Name()).To(dto.Wait{})
    84  	injector.BindMap(new(dto.State), new(states.PlaceOrder).Name()).To(dto.Wait{})
    85  	injector.BindMap(new(dto.State), new(states.ValidatePayment).Name()).To(dto.Wait{})
    86  	injector.BindMap(new(dto.State), new(states.WaitForCustomer).Name()).To(dto.WaitForCustomer{})
    87  	injector.BindMap(new(dto.State), new(states.Success).Name()).To(dto.Success{})
    88  	injector.BindMap(new(dto.State), new(states.Failed).Name()).To(dto.Failed{})
    89  	injector.BindMap(new(dto.State), new(states.ShowHTML).Name()).To(dto.ShowHTML{})
    90  	injector.BindMap(new(dto.State), new(states.ShowWalletPayment).Name()).To(dto.ShowWalletPayment{})
    91  	injector.BindMap(new(dto.State), new(states.ShowIframe).Name()).To(dto.ShowIframe{})
    92  	injector.BindMap(new(dto.State), new(states.Redirect).Name()).To(dto.Redirect{})
    93  	injector.BindMap(new(dto.State), new(states.PostRedirect).Name()).To(dto.PostRedirect{})
    94  	injector.BindMap(new(dto.State), new(states.TriggerClientSDK).Name()).To(dto.TriggerClientSDK{})
    95  
    96  	web.BindRoutes(injector, new(routes))
    97  	web.BindRoutes(injector, new(apiRoutes))
    98  
    99  	injector.BindMulti(new(flamingographql.Service)).To(graphql.Service{})
   100  }
   101  
   102  // CueConfig definition
   103  func (m *Module) CueConfig() string {
   104  	// language=cue
   105  	return `
   106  commerce: checkout: {
   107  	Redis :: {
   108  		maxIdle:                 number | *25
   109  		idleTimeoutMilliseconds: number | *240000
   110  		network:                 string | *"tcp"
   111  		address:                 string | *"localhost:6379"
   112  		database:                number | *0
   113  		ttl:                     string | *"2h"
   114  	}
   115  	useDeliveryForms:                 bool | *true
   116  	usePersonalDataForm:              bool | *false
   117  	skipReviewAction:                 bool | *false
   118  	skipStartAction?:                 bool 
   119  	showReviewStepAfterPaymentError?: bool
   120  	showEmptyCartPageIfNoItems?:      bool
   121  	redirectToCartOnInvalidCart?:     bool
   122  	privacyPolicyRequired?:           bool
   123  	placeorder: {
   124  		lock: {
   125  			type: *"memory" | "redis"
   126  			if type == "redis" {
   127  				redis: Redis
   128  			}
   129  		}
   130  		contextstore: {
   131  			type: *"memory" | "redis"
   132  			if type == "redis" {
   133  				redis: Redis
   134  			}
   135  		}
   136  		states: {
   137  			placeorder: {
   138  				cancelOrdersDuringRollback: bool | *false		
   139  			}
   140  		}
   141  	}
   142  }`
   143  }
   144  
   145  // FlamingoLegacyConfigAlias mapping
   146  func (m *Module) FlamingoLegacyConfigAlias() map[string]string {
   147  	return map[string]string{
   148  		"checkout.useDeliveryForms":                "commerce.checkout.useDeliveryForms",
   149  		"checkout.usePersonalDataForm":             "commerce.checkout.usePersonalDataForm",
   150  		"checkout.skipReviewAction":                "commerce.checkout.skipReviewAction",
   151  		"checkout.skipStartAction":                 "commerce.checkout.skipStartAction",
   152  		"checkout.showReviewStepAfterPaymentError": "commerce.checkout.showReviewStepAfterPaymentError",
   153  		"checkout.showEmptyCartPageIfNoItems":      "commerce.checkout.showEmptyCartPageIfNoItems",
   154  		"checkout.redirectToCartOnInvalideCart":    "commerce.checkout.redirectToCartOnInvalidCart",
   155  		"checkout.privacyPolicyRequired":           "commerce.checkout.privacyPolicyRequired",
   156  	}
   157  }
   158  
   159  type routes struct {
   160  	controller *controller.CheckoutController
   161  }
   162  
   163  // Inject required controller
   164  func (r *routes) Inject(controller *controller.CheckoutController) {
   165  	r.controller = controller
   166  }
   167  
   168  // Routes  configuration for checkout controllers
   169  func (r *routes) Routes(registry *web.RouterRegistry) {
   170  	// routes
   171  	registry.HandleAny("checkout.start", r.controller.StartAction)
   172  	registry.MustRoute("/checkout/start", "checkout.start")
   173  
   174  	registry.HandleAny("checkout.review", r.controller.ReviewAction)
   175  	registry.MustRoute("/checkout/review", `checkout.review`)
   176  
   177  	registry.HandleAny("checkout", r.controller.SubmitCheckoutAction)
   178  	registry.MustRoute("/checkout", "checkout")
   179  
   180  	registry.HandleAny("checkout.payment", r.controller.PaymentAction)
   181  	registry.MustRoute("/checkout/payment", "checkout.payment")
   182  
   183  	registry.HandleAny("checkout.success", r.controller.SuccessAction)
   184  	registry.MustRoute("/checkout/success", "checkout.success")
   185  
   186  	registry.HandleAny("checkout.expired", r.controller.ExpiredAction)
   187  	registry.MustRoute("/checkout/expired", "checkout.expired")
   188  
   189  	registry.HandleAny("checkout.placeorder", r.controller.PlaceOrderAction)
   190  	registry.MustRoute("/checkout/placeorder", "checkout.placeorder")
   191  }
   192  
   193  // Depends on other modules
   194  func (m *Module) Depends() []dingo.Module {
   195  	return []dingo.Module{
   196  		new(cart.Module),
   197  		new(payment.Module),
   198  		new(flamingo.SessionModule),
   199  	}
   200  }
   201  
   202  type apiRoutes struct {
   203  	apiController *controller.APIController
   204  }
   205  
   206  func (r *apiRoutes) Inject(apiController *controller.APIController) {
   207  	r.apiController = apiController
   208  }
   209  
   210  func (r *apiRoutes) Routes(registry *web.RouterRegistry) {
   211  	registry.MustRoute("/api/v1/checkout/placeorder", "checkout.api.placeorder")
   212  	registry.HandleGet("checkout.api.placeorder", r.apiController.CurrentPlaceOrderContextAction)
   213  	registry.HandlePut("checkout.api.placeorder", r.apiController.StartPlaceOrderAction)
   214  	registry.HandleDelete("checkout.api.placeorder", r.apiController.ClearPlaceOrderAction)
   215  
   216  	registry.MustRoute("/api/v1/checkout/placeorder/cancel", "checkout.api.placeorder.cancel")
   217  	registry.HandlePost("checkout.api.placeorder.cancel", r.apiController.CancelPlaceOrderAction)
   218  
   219  	registry.MustRoute("/api/v1/checkout/placeorder/refresh", "checkout.api.placeorder.refresh")
   220  	registry.HandlePost("checkout.api.placeorder.refresh", r.apiController.RefreshPlaceOrderAction)
   221  
   222  	registry.MustRoute("/api/v1/checkout/placeorder/refresh-blocking", "checkout.api.placeorder.refreshblocking")
   223  	registry.HandlePost("checkout.api.placeorder.refreshblocking", r.apiController.RefreshPlaceOrderBlockingAction)
   224  }