Skip to content

Commit

Permalink
Rework checkout: Use new cart forms in a checkout composite form / Us…
Browse files Browse the repository at this point in the history
…e new Payment Gateway
  • Loading branch information
danielpoe authored and bastianccm committed Apr 2, 2019
1 parent 9d69445 commit c933e1a
Show file tree
Hide file tree
Showing 9 changed files with 457 additions and 272 deletions.
4 changes: 2 additions & 2 deletions Makefile
@@ -1,6 +1,6 @@
CONTEXT?=dev
REPLACE?=-replace flamingo.me/flamingo/v3=../flamingo
DROPREPLACE?=-dropreplace flamingo.me/flamingo/v3
REPLACE?=-replace flamingo.me/flamingo/v3=../flamingo -replace flamingo.me/form=../form
DROPREPLACE?=-dropreplace flamingo.me/flamingo/v3 -dropreplace flamingo.me/form

.PHONY: local unlocal

Expand Down
42 changes: 23 additions & 19 deletions checkout/Readme.md
Expand Up @@ -9,15 +9,29 @@ This package provides a One Page standard checkout with the following features:

This module implements controller and services for the following checkout flow (the checkout process for the end customer):

1. check if user is logged in
* yes: next action
* no: show start template (where the user can login)
2. Show checkout for user or for guest
* this is the main step, and the template should render the big checkout form (or at least the parts that are interesting)
* on submit and if everything was valid and update of the cart was sucessfull - the next action is called
3. Show Review Page
4. Check and Process Payment: If the payment requires a redirect to an external PSP (hosted payment page) the redirect is done and the results are proccessed.
5. Submit Order and show success page
1. StartAction (optional)
* check if user is logged in
* yes: next action
* no: show start template (where the user can login)
2. Checkout Action
* this is the main step, and the template should render the big checkout form (or at least the parts that are interesting).
* on submit and if everything was valid:
* Action will update the cart - specifically the following informations:
* Update billing (on cart level)
* Update deliveryinfos on (each) delivery in the cart (e.g. used to set shipping address)
* Select Payment Gateway and prefered Payment Method
* Optional Save the wished payment split for each item in the cart
* Optional add Vouchers (may already happend before)
* Forward to next Action
3. Review Action (Optional)
* Renderes "review" template that can be used to review the cart
* After confirming:
* Action will give control to the selected PaymentFlow (see payment module)
4. Place Order Action
* Get PaymentFlow Result
* Place Order and forward to success
5. Success Action:
* Renders order success template

## Configurations

Expand Down Expand Up @@ -52,13 +66,3 @@ checkout:
billingAddress_city: NoCity
billingAddress_postCode: "99999"
```

## Registering own Payment Providers

You need to implement the secondary port "PaymentProvider" and register the Payment provider in your module.go:

```go
func (pp *PaymarkProvider) Configure(injector *dingo.Injector) {
injector.BindMap((*payment.PaymentProvider)(nil), pp.ProviderCode).To(infrastructure.PaymarkAdapter{})
}
```
34 changes: 18 additions & 16 deletions checkout/application/orderService.go
Expand Up @@ -8,32 +8,38 @@ import (
"flamingo.me/flamingo-commerce/v3/cart/domain/cart"
"flamingo.me/flamingo-commerce/v3/checkout/domain"
"flamingo.me/flamingo/v3/framework/flamingo"
"flamingo.me/flamingo/v3/framework/opencensus"
"flamingo.me/flamingo/v3/framework/web"
"go.opencensus.io/stats"
"go.opencensus.io/stats/view"
)

type (
// OrderService defines the order service
OrderService struct {
sourcingEngine *domain.SourcingEngine
paymentService *PaymentService
logger flamingo.Logger
cartService *application.CartService
cartReceiverService *application.CartReceiverService
deliveryInfoBuilder cart.DeliveryInfoBuilder
}
)

var orderFailedStat = stats.Int64("flamingo-commerce/orderfailed", "my stat records 1 occurences per error", stats.UnitDimensionless)

func init() {
opencensus.View("flamingo-commerce/orderfailed/count", orderFailedStat, view.Count())
}

// Inject dependencies
func (os *OrderService) Inject(
SourcingEngine *domain.SourcingEngine,
PaymentService *PaymentService,
Logger flamingo.Logger,
CartService *application.CartService,
CartReceiverService *application.CartReceiverService,
DeliveryInfoBuilder cart.DeliveryInfoBuilder,
) {
os.sourcingEngine = SourcingEngine
os.paymentService = PaymentService
os.logger = Logger
os.cartService = CartService
os.cartReceiverService = CartReceiverService
Expand All @@ -55,16 +61,6 @@ func (os *OrderService) SetSources(ctx context.Context, session *web.Session) er
return nil
}

// PlaceOrder places the order
func (os *OrderService) PlaceOrder(ctx context.Context, session *web.Session, decoratedCart *cart.DecoratedCart, payment *cart.Payment) (cart.PlacedOrderInfos, error) {
validationResult := os.cartService.ValidateCart(ctx, session, decoratedCart)
if !validationResult.IsValid() {
os.logger.Warn("Try to place an invalid cart")
return nil, errors.New("cart is invalid")
}
return os.cartService.PlaceOrder(ctx, session, payment)
}

// CurrentCartSaveInfos saves additional informations on current cart
func (os *OrderService) CurrentCartSaveInfos(ctx context.Context, session *web.Session, billingAddress *cart.Address, shippingAddress *cart.Address, purchaser *cart.Person, additionalData *cart.AdditionalData) error {
os.logger.Debug("CurrentCartSaveInfos call billingAddress:%v shippingAddress:%v payment:%v", billingAddress, shippingAddress)
Expand Down Expand Up @@ -119,24 +115,30 @@ func (os *OrderService) CurrentCartSaveInfos(ctx context.Context, session *web.S
return nil
}

//CurrentCartPlaceOrder - probably the best choice for a simple checkout
// Assumptions: Only one BuildDeliveryInfo is used on the cart!
//CurrentCartPlaceOrder - use to place the current cart
func (os *OrderService) CurrentCartPlaceOrder(ctx context.Context, session *web.Session, payment cart.Payment) (cart.PlacedOrderInfos, error) {
decoratedCart, err := os.cartReceiverService.ViewDecoratedCart(ctx, session)

if err != nil {
// record failcount metric
stats.Record(ctx, orderFailedStat.M(1))
os.logger.Error("OnStepCurrentCartPlaceOrder GetDecoratedCart Error %v", err)
return nil, err
}

validationResult := os.cartService.ValidateCart(ctx, session, decoratedCart)
if !validationResult.IsValid() {
// record failcount metric
stats.Record(ctx, orderFailedStat.M(1))
os.logger.Warn("Try to place an invalid cart")
return nil, errors.New("cart is invalid")
}

placedOrderInfos, err := os.PlaceOrder(ctx, session, decoratedCart, &payment)
placedOrderInfos, err := os.cartService.PlaceOrder(ctx, session, &payment)

if err != nil {
// record failcount metric
stats.Record(ctx, orderFailedStat.M(1))
os.logger.WithField("category", "checkout.orderService").Error("Error during place Order: %v", err)
return nil, errors.New("error while placing the order. please contact customer support")
}
Expand Down

0 comments on commit c933e1a

Please sign in to comment.