File size: 2,553 Bytes
5a22efd
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
package sequence

import (
	"fmt"
	"slices"
	"strings"

	"github.com/openmeterio/openmeter/pkg/currencyx"
)

type NextSequenceNumberInput struct {
	Namespace string
	Scope     string
}

func (n NextSequenceNumberInput) Validate() error {
	if n.Namespace == "" {
		return fmt.Errorf("namespace is required")
	}

	if n.Scope == "" {
		return fmt.Errorf("scope is required")
	}

	return nil
}

type Definition struct {
	Prefix         string
	SuffixTemplate string
	Scope          string
	CommitMode     CommitMode
}

func (d Definition) Validate() error {
	if d.Prefix == "" {
		return fmt.Errorf("prefix is required")
	}

	if d.SuffixTemplate == "" {
		return fmt.Errorf("suffix template is required")
	}

	if d.Scope == "" {
		return fmt.Errorf("scope is required")
	}

	if err := d.CommitMode.Validate(); err != nil {
		return err
	}

	return nil
}

func (d Definition) PrefixMatches(s string) bool {
	return strings.HasPrefix(s, d.Prefix+"-")
}

// CommitMode controls when a sequence allocation is committed. WithCaller
// allows the number to be reused if the caller rolls back; Independent retains
// the allocation despite caller rollback, which can create gaps.
type CommitMode string

const (
	CommitModeWithCaller  CommitMode = "with_caller"
	CommitModeIndependent CommitMode = "independent"
)

func (m CommitMode) Validate() error {
	if m == "" {
		return fmt.Errorf("commit mode is required")
	}

	if !slices.Contains([]CommitMode{CommitModeWithCaller, CommitModeIndependent}, m) {
		return fmt.Errorf("commit mode is invalid: %s", m)
	}

	return nil
}

var (
	GatheringInvoiceSequenceNumber = Definition{
		Prefix:         "GATHER",
		SuffixTemplate: "{{.CustomerPrefix}}-{{.Currency}}-{{.NextSequenceNumber}}",
		Scope:          "invoices/gathering",
		CommitMode:     CommitModeIndependent,
	}
	DraftInvoiceSequenceNumber = Definition{
		Prefix:         "DRAFT",
		SuffixTemplate: "{{.CustomerPrefix}}-{{.NextSequenceNumber}}",
		Scope:          "invoices/draft",
		// Draft numbers are temporary and replaced by the invoicing app's final
		// invoice number, so gaps from retained allocations are acceptable.
		CommitMode: CommitModeIndependent,
	}
)

type GenerationInput struct {
	Namespace    string
	CustomerName string
	Currency     currencyx.Code
}

func (i GenerationInput) Validate() error {
	if i.CustomerName == "" {
		return fmt.Errorf("customer name is required")
	}

	if i.Currency == "" {
		return fmt.Errorf("currency is required")
	}

	if i.Namespace == "" {
		return fmt.Errorf("namespace is required")
	}

	return nil
}