114 lines
2.8 KiB
Go
114 lines
2.8 KiB
Go
package httpinvoce
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"time"
|
|
|
|
"git.schreifuchs.ch/lou-taylor/accounting/internal/email"
|
|
"git.schreifuchs.ch/lou-taylor/accounting/pkg/invoice"
|
|
)
|
|
|
|
const bufSize = 1024 * 1024 // 1Mib
|
|
|
|
func (s Service) createInvoice(w http.ResponseWriter, r *http.Request) {
|
|
var req invoiceReq
|
|
|
|
err := json.NewDecoder(r.Body).Decode(&req)
|
|
if err != nil {
|
|
s.sendErr(w, http.StatusBadRequest, "cannot read body")
|
|
return
|
|
}
|
|
|
|
repos, err := req.GetRepos()
|
|
if err != nil {
|
|
s.sendErr(w, http.StatusInternalServerError, "cannot get repos")
|
|
return
|
|
}
|
|
|
|
opts := invoice.DefaultOptions
|
|
opts.Mindur = time.Duration(req.DurationThreshold)
|
|
invoice, report, err := s.invoice.Generate(req.Creditor, &req.Debtor, req.HourlyRate, repos, &opts)
|
|
if err != nil {
|
|
s.sendErr(w, http.StatusInternalServerError, "internal server error")
|
|
return
|
|
}
|
|
// if no time has to be billed aka if bill for 0 CHF
|
|
if report.Total() <= time.Duration(0) {
|
|
s.sendErrf(w, http.StatusNotFound, "no suitable issues to be billed")
|
|
return
|
|
}
|
|
|
|
w.Header().Set("Content-type", "application/pdf")
|
|
w.Header().Set(
|
|
"Content-Disposition",
|
|
fmt.Sprintf("attachment; filename=\"%s\"", invoiceName()),
|
|
)
|
|
|
|
_, err = io.Copy(w, invoice)
|
|
if err != nil {
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
return
|
|
}
|
|
}
|
|
|
|
func (s Service) sendInvoice(w http.ResponseWriter, r *http.Request) {
|
|
var req sendReq
|
|
err := json.NewDecoder(r.Body).Decode(&req)
|
|
if err != nil {
|
|
s.sendErrf(w, http.StatusBadRequest, "cannot read body: %v", err)
|
|
return
|
|
}
|
|
|
|
repos, err := req.Invoice.GetRepos()
|
|
if err != nil {
|
|
s.sendErr(w, 500, err.Error())
|
|
return
|
|
}
|
|
|
|
opts := invoice.DefaultOptions
|
|
opts.Mindur = time.Duration(req.Invoice.DurationThreshold)
|
|
invoice, report, err := s.invoice.Generate(req.Invoice.Creditor, &req.Invoice.Debtor, req.Invoice.HourlyRate, repos, &opts)
|
|
if err != nil {
|
|
s.sendErr(w, http.StatusInternalServerError, "error while processing invoice:", err)
|
|
return
|
|
}
|
|
|
|
// if no time has to be billed aka if bill for 0 CHF
|
|
if report.Total() <= time.Duration(0) {
|
|
s.sendErr(w, http.StatusNotFound, "no suitable issues to be billed")
|
|
return
|
|
}
|
|
|
|
invoiceData, err := io.ReadAll(invoice)
|
|
if err != nil {
|
|
s.sendErrf(w, http.StatusInternalServerError, "error while creating pdf: %v", err)
|
|
return
|
|
}
|
|
|
|
mail := req.ToEMail()
|
|
mail.Attachments = append(mail.Attachments, email.Attachment{
|
|
Name: invoiceName(),
|
|
MimeType: "application/pdf",
|
|
Content: bytes.NewReader(invoiceData),
|
|
})
|
|
|
|
err = s.mail.Send(mail)
|
|
if err != nil {
|
|
s.sendErrf(w, http.StatusInternalServerError, "error while sending mail: %v", err)
|
|
return
|
|
}
|
|
|
|
_, err = w.Write(invoiceData)
|
|
if err != nil {
|
|
s.sendErr(w, http.StatusInternalServerError, "")
|
|
}
|
|
}
|
|
|
|
func invoiceName() string {
|
|
return fmt.Sprintf("%s_invoice.pdf", time.Now().Format("20060102"))
|
|
}
|