update
All checks were successful
Build and Publish / BuildAndDeployAmd64 (push) Successful in 44s
Build and Publish / BuildAndDeployArm64 (push) Successful in 4m57s

This commit is contained in:
2025-12-03 17:45:38 +01:00
parent ca7d23f122
commit ad24d503ba
3 changed files with 209 additions and 2 deletions

View File

@@ -52,6 +52,29 @@ func (s *CheckoutPoolServer) KlarnaHtmlCheckoutHandler(w http.ResponseWriter, r
} }
func (s *CheckoutPoolServer) KlarnaSessionHandler(w http.ResponseWriter, r *http.Request, checkoutId checkout.CheckoutId) error {
orderId := r.URL.Query().Get("order_id")
var order *CheckoutOrder
var err error
if orderId == "" {
order, err = s.CreateOrUpdateCheckout(r, checkoutId)
if err != nil {
logger.Error("unable to create klarna session", "error", err)
return err
}
// s.ApplyKlarnaPaymentStarted(r.Context(), order, checkoutId)
}
order, err = s.klarnaClient.GetOrder(r.Context(), orderId)
if err != nil {
return err
}
w.Header().Set("Content-Type", "application/json; charset=utf-8")
return json.NewEncoder(w).Encode(order)
}
func (s *CheckoutPoolServer) KlarnaConfirmationHandler(w http.ResponseWriter, r *http.Request) { func (s *CheckoutPoolServer) KlarnaConfirmationHandler(w http.ResponseWriter, r *http.Request) {
orderId := r.PathValue("order_id") orderId := r.PathValue("order_id")

View File

@@ -4,12 +4,14 @@ import (
"bytes" "bytes"
"context" "context"
"encoding/json" "encoding/json"
"fmt"
"log" "log"
"net/http" "net/http"
"os" "os"
"time" "time"
"git.k6n.net/go-cart-actor/pkg/actor" "git.k6n.net/go-cart-actor/pkg/actor"
"git.k6n.net/go-cart-actor/pkg/cart"
"git.k6n.net/go-cart-actor/pkg/checkout" "git.k6n.net/go-cart-actor/pkg/checkout"
messages "git.k6n.net/go-cart-actor/proto/checkout" messages "git.k6n.net/go-cart-actor/proto/checkout"
@@ -22,6 +24,7 @@ import (
"go.opentelemetry.io/contrib/bridges/otelslog" "go.opentelemetry.io/contrib/bridges/otelslog"
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
"google.golang.org/protobuf/proto" "google.golang.org/protobuf/proto"
"google.golang.org/protobuf/types/known/anypb"
"google.golang.org/protobuf/types/known/timestamppb" "google.golang.org/protobuf/types/known/timestamppb"
"go.opentelemetry.io/otel" "go.opentelemetry.io/otel"
@@ -75,6 +78,162 @@ func (s *CheckoutPoolServer) GetCheckoutHandler(w http.ResponseWriter, r *http.R
return s.WriteResult(w, grain) return s.WriteResult(w, grain)
} }
func (s *CheckoutPoolServer) SetDeliveryHandler(w http.ResponseWriter, r *http.Request, id checkout.CheckoutId) error {
var msg messages.SetDelivery
if err := json.NewDecoder(r.Body).Decode(&msg); err != nil {
return err
}
result, err := s.ApplyLocal(r.Context(), id, &msg)
if err != nil {
return err
}
return s.WriteResult(w, result.Result)
}
func (s *CheckoutPoolServer) RemoveDeliveryHandler(w http.ResponseWriter, r *http.Request, id checkout.CheckoutId) error {
var msg messages.RemoveDelivery
if err := json.NewDecoder(r.Body).Decode(&msg); err != nil {
return err
}
result, err := s.ApplyLocal(r.Context(), id, &msg)
if err != nil {
return err
}
return s.WriteResult(w, result.Result)
}
func (s *CheckoutPoolServer) SetPickupPointHandler(w http.ResponseWriter, r *http.Request, id checkout.CheckoutId) error {
var msg messages.SetPickupPoint
if err := json.NewDecoder(r.Body).Decode(&msg); err != nil {
return err
}
result, err := s.ApplyLocal(r.Context(), id, &msg)
if err != nil {
return err
}
return s.WriteResult(w, result.Result)
}
func (s *CheckoutPoolServer) InitializeCheckoutHandler(w http.ResponseWriter, r *http.Request, id checkout.CheckoutId) error {
var msg messages.InitializeCheckout
if err := json.NewDecoder(r.Body).Decode(&msg); err != nil {
return err
}
result, err := s.ApplyLocal(r.Context(), id, &msg)
if err != nil {
return err
}
return s.WriteResult(w, result.Result)
}
func (s *CheckoutPoolServer) InventoryReservedHandler(w http.ResponseWriter, r *http.Request, id checkout.CheckoutId) error {
var msg messages.InventoryReserved
if err := json.NewDecoder(r.Body).Decode(&msg); err != nil {
return err
}
result, err := s.ApplyLocal(r.Context(), id, &msg)
if err != nil {
return err
}
return s.WriteResult(w, result.Result)
}
func (s *CheckoutPoolServer) OrderCreatedHandler(w http.ResponseWriter, r *http.Request, id checkout.CheckoutId) error {
var msg messages.OrderCreated
if err := json.NewDecoder(r.Body).Decode(&msg); err != nil {
return err
}
result, err := s.ApplyLocal(r.Context(), id, &msg)
if err != nil {
return err
}
return s.WriteResult(w, result.Result)
}
func (s *CheckoutPoolServer) ConfirmationViewedHandler(w http.ResponseWriter, r *http.Request, id checkout.CheckoutId) error {
var msg messages.ConfirmationViewed
if err := json.NewDecoder(r.Body).Decode(&msg); err != nil {
return err
}
result, err := s.ApplyLocal(r.Context(), id, &msg)
if err != nil {
return err
}
return s.WriteResult(w, result.Result)
}
func (s *CheckoutPoolServer) StartCheckoutHandler(w http.ResponseWriter, r *http.Request) {
cartIdStr := r.PathValue("cartid")
if cartIdStr == "" {
http.Error(w, "cart id required", http.StatusBadRequest)
return
}
cartId, ok := cart.ParseCartId(cartIdStr)
if !ok {
http.Error(w, "invalid cart id", http.StatusBadRequest)
return
}
// Fetch cart state from cart service
cartGrain, err := s.cartClient.getCartGrain(r.Context(), cartId)
if err != nil {
logger.Error("failed to fetch cart", "error", err, "cartId", cartId)
http.Error(w, "failed to fetch cart", http.StatusInternalServerError)
return
}
// Serialize cart state to Any
cartStateBytes, err := json.Marshal(cartGrain)
if err != nil {
logger.Error("failed to marshal cart state", "error", err)
http.Error(w, "failed to process cart state", http.StatusInternalServerError)
return
}
// Create checkout with same ID as cart
checkoutId := checkout.CheckoutId(cartId)
// Initialize checkout with cart state wrapped in Any
cartStateAny := &messages.InitializeCheckout{
OrderId: "",
CartId: uint64(cartId),
Version: uint32(cartGrain.Version),
CartState: &anypb.Any{
TypeUrl: "type.googleapis.com/cart.CartGrain",
Value: cartStateBytes,
},
}
result, err := s.ApplyLocal(r.Context(), checkoutId, cartStateAny)
if err != nil {
logger.Error("failed to initialize checkout", "error", err)
http.Error(w, "failed to initialize checkout", http.StatusInternalServerError)
return
}
// Set checkout cookie
w.Header().Set("Set-Cookie", fmt.Sprintf("checkout_id=%s; Path=/; HttpOnly; SameSite=Lax", checkoutId.String()))
if err := s.WriteResult(w, result.Result); err != nil {
logger.Error("failed to write result", "error", err)
}
}
func (s *CheckoutPoolServer) WriteResult(w http.ResponseWriter, result any) error { func (s *CheckoutPoolServer) WriteResult(w http.ResponseWriter, result any) error {
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
w.Header().Set("Cache-Control", "no-cache") w.Header().Set("Cache-Control", "no-cache")
@@ -223,8 +382,19 @@ func (s *CheckoutPoolServer) Serve(mux *http.ServeMux) {
orderHandler := NewAmqpOrderHandler(conn) orderHandler := NewAmqpOrderHandler(conn)
orderHandler.DefineQueue() orderHandler.DefineQueue()
handleFunc("GET /checkout", CheckoutIdHandler(s.ProxyHandler(s.KlarnaHtmlCheckoutHandler))) handleFunc("POST /api/checkout/start/{cartid}", s.StartCheckoutHandler)
handleFunc("GET /api/checkout", CheckoutIdHandler(s.ProxyHandler(s.GetCheckoutHandler)))
handleFunc("POST /api/checkout/delivery", CheckoutIdHandler(s.ProxyHandler(s.SetDeliveryHandler)))
handleFunc("DELETE /api/checkout/delivery", CheckoutIdHandler(s.ProxyHandler(s.RemoveDeliveryHandler)))
handleFunc("POST /api/checkout/pickup-point", CheckoutIdHandler(s.ProxyHandler(s.SetPickupPointHandler)))
handleFunc("POST /api/checkout/initialize", CheckoutIdHandler(s.ProxyHandler(s.InitializeCheckoutHandler)))
handleFunc("POST /api/checkout/inventory-reserved", CheckoutIdHandler(s.ProxyHandler(s.InventoryReservedHandler)))
handleFunc("POST /api/checkout/order-created", CheckoutIdHandler(s.ProxyHandler(s.OrderCreatedHandler)))
handleFunc("POST /api/checkout/confirmation-viewed", CheckoutIdHandler(s.ProxyHandler(s.ConfirmationViewedHandler)))
handleFunc("GET /confirmation/{order_id}", s.KlarnaConfirmationHandler) handleFunc("GET /payment/klarna/session", CheckoutIdHandler(s.ProxyHandler(s.KlarnaSessionHandler)))
handleFunc("GET /payment/klarna/checkout", CheckoutIdHandler(s.ProxyHandler(s.KlarnaHtmlCheckoutHandler)))
handleFunc("GET /payment/klarna/confirmation/{order_id}", s.KlarnaConfirmationHandler)
} }

View File

@@ -531,6 +531,20 @@ spec:
name: cart-actor name: cart-actor
port: port:
number: 8080 number: 8080
- path: /api/checkout
pathType: Prefix
backend:
service:
name: checkout-actor
port:
number: 8080
- path: /payment
pathType: Prefix
backend:
service:
name: checkout-actor
port:
number: 8080
--- ---
apiVersion: networking.k8s.io/v1 apiVersion: networking.k8s.io/v1
kind: Ingress kind: Ingress