diff --git a/api/pb/v1/oracle.pb.go b/api/pb/v1/oracle.pb.go index e4cb1e4..a075586 100644 --- a/api/pb/v1/oracle.pb.go +++ b/api/pb/v1/oracle.pb.go @@ -3,7 +3,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.6 +// protoc-gen-go v1.36.9 // protoc (unknown) // source: pb/v1/oracle.proto @@ -748,6 +748,274 @@ func (x *GetClaimRequest) GetClaimId() string { return "" } +type UploadInvoiceRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + FileContent string `protobuf:"bytes,1,opt,name=file_content,json=fileContent,proto3" json:"file_content,omitempty"` + Location string `protobuf:"bytes,2,opt,name=location,proto3" json:"location,omitempty"` + BucketName string `protobuf:"bytes,3,opt,name=bucket_name,json=bucketName,proto3" json:"bucket_name,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *UploadInvoiceRequest) Reset() { + *x = UploadInvoiceRequest{} + mi := &file_pb_v1_oracle_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UploadInvoiceRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UploadInvoiceRequest) ProtoMessage() {} + +func (x *UploadInvoiceRequest) ProtoReflect() protoreflect.Message { + mi := &file_pb_v1_oracle_proto_msgTypes[7] + 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 UploadInvoiceRequest.ProtoReflect.Descriptor instead. +func (*UploadInvoiceRequest) Descriptor() ([]byte, []int) { + return file_pb_v1_oracle_proto_rawDescGZIP(), []int{7} +} + +func (x *UploadInvoiceRequest) GetFileContent() string { + if x != nil { + return x.FileContent + } + return "" +} + +func (x *UploadInvoiceRequest) GetLocation() string { + if x != nil { + return x.Location + } + return "" +} + +func (x *UploadInvoiceRequest) GetBucketName() string { + if x != nil { + return x.BucketName + } + return "" +} + +type UploadInvoiceResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + InvoiceId string `protobuf:"bytes,1,opt,name=invoice_id,json=invoiceId,proto3" json:"invoice_id,omitempty"` + State string `protobuf:"bytes,2,opt,name=state,proto3" json:"state,omitempty"` + // Types that are valid to be assigned to Result: + // + // *UploadInvoiceResponse_Exception + Result isUploadInvoiceResponse_Result `protobuf_oneof:"result"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *UploadInvoiceResponse) Reset() { + *x = UploadInvoiceResponse{} + mi := &file_pb_v1_oracle_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UploadInvoiceResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UploadInvoiceResponse) ProtoMessage() {} + +func (x *UploadInvoiceResponse) ProtoReflect() protoreflect.Message { + mi := &file_pb_v1_oracle_proto_msgTypes[8] + 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 UploadInvoiceResponse.ProtoReflect.Descriptor instead. +func (*UploadInvoiceResponse) Descriptor() ([]byte, []int) { + return file_pb_v1_oracle_proto_rawDescGZIP(), []int{8} +} + +func (x *UploadInvoiceResponse) GetInvoiceId() string { + if x != nil { + return x.InvoiceId + } + return "" +} + +func (x *UploadInvoiceResponse) GetState() string { + if x != nil { + return x.State + } + return "" +} + +func (x *UploadInvoiceResponse) GetResult() isUploadInvoiceResponse_Result { + if x != nil { + return x.Result + } + return nil +} + +func (x *UploadInvoiceResponse) GetException() *v1.Exception { + if x != nil { + if x, ok := x.Result.(*UploadInvoiceResponse_Exception); ok { + return x.Exception + } + } + return nil +} + +type isUploadInvoiceResponse_Result interface { + isUploadInvoiceResponse_Result() +} + +type UploadInvoiceResponse_Exception struct { + Exception *v1.Exception `protobuf:"bytes,3,opt,name=exception,proto3,oneof"` +} + +func (*UploadInvoiceResponse_Exception) isUploadInvoiceResponse_Result() {} + +type ProcessInvoiceRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + InvoiceId string `protobuf:"bytes,1,opt,name=invoice_id,json=invoiceId,proto3" json:"invoice_id,omitempty"` // The invoice ID created by UploadInvoice + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ProcessInvoiceRequest) Reset() { + *x = ProcessInvoiceRequest{} + mi := &file_pb_v1_oracle_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ProcessInvoiceRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ProcessInvoiceRequest) ProtoMessage() {} + +func (x *ProcessInvoiceRequest) ProtoReflect() protoreflect.Message { + mi := &file_pb_v1_oracle_proto_msgTypes[9] + 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 ProcessInvoiceRequest.ProtoReflect.Descriptor instead. +func (*ProcessInvoiceRequest) Descriptor() ([]byte, []int) { + return file_pb_v1_oracle_proto_rawDescGZIP(), []int{9} +} + +func (x *ProcessInvoiceRequest) GetInvoiceId() string { + if x != nil { + return x.InvoiceId + } + return "" +} + +type ProcessInvoiceResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + InvoiceId string `protobuf:"bytes,1,opt,name=invoice_id,json=invoiceId,proto3" json:"invoice_id,omitempty"` + State string `protobuf:"bytes,2,opt,name=state,proto3" json:"state,omitempty"` + // Types that are valid to be assigned to Result: + // + // *ProcessInvoiceResponse_Exception + Result isProcessInvoiceResponse_Result `protobuf_oneof:"result"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ProcessInvoiceResponse) Reset() { + *x = ProcessInvoiceResponse{} + mi := &file_pb_v1_oracle_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ProcessInvoiceResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ProcessInvoiceResponse) ProtoMessage() {} + +func (x *ProcessInvoiceResponse) ProtoReflect() protoreflect.Message { + mi := &file_pb_v1_oracle_proto_msgTypes[10] + 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 ProcessInvoiceResponse.ProtoReflect.Descriptor instead. +func (*ProcessInvoiceResponse) Descriptor() ([]byte, []int) { + return file_pb_v1_oracle_proto_rawDescGZIP(), []int{10} +} + +func (x *ProcessInvoiceResponse) GetInvoiceId() string { + if x != nil { + return x.InvoiceId + } + return "" +} + +func (x *ProcessInvoiceResponse) GetState() string { + if x != nil { + return x.State + } + return "" +} + +func (x *ProcessInvoiceResponse) GetResult() isProcessInvoiceResponse_Result { + if x != nil { + return x.Result + } + return nil +} + +func (x *ProcessInvoiceResponse) GetException() *v1.Exception { + if x != nil { + if x, ok := x.Result.(*ProcessInvoiceResponse_Exception); ok { + return x.Exception + } + } + return nil +} + +type isProcessInvoiceResponse_Result interface { + isProcessInvoiceResponse_Result() +} + +type ProcessInvoiceResponse_Exception struct { + Exception *v1.Exception `protobuf:"bytes,3,opt,name=exception,proto3,oneof"` +} + +func (*ProcessInvoiceResponse_Exception) isProcessInvoiceResponse_Result() {} + // Response containing the requested claim. type GetClaimResponse struct { state protoimpl.MessageState `protogen:"open.v1"` @@ -762,7 +1030,7 @@ type GetClaimResponse struct { func (x *GetClaimResponse) Reset() { *x = GetClaimResponse{} - mi := &file_pb_v1_oracle_proto_msgTypes[7] + mi := &file_pb_v1_oracle_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -774,7 +1042,7 @@ func (x *GetClaimResponse) String() string { func (*GetClaimResponse) ProtoMessage() {} func (x *GetClaimResponse) ProtoReflect() protoreflect.Message { - mi := &file_pb_v1_oracle_proto_msgTypes[7] + mi := &file_pb_v1_oracle_proto_msgTypes[11] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -787,7 +1055,7 @@ func (x *GetClaimResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetClaimResponse.ProtoReflect.Descriptor instead. func (*GetClaimResponse) Descriptor() ([]byte, []int) { - return file_pb_v1_oracle_proto_rawDescGZIP(), []int{7} + return file_pb_v1_oracle_proto_rawDescGZIP(), []int{11} } func (x *GetClaimResponse) GetResult() isGetClaimResponse_Result { @@ -873,7 +1141,27 @@ const file_pb_v1_oracle_proto_rawDesc = "" + "\x05claim\x18\x02 \x01(\v2\f.pb.v1.ClaimH\x00R\x05claimB\b\n" + "\x06result\",\n" + "\x0fGetClaimRequest\x12\x19\n" + - "\bclaim_id\x18\x01 \x01(\tR\aclaimId\"x\n" + + "\bclaim_id\x18\x01 \x01(\tR\aclaimId\"v\n" + + "\x14UploadInvoiceRequest\x12!\n" + + "\ffile_content\x18\x01 \x01(\tR\vfileContent\x12\x1a\n" + + "\blocation\x18\x02 \x01(\tR\blocation\x12\x1f\n" + + "\vbucket_name\x18\x03 \x01(\tR\n" + + "bucketName\"\x8c\x01\n" + + "\x15UploadInvoiceResponse\x12\x1d\n" + + "\n" + + "invoice_id\x18\x01 \x01(\tR\tinvoiceId\x12\x14\n" + + "\x05state\x18\x02 \x01(\tR\x05state\x124\n" + + "\texception\x18\x03 \x01(\v2\x14.common.v1.ExceptionH\x00R\texceptionB\b\n" + + "\x06result\"6\n" + + "\x15ProcessInvoiceRequest\x12\x1d\n" + + "\n" + + "invoice_id\x18\x01 \x01(\tR\tinvoiceId\"\x8d\x01\n" + + "\x16ProcessInvoiceResponse\x12\x1d\n" + + "\n" + + "invoice_id\x18\x01 \x01(\tR\tinvoiceId\x12\x14\n" + + "\x05state\x18\x02 \x01(\tR\x05state\x124\n" + + "\texception\x18\x03 \x01(\v2\x14.common.v1.ExceptionH\x00R\texceptionB\b\n" + + "\x06result\"x\n" + "\x10GetClaimResponse\x124\n" + "\texception\x18\x01 \x01(\v2\x14.common.v1.ExceptionH\x00R\texception\x12$\n" + "\x05claim\x18\x02 \x01(\v2\f.pb.v1.ClaimH\x00R\x05claimB\b\n" + @@ -916,38 +1204,44 @@ func file_pb_v1_oracle_proto_rawDescGZIP() []byte { } var file_pb_v1_oracle_proto_enumTypes = make([]protoimpl.EnumInfo, 3) -var file_pb_v1_oracle_proto_msgTypes = make([]protoimpl.MessageInfo, 8) +var file_pb_v1_oracle_proto_msgTypes = make([]protoimpl.MessageInfo, 12) var file_pb_v1_oracle_proto_goTypes = []any{ - (Nationality)(0), // 0: pb.v1.Nationality - (Status)(0), // 1: pb.v1.Status - (ClaimState)(0), // 2: pb.v1.ClaimState - (*Claimant)(nil), // 3: pb.v1.Claimant - (*CreateClaimRequest)(nil), // 4: pb.v1.CreateClaimRequest - (*Claim)(nil), // 5: pb.v1.Claim - (*CreateClaimResponse)(nil), // 6: pb.v1.CreateClaimResponse - (*AddClaimantRequest)(nil), // 7: pb.v1.AddClaimantRequest - (*AddClaimantResponse)(nil), // 8: pb.v1.AddClaimantResponse - (*GetClaimRequest)(nil), // 9: pb.v1.GetClaimRequest - (*GetClaimResponse)(nil), // 10: pb.v1.GetClaimResponse - (*v1.Exception)(nil), // 11: common.v1.Exception + (Nationality)(0), // 0: pb.v1.Nationality + (Status)(0), // 1: pb.v1.Status + (ClaimState)(0), // 2: pb.v1.ClaimState + (*Claimant)(nil), // 3: pb.v1.Claimant + (*CreateClaimRequest)(nil), // 4: pb.v1.CreateClaimRequest + (*Claim)(nil), // 5: pb.v1.Claim + (*CreateClaimResponse)(nil), // 6: pb.v1.CreateClaimResponse + (*AddClaimantRequest)(nil), // 7: pb.v1.AddClaimantRequest + (*AddClaimantResponse)(nil), // 8: pb.v1.AddClaimantResponse + (*GetClaimRequest)(nil), // 9: pb.v1.GetClaimRequest + (*UploadInvoiceRequest)(nil), // 10: pb.v1.UploadInvoiceRequest + (*UploadInvoiceResponse)(nil), // 11: pb.v1.UploadInvoiceResponse + (*ProcessInvoiceRequest)(nil), // 12: pb.v1.ProcessInvoiceRequest + (*ProcessInvoiceResponse)(nil), // 13: pb.v1.ProcessInvoiceResponse + (*GetClaimResponse)(nil), // 14: pb.v1.GetClaimResponse + (*v1.Exception)(nil), // 15: common.v1.Exception } var file_pb_v1_oracle_proto_depIdxs = []int32{ 0, // 0: pb.v1.Claimant.nationality:type_name -> pb.v1.Nationality 2, // 1: pb.v1.Claim.state:type_name -> pb.v1.ClaimState 3, // 2: pb.v1.Claim.claimant:type_name -> pb.v1.Claimant 1, // 3: pb.v1.Claim.status:type_name -> pb.v1.Status - 11, // 4: pb.v1.CreateClaimResponse.exception:type_name -> common.v1.Exception + 15, // 4: pb.v1.CreateClaimResponse.exception:type_name -> common.v1.Exception 5, // 5: pb.v1.CreateClaimResponse.claim:type_name -> pb.v1.Claim 3, // 6: pb.v1.AddClaimantRequest.claimant:type_name -> pb.v1.Claimant - 11, // 7: pb.v1.AddClaimantResponse.exception:type_name -> common.v1.Exception + 15, // 7: pb.v1.AddClaimantResponse.exception:type_name -> common.v1.Exception 5, // 8: pb.v1.AddClaimantResponse.claim:type_name -> pb.v1.Claim - 11, // 9: pb.v1.GetClaimResponse.exception:type_name -> common.v1.Exception - 5, // 10: pb.v1.GetClaimResponse.claim:type_name -> pb.v1.Claim - 11, // [11:11] is the sub-list for method output_type - 11, // [11:11] is the sub-list for method input_type - 11, // [11:11] is the sub-list for extension type_name - 11, // [11:11] is the sub-list for extension extendee - 0, // [0:11] is the sub-list for field type_name + 15, // 9: pb.v1.UploadInvoiceResponse.exception:type_name -> common.v1.Exception + 15, // 10: pb.v1.ProcessInvoiceResponse.exception:type_name -> common.v1.Exception + 15, // 11: pb.v1.GetClaimResponse.exception:type_name -> common.v1.Exception + 5, // 12: pb.v1.GetClaimResponse.claim:type_name -> pb.v1.Claim + 13, // [13:13] is the sub-list for method output_type + 13, // [13:13] is the sub-list for method input_type + 13, // [13:13] is the sub-list for extension type_name + 13, // [13:13] is the sub-list for extension extendee + 0, // [0:13] is the sub-list for field type_name } func init() { file_pb_v1_oracle_proto_init() } @@ -963,7 +1257,13 @@ func file_pb_v1_oracle_proto_init() { (*AddClaimantResponse_Exception)(nil), (*AddClaimantResponse_Claim)(nil), } - file_pb_v1_oracle_proto_msgTypes[7].OneofWrappers = []any{ + file_pb_v1_oracle_proto_msgTypes[8].OneofWrappers = []any{ + (*UploadInvoiceResponse_Exception)(nil), + } + file_pb_v1_oracle_proto_msgTypes[10].OneofWrappers = []any{ + (*ProcessInvoiceResponse_Exception)(nil), + } + file_pb_v1_oracle_proto_msgTypes[11].OneofWrappers = []any{ (*GetClaimResponse_Exception)(nil), (*GetClaimResponse_Claim)(nil), } @@ -973,7 +1273,7 @@ func file_pb_v1_oracle_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_pb_v1_oracle_proto_rawDesc), len(file_pb_v1_oracle_proto_rawDesc)), NumEnums: 3, - NumMessages: 8, + NumMessages: 12, NumExtensions: 0, NumServices: 0, }, diff --git a/api/pb/v1/oracle.proto b/api/pb/v1/oracle.proto index 9dc0517..3fdf204 100644 --- a/api/pb/v1/oracle.proto +++ b/api/pb/v1/oracle.proto @@ -100,6 +100,39 @@ message GetClaimRequest { string claim_id = 1; // Unique identifier of the claim to fetch } +message UploadInvoiceRequest { + string file_content = 1; + string location = 2; + string bucket_name = 3; +} + +message UploadInvoiceResponse { + string invoice_id = 1; + string state = 2; + + oneof result { + common.v1.Exception exception = 3; + } +} + +message ProcessInvoiceRequest { + string invoice_id = 1; // The invoice ID created by UploadInvoice +} + +message ProcessInvoiceResponse { + string invoice_id = 1; + string state = 2; + + oneof result { + common.v1.Exception exception = 3; + } +} + +// message UploadInvoiceResult { +// string invoice_id = 1; +// string state = 2; +// } + // Response containing the requested claim. message GetClaimResponse { oneof result { diff --git a/api/srvpb/v1/oracle.pb.go b/api/srvpb/v1/oracle.pb.go index 465f471..a010e28 100644 --- a/api/srvpb/v1/oracle.pb.go +++ b/api/srvpb/v1/oracle.pb.go @@ -4,7 +4,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.6 +// protoc-gen-go v1.36.9 // protoc (unknown) // source: srvpb/v1/oracle.proto @@ -32,7 +32,7 @@ var File_srvpb_v1_oracle_proto protoreflect.FileDescriptor const file_srvpb_v1_oracle_proto_rawDesc = "" + "\n" + - "\x15srvpb/v1/oracle.proto\x12\bsrvpb.v1\x1a\x1cgoogle/api/annotations.proto\x1a healthcheck/v1/healthcheck.proto\x1a\x12pb/v1/oracle.proto\x1a.protoc-gen-openapiv2/options/annotations.proto2\x82\x04\n" + + "\x15srvpb/v1/oracle.proto\x12\bsrvpb.v1\x1a\x1cgoogle/api/annotations.proto\x1a healthcheck/v1/healthcheck.proto\x1a\x12pb/v1/oracle.proto\x1a.protoc-gen-openapiv2/options/annotations.proto2\x83\x06\n" + "\x0eSandboxService\x12\x8d\x01\n" + "\x0eGetHealthCheck\x12%.healthcheck.v1.GetHealthCheckRequest\x1a&.healthcheck.v1.GetHealthCheckResponse\",\x92A\t\n" + "\aService\x82\xd3\xe4\x93\x02\x1a\x12\x18/v1/sandbox/health_check\x12l\n" + @@ -41,7 +41,11 @@ const file_srvpb_v1_oracle_proto_rawDesc = "" + "\vAddClaimant\x12\x19.pb.v1.AddClaimantRequest\x1a\x1a.pb.v1.AddClaimantResponse\"<\x92A\t\n" + "\aService\x82\xd3\xe4\x93\x02*:\x01*\"%/v1/sandbox/claim/{claim_id}/claimant\x12m\n" + "\bGetClaim\x12\x16.pb.v1.GetClaimRequest\x1a\x17.pb.v1.GetClaimResponse\"0\x92A\t\n" + - "\aService\x82\xd3\xe4\x93\x02\x1e\x12\x1c/v1/sandbox/claim/{claim_id}B\xaa\x05\x92A\xa0\x04\x12\x12\n" + + "\aService\x82\xd3\xe4\x93\x02\x1e\x12\x1c/v1/sandbox/claim/{claim_id}\x12|\n" + + "\rUploadInvoice\x12\x1b.pb.v1.UploadInvoiceRequest\x1a\x1c.pb.v1.UploadInvoiceResponse\"0\x92A\t\n" + + "\aService\x82\xd3\xe4\x93\x02\x1e:\x01*\"\x19/v1/sandbox/UploadInvoice\x12\x80\x01\n" + + "\x0eProcessInvoice\x12\x1c.pb.v1.ProcessInvoiceRequest\x1a\x1d.pb.v1.ProcessInvoiceResponse\"1\x92A\t\n" + + "\aService\x82\xd3\xe4\x93\x02\x1f:\x01*\"\x1a/v1/sandbox/ProcessInvoiceB\xaa\x05\x92A\xa0\x04\x12\x12\n" + "\vSandbox API2\x031.0*\x01\x022\x10application/json:\x10application/jsonRS\n" + "\x03400\x12L\n" + "(Bad request determined by business logic\x12 \n" + @@ -69,29 +73,37 @@ const file_srvpb_v1_oracle_proto_rawDesc = "" + "\fcom.srvpb.v1B\vOracleProtoP\x01Z(github.com/luthersystems/sandbox/api/srv\xa2\x02\x03SXX\xaa\x02\bSrvpb.V1\xca\x02\bSrvpb\\V1\xe2\x02\x14Srvpb\\V1\\GPBMetadata\xea\x02\tSrvpb::V1b\x06proto3" var file_srvpb_v1_oracle_proto_goTypes = []any{ - (*v1.GetHealthCheckRequest)(nil), // 0: healthcheck.v1.GetHealthCheckRequest - (*v11.CreateClaimRequest)(nil), // 1: pb.v1.CreateClaimRequest - (*v11.AddClaimantRequest)(nil), // 2: pb.v1.AddClaimantRequest - (*v11.GetClaimRequest)(nil), // 3: pb.v1.GetClaimRequest - (*v1.GetHealthCheckResponse)(nil), // 4: healthcheck.v1.GetHealthCheckResponse - (*v11.CreateClaimResponse)(nil), // 5: pb.v1.CreateClaimResponse - (*v11.AddClaimantResponse)(nil), // 6: pb.v1.AddClaimantResponse - (*v11.GetClaimResponse)(nil), // 7: pb.v1.GetClaimResponse + (*v1.GetHealthCheckRequest)(nil), // 0: healthcheck.v1.GetHealthCheckRequest + (*v11.CreateClaimRequest)(nil), // 1: pb.v1.CreateClaimRequest + (*v11.AddClaimantRequest)(nil), // 2: pb.v1.AddClaimantRequest + (*v11.GetClaimRequest)(nil), // 3: pb.v1.GetClaimRequest + (*v11.UploadInvoiceRequest)(nil), // 4: pb.v1.UploadInvoiceRequest + (*v11.ProcessInvoiceRequest)(nil), // 5: pb.v1.ProcessInvoiceRequest + (*v1.GetHealthCheckResponse)(nil), // 6: healthcheck.v1.GetHealthCheckResponse + (*v11.CreateClaimResponse)(nil), // 7: pb.v1.CreateClaimResponse + (*v11.AddClaimantResponse)(nil), // 8: pb.v1.AddClaimantResponse + (*v11.GetClaimResponse)(nil), // 9: pb.v1.GetClaimResponse + (*v11.UploadInvoiceResponse)(nil), // 10: pb.v1.UploadInvoiceResponse + (*v11.ProcessInvoiceResponse)(nil), // 11: pb.v1.ProcessInvoiceResponse } var file_srvpb_v1_oracle_proto_depIdxs = []int32{ - 0, // 0: srvpb.v1.SandboxService.GetHealthCheck:input_type -> healthcheck.v1.GetHealthCheckRequest - 1, // 1: srvpb.v1.SandboxService.CreateClaim:input_type -> pb.v1.CreateClaimRequest - 2, // 2: srvpb.v1.SandboxService.AddClaimant:input_type -> pb.v1.AddClaimantRequest - 3, // 3: srvpb.v1.SandboxService.GetClaim:input_type -> pb.v1.GetClaimRequest - 4, // 4: srvpb.v1.SandboxService.GetHealthCheck:output_type -> healthcheck.v1.GetHealthCheckResponse - 5, // 5: srvpb.v1.SandboxService.CreateClaim:output_type -> pb.v1.CreateClaimResponse - 6, // 6: srvpb.v1.SandboxService.AddClaimant:output_type -> pb.v1.AddClaimantResponse - 7, // 7: srvpb.v1.SandboxService.GetClaim:output_type -> pb.v1.GetClaimResponse - 4, // [4:8] is the sub-list for method output_type - 0, // [0:4] is the sub-list for method input_type - 0, // [0:0] is the sub-list for extension type_name - 0, // [0:0] is the sub-list for extension extendee - 0, // [0:0] is the sub-list for field type_name + 0, // 0: srvpb.v1.SandboxService.GetHealthCheck:input_type -> healthcheck.v1.GetHealthCheckRequest + 1, // 1: srvpb.v1.SandboxService.CreateClaim:input_type -> pb.v1.CreateClaimRequest + 2, // 2: srvpb.v1.SandboxService.AddClaimant:input_type -> pb.v1.AddClaimantRequest + 3, // 3: srvpb.v1.SandboxService.GetClaim:input_type -> pb.v1.GetClaimRequest + 4, // 4: srvpb.v1.SandboxService.UploadInvoice:input_type -> pb.v1.UploadInvoiceRequest + 5, // 5: srvpb.v1.SandboxService.ProcessInvoice:input_type -> pb.v1.ProcessInvoiceRequest + 6, // 6: srvpb.v1.SandboxService.GetHealthCheck:output_type -> healthcheck.v1.GetHealthCheckResponse + 7, // 7: srvpb.v1.SandboxService.CreateClaim:output_type -> pb.v1.CreateClaimResponse + 8, // 8: srvpb.v1.SandboxService.AddClaimant:output_type -> pb.v1.AddClaimantResponse + 9, // 9: srvpb.v1.SandboxService.GetClaim:output_type -> pb.v1.GetClaimResponse + 10, // 10: srvpb.v1.SandboxService.UploadInvoice:output_type -> pb.v1.UploadInvoiceResponse + 11, // 11: srvpb.v1.SandboxService.ProcessInvoice:output_type -> pb.v1.ProcessInvoiceResponse + 6, // [6:12] is the sub-list for method output_type + 0, // [0:6] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name } func init() { file_srvpb_v1_oracle_proto_init() } diff --git a/api/srvpb/v1/oracle.pb.gw.go b/api/srvpb/v1/oracle.pb.gw.go index ff82c74..8e9b341 100644 --- a/api/srvpb/v1/oracle.pb.gw.go +++ b/api/srvpb/v1/oracle.pb.gw.go @@ -217,6 +217,58 @@ func local_request_SandboxService_GetClaim_0(ctx context.Context, marshaler runt } +func request_SandboxService_UploadInvoice_0(ctx context.Context, marshaler runtime.Marshaler, client SandboxServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq v1_1.UploadInvoiceRequest + var metadata runtime.ServerMetadata + + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.UploadInvoice(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_SandboxService_UploadInvoice_0(ctx context.Context, marshaler runtime.Marshaler, server SandboxServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq v1_1.UploadInvoiceRequest + var metadata runtime.ServerMetadata + + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.UploadInvoice(ctx, &protoReq) + return msg, metadata, err + +} + +func request_SandboxService_ProcessInvoice_0(ctx context.Context, marshaler runtime.Marshaler, client SandboxServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq v1_1.ProcessInvoiceRequest + var metadata runtime.ServerMetadata + + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.ProcessInvoice(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_SandboxService_ProcessInvoice_0(ctx context.Context, marshaler runtime.Marshaler, server SandboxServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq v1_1.ProcessInvoiceRequest + var metadata runtime.ServerMetadata + + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.ProcessInvoice(ctx, &protoReq) + return msg, metadata, err + +} + // RegisterSandboxServiceHandlerServer registers the http handlers for service SandboxService to "mux". // UnaryRPC :call SandboxServiceServer directly. // StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. @@ -323,6 +375,56 @@ func RegisterSandboxServiceHandlerServer(ctx context.Context, mux *runtime.Serve }) + mux.Handle("POST", pattern_SandboxService_UploadInvoice_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + var err error + var annotatedContext context.Context + annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/srvpb.v1.SandboxService/UploadInvoice", runtime.WithHTTPPathPattern("/v1/sandbox/UploadInvoice")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_SandboxService_UploadInvoice_0(annotatedContext, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + + forward_SandboxService_UploadInvoice_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("POST", pattern_SandboxService_ProcessInvoice_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + var err error + var annotatedContext context.Context + annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/srvpb.v1.SandboxService/ProcessInvoice", runtime.WithHTTPPathPattern("/v1/sandbox/ProcessInvoice")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_SandboxService_ProcessInvoice_0(annotatedContext, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + + forward_SandboxService_ProcessInvoice_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -452,6 +554,50 @@ func RegisterSandboxServiceHandlerClient(ctx context.Context, mux *runtime.Serve }) + mux.Handle("POST", pattern_SandboxService_UploadInvoice_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + var err error + var annotatedContext context.Context + annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/srvpb.v1.SandboxService/UploadInvoice", runtime.WithHTTPPathPattern("/v1/sandbox/UploadInvoice")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_SandboxService_UploadInvoice_0(annotatedContext, inboundMarshaler, client, req, pathParams) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + + forward_SandboxService_UploadInvoice_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("POST", pattern_SandboxService_ProcessInvoice_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + var err error + var annotatedContext context.Context + annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/srvpb.v1.SandboxService/ProcessInvoice", runtime.WithHTTPPathPattern("/v1/sandbox/ProcessInvoice")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_SandboxService_ProcessInvoice_0(annotatedContext, inboundMarshaler, client, req, pathParams) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + + forward_SandboxService_ProcessInvoice_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -463,6 +609,10 @@ var ( pattern_SandboxService_AddClaimant_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 2, 4}, []string{"v1", "sandbox", "claim", "claim_id", "claimant"}, "")) pattern_SandboxService_GetClaim_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"v1", "sandbox", "claim", "claim_id"}, "")) + + pattern_SandboxService_UploadInvoice_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "sandbox", "UploadInvoice"}, "")) + + pattern_SandboxService_ProcessInvoice_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "sandbox", "ProcessInvoice"}, "")) ) var ( @@ -473,4 +623,8 @@ var ( forward_SandboxService_AddClaimant_0 = runtime.ForwardResponseMessage forward_SandboxService_GetClaim_0 = runtime.ForwardResponseMessage + + forward_SandboxService_UploadInvoice_0 = runtime.ForwardResponseMessage + + forward_SandboxService_ProcessInvoice_0 = runtime.ForwardResponseMessage ) diff --git a/api/srvpb/v1/oracle.proto b/api/srvpb/v1/oracle.proto index af91e08..975f79f 100644 --- a/api/srvpb/v1/oracle.proto +++ b/api/srvpb/v1/oracle.proto @@ -121,4 +121,20 @@ service SandboxService { option (google.api.http) = {get: "/v1/sandbox/claim/{claim_id}"}; option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {tags: "Service"}; } + + rpc UploadInvoice(pb.v1.UploadInvoiceRequest) returns (pb.v1.UploadInvoiceResponse) { + option (google.api.http) = { + post: "/v1/sandbox/UploadInvoice" + body: "*" + }; + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {tags: "Service"}; + } + + rpc ProcessInvoice(pb.v1.ProcessInvoiceRequest) returns (pb.v1.ProcessInvoiceResponse) { + option (google.api.http) = { + post: "/v1/sandbox/ProcessInvoice" + body: "*" + }; + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {tags: "Service"}; + } } diff --git a/api/srvpb/v1/oracle.swagger.json b/api/srvpb/v1/oracle.swagger.json index 97d300f..54e6de3 100644 --- a/api/srvpb/v1/oracle.swagger.json +++ b/api/srvpb/v1/oracle.swagger.json @@ -19,6 +19,156 @@ "application/json" ], "paths": { + "/v1/sandbox/ProcessInvoice": { + "post": { + "operationId": "SandboxService_ProcessInvoice", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1ProcessInvoiceResponse" + } + }, + "400": { + "description": "Bad request determined by business logic", + "schema": { + "$ref": "#/definitions/v1ExceptionResponse" + } + }, + "401": { + "description": "Authorization failed", + "schema": { + "$ref": "#/definitions/v1ExceptionResponse" + } + }, + "403": { + "description": "Permission denied", + "schema": { + "$ref": "#/definitions/v1ExceptionResponse" + } + }, + "404": { + "description": "Missing resource", + "schema": { + "$ref": "#/definitions/v1ExceptionResponse" + } + }, + "405": { + "description": "Method not allowed", + "schema": { + "type": "string", + "format": "string" + } + }, + "500": { + "description": "Unexpected internal server error", + "schema": { + "$ref": "#/definitions/v1ExceptionResponse" + } + }, + "503": { + "description": "Service not available", + "schema": { + "$ref": "#/definitions/v1ExceptionResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/googlerpcStatus" + } + } + }, + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1ProcessInvoiceRequest" + } + } + ], + "tags": [ + "Service" + ] + } + }, + "/v1/sandbox/UploadInvoice": { + "post": { + "operationId": "SandboxService_UploadInvoice", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1UploadInvoiceResponse" + } + }, + "400": { + "description": "Bad request determined by business logic", + "schema": { + "$ref": "#/definitions/v1ExceptionResponse" + } + }, + "401": { + "description": "Authorization failed", + "schema": { + "$ref": "#/definitions/v1ExceptionResponse" + } + }, + "403": { + "description": "Permission denied", + "schema": { + "$ref": "#/definitions/v1ExceptionResponse" + } + }, + "404": { + "description": "Missing resource", + "schema": { + "$ref": "#/definitions/v1ExceptionResponse" + } + }, + "405": { + "description": "Method not allowed", + "schema": { + "type": "string", + "format": "string" + } + }, + "500": { + "description": "Unexpected internal server error", + "schema": { + "$ref": "#/definitions/v1ExceptionResponse" + } + }, + "503": { + "description": "Service not available", + "schema": { + "$ref": "#/definitions/v1ExceptionResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/googlerpcStatus" + } + } + }, + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1UploadInvoiceRequest" + } + } + ], + "tags": [ + "Service" + ] + } + }, "/v1/sandbox/claim/{claimId}": { "get": { "summary": "Retrieve claim details.", @@ -639,6 +789,57 @@ ], "default": "NATIONALITY_UNSPECIFIED", "description": "Represents a nationality using an enum for structured validation.\n\n - NATIONALITY_UNSPECIFIED: Default value (should not be used)\n - NATIONALITY_GB: United Kingdom\n - NATIONALITY_US: United States\n - NATIONALITY_FR: France\n - NATIONALITY_DE: Germany" + }, + "v1ProcessInvoiceRequest": { + "type": "object", + "properties": { + "invoiceId": { + "type": "string", + "title": "The invoice ID created by UploadInvoice" + } + } + }, + "v1ProcessInvoiceResponse": { + "type": "object", + "properties": { + "invoiceId": { + "type": "string" + }, + "state": { + "type": "string" + }, + "exception": { + "$ref": "#/definitions/v1Exception" + } + } + }, + "v1UploadInvoiceRequest": { + "type": "object", + "properties": { + "fileContent": { + "type": "string" + }, + "location": { + "type": "string" + }, + "bucketName": { + "type": "string" + } + } + }, + "v1UploadInvoiceResponse": { + "type": "object", + "properties": { + "invoiceId": { + "type": "string" + }, + "state": { + "type": "string" + }, + "exception": { + "$ref": "#/definitions/v1Exception" + } + } } }, "securityDefinitions": { diff --git a/api/srvpb/v1/oracle_grpc.pb.go b/api/srvpb/v1/oracle_grpc.pb.go index 5db0ad0..dcbe68c 100644 --- a/api/srvpb/v1/oracle_grpc.pb.go +++ b/api/srvpb/v1/oracle_grpc.pb.go @@ -29,6 +29,8 @@ const ( SandboxService_CreateClaim_FullMethodName = "/srvpb.v1.SandboxService/CreateClaim" SandboxService_AddClaimant_FullMethodName = "/srvpb.v1.SandboxService/AddClaimant" SandboxService_GetClaim_FullMethodName = "/srvpb.v1.SandboxService/GetClaim" + SandboxService_UploadInvoice_FullMethodName = "/srvpb.v1.SandboxService/UploadInvoice" + SandboxService_ProcessInvoice_FullMethodName = "/srvpb.v1.SandboxService/ProcessInvoice" ) // SandboxServiceClient is the client API for SandboxService service. @@ -45,6 +47,8 @@ type SandboxServiceClient interface { AddClaimant(ctx context.Context, in *v11.AddClaimantRequest, opts ...grpc.CallOption) (*v11.AddClaimantResponse, error) // Retrieve claim details. GetClaim(ctx context.Context, in *v11.GetClaimRequest, opts ...grpc.CallOption) (*v11.GetClaimResponse, error) + UploadInvoice(ctx context.Context, in *v11.UploadInvoiceRequest, opts ...grpc.CallOption) (*v11.UploadInvoiceResponse, error) + ProcessInvoice(ctx context.Context, in *v11.ProcessInvoiceRequest, opts ...grpc.CallOption) (*v11.ProcessInvoiceResponse, error) } type sandboxServiceClient struct { @@ -95,6 +99,26 @@ func (c *sandboxServiceClient) GetClaim(ctx context.Context, in *v11.GetClaimReq return out, nil } +func (c *sandboxServiceClient) UploadInvoice(ctx context.Context, in *v11.UploadInvoiceRequest, opts ...grpc.CallOption) (*v11.UploadInvoiceResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(v11.UploadInvoiceResponse) + err := c.cc.Invoke(ctx, SandboxService_UploadInvoice_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *sandboxServiceClient) ProcessInvoice(ctx context.Context, in *v11.ProcessInvoiceRequest, opts ...grpc.CallOption) (*v11.ProcessInvoiceResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(v11.ProcessInvoiceResponse) + err := c.cc.Invoke(ctx, SandboxService_ProcessInvoice_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + // SandboxServiceServer is the server API for SandboxService service. // All implementations must embed UnimplementedSandboxServiceServer // for forward compatibility. @@ -109,6 +133,8 @@ type SandboxServiceServer interface { AddClaimant(context.Context, *v11.AddClaimantRequest) (*v11.AddClaimantResponse, error) // Retrieve claim details. GetClaim(context.Context, *v11.GetClaimRequest) (*v11.GetClaimResponse, error) + UploadInvoice(context.Context, *v11.UploadInvoiceRequest) (*v11.UploadInvoiceResponse, error) + ProcessInvoice(context.Context, *v11.ProcessInvoiceRequest) (*v11.ProcessInvoiceResponse, error) mustEmbedUnimplementedSandboxServiceServer() } @@ -131,6 +157,12 @@ func (UnimplementedSandboxServiceServer) AddClaimant(context.Context, *v11.AddCl func (UnimplementedSandboxServiceServer) GetClaim(context.Context, *v11.GetClaimRequest) (*v11.GetClaimResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method GetClaim not implemented") } +func (UnimplementedSandboxServiceServer) UploadInvoice(context.Context, *v11.UploadInvoiceRequest) (*v11.UploadInvoiceResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method UploadInvoice not implemented") +} +func (UnimplementedSandboxServiceServer) ProcessInvoice(context.Context, *v11.ProcessInvoiceRequest) (*v11.ProcessInvoiceResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ProcessInvoice not implemented") +} func (UnimplementedSandboxServiceServer) mustEmbedUnimplementedSandboxServiceServer() {} func (UnimplementedSandboxServiceServer) testEmbeddedByValue() {} @@ -224,6 +256,42 @@ func _SandboxService_GetClaim_Handler(srv interface{}, ctx context.Context, dec return interceptor(ctx, in, info, handler) } +func _SandboxService_UploadInvoice_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(v11.UploadInvoiceRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(SandboxServiceServer).UploadInvoice(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: SandboxService_UploadInvoice_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(SandboxServiceServer).UploadInvoice(ctx, req.(*v11.UploadInvoiceRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _SandboxService_ProcessInvoice_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(v11.ProcessInvoiceRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(SandboxServiceServer).ProcessInvoice(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: SandboxService_ProcessInvoice_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(SandboxServiceServer).ProcessInvoice(ctx, req.(*v11.ProcessInvoiceRequest)) + } + return interceptor(ctx, in, info, handler) +} + // SandboxService_ServiceDesc is the grpc.ServiceDesc for SandboxService service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -247,6 +315,14 @@ var SandboxService_ServiceDesc = grpc.ServiceDesc{ MethodName: "GetClaim", Handler: _SandboxService_GetClaim_Handler, }, + { + MethodName: "UploadInvoice", + Handler: _SandboxService_UploadInvoice_Handler, + }, + { + MethodName: "ProcessInvoice", + Handler: _SandboxService_ProcessInvoice_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "srvpb/v1/oracle.proto", diff --git a/phylum/claim.lisp b/phylum/claim.lisp index f06debf..a816b0f 100644 --- a/phylum/claim.lisp +++ b/phylum/claim.lisp @@ -32,8 +32,8 @@ ;; Used by `next-state` in mk-claim to determine the next processing step. (set 'state-transitions (make-state-chain (vector - "CLAIM_STATE_LOECLAIM_DETAILS_COLLECTED" - "CLAIM_STATE_LOECLAIM_ID_VERIFIED" + ; "CLAIM_STATE_LOECLAIM_DETAILS_COLLECTED" + ; "CLAIM_STATE_LOECLAIM_ID_VERIFIED" "CLAIM_STATE_OOECLAIM_REVIEWED" "CLAIM_STATE_OOECLAIM_VALIDATED" "CLAIM_STATE_LOEFIN_INVOICE_ISSUED" @@ -50,14 +50,14 @@ ;; TODO: for now it's all 1 connector, but in final version each connector ;; is run by a separate org (participant). (sorted-map - "CLAIMS_PORTAL_UI" "Org1MSP" - "EQUIFAX_ID_VERIFY" "Org1MSP" - "POSTGRES_CLAIMS_DB" "Org1MSP" - "CAMUNDA_WORKFLOW" "Org1MSP" - "INVOICE_NINJA" "Org1MSP" - "CAMUNDA_TASKLIST" "Org1MSP" + "CLAIMS PORTAL UI" "Org1MSP" + ; "EQUIFAX ID VERIFY" "Org1MSP" + "POSTGRES CLAIMS DB" "Org1MSP" + "CAMUNDA WORKFLOW" "Org1MSP" + "INVOICE NINJA" "Org1MSP" + "CAMUNDA TASKLIST" "Org1MSP" "EMAIL" "Org1MSP" - "STRIPE_PAYMENT" "Org1MSP")) + "STRIPE PAYMENT" "Org1MSP")) ;; event-desc-record returns metadata describing the system and action to trigger. ;; Used when building connector events for a specific state. @@ -71,22 +71,29 @@ (set 'claims-state-event-desc (sorted-map "CLAIM_STATE_UNSPECIFIED" () - "CLAIM_STATE_NEW" (event-desc-record "CLAIMS_PORTAL_UI" "input claim details") - "CLAIM_STATE_LOECLAIM_DETAILS_COLLECTED" (event-desc-record "EQUIFAX_ID_VERIFY" "verify customer identity") - "CLAIM_STATE_LOECLAIM_ID_VERIFIED" (event-desc-record "CAMUNDA_WORKFLOW" "collect policy details") - "CLAIM_STATE_OOECLAIM_REVIEWED" (event-desc-record "POSTGRES_CLAIMS_DB" "verify policy") - "CLAIM_STATE_OOECLAIM_VALIDATED" (event-desc-record "INVOICE_NINJA" "generate invoice") - "CLAIM_STATE_LOEFIN_INVOICE_ISSUED" (event-desc-record "CAMUNDA_TASKLIST" "approve invoice") + "CLAIM_STATE_NEW" (event-desc-record "CLAIMS PORTAL UI" "input claim details") + ; "CLAIM_STATE_LOECLAIM_DETAILS_COLLECTED" (event-desc-record "EQUIFAX ID VERIFY" "verify customer identity") + ; "CLAIM_STATE_LOECLAIM_DETAILS_COLLECTED" (event-desc-record "CAMUNDA WORKFLOW" "collect policy details") + "CLAIM_STATE_OOECLAIM_REVIEWED" (event-desc-record "POSTGRES CLAIMS DB" "verify policy") + "CLAIM_STATE_OOECLAIM_VALIDATED" (event-desc-record "INVOICE NINJA" "generate invoice") + "CLAIM_STATE_LOEFIN_INVOICE_ISSUED" (event-desc-record "CAMUNDA TASKLIST" "approve invoice") "CLAIM_STATE_OOEFIN_INVOICE_REVIEWED" (event-desc-record "EMAIL" "email invoice") - "CLAIM_STATE_OOEFIN_INVOICE_APPROVED" (event-desc-record "STRIPE_PAYMENT" "make payment") + "CLAIM_STATE_OOEFIN_INVOICE_APPROVED" (event-desc-record "STRIPE PAYMENT" "make payment") "CLAIM_STATE_OOEPAY_PAYMENT_TRIGGERED" () "CLAIM_STATE_DONE" ())) ;; mk-verify-policy-req creates a request to verify a policy ;; For now, just returns a simple health check query (defun mk-verify-policy-req (policy-id) - (mk-psql-req "SELECT 1")) - + (mk-connector-req + (sorted-map + "kind" "KIND_POSTGRES_POC" + "operation" "search-hotels-by-name" + "args" (sorted-map + "name" "l")))) + ; (let* ([req-body (mk-psql-req "SELECT 1")]) + ; (cc:infof (sorted-map "sql req" req-body) "here") + ; req-body)) ;; mk-claim returns a stateful handler for a claim. ;; Supports operations: @@ -121,6 +128,8 @@ "sys" (get desc "sys") "eng" (get desc "eng") "req" event-req)]) + (cc:infof (sorted-map "event" event) "add-event event") + (when event-req (append! events event)))] ;; next-state upates `claim` to the next state. @@ -132,8 +141,13 @@ ;; ret-save returns a map that the connector hub API can use to store ;; new data for the object, and raise events for subsequent processing. [ret-save () - (next-state) - (sorted-map "put" claim "events" events)] + (cc:infof (sorted-map + "claim_id" (get claim "claim_id") + "state" (get claim "state") + "events" events) + "ret-save") + (next-state) + (sorted-map "put" claim "events" events)] ;; init initializes a new claim with the initial state. ;; Should be called only once on a newly created claim object. @@ -154,28 +168,36 @@ ;; - Advances the state machine ;; Returns updated claim data and any new events to raise. [handle (resp) + (cc:infof (sorted-map "state" (get-state) "resp" resp) "in handle") (let* ([resp-body (get resp "response")] [resp-err (get resp "error")] [state (get-state)]) + (cc:infof (sorted-map "resp" resp-body) "here") (when resp-err (set-exception-unexpected (format-string "unhandled response error: {}" resp-err))) (cc:infof (assoc resp-body "state" state) "handle") (cond - ((equal? state "CLAIM_STATE_LOECLAIM_DETAILS_COLLECTED") - ;; equifax event does not have NATIONALITY prefix - (let* ([nationality (string:trim-left (get resp "nationality") "NATIONALITY_")] - [person (assoc resp "nationality" nationality)]) - (add-event (mk-equifax-req (trace person "equifax"))))) - - ((equal? state "CLAIM_STATE_LOECLAIM_ID_VERIFIED") + ((equal? state "CLAIM_STATE_OOECLAIM_REVIEWED") + ; ;; equifax event does not have NATIONALITY prefix + ; (let* ([nationality (string:trim-left (get resp "nationality") "NATIONALITY_")] + ; [person (assoc resp "nationality" nationality)]) + ; (add-event (mk-verify-policy-req (get resp "policy_id"))) + ; (add-event (mk-equifax-req (trace person "equifax"))))) + + ; ((equal? state "CLAIM_STATE_LOECLAIM_ID_VERIFIED") (add-event (mk-camunda-start-req "a1" (sorted-map "x" "fnord")))) - ((equal? state "CLAIM_STATE_OOECLAIM_REVIEWED") + ; ((equal? state "CLAIM_STATE_OOECLAIM_REVIEWED") (add-event (mk-verify-policy-req (get resp "policy_id")))) ((equal? state "CLAIM_STATE_OOECLAIM_VALIDATED") + (trace resp "ooe claim validated") + (let* ([generic-resp (mk-connector-resp resp)]) + + (cc:infof (sorted-map "generic-resp" generic-resp) "maybe here")) + (add-event (mk-invoice-ninja-email-req (sorted-map "invoice_id" "mock_invoice_id")))) @@ -236,7 +258,8 @@ ;; Returns the result of the initial state transition (usually includes events). [new-claim () (let* ([claim-data (sorted-map "claim_id" (mk-uuid))] - [claim (mk-claim claim-data)]) + [claim (mk-claim claim-data)]) + (cc:infof (sorted-map "claim" claim) "new-claim") (claim 'init))] ;; storage-get-claim: load claim from sidedb by ID diff --git a/phylum/claim_test.lisp b/phylum/claim_test.lisp index e0dcb14..c4d7fbe 100644 --- a/phylum/claim_test.lisp +++ b/phylum/claim_test.lisp @@ -147,4 +147,10 @@ ;; Integration test for full claim processing loop. ;; Runs 7 connector event cycles from new claim to DONE state. -(test "test-claim-factory" (process-event-loop 7 true)) +; (test "test-claim-factory" (process-event-loop 7 true)) + +(test "builds s3 request" (mk-s3-upload-req "abc" "foo.txt" "my-bucket")) +(test "inline factory name" (inline-upload-factory 'name)) +(test "inline factory put" (inline-upload-factory 'put (sorted-map "upload_id" "123"))) +(test "builds upload transition" (build-upload-transition (mk-s3-upload-req "abc" "foo.txt" "my-bucket"))) + diff --git a/phylum/invoice_endpoints.lisp b/phylum/invoice_endpoints.lisp new file mode 100644 index 0000000..7c5557c --- /dev/null +++ b/phylum/invoice_endpoints.lisp @@ -0,0 +1,41 @@ +(in-package 'sandbox) + +(use-package 'connector) + +(defendpoint "upload_invoice" (req) + (let* ([fc (get req "file_content")] + [file-content (or (if (string? fc) fc (json:dump-string fc)) + (set-exception-business "missing file_content"))] + [file-name (or (get req "location") + (set-exception-business "missing location"))] + [bucket-name (or (get req "bucket_name") + (set-exception-business "missing bucket_name"))] + + ;; Build base invoice doc (durable state) + [invoice (new-connector-object invoice-manager)] + [invoice-id (get invoice "invoice_id")] + [invoice (assoc! invoice "state" "INVOICE_STATE_NEW")] + + ;; Emulate ConnectorHub response payload (what parse expects) + [chresp (sorted-map + "file_content" file-content + "file_name" file-name + "bucket_name" bucket-name)] + + ;; Run one state step (parse → stage-ephemeral → stage-durable → transition) + [step (run-state-step "invoice" "invoice_id" invoice chresp)] + [inv1 (get step "put")] + [events (get step "events")]) + + ;; Persist updated durable doc and trigger connector events + (invoice-manager 'put inv1) + (trigger-connector-object invoice-manager invoice-id + (sorted-map "put" inv1 "events" events)) + + (route-success + (sorted-map + "invoice_id" invoice-id + "state" (get inv1 "state"))))) + +(defun trigger-invoice (invoice-id resp) + (trigger-connector-object invoice-manager invoice-id resp)) \ No newline at end of file diff --git a/phylum/invoice_events.lisp b/phylum/invoice_events.lisp new file mode 100644 index 0000000..e70d91f --- /dev/null +++ b/phylum/invoice_events.lisp @@ -0,0 +1,55 @@ +;; invoice_transition.lisp +;; ----------------------- +;; Core transition builder utilities for invoice state machines. +;; +;; Defines `build-event`, a generic helper that wraps an invoice object +;; and a connector request/response (`resp`) into a transition map: +;; +;; { +;; "put": +;; "events": [] +;; } +;; +;; Each event includes: +;; - "oid": invoice_id +;; - "key": unique event key (UUID) +;; - "pdc": "private" (data collection) +;; - "msp": "Org1MSP" (organization identity) +;; - "sys": connector system name (e.g. "AWSS3", "MYSQL", "CAMUNDA") +;; - "eng": human-readable action (e.g. "upload file", "insert doc") +;; - "req": connector request payload +;; +;; System-specific wrappers (build-s3-event, build-mysql-event, +;; build-camunda-event) are provided for convenience and consistency. +;; +;; New connectors should follow the same pattern: +;; (defun build--transition (invoice resp action) +;; (build-event invoice resp action "")) + + +(in-package 'sandbox) + +(use-package 'connector) + +;; Build a generic connector event with common metadata. +(defun build-event (invoice resp action sys-name) + (sorted-map + "oid" (get invoice "invoice_id") + "key" (mk-uuid) + "pdc" "private" + "msp" "Org1MSP" + "sys" sys-name + "eng" action + "req" resp)) + +;; Build an event targeting AWS S3 +(defun build-s3-event (invoice resp action) + (build-event invoice resp action "AWSS3")) + +;; Build an event targeting MYSQL +(defun build-mysql-event (invoice resp action) + (build-event invoice resp action "MYSQL")) + +;; Build an event targeting Camunda workflow +(defun build-camunda-event (invoice resp action) + (build-event invoice resp action "CAMUNDA")) diff --git a/phylum/invoice_process_registration.lisp b/phylum/invoice_process_registration.lisp new file mode 100644 index 0000000..6c753d8 --- /dev/null +++ b/phylum/invoice_process_registration.lisp @@ -0,0 +1,32 @@ +(in-package 'sandbox) + +(use-package 'connector) + +; ----------------------------------------------------------------------------- +; Create the state machine +; ----------------------------------------------------------------------------- + +(set 'state-spec + (sorted-map + "INVOICE_STATE_NEW" (invoice-new-state-handler) + "INVOICE_STATE_S3_UPLOADED" (invoice-s3-uploaded-state-handler) + "INVOICE_STATE_S3_RETRIEVED" (invoice-s3-retrieved-state-handler) + "INVOICE_STATE_MYSQL_VALIDATED" (invoice-mysql-validated-state-handler) + "INVOICE_STATE_MYSQL_UPDATED" (invoice-mysql-updated-state-handler))) + +; ----------------------------------------------------------------------------- +;; Build the invoices connector from the generic factory +; ----------------------------------------------------------------------------- + +(set 'invoice-manager + (singleton (mk-entity-manager + "invoice" + "invoice_id" + "INVOICE_STATE_NEW" + state-spec))) + +(register-connector-factory invoice-manager) + +;; Helper to create a new invoice connector object via factory +(defun create-invoice () + (new-connector-object invoice-manager)) \ No newline at end of file diff --git a/phylum/invoice_state_transitions.lisp b/phylum/invoice_state_transitions.lisp new file mode 100644 index 0000000..aafde92 --- /dev/null +++ b/phylum/invoice_state_transitions.lisp @@ -0,0 +1,152 @@ + +;; ----------------------------------------------------------------------------- +;; Example state handlers (invoice) +;; ----------------------------------------------------------------------------- + +;; INVOICE_STATE_NEW -> INVOICE_STATE_S3_UPLOADED +(defun invoice-new-state-handler () + (labels + ;; parse: validate + extract fields for this step (not persisted unless staged) + ([parse (resp entity) + (let* ([file-content (get resp "file_content")] + [file-name (get resp "file_name")] + [bucket-name (get resp "bucket_name")]) + (sorted-map + "file_content" file-content + "file_name" file-name + "bucket_name" bucket-name))] + + ;; ephemeral: keep raw file content until we see S3 upload succeed + [stage-ephemeral (entity parsed accessors) + (vector + (sorted-map :key "file_content" + :value (get parsed "file_content") + :drop-state "INVOICE_STATE_S3_UPLOADED"))] + + ;; durable: persist metadata + [stage-durable (entity parsed accessors) + (sorted-map + "file_name" (get parsed "file_name") + "bucket_name" (get parsed "bucket_name"))] + + ;; events: S3 upload using parsed content + durable metadata + [create-events (entity parsed accessors) + (let* ([file-name (get entity "file_name")] + [bucket-name (get entity "bucket_name")] + [content (get parsed "file_content")]) + (vector + (mk-s3-upload-event entity content file-name bucket-name)))]) + (mk-state-handler + :next "INVOICE_STATE_S3_UPLOADED" + :parse parse + :stage-ephemeral stage-ephemeral + :stage-durable stage-durable + :create-events create-events))) + + +;; INVOICE_STATE_S3_UPLOADED -> INVOICE_STATE_S3_RETRIEVED +(defun invoice-s3-uploaded-state-handler () + (labels + ;; parse S3 upload response (domain helper) + ([parse (resp entity) + (parse-s3-resp resp)] + + ;; no new ephemerals + [stage-ephemeral (entity parsed accessors) ()] + + ;; no durable changes + [stage-durable (entity parsed accessors) ()] + + ;; events: request S3 GET; demonstrate ephem-get before purge + [create-events (entity parsed accessors) + (let* ([entity-id (get entity "invoice_id")] + [get-ephem (get accessors :get-ephem)] + [file-content (get-ephem "file_content")]) + (vector (mk-s3-get-event entity)))]) + (mk-state-handler + :next "INVOICE_STATE_S3_RETRIEVED" + :parse parse + :stage-ephemeral stage-ephemeral + :stage-durable stage-durable + :create-events create-events))) + + +;; INVOICE_STATE_S3_RETRIEVED -> INVOICE_STATE_MYSQL_VALIDATED +(defun invoice-s3-retrieved-state-handler () + (labels + ;; parse GET response (string/bytes → string) + ([parse (resp entity) + (parse-s3-resp resp)] + + ;; keep raw S3 body temporarily, drop once MySQL update succeeds + [stage-ephemeral (entity parsed accessors) ()] + + ;; durable: extract invoice_number + [stage-durable (entity parsed accessors) + (let* ([j (json:load-string parsed)] + [inv-num (get j "invoice_number")]) + (sorted-map "invoice_number" inv-num))] + + ;; events: validate invoice in MySQL + [create-events (entity parsed accessors) + (vector + (mk-mysql-select-invoices-by-numbers-event + entity + (list (get entity "invoice_number"))))]) + (mk-state-handler + :next "INVOICE_STATE_MYSQL_VALIDATED" + :parse parse + :stage-ephemeral stage-ephemeral + :stage-durable stage-durable + :create-events create-events))) + + +;; INVOICE_STATE_MYSQL_VALIDATED -> INVOICE_STATE_MYSQL_UPDATED +(defun invoice-mysql-validated-state-handler () + (labels + ;; parse MySQL SELECT response + ([parse (resp entity) + (parse-mysql-select resp)] + + ;; no ephemerals here + [stage-ephemeral (entity parsed accessors) ()] + + ;; no durable changes + [stage-durable (entity parsed accessors) ()] + + ;; events: update invoice status in MySQL + [create-events (entity parsed accessors) + (vector + (mk-mysql-update-invoice-status-event + entity + (list (get entity "invoice_number"))))]) + (mk-state-handler + :next "INVOICE_STATE_MYSQL_UPDATED" + :parse parse + :stage-ephemeral stage-ephemeral + :stage-durable stage-durable + :create-events create-events))) + + +;; INVOICE_STATE_MYSQL_UPDATED -> INVOICE_STATE_DONE +(defun invoice-mysql-updated-state-handler () + (labels + ;; parse MySQL UPDATE/EXEC response + ([parse (resp entity) + (parse-mysql-exec resp)] + + ;; final cleanups if any (none here) + [stage-ephemeral (entity parsed accessors) ()] + + ;; no durable changes + [stage-durable (entity parsed accessors) ()] + + ;; no further events + [create-events (entity parsed accessors) + (vector)]) + (mk-state-handler + :next "INVOICE_STATE_DONE" + :parse parse + :stage-ephemeral stage-ephemeral + :stage-durable stage-durable + :create-events create-events))) diff --git a/phylum/invoice_transitions_camunda.lisp b/phylum/invoice_transitions_camunda.lisp new file mode 100644 index 0000000..462ce7b --- /dev/null +++ b/phylum/invoice_transitions_camunda.lisp @@ -0,0 +1,16 @@ +;; camunda_transitions.lisp +;; ------------------------ +;; Defines high-level transition builders for Camunda connector. +;; Uses mk-camunda-start-req and wraps into standard transition events +;; via build-camunda-event (from invoice_transition.lisp). + +(in-package 'sandbox) + +(use-package 'connector) + +(defun mk-camunda-start-transition (invoice pdk &optional vars-map) + ;; Start a Camunda workflow and emit an event. + (build-camunda-event + invoice + (mk-camunda-start-req pdk vars-map) + "start workflow")) \ No newline at end of file diff --git a/phylum/invoice_transitions_mysql.lisp b/phylum/invoice_transitions_mysql.lisp new file mode 100644 index 0000000..6223981 --- /dev/null +++ b/phylum/invoice_transitions_mysql.lisp @@ -0,0 +1,119 @@ +(in-package 'sandbox) + +(use-package 'connector) + +;; ====================== +;; MySQL request builders +;; ====================== + +(defun mk-mysql-req (sql) + ;; Wrap raw SQL into connectorhub request. + (mk-connector-req + (sorted-map + "kind" "KIND_MYSQL" + "operation" "mysql_query" + "args" (sorted-map "sql" sql)))) + + +(defun parse-mysql-resp (resp) + (parse-generic-resp resp)) + +(defun mk-mysql-insert-pos-basic-req () + (mk-mysql-req + "INSERT INTO purchase_orders (po_number, vendor_id, amount, status) VALUES ('PO1004', 1, 5000.00, 'OPEN'), ('PO2005', 2, 7500.00, 'OPEN');")) + +(defun mk-mysql-select-docs-req (ids) + ;; Build a SELECT for multiple invoice_ids using IN. + ; (let* ((id-str (string-join (map string ids) ","))) + (mk-mysql-req "SELECT * FROM invoices WHERE invoice_id IN (1,2)")) + +(defun mk-mysql-delete-doc-req (invoice-id filename) + ;; Build a DELETE statement for a specific doc by invoice + filename. + (mk-mysql-req + (format-string + "DELETE FROM invoices WHERE invoice_id='{}' AND filename='{}'" + invoice-id filename))) + + +;; ====================== +;; High-level transitions +;; ====================== + +(defun mk-mysql-insert-doc-transition (invoice invoice-id filename bucket) + ;; Insert a new document record and emit an event. + (build-mysql-event + invoice + (mk-mysql-insert-pos-basic-req) + "insert doc")) + + +(defun mk-mysql-select-docs-transition (invoice invoice-ids) + ;; Query documents for an invoice and emit an event. + (build-mysql-event + invoice + (mk-mysql-select-docs-req invoice-ids) + "select docs")) + + +(defun mk-mysql-delete-doc-transition (invoice invoice-id filename) + ;; Delete a document record and emit an event. + (build-mysql-event + invoice + (mk-mysql-delete-doc-req invoice-id filename) + "delete doc")) + +(defun mk-mysql-insert-pos-basic-transition (invoice) + (build-mysql-event + invoice + (mk-mysql-insert-pos-basic-req) + "basic insert")) + +(defun parse-mysql-exec (resp) + (let* ([parsed (parse-mysql-resp resp)]) + (cc:infof (sorted-map "parsed-response" parsed) "parse-mysql-exec") + "ok")) + +(defun parse-mysql-select (resp) + (let* ([parsed (parse-mysql-resp resp)] + [rows (cond + ((vector? parsed) parsed) + ((sorted-map? parsed) (vector parsed)) + (:else (vector)))]) + rows)) + +(defun extract-invoice-statuses (rows) + (when (vector? rows) + (let* ([fn (lambda (row) + (format-string "{}:{}" + (get row "invoice_number") + (get row "status")))]) + (map 'vector fn rows)))) + +(defun mk-mysql-select-invoices-by-numbers-req (numbers) + ;; Build a SELECT for multiple invoice_numbers using IN. + (let* ([quoted (map 'list (lambda (n) (format-string "'{}'" n)) numbers)] + [joined (string:join quoted ",")]) + (mk-mysql-req + (format-string + "SELECT * FROM invoices WHERE invoice_number IN ({})" + joined)))) + +(defun mk-mysql-update-invoice-status-req (numbers) + ;; Update invoices matching invoice_numbers from PENDING to VERIFIED. + (let* ([quoted (map 'list (lambda (n) (format-string "'{}'" n)) numbers)] + [joined (string:join quoted ",")]) + (mk-mysql-req + (format-string "UPDATE invoices SET status = 'VERIFIED' WHERE invoice_number IN ({}) AND status = 'PENDING'" + joined)))) + +(defun mk-mysql-select-invoices-by-numbers-event (invoice numbers) + (build-mysql-event + invoice + (mk-mysql-select-invoices-by-numbers-req numbers) + "select invoices by numbers")) + +(defun mk-mysql-update-invoice-status-event (invoice numbers) + (build-mysql-event + invoice + (mk-mysql-update-invoice-status-req numbers) + "update invoice statuses")) \ No newline at end of file diff --git a/phylum/invoice_transitions_s3.lisp b/phylum/invoice_transitions_s3.lisp new file mode 100644 index 0000000..2de0fa2 --- /dev/null +++ b/phylum/invoice_transitions_s3.lisp @@ -0,0 +1,69 @@ +(in-package 'sandbox) + +(use-package 'connector) + +;; ====================== +;; S3 request builders +;; ====================== + +(defun mk-s3-req (op args) + ;; Wrap args inside an "args" map for mk-connector-req + (mk-connector-req + (sorted-map + "kind" "KIND_AWS_S3" + "operation" op + "args" args))) + +(defun parse-s3-resp (resp) + (parse-generic-resp resp)) + +(defun mk-s3-upload-req (file-content file-name bucket-name) + (mk-s3-req "put_object" + (sorted-map + "body" (json:dump-string file-content) + "key" file-name + "bucket_name" bucket-name))) + +(defun mk-s3-get-req (file-name bucket-name) + (mk-s3-req "get_object" + (sorted-map + "key" file-name + "bucket_name" bucket-name))) + + +(defun mk-s3-del-req (file-name bucket-name) + (mk-s3-req "delete_object" + (sorted-map + "key" file-name + "bucket_name" bucket-name))) + + +;; ====================== +;; High-level transitions +;; ====================== + + +(defun mk-s3-upload-event (invoice file-content file-name bucket-name) + ;; Build an upload transition (put_object + event) + (build-s3-event + invoice + (mk-s3-upload-req file-content file-name bucket-name) + "upload file")) + +(defun mk-s3-get-event (invoice) + ;; Build a get transition (get_object + event). + (let* ([file-name (get invoice "file_name")] + [bucket-name (get invoice "bucket_name")]) + (build-s3-event + invoice + (mk-s3-get-req file-name bucket-name) + "get file"))) + +(defun mk-s3-del-event (invoice) + ;; Build a delete transition (del_object + event). + (let* ([file-name (get invoice "file_name")] + [bucket-name (get invoice "bucket_name")]) + (build-s3-event + invoice + (mk-s3-del-req file-name bucket-name) + "delete file"))) \ No newline at end of file diff --git a/phylum/main.lisp b/phylum/main.lisp index 1a40c1e..a4a4727 100644 --- a/phylum/main.lisp +++ b/phylum/main.lisp @@ -21,4 +21,16 @@ ;; Load all route definitions and core business logic for this phylum. (load-file "routes.lisp") -(load-file "claim.lisp") +; (load-file "claim.lisp") + +(load-file "invoice_endpoints.lisp") +(load-file "invoice_transitions_camunda.lisp") +(load-file "invoice_transitions_mysql.lisp") +(load-file "invoice_transitions_s3.lisp") +(load-file "invoice_events.lisp") +(load-file "substr_generic_state_machine.lisp") +(load-file "substr_ephemeral_storage.lisp") +(load-file "substr_generic_parser.lisp") +(load-file "invoice_state_transitions.lisp") +(load-file "invoice_process_registration.lisp") + diff --git a/phylum/routes.lisp b/phylum/routes.lisp index 542afd2..6ac73ff 100644 --- a/phylum/routes.lisp +++ b/phylum/routes.lisp @@ -15,6 +15,8 @@ ;; ---------------------------------------------------------------------------- (in-package 'sandbox) +(use-package 'connector) + ;; wrap-endpoint is a simple wrapper for endpoints which allows them to call ;; set-exception and shortcircuit the endpoint handler. wrap-endpoint may be ;; customised to add universal logging or book-keeping that should be present @@ -100,3 +102,4 @@ (format-string "missing claim {}" claim-id)))] [data (claim 'data)]) (route-success (sorted-map "claim" data)))) + diff --git a/phylum/substr_ephemeral_storage.lisp b/phylum/substr_ephemeral_storage.lisp new file mode 100644 index 0000000..7929171 --- /dev/null +++ b/phylum/substr_ephemeral_storage.lisp @@ -0,0 +1,85 @@ +(in-package 'sandbox) +(use-package 'connector) + +;; ---------- helpers for safe prefix handling ---------- +(defun _prefix-range (prefix) + ;; Return [start end] range for scanning a prefixed keyspace + (vector prefix (format-string "{}\uffff" prefix))) + +(defun ephem-index-key (entity-name entity-id drop-state) + (join-index-cols "sandbox" entity-name "ephem" "index" entity-id drop-state)) + +;; ---------- Ephemeral bucket/router keys ---------- +(defun ephem-bucket-key (entity-name entity-id drop-state) + ;; sandbox::ephem:bucket:: + (join-index-cols "sandbox" entity-name "ephem" "bucket" entity-id drop-state)) + +(defun ephem-router-key (entity-name entity-id ekey) + ;; sandbox::ephem:router:: + (join-index-cols "sandbox" entity-name "ephem" "router" entity-id ekey)) + +(defun ephem-router-prefix (entity-name entity-id) + ;; prefix for scanning all router entries for an entity + (join-index-cols "sandbox" entity-name "ephem" "router" entity-id)) + +;; Read by key: router -> bucket -> value +(defun ephem-get (entity-name entity-id ekey) + (let* ([ds (sidedb:get (ephem-router-key entity-name entity-id ekey))]) + (when ds + (let* ([bkey (ephem-bucket-key entity-name entity-id ds)] + [bucket (sidedb:get bkey)]) + (and bucket (get bucket ekey)))))) + +;; Persist a vector of intents returned by stage-ephemeral +;; Each intent: {:key :value [:drop-state ]} +(defun ephem-persist-staged! (entity-name entity-id default-drop-state intents) + (map () + (lambda (it) + (let* ([ekey (get it :key)] + [eval (get it :value)] + [ds (or (get it :drop-state) default-drop-state)] + [bkey (ephem-bucket-key entity-name entity-id ds)] + [bucket (or (sidedb:get bkey) (sorted-map))]) + + ;; Validate the drop-state before persisting + (validate-state-exists! ds) + + ;; write bucket first + (assoc! bucket ekey eval) + (sidedb:put bkey bucket) + + ;; write router + (sidedb:put (ephem-router-key entity-name entity-id ekey) ds) + + ;; append ekey to index list + (let* ([ikey (ephem-index-key entity-name entity-id ds)] + [index (or (sidedb:get ikey) (vector))]) + (append! index ekey) ; in-place append + (sidedb:put ikey index)))) + intents) + (sorted-map "ok" true)) + +;; Purge everything whose drop-state == +;; - delete the whole bucket +;; - clean router entries whose VALUE equals +(defun ephem-purge-for-state! (entity-name entity-id drop-state) + (let* ([bkey (ephem-bucket-key entity-name entity-id drop-state)] + [ikey (ephem-index-key entity-name entity-id drop-state)] + [ekeys (or (sidedb:get ikey) (vector))]) + + ;; purge all router entries + (map () + (lambda (ek) + (sidedb:purge (ephem-router-key entity-name entity-id ek))) + ekeys) + + ;; purge bucket + index + (sidedb:purge bkey) + (sidedb:purge ikey)) + + (sorted-map "ok" true)) + + (defun validate-state-exists! (state) + (when (or (nil? state) (nil? (lookup-state-spec state))) + (set-exception-unexpected + (format-string "invalid or missing state name: {}" state)))) diff --git a/phylum/substr_generic_parser.lisp b/phylum/substr_generic_parser.lisp new file mode 100644 index 0000000..b30ca91 --- /dev/null +++ b/phylum/substr_generic_parser.lisp @@ -0,0 +1,20 @@ +(in-package 'sandbox) +(use-package 'connector) + +;; ---------------- Convenience: generic parser helper ---------------- + +(defun parse-generic-resp (resp &key skip-inner-error-check) + (let* ([resp-body (get resp "response")] + [resp-err (get resp "error")]) + (when resp-err + (set-exception-unexpected + (format-string "unhandled response error: {}" resp-err))) + (let* ([container (and resp-body (get resp-body "generic"))] + [text-json (and container (get container "text"))] + [parsed (and text-json (json:load-string text-json))]) + (when (and (not skip-inner-error-check) (sorted-map? parsed)) + (let ([inner-error (get parsed "error")]) + (when inner-error + (set-exception-unexpected + (format-string "connector inner error: {}" inner-error))))) + parsed))) diff --git a/phylum/substr_generic_state_machine.lisp b/phylum/substr_generic_state_machine.lisp new file mode 100644 index 0000000..26eeaf3 --- /dev/null +++ b/phylum/substr_generic_state_machine.lisp @@ -0,0 +1,199 @@ +(in-package 'sandbox) +(use-package 'connector) + +;; ----------------------------------------------------------------------------- +;; Sandbox Entity State Machine Framework +;; ----------------------------------------------------------------------------- +;; +;; Core runtime + ephemeral storage layer for declarative state machines. +;; +;; Per-step flow: +;; parse(resp, entity) +;; → stage-ephemeral(entity, parsed) ; vector of ephemeral intents +;; → stage-durable(entity, parsed) ; partial or full durable updates +;; → create-events(entity, parsed) ; emit connector events (no mutation) +;; → persist ephemerals (default drop-state = :next) +;; → advance durable entity state to :next +;; → purge ephemerals scheduled for the state we just entered +;; +;; Ephemeral storage in SideDB: +;; sandbox::ephem:bucket:: ; value buckets (map key→value) +;; sandbox::ephem:router:: ; router key → dropState +;; sandbox::ephem:index:: ; list of keys for drop-state +;; +;; Each ephemeral intent is a map: +;; { :key :value :drop-state } +;; Data survives until the entity enters that drop-state; then it's purged. +;; +;; State specs (registered in global `state-spec`) are built with (mk-state-handler) +;; and define: :parse, :stage-ephemeral, :stage-durable, :create-events, and :next. +;; ----------------------------------------------------------------------------- + + +;; ----------------------------------------------------------------------------- +;; Entity Manager +;; ----------------------------------------------------------------------------- +;; Builds a manager for a domain entity to create/load/save/delete instances. +;; +;; API (returned closure): +;; ('name) -> entity-name +;; ('new) -> transition map { "put": entity, "events": [...] } +;; ('get ) -> entity-instance | () +;; ('put ) -> () +;; ('del ) -> () +;; +(defun mk-entity-manager (entity-name entity-key initial-state states) + (lambda () + (labels + ([name () entity-name] + + ;; Key in PDC: "sandbox::" + [mk-storage-key (entity-id) + (join-index-cols "sandbox" entity-name entity-id)] + + ;; persistence (PDC) + [storage-put (entity-doc) + (sidedb:put (mk-storage-key (get entity-doc entity-key)) entity-doc)] + + [storage-get (entity-id) + (let* ([key (mk-storage-key entity-id)] + [entity-doc (sidedb:get key)]) + (when entity-doc + (mk-entity-instance entity-name entity-key initial-state states entity-doc)))] + + [storage-del (entity-id) + (sidedb:purge (mk-storage-key entity-id))] + + ;; constructor + [new-instance () + (let* ([doc (sorted-map entity-key (mk-uuid))] + [instance (mk-entity-instance entity-name entity-key initial-state states doc)]) + (instance 'init))] + + [ephemeral-get (entity-id ekey) + (ephem-get entity-name entity-id ekey)]) + + (lambda (op &rest args) + (cond ((equal? op 'name) (apply name args)) + ((equal? op 'new) (apply new-instance args)) + ((equal? op 'get) (apply storage-get args)) + ((equal? op 'del) (apply storage-del args)) + ((equal? op 'put) (apply storage-put args)) + + ((equal? op 'ephem-get) (apply ephemeral-get args)) + (:else (error 'unknown-operation op))))))) + + +;; ----------------------------------------------------------------------------- +;; Entity Instance +;; ----------------------------------------------------------------------------- +;; Instance with: +;; ('init) -> { "put": entity, "events": [] } +;; ('handle) -> advance one step given a connector response +;; +(defun mk-entity-instance (entity-name entity-key initial-state states entity) + (labels + ([init () + (when (nil? (get entity entity-key)) (assoc! entity entity-key (mk-uuid))) + (when (nil? (get entity "state")) (assoc! entity "state" initial-state)) + (sorted-map "put" entity "events" (vector))] + + [handle (resp) + (run-state-step entity-name entity-key entity resp)]) + + (lambda (op &rest args) + (cond ((equal? op 'init) (apply init args)) + ((equal? op 'handle) (apply handle args)) + (:else (error 'unknown-entity-op op)))))) + + +;; ----------------------------------------------------------------------------- +;; Step runner (no process-local ephemeral; uses staged ephemerals API) +;; ----------------------------------------------------------------------------- +(defun run-state-step (entity-name entity-key instance resp) + (let* ([state (get instance "state")] + [spec (lookup-state-spec state)] + + ;; 1) parse + [parsed ((spec-parse spec) resp instance)] + + ;; Look ahead to next state (constant per spec) + [next-state (spec-next spec)] + + ;; Prepare ctx for handlers that need ephems/id/state/next + [entity-id0 (get instance entity-key)] + [accessors (sorted-map + :state state + :next next-state + :entity-id entity-id0 + :get-ephem (lambda (k) (ephem-get entity-name entity-id0 k)))] + + ;; 2) stage-ephemeral (pure; can use ctx for dynamic drop-state/reads) + [staged-ephemeral ((spec-stage-ephemeral spec) instance parsed accessors)] + + ;; 3) stage-durable (pure) + [staged-durable ((spec-stage-durable spec) instance parsed accessors)] + + ;; Merge durable updates into the current entity. + [durable-entity + (cond + ((and (sorted-map? staged-durable) + (key? staged-durable entity-key)) staged-durable) ; full entity + ((sorted-map? staged-durable) (make-mergemap instance staged-durable)) ; diff + (:else instance))] + + ;; 4) events (pure; may read ephems via ctx) + [events ((spec-create-events spec) durable-entity parsed accessors)] + + [next-state (spec-next spec)] + [entity-id (get durable-entity entity-key)]) + + ;; persist staged ephemerals for the default drop-state = next-state + (when (and entity-id (> (length staged-ephemeral) 0)) + (ephem-persist-staged! entity-name entity-id next-state staged-ephemeral)) + + ;; advance state on the durable entity + (assoc! durable-entity "state" next-state) + + ;; purge ephemerals scheduled for the state we just entered + (when entity-id + (ephem-purge-for-state! entity-name entity-id next-state)) + + ;; return transition payload + (sorted-map + "put" durable-entity + "events" (if (vector? events) events (vector))))) + + +;; ---------------- Spec builder + defaults + accessors ---------------- + +(defun mk-state-handler (&key next parse stage-durable stage-ephemeral create-events) + (sorted-map + :next (or next "STATE_UNKNOWN") + :parse (or parse _noop-parse) + :stage-durable (or stage-durable _noop-stage-durable) + :stage-ephemeral (or stage-ephemeral _noop-stage-ephemeral) + :create-events (or create-events _noop-create-events))) + +;; safe defaults +(defun _noop-parse (resp entity) resp) + +;; return a vector of ephemeral intents (empty by default) +(defun _noop-stage-ephemeral (entity parsed accessors) (vector)) + +;; no durable changes by default +(defun _noop-stage-durable (entity parsed accessors) ()) + +;; no events by default +(defun _noop-create-events (entity parsed accessors) (vector)) + +;; registry / lookup +(defun lookup-state-spec (state) + (or (get state-spec state) (sorted-map))) + +;; accessors (with fallbacks) +(defun spec-next (spec) (or (get spec :next) "STATE_UNKNOWN")) +(defun spec-parse (spec) (or (get spec :parse) _noop-parse)) +(defun spec-stage-ephemeral (spec) (or (get spec :stage-ephemeral) _noop-stage-ephemeral)) +(defun spec-stage-durable (spec) (or (get spec :stage-durable) _noop-stage-durable)) +(defun spec-create-events (spec) (or (get spec :create-events) _noop-create-events)) \ No newline at end of file