Files

277 lines
6.5 KiB
Go

package lib
import (
"fmt"
"net/http"
"os"
"path/filepath"
"time"
"github.com/google/uuid"
"github.com/gorilla/sessions"
"github.com/johnfercher/maroto/v2"
"github.com/johnfercher/maroto/v2/pkg/components/col"
"github.com/johnfercher/maroto/v2/pkg/components/image"
"github.com/johnfercher/maroto/v2/pkg/components/row"
"github.com/johnfercher/maroto/v2/pkg/components/text"
"github.com/johnfercher/maroto/v2/pkg/config"
"github.com/johnfercher/maroto/v2/pkg/consts/align"
"github.com/johnfercher/maroto/v2/pkg/consts/fontstyle"
"github.com/johnfercher/maroto/v2/pkg/core"
"github.com/johnfercher/maroto/v2/pkg/props"
"github.com/labstack/echo/v4"
"golang.org/x/crypto/bcrypt"
"github.com/hazemKrimi/crimson-vault/internal/types"
)
func GetConfigDirectoryPath() (string, error) {
home, err := os.UserHomeDir()
if err != nil {
return "", err
}
config, err := filepath.Abs(filepath.Join(home, DEFAULT_CONFIG_DIRECTORY))
return config, nil
}
func SaveSession(session *sessions.Session, context echo.Context) error {
if err := session.Save(context.Request(), context.Response()); err != nil {
return types.Error{Code: http.StatusInternalServerError, Cause: err, Messages: []string{"Unexpected error saving User session!"}}
}
return nil
}
func CreateSession(session *sessions.Session, context echo.Context, user *types.User) error {
if err := uuid.Validate(user.SessionID); err != nil {
return types.Error{Code: http.StatusInternalServerError, Cause: err, Messages: []string{"Unexpected error saving User session!"}}
}
session.Options = &sessions.Options{
Path: "/",
MaxAge: 3600,
HttpOnly: true,
}
session.Values["id"] = user.ID
session.Values["sessionId"] = user.SessionID
session.Values["username"] = user.Username
if err := SaveSession(session, context); err != nil {
return types.Error{Code: http.StatusInternalServerError, Cause: err, Messages: []string{"Unexpected error saving User session!"}}
}
return nil
}
func DeleteSession(session *sessions.Session, context echo.Context) error {
session.Options.MaxAge = -1
if err := SaveSession(session, context); err != nil {
return types.Error{Code: http.StatusInternalServerError, Cause: err, Messages: []string{"Unexpected error saving User session!"}}
}
return nil
}
func HashPassword(password string) (string, error) {
bytes, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
return string(bytes), err
}
func CheckPasswordHash(password, hash string) bool {
err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
return err == nil
}
func getGrayColor() *props.Color {
return &props.Color{
Red: 200,
Green: 200,
Blue: 200,
}
}
func getDarkGrayColor() *props.Color {
return &props.Color{
Red: 200,
Green: 200,
Blue: 200,
}
}
func getBlueColor() *props.Color {
return &props.Color{
Red: 10,
Green: 10,
Blue: 150,
}
}
func getRedColor() *props.Color {
return &props.Color{
Red: 150,
Green: 10,
Blue: 10,
}
}
func getPageHeader(client types.Client, logo string) core.Row {
return row.New(20).Add(
image.NewFromFileCol(3, logo, props.Rect{
Center: true,
Percent: 80,
}),
col.New(6),
col.New(3).Add(
text.New(fmt.Sprintf("%s, %s, %s", client.Address, client.Zip, client.Country), props.Text{
Size: 8,
Align: align.Right,
Color: getRedColor(),
}),
text.New(client.Phone, props.Text{
Top: 12,
Style: fontstyle.BoldItalic,
Size: 8,
Align: align.Right,
Color: getBlueColor(),
}),
),
)
}
func getPageFooter(user types.User) core.Row {
return row.New(20).Add(
col.New(12).Add(
text.New(user.Phone, props.Text{
Top: 13,
Style: fontstyle.BoldItalic,
Size: 8,
Align: align.Left,
Color: getBlueColor(),
}),
),
)
}
func getTransactions(items []types.Item) []core.Row {
rows := []core.Row{
row.New(5).Add(
col.New(3),
text.NewCol(4, "Service", props.Text{Size: 9, Align: align.Center, Style: fontstyle.Bold}),
text.NewCol(2, "Quantity", props.Text{Size: 9, Align: align.Center, Style: fontstyle.Bold}),
text.NewCol(3, "Price", props.Text{Size: 9, Align: align.Center, Style: fontstyle.Bold}),
),
}
var contentsRow []core.Row
for i, item := range items {
r := row.New(4).Add(
col.New(3),
text.NewCol(4, item.Name, props.Text{Size: 8, Align: align.Center}),
text.NewCol(2, fmt.Sprintf("%d", item.Quantity), props.Text{Size: 8, Align: align.Center}),
text.NewCol(3, fmt.Sprintf("%.2f", item.Price), props.Text{Size: 8, Align: align.Center}),
)
if i%2 == 0 {
gray := getGrayColor()
r.WithStyle(&props.Cell{BackgroundColor: gray})
}
contentsRow = append(contentsRow, r)
}
rows = append(rows, contentsRow...)
rows = append(rows, row.New(20).Add(
col.New(7),
text.NewCol(2, "Total:", props.Text{
Top: 5,
Style: fontstyle.Bold,
Size: 8,
Align: align.Right,
}),
text.NewCol(3, "$2.567,00", props.Text{
Top: 5,
Style: fontstyle.Bold,
Size: 8,
Align: align.Center,
}),
))
return rows
}
func GenerateInvoice(invoice types.Invoice, user types.User, client types.Client) (string, error) {
cfg := config.NewBuilder().WithPageNumber().WithLeftMargin(10).WithRightMargin(10).WithTopMargin(15).Build()
darkGray := getDarkGrayColor()
mrt := maroto.New(cfg)
m := maroto.NewMetricsDecorator(mrt)
err := m.RegisterHeader(getPageHeader(client, user.Logo))
if err != nil {
return "", err
}
err = m.RegisterFooter(getPageFooter(user))
if err != nil {
return "", err
}
m.AddRows(text.NewRow(10, fmt.Sprintf("Invoice %s", invoice.ID), props.Text{
Top: 3,
Style: fontstyle.Bold,
Align: align.Center,
}))
m.AddRow(7,
text.NewCol(3, "Items", props.Text{
Top: 1.5,
Size: 9,
Style: fontstyle.Bold,
Align: align.Center,
Color: &props.WhiteColor,
}),
).WithStyle(&props.Cell{BackgroundColor: darkGray})
m.AddRows(getTransactions(invoice.Items)...)
document, err := m.Generate()
if err != nil {
return "", err
}
configDir, err := GetConfigDirectoryPath()
if err != nil {
return "", err
}
invoicesDir := filepath.Join(configDir, user.Username, client.ID)
if err := os.MkdirAll(invoicesDir, os.ModePerm); err != nil {
return "", err
}
invoiceFileName := fmt.Sprintf("%s.pdf", invoice.ID)
invoicePath := filepath.Join(invoicesDir, invoiceFileName)
err = document.Save(invoicePath)
if err != nil {
return "", err
}
return invoicePath, nil
}
func GenerateInvoiceReference(invoiceNumber uint32) string {
year, _, _ := time.Now().Date()
return fmt.Sprintf("INV/%d/%05d", year, invoiceNumber)
}