generated from vshn/go-bootstrap
-
Notifications
You must be signed in to change notification settings - Fork 0
/
invoice_command.go
142 lines (118 loc) · 4.3 KB
/
invoice_command.go
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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
package main
import (
"database/sql"
_ "embed"
"fmt"
"os"
"path/filepath"
"time"
"github.com/appuio/appuio-cloud-reporting/pkg/db"
reportinvoice "github.com/appuio/appuio-cloud-reporting/pkg/invoice"
"github.com/go-logr/logr"
"github.com/urfave/cli/v2"
"gopkg.in/yaml.v3"
"github.com/vshn/appuio-odoo-adapter/invoice"
"github.com/vshn/appuio-odoo-adapter/invoice/desctmpl"
"github.com/vshn/appuio-odoo-adapter/odoo"
"github.com/vshn/appuio-odoo-adapter/odoo/model"
)
//go:embed invoice-defaults.yaml
var invoiceDefaultsYAML string
type invoiceCommand struct {
OdooURL string
DatabaseURL string
Year int
Month time.Month
InvoiceDefaultsPath string
ItemDescriptionTemplatesPath string
InvoiceTitle string
}
var invoiceCommandName = "invoice"
func newinvoiceCommand() *cli.Command {
command := &invoiceCommand{}
return &cli.Command{
Name: invoiceCommandName,
Usage: "Create Odoo invoices from APPUiO Cloud",
Action: command.execute,
Flags: []cli.Flag{
newOdooURLFlag(&command.OdooURL),
newDatabaseURLFlag(&command.DatabaseURL),
&cli.IntFlag{Name: "year", Usage: "Year to generate the report for.",
EnvVars: envVars("YEAR"), Destination: &command.Year, Required: true, Base: 10},
&cli.IntFlag{Name: "month", Usage: "Month to generate the report for.",
EnvVars: envVars("MONTH"), Destination: (*int)(&command.Month), Required: true, Base: 10},
&cli.StringFlag{Name: "invoice-defaults-path", Usage: "Path to a file with invoice defaults.",
EnvVars: envVars("INVOICE_DEFAULTS_PATH"), Destination: &command.InvoiceDefaultsPath, Required: false},
&cli.StringFlag{Name: "item-description-templates-path", Usage: "Path to a directory with templates. The Files must be named `PRODUCT_SOURCE.gotmpl`.",
EnvVars: envVars("ITEM_DESCRIPTION_TEMPLATES_PATH"), Destination: &command.ItemDescriptionTemplatesPath, Value: "description_templates/", Required: false},
&cli.StringFlag{Name: "invoice-title", Usage: "Title of the generated invoice.",
EnvVars: envVars("INVOICE_TITLE"), Destination: &command.InvoiceTitle, Value: "APPUiO Cloud", Required: false},
},
}
}
func (cmd *invoiceCommand) execute(context *cli.Context) error {
ctx := context.Context
_ = LogMetadata(context)
log := AppLogger(context).WithName(invoiceCommandName)
invDefault, invLineDefault, err := cmd.loadInvoiceDefaults()
if err != nil {
return fmt.Errorf("failed to load defaults: %w", err)
}
odooCtx := logr.NewContext(context.Context, log)
log.V(1).Info("Logging in to Odoo...")
session, err := odoo.Open(odooCtx, cmd.OdooURL, odoo.ClientOptions{UseDebugLogger: context.Bool("debug")})
if err != nil {
return err
}
log.Info("login succeeded", "uid", session.UID)
o := model.NewOdoo(session)
log.V(1).Info("Opening database connection...")
rdb, err := db.Openx(cmd.DatabaseURL)
if err != nil {
return err
}
defer rdb.Close()
log.V(1).Info("Begin transaction")
tx, err := rdb.BeginTxx(ctx, &sql.TxOptions{ReadOnly: true})
if err != nil {
return err
}
defer tx.Rollback()
invoices, err := reportinvoice.Generate(ctx, tx, cmd.Year, cmd.Month)
if err != nil {
return err
}
descTemplates, err := desctmpl.ItemDescriptionTemplateRendererFromFS(os.DirFS(cmd.ItemDescriptionTemplatesPath), ".gotmpl")
if err != nil {
return fmt.Errorf("error loading templates for item description: %w", err)
}
for _, inv := range invoices {
id, err := invoice.CreateInvoice(ctx, o, inv, cmd.InvoiceTitle,
invoice.WithInvoiceDefaults(invDefault),
invoice.WithInvoiceLineDefaults(invLineDefault),
invoice.WithItemDescriptionRenderer(descTemplates),
)
if err != nil {
return fmt.Errorf("error creating invoice %+v: %w", inv, err)
}
log.Info("Created invoice", "id", id)
}
return nil
}
func (cmd *invoiceCommand) loadInvoiceDefaults() (model.Invoice, model.InvoiceLine, error) {
type load struct {
Invoice model.Invoice `yaml:"invoice"`
InvoiceLine model.InvoiceLine `yaml:"invoice_line"`
}
raw := []byte(invoiceDefaultsYAML)
if cmd.InvoiceDefaultsPath != "" {
var err error
raw, err = os.ReadFile(filepath.Join(".", cmd.InvoiceDefaultsPath))
if err != nil {
return model.Invoice{}, model.InvoiceLine{}, fmt.Errorf("error reading defaults file: %w", err)
}
}
var out load
err := yaml.Unmarshal([]byte(raw), &out)
return out.Invoice, out.InvoiceLine, err
}