add cancel
Some checks failed
Build and Publish / BuildAndDeployAmd64 (push) Successful in 45s
Build and Publish / BuildAndDeployArm64 (push) Has been cancelled

This commit is contained in:
matst80
2025-12-05 08:30:59 +01:00
parent b4ffb9da85
commit ea3eb2f0f3
7 changed files with 172 additions and 52 deletions

View File

@@ -195,6 +195,19 @@ func (s *CheckoutPoolServer) ContactDetailsUpdatedHandler(w http.ResponseWriter,
return s.WriteResult(w, result) return s.WriteResult(w, result)
} }
func (s *CheckoutPoolServer) CancelPaymentHandler(w http.ResponseWriter, r *http.Request, checkoutId checkout.CheckoutId) error {
paymentId := r.PathValue("id")
result, err := s.ApplyLocal(r.Context(), checkoutId, &messages.CancelPayment{
PaymentId: paymentId,
CancelledAt: timestamppb.New(time.Now()),
})
if err != nil {
return err
}
return s.WriteResult(w, result)
}
func (s *CheckoutPoolServer) StartCheckoutHandler(w http.ResponseWriter, r *http.Request) { func (s *CheckoutPoolServer) StartCheckoutHandler(w http.ResponseWriter, r *http.Request) {
cartIdStr := r.PathValue("cartid") cartIdStr := r.PathValue("cartid")
if cartIdStr == "" { if cartIdStr == "" {
@@ -530,6 +543,7 @@ func (s *CheckoutPoolServer) Serve(mux *http.ServeMux) {
handleFunc("POST /api/checkout/contact-details", CookieCheckoutIdHandler(s.ProxyHandler(s.ContactDetailsUpdatedHandler))) handleFunc("POST /api/checkout/contact-details", CookieCheckoutIdHandler(s.ProxyHandler(s.ContactDetailsUpdatedHandler)))
handleFunc("POST /payment", CookieCheckoutIdHandler(s.ProxyHandler(s.StartPaymentHandler))) handleFunc("POST /payment", CookieCheckoutIdHandler(s.ProxyHandler(s.StartPaymentHandler)))
handleFunc("POST /payment/{id}/session", CookieCheckoutIdHandler(s.ProxyHandler(s.GetPaymentSessionHandler))) handleFunc("POST /payment/{id}/session", CookieCheckoutIdHandler(s.ProxyHandler(s.GetPaymentSessionHandler)))
handleFunc("DELETE /payment/{id}", CookieCheckoutIdHandler(s.ProxyHandler(s.CancelPaymentHandler)))
// handleFunc("POST /api/checkout/initialize", CookieCheckoutIdHandler(s.ProxyHandler(s.InitializeCheckoutHandler))) // handleFunc("POST /api/checkout/initialize", CookieCheckoutIdHandler(s.ProxyHandler(s.InitializeCheckoutHandler)))
// handleFunc("POST /api/checkout/inventory-reserved", CookieCheckoutIdHandler(s.ProxyHandler(s.InventoryReservedHandler))) // handleFunc("POST /api/checkout/inventory-reserved", CookieCheckoutIdHandler(s.ProxyHandler(s.InventoryReservedHandler)))
// handleFunc("POST /api/checkout/order-created", CookieCheckoutIdHandler(s.ProxyHandler(s.OrderCreatedHandler))) // handleFunc("POST /api/checkout/order-created", CookieCheckoutIdHandler(s.ProxyHandler(s.OrderCreatedHandler)))

View File

@@ -27,6 +27,7 @@ func NewCheckoutMutationRegistry(ctx *CheckoutMutationContext) actor.MutationReg
actor.NewMutation(HandleSetPickupPoint), actor.NewMutation(HandleSetPickupPoint),
actor.NewMutation(HandleRemoveDelivery), actor.NewMutation(HandleRemoveDelivery),
actor.NewMutation(HandleContactDetailsUpdated), actor.NewMutation(HandleContactDetailsUpdated),
actor.NewMutation(HandlePaymentCancelled),
) )
return reg return reg
} }

View File

@@ -0,0 +1,30 @@
package checkout
import (
"errors"
"slices"
messages "git.k6n.net/go-cart-actor/proto/checkout"
)
func HandlePaymentCancelled(g *CheckoutGrain, m *messages.PaymentDeclined) error {
payment, found := g.FindPayment(m.PaymentId)
if !found {
return ErrPaymentNotFound
}
if payment.CompletedAt != nil {
return errors.New("payment already completed")
}
g.PaymentInProgress--
g.AmountInCentsStarted -= payment.Amount
g.Payments = removePayment(g.Payments, payment.PaymentId)
return nil
}
func removePayment(payment []*Payment, s string) []*Payment {
return slices.DeleteFunc(payment, func(p *Payment) bool {
return p.PaymentId == s
})
}

View File

@@ -11,13 +11,21 @@ func asPickupPoint(p *messages.PickupPoint, deliveryId uint32) *PickupPoint {
if p == nil { if p == nil {
return nil return nil
} }
if p.Address == nil {
return &PickupPoint{
Id: p.Id,
Name: p.Name,
DeliveryId: deliveryId,
}
}
return &PickupPoint{ return &PickupPoint{
Id: p.Id, DeliveryId: deliveryId,
Name: p.Name, Id: p.Id,
Address: p.Address, Name: p.Name,
City: p.City, Address: &p.Address.AddressLine1,
Country: p.Country, City: &p.Address.City,
Zip: p.Zip, Zip: &p.Address.Zip,
Country: &p.Address.Country,
} }
} }

View File

@@ -36,14 +36,7 @@ func HandleSetPickupPoint(g *CheckoutGrain, m *messages.SetPickupPoint) error {
for _, d := range g.Deliveries { for _, d := range g.Deliveries {
if d.Id == uint32(m.DeliveryId) { if d.Id == uint32(m.DeliveryId) {
d.PickupPoint = &PickupPoint{ d.PickupPoint = asPickupPoint(m.PickupPoint, d.Id)
Id: m.PickupPoint.Id,
Name: m.PickupPoint.Name,
Address: m.PickupPoint.Address,
City: m.PickupPoint.City,
Zip: m.PickupPoint.Zip,
Country: m.PickupPoint.Country,
}
return nil return nil
} }
} }

View File

@@ -95,6 +95,12 @@ message ContactDetailsUpdated {
optional string name = 3; optional string name = 3;
} }
message CancelPayment {
string paymentId = 1;
optional string reason = 2;
google.protobuf.Timestamp cancelledAt = 3;
}
message InventoryReserved { message InventoryReserved {
string id = 1; string id = 1;
string status = 2; string status = 2;

View File

@@ -915,6 +915,66 @@ func (x *ContactDetailsUpdated) GetName() string {
return "" return ""
} }
type CancelPayment struct {
state protoimpl.MessageState `protogen:"open.v1"`
PaymentId string `protobuf:"bytes,1,opt,name=paymentId,proto3" json:"paymentId,omitempty"`
Reason *string `protobuf:"bytes,2,opt,name=reason,proto3,oneof" json:"reason,omitempty"`
CancelledAt *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=cancelledAt,proto3" json:"cancelledAt,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *CancelPayment) Reset() {
*x = CancelPayment{}
mi := &file_checkout_proto_msgTypes[13]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *CancelPayment) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CancelPayment) ProtoMessage() {}
func (x *CancelPayment) ProtoReflect() protoreflect.Message {
mi := &file_checkout_proto_msgTypes[13]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use CancelPayment.ProtoReflect.Descriptor instead.
func (*CancelPayment) Descriptor() ([]byte, []int) {
return file_checkout_proto_rawDescGZIP(), []int{13}
}
func (x *CancelPayment) GetPaymentId() string {
if x != nil {
return x.PaymentId
}
return ""
}
func (x *CancelPayment) GetReason() string {
if x != nil && x.Reason != nil {
return *x.Reason
}
return ""
}
func (x *CancelPayment) GetCancelledAt() *timestamppb.Timestamp {
if x != nil {
return x.CancelledAt
}
return nil
}
type InventoryReserved struct { type InventoryReserved struct {
state protoimpl.MessageState `protogen:"open.v1"` state protoimpl.MessageState `protogen:"open.v1"`
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
@@ -926,7 +986,7 @@ type InventoryReserved struct {
func (x *InventoryReserved) Reset() { func (x *InventoryReserved) Reset() {
*x = InventoryReserved{} *x = InventoryReserved{}
mi := &file_checkout_proto_msgTypes[13] mi := &file_checkout_proto_msgTypes[14]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@@ -938,7 +998,7 @@ func (x *InventoryReserved) String() string {
func (*InventoryReserved) ProtoMessage() {} func (*InventoryReserved) ProtoMessage() {}
func (x *InventoryReserved) ProtoReflect() protoreflect.Message { func (x *InventoryReserved) ProtoReflect() protoreflect.Message {
mi := &file_checkout_proto_msgTypes[13] mi := &file_checkout_proto_msgTypes[14]
if x != nil { if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@@ -951,7 +1011,7 @@ func (x *InventoryReserved) ProtoReflect() protoreflect.Message {
// Deprecated: Use InventoryReserved.ProtoReflect.Descriptor instead. // Deprecated: Use InventoryReserved.ProtoReflect.Descriptor instead.
func (*InventoryReserved) Descriptor() ([]byte, []int) { func (*InventoryReserved) Descriptor() ([]byte, []int) {
return file_checkout_proto_rawDescGZIP(), []int{13} return file_checkout_proto_rawDescGZIP(), []int{14}
} }
func (x *InventoryReserved) GetId() string { func (x *InventoryReserved) GetId() string {
@@ -998,7 +1058,7 @@ type Mutation struct {
func (x *Mutation) Reset() { func (x *Mutation) Reset() {
*x = Mutation{} *x = Mutation{}
mi := &file_checkout_proto_msgTypes[14] mi := &file_checkout_proto_msgTypes[15]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@@ -1010,7 +1070,7 @@ func (x *Mutation) String() string {
func (*Mutation) ProtoMessage() {} func (*Mutation) ProtoMessage() {}
func (x *Mutation) ProtoReflect() protoreflect.Message { func (x *Mutation) ProtoReflect() protoreflect.Message {
mi := &file_checkout_proto_msgTypes[14] mi := &file_checkout_proto_msgTypes[15]
if x != nil { if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@@ -1023,7 +1083,7 @@ func (x *Mutation) ProtoReflect() protoreflect.Message {
// Deprecated: Use Mutation.ProtoReflect.Descriptor instead. // Deprecated: Use Mutation.ProtoReflect.Descriptor instead.
func (*Mutation) Descriptor() ([]byte, []int) { func (*Mutation) Descriptor() ([]byte, []int) {
return file_checkout_proto_rawDescGZIP(), []int{14} return file_checkout_proto_rawDescGZIP(), []int{15}
} }
func (x *Mutation) GetType() isMutation_Type { func (x *Mutation) GetType() isMutation_Type {
@@ -1311,7 +1371,12 @@ const file_checkout_proto_rawDesc = "" +
"\x06_emailB\r\n" + "\x06_emailB\r\n" +
"\v_postalCodeB\b\n" + "\v_postalCodeB\b\n" +
"\x06_phoneB\a\n" + "\x06_phoneB\a\n" +
"\x05_name\"f\n" + "\x05_name\"\x93\x01\n" +
"\rCancelPayment\x12\x1c\n" +
"\tpaymentId\x18\x01 \x01(\tR\tpaymentId\x12\x1b\n" +
"\x06reason\x18\x02 \x01(\tH\x00R\x06reason\x88\x01\x01\x12<\n" +
"\vcancelledAt\x18\x03 \x01(\v2\x1a.google.protobuf.TimestampR\vcancelledAtB\t\n" +
"\a_reason\"f\n" +
"\x11InventoryReserved\x12\x0e\n" + "\x11InventoryReserved\x12\x0e\n" +
"\x02id\x18\x01 \x01(\tR\x02id\x12\x16\n" + "\x02id\x18\x01 \x01(\tR\x02id\x12\x16\n" +
"\x06status\x18\x02 \x01(\tR\x06status\x12\x1d\n" + "\x06status\x18\x02 \x01(\tR\x06status\x12\x1d\n" +
@@ -1346,7 +1411,7 @@ func file_checkout_proto_rawDescGZIP() []byte {
return file_checkout_proto_rawDescData return file_checkout_proto_rawDescData
} }
var file_checkout_proto_msgTypes = make([]protoimpl.MessageInfo, 15) var file_checkout_proto_msgTypes = make([]protoimpl.MessageInfo, 16)
var file_checkout_proto_goTypes = []any{ var file_checkout_proto_goTypes = []any{
(*SetDelivery)(nil), // 0: checkout_messages.SetDelivery (*SetDelivery)(nil), // 0: checkout_messages.SetDelivery
(*Address)(nil), // 1: checkout_messages.Address (*Address)(nil), // 1: checkout_messages.Address
@@ -1361,40 +1426,42 @@ var file_checkout_proto_goTypes = []any{
(*OrderCreated)(nil), // 10: checkout_messages.OrderCreated (*OrderCreated)(nil), // 10: checkout_messages.OrderCreated
(*InitializeCheckout)(nil), // 11: checkout_messages.InitializeCheckout (*InitializeCheckout)(nil), // 11: checkout_messages.InitializeCheckout
(*ContactDetailsUpdated)(nil), // 12: checkout_messages.ContactDetailsUpdated (*ContactDetailsUpdated)(nil), // 12: checkout_messages.ContactDetailsUpdated
(*InventoryReserved)(nil), // 13: checkout_messages.InventoryReserved (*CancelPayment)(nil), // 13: checkout_messages.CancelPayment
(*Mutation)(nil), // 14: checkout_messages.Mutation (*InventoryReserved)(nil), // 14: checkout_messages.InventoryReserved
(*timestamppb.Timestamp)(nil), // 15: google.protobuf.Timestamp (*Mutation)(nil), // 15: checkout_messages.Mutation
(*anypb.Any)(nil), // 16: google.protobuf.Any (*timestamppb.Timestamp)(nil), // 16: google.protobuf.Timestamp
(*anypb.Any)(nil), // 17: google.protobuf.Any
} }
var file_checkout_proto_depIdxs = []int32{ var file_checkout_proto_depIdxs = []int32{
3, // 0: checkout_messages.SetDelivery.pickupPoint:type_name -> checkout_messages.PickupPoint 3, // 0: checkout_messages.SetDelivery.pickupPoint:type_name -> checkout_messages.PickupPoint
3, // 1: checkout_messages.SetPickupPoint.pickupPoint:type_name -> checkout_messages.PickupPoint 3, // 1: checkout_messages.SetPickupPoint.pickupPoint:type_name -> checkout_messages.PickupPoint
1, // 2: checkout_messages.PickupPoint.address:type_name -> checkout_messages.Address 1, // 2: checkout_messages.PickupPoint.address:type_name -> checkout_messages.Address
1, // 3: checkout_messages.PaymentStarted.billingAddress:type_name -> checkout_messages.Address 1, // 3: checkout_messages.PaymentStarted.billingAddress:type_name -> checkout_messages.Address
15, // 4: checkout_messages.PaymentStarted.startedAt:type_name -> google.protobuf.Timestamp 16, // 4: checkout_messages.PaymentStarted.startedAt:type_name -> google.protobuf.Timestamp
16, // 5: checkout_messages.PaymentStarted.sessionData:type_name -> google.protobuf.Any 17, // 5: checkout_messages.PaymentStarted.sessionData:type_name -> google.protobuf.Any
15, // 6: checkout_messages.PaymentCompleted.completedAt:type_name -> google.protobuf.Timestamp 16, // 6: checkout_messages.PaymentCompleted.completedAt:type_name -> google.protobuf.Timestamp
16, // 7: checkout_messages.PaymentEvent.data:type_name -> google.protobuf.Any 17, // 7: checkout_messages.PaymentEvent.data:type_name -> google.protobuf.Any
15, // 8: checkout_messages.ConfirmationViewed.viewedAt:type_name -> google.protobuf.Timestamp 16, // 8: checkout_messages.ConfirmationViewed.viewedAt:type_name -> google.protobuf.Timestamp
15, // 9: checkout_messages.OrderCreated.createdAt:type_name -> google.protobuf.Timestamp 16, // 9: checkout_messages.OrderCreated.createdAt:type_name -> google.protobuf.Timestamp
16, // 10: checkout_messages.InitializeCheckout.cartState:type_name -> google.protobuf.Any 17, // 10: checkout_messages.InitializeCheckout.cartState:type_name -> google.protobuf.Any
0, // 11: checkout_messages.Mutation.set_delivery:type_name -> checkout_messages.SetDelivery 16, // 11: checkout_messages.CancelPayment.cancelledAt:type_name -> google.protobuf.Timestamp
2, // 12: checkout_messages.Mutation.set_pickup_point:type_name -> checkout_messages.SetPickupPoint 0, // 12: checkout_messages.Mutation.set_delivery:type_name -> checkout_messages.SetDelivery
4, // 13: checkout_messages.Mutation.remove_delivery:type_name -> checkout_messages.RemoveDelivery 2, // 13: checkout_messages.Mutation.set_pickup_point:type_name -> checkout_messages.SetPickupPoint
7, // 14: checkout_messages.Mutation.payment_declined:type_name -> checkout_messages.PaymentDeclined 4, // 14: checkout_messages.Mutation.remove_delivery:type_name -> checkout_messages.RemoveDelivery
9, // 15: checkout_messages.Mutation.confirmation_viewed:type_name -> checkout_messages.ConfirmationViewed 7, // 15: checkout_messages.Mutation.payment_declined:type_name -> checkout_messages.PaymentDeclined
12, // 16: checkout_messages.Mutation.contact_details_updated:type_name -> checkout_messages.ContactDetailsUpdated 9, // 16: checkout_messages.Mutation.confirmation_viewed:type_name -> checkout_messages.ConfirmationViewed
10, // 17: checkout_messages.Mutation.order_created:type_name -> checkout_messages.OrderCreated 12, // 17: checkout_messages.Mutation.contact_details_updated:type_name -> checkout_messages.ContactDetailsUpdated
11, // 18: checkout_messages.Mutation.initialize_checkout:type_name -> checkout_messages.InitializeCheckout 10, // 18: checkout_messages.Mutation.order_created:type_name -> checkout_messages.OrderCreated
13, // 19: checkout_messages.Mutation.inventory_reserved:type_name -> checkout_messages.InventoryReserved 11, // 19: checkout_messages.Mutation.initialize_checkout:type_name -> checkout_messages.InitializeCheckout
5, // 20: checkout_messages.Mutation.payment_started:type_name -> checkout_messages.PaymentStarted 14, // 20: checkout_messages.Mutation.inventory_reserved:type_name -> checkout_messages.InventoryReserved
6, // 21: checkout_messages.Mutation.payment_completed:type_name -> checkout_messages.PaymentCompleted 5, // 21: checkout_messages.Mutation.payment_started:type_name -> checkout_messages.PaymentStarted
8, // 22: checkout_messages.Mutation.payment_event:type_name -> checkout_messages.PaymentEvent 6, // 22: checkout_messages.Mutation.payment_completed:type_name -> checkout_messages.PaymentCompleted
23, // [23:23] is the sub-list for method output_type 8, // 23: checkout_messages.Mutation.payment_event:type_name -> checkout_messages.PaymentEvent
23, // [23:23] is the sub-list for method input_type 24, // [24:24] is the sub-list for method output_type
23, // [23:23] is the sub-list for extension type_name 24, // [24:24] is the sub-list for method input_type
23, // [23:23] is the sub-list for extension extendee 24, // [24:24] is the sub-list for extension type_name
0, // [0:23] is the sub-list for field type_name 24, // [24:24] is the sub-list for extension extendee
0, // [0:24] is the sub-list for field type_name
} }
func init() { file_checkout_proto_init() } func init() { file_checkout_proto_init() }
@@ -1410,7 +1477,8 @@ func file_checkout_proto_init() {
file_checkout_proto_msgTypes[7].OneofWrappers = []any{} file_checkout_proto_msgTypes[7].OneofWrappers = []any{}
file_checkout_proto_msgTypes[12].OneofWrappers = []any{} file_checkout_proto_msgTypes[12].OneofWrappers = []any{}
file_checkout_proto_msgTypes[13].OneofWrappers = []any{} file_checkout_proto_msgTypes[13].OneofWrappers = []any{}
file_checkout_proto_msgTypes[14].OneofWrappers = []any{ file_checkout_proto_msgTypes[14].OneofWrappers = []any{}
file_checkout_proto_msgTypes[15].OneofWrappers = []any{
(*Mutation_SetDelivery)(nil), (*Mutation_SetDelivery)(nil),
(*Mutation_SetPickupPoint)(nil), (*Mutation_SetPickupPoint)(nil),
(*Mutation_RemoveDelivery)(nil), (*Mutation_RemoveDelivery)(nil),
@@ -1430,7 +1498,7 @@ func file_checkout_proto_init() {
GoPackagePath: reflect.TypeOf(x{}).PkgPath(), GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_checkout_proto_rawDesc), len(file_checkout_proto_rawDesc)), RawDescriptor: unsafe.Slice(unsafe.StringData(file_checkout_proto_rawDesc), len(file_checkout_proto_rawDesc)),
NumEnums: 0, NumEnums: 0,
NumMessages: 15, NumMessages: 16,
NumExtensions: 0, NumExtensions: 0,
NumServices: 0, NumServices: 0,
}, },