From 220c5d24a375e7668821c3b651198fbd64b8fe88 Mon Sep 17 00:00:00 2001 From: Serge Bazanski Date: Mon, 16 Nov 2020 22:04:23 +0100 Subject: [PATCH] invoice: move validation to separate layer, validate GTU/SP codes Change-Id: I0af85b054356eaae81b528e5e64bf74c10bd3ae4 --- bgpwtf/invoice/BUILD.bazel | 1 + bgpwtf/invoice/main.go | 38 +---------- bgpwtf/invoice/validation.go | 123 +++++++++++++++++++++++++++++++++++ 3 files changed, 126 insertions(+), 36 deletions(-) create mode 100644 bgpwtf/invoice/validation.go diff --git a/bgpwtf/invoice/BUILD.bazel b/bgpwtf/invoice/BUILD.bazel index c85bb4d9..900f0b3c 100644 --- a/bgpwtf/invoice/BUILD.bazel +++ b/bgpwtf/invoice/BUILD.bazel @@ -8,6 +8,7 @@ go_library( "model.go", "render.go", "statusz.go", + "validation.go", ], importpath = "code.hackerspace.pl/hscloud/bgpwtf/invoice", visibility = ["//visibility:private"], diff --git a/bgpwtf/invoice/main.go b/bgpwtf/invoice/main.go index d93034ca..5133010a 100644 --- a/bgpwtf/invoice/main.go +++ b/bgpwtf/invoice/main.go @@ -23,42 +23,8 @@ type service struct { } func (s *service) CreateInvoice(ctx context.Context, req *pb.CreateInvoiceRequest) (*pb.CreateInvoiceResponse, error) { - if req.InvoiceData == nil { - return nil, status.Error(codes.InvalidArgument, "invoice data must be given") - } - if len(req.InvoiceData.Item) < 1 { - return nil, status.Error(codes.InvalidArgument, "invoice data must contain at least one item") - } - for i, item := range req.InvoiceData.Item { - if item.Title == "" { - return nil, status.Errorf(codes.InvalidArgument, "invoice data item %d must have title set", i) - } - if item.Count == 0 || item.Count > 1000000 { - return nil, status.Errorf(codes.InvalidArgument, "invoice data item %d must have correct count", i) - } - if item.UnitPrice == 0 { - return nil, status.Errorf(codes.InvalidArgument, "invoice data item %d must have correct unit price", i) - } - if item.Vat > 100000 { - return nil, status.Errorf(codes.InvalidArgument, "invoice data item %d must have correct vat set", i) - } - } - if len(req.InvoiceData.CustomerBilling) < 1 { - return nil, status.Error(codes.InvalidArgument, "invoice data must contain at least one line of the customer's billing address") - } - if len(req.InvoiceData.InvoicerBilling) < 1 { - return nil, status.Error(codes.InvalidArgument, "invoice data must contain at least one line of the invoicer's billing address") - } - for i, c := range req.InvoiceData.InvoicerContact { - if c.Medium == "" { - return nil, status.Errorf(codes.InvalidArgument, "contact point %d must have medium set", i) - } - if c.Contact == "" { - return nil, status.Errorf(codes.InvalidArgument, "contact point %d must have contact set", i) - } - } - if req.InvoiceData.InvoicerVatId == "" { - return nil, status.Error(codes.InvalidArgument, "invoice data must contain invoicer's vat id") + if err := validateInvoiceData(req.InvoiceData); err != nil { + return nil, status.Errorf(codes.InvalidArgument, "invoice data: %v", err) } uid, err := s.m.createInvoice(ctx, req.InvoiceData) diff --git a/bgpwtf/invoice/validation.go b/bgpwtf/invoice/validation.go new file mode 100644 index 00000000..d9fd820d --- /dev/null +++ b/bgpwtf/invoice/validation.go @@ -0,0 +1,123 @@ +package main + +import ( + "fmt" + + pb "code.hackerspace.pl/hscloud/bgpwtf/invoice/proto" +) + +// validateGTUCodde returns a non-nil error if the given GTU (Grupy Towarów i +// Usług) code is invalid. +func validateGTUCode(c pb.GTUCode) error { + switch c { + case pb.GTUCode_GTU_01: + case pb.GTUCode_GTU_02: + case pb.GTUCode_GTU_03: + case pb.GTUCode_GTU_04: + case pb.GTUCode_GTU_05: + case pb.GTUCode_GTU_06: + case pb.GTUCode_GTU_07: + case pb.GTUCode_GTU_09: + case pb.GTUCode_GTU_10: + case pb.GTUCode_GTU_11: + case pb.GTUCode_GTU_12: + case pb.GTUCode_GTU_13: + default: + return fmt.Errorf("must be 1-13, is %d", c) + } + return nil +} + +// validateGTUCodde returns a non-nil error if the given SP (Symbol Procedury) +// code is invalid. +func validateSPCode(c pb.SPCode) error { + switch c { + case pb.SPCode_SP_SW: + case pb.SPCode_SP_EE: + case pb.SPCode_SP_TP: + case pb.SPCode_SP_TT_WNT: + case pb.SPCode_SP_TT_D: + case pb.SPCode_SP_MR_T: + case pb.SPCode_SP_MR_UZ: + case pb.SPCode_SP_I_42: + case pb.SPCode_SP_I_63: + case pb.SPCode_SP_B_SPV: + case pb.SPCode_SP_B_SPV_DOSTAWA: + case pb.SPCode_SP_B_MPV_PROWIZJA: + case pb.SPCode_SP_MPP: + default: + return fmt.Errorf("unsupported value") + } + return nil +} + +// validateItem returns a non-nil error if the given Item is invalid as part of +// an InvoiceData when an invoice is being created. +func validateItem(i *pb.Item) error { + if i.Title == "" { + return fmt.Errorf("must have title set") + } + if i.Count == 0 || i.Count > 1000000 { + return fmt.Errorf("must have correct count") + } + if i.UnitPrice == 0 { + return fmt.Errorf("must have correct unit price") + } + if i.Vat > 100000 { + return fmt.Errorf("must have correct vat set") + } + for i, code := range i.GtuCode { + if err := validateGTUCode(code); err != nil { + return fmt.Errorf("GTU code %d: %v", i, err) + } + } + return nil +} + +// validateContactPoint returns a non-nil error if the given ContactPoint is +// invalid as part of an InvoiceData when an invoice is being created. +func validateContactPoint(cp *pb.ContactPoint) error { + if cp.Medium == "" { + return fmt.Errorf("must have medium set") + } + if cp.Contact == "" { + return fmt.Errorf("must have contact set") + } + return nil +} + +// validateInvoiceData returns a non-nil error if the given InvoiceData cannot +// be used to createa new invoice. +func validateInvoiceData(id *pb.InvoiceData) error { + if id == nil { + return fmt.Errorf("must be given") + } + if len(id.Item) < 1 { + return fmt.Errorf("must contain at least one item") + } + for i, item := range id.Item { + if err := validateItem(item); err != nil { + return fmt.Errorf("invoice data item %d: %v", i, err) + } + } + if len(id.CustomerBilling) < 1 { + return fmt.Errorf("must contain at least one line of the customer's billing address") + } + if len(id.InvoicerBilling) < 1 { + return fmt.Errorf("must contain at least one line of the invoicer's billing address") + } + for i, c := range id.InvoicerContact { + if err := validateContactPoint(c); err != nil { + return fmt.Errorf("contact point %d: %v", i, err) + } + } + if id.InvoicerVatId == "" { + return fmt.Errorf("must contain invoicer's vat id") + } + for i, code := range id.SpCode { + if err := validateSPCode(code); err != nil { + return fmt.Errorf("SP code %d: %v", i, err) + } + } + return nil +}