Compare commits
11 Commits
8ce01417e7
...
priceCalcu
| Author | SHA1 | Date | |
|---|---|---|---|
|
249cccd240
|
|||
|
db3dc9ecd1
|
|||
|
b75c46ec2f
|
|||
|
16c68cd0f8
|
|||
|
ad5573ee2c
|
|||
|
6c0440f06d
|
|||
|
9e638dcfc2
|
|||
|
6c59d1233f
|
|||
|
7025f526c1
|
|||
|
992b9c17c3
|
|||
|
4b0649439c
|
@@ -21,6 +21,9 @@ type ConfigController interface {
|
|||||||
PaperHandler(*gin.Context)
|
PaperHandler(*gin.Context)
|
||||||
AddPaperHandler(*gin.Context)
|
AddPaperHandler(*gin.Context)
|
||||||
|
|
||||||
|
InvoiceView(*gin.Context)
|
||||||
|
InvoiceHandler(*gin.Context)
|
||||||
|
|
||||||
CreateTag(*gin.Context)
|
CreateTag(*gin.Context)
|
||||||
GetAllTags(*gin.Context)
|
GetAllTags(*gin.Context)
|
||||||
TagView(*gin.Context)
|
TagView(*gin.Context)
|
||||||
@@ -208,6 +211,35 @@ func (rc *configController) GetAllPaper(c *gin.Context) {
|
|||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
func (rc *configController) InvoiceView(c *gin.Context) {
|
||||||
|
invoices, err := repositories.Invoices.GetAllNewestFirst()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
c.HTML(http.StatusBadRequest, "invoiceview.html", gin.H{"data": gin.H{"error": err}})
|
||||||
|
}
|
||||||
|
|
||||||
|
data := CreateSessionData(c, gin.H{
|
||||||
|
"invoices": invoices,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
c.HTML(http.StatusBadRequest, "invoiceview.html", data)
|
||||||
|
}
|
||||||
|
|
||||||
|
c.HTML(http.StatusOK, "invoiceview.html", data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rc *configController) InvoiceHandler(ctx *gin.Context) {
|
||||||
|
action := ctx.PostForm("action")
|
||||||
|
if action == "delete" {
|
||||||
|
repositories.Invoices.DeleteById(ctx.Param("id"))
|
||||||
|
}
|
||||||
|
|
||||||
|
rc.InvoiceView(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
func (rc *configController) TagHandler(ctx *gin.Context) {
|
func (rc *configController) TagHandler(ctx *gin.Context) {
|
||||||
name := ctx.PostForm("name")
|
name := ctx.PostForm("name")
|
||||||
color := ctx.PostForm("color")
|
color := ctx.PostForm("color")
|
||||||
|
|||||||
@@ -2,13 +2,11 @@ package controllers
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"git.dynamicdiscord.de/kalipso/zineshop/models"
|
"git.dynamicdiscord.de/kalipso/zineshop/models"
|
||||||
"git.dynamicdiscord.de/kalipso/zineshop/repositories"
|
"git.dynamicdiscord.de/kalipso/zineshop/repositories"
|
||||||
"git.dynamicdiscord.de/kalipso/zineshop/utils"
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -115,6 +113,7 @@ func (rc *printController) PrintHandler(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var printJobs []models.PrintJob
|
var printJobs []models.PrintJob
|
||||||
|
priceTotal := 0.0
|
||||||
for idx := range variantIds {
|
for idx := range variantIds {
|
||||||
variant, err := repositories.ShopItems.GetVariantById(variantIds[idx])
|
variant, err := repositories.ShopItems.GetVariantById(variantIds[idx])
|
||||||
|
|
||||||
@@ -136,47 +135,15 @@ func (rc *printController) PrintHandler(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var coverPage models.Paper
|
var coverPage *models.Paper
|
||||||
doPrintCoverpage := false
|
|
||||||
if variantCoverPages[idx] != "0" {
|
if variantCoverPages[idx] != "0" {
|
||||||
coverPage, err = repositories.Papers.GetById(fmt.Sprintf("%v", variantCoverPages[idx]))
|
coverPageTmp, err := repositories.Papers.GetById(fmt.Sprintf("%v", variantCoverPages[idx]))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.HTML(http.StatusBadRequest, "error.html", gin.H{"data": gin.H{"error": err}})
|
c.HTML(http.StatusBadRequest, "error.html", gin.H{"data": gin.H{"error": err}})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
doPrintCoverpage = true
|
coverPage = &coverPageTmp
|
||||||
}
|
|
||||||
|
|
||||||
calculatePrintCosts := func(shopItem models.ShopItem, paperType models.Paper, coverPagePaperType models.Paper, colored bool, amount int) (float64, error) {
|
|
||||||
pageCount := utils.CountPagesAtPath(shopItem.Pdf)
|
|
||||||
printMode := models.GetPrintMode(shopItem.PrintMode)
|
|
||||||
|
|
||||||
//Get actual pagecount depending on printmode
|
|
||||||
actualPageCount := pageCount
|
|
||||||
|
|
||||||
if printMode == models.CreateBooklet {
|
|
||||||
dividedCount := float64(pageCount) / 4.0
|
|
||||||
actualPageCount = int(math.Ceil(dividedCount))
|
|
||||||
}
|
|
||||||
|
|
||||||
if printMode == models.LongEdge || printMode == models.ShortEdge {
|
|
||||||
dividedCount := float64(pageCount) / 2.0
|
|
||||||
actualPageCount = int(math.Ceil(dividedCount))
|
|
||||||
}
|
|
||||||
|
|
||||||
PPC := 0.002604
|
|
||||||
partCost := 0.0067
|
|
||||||
if colored {
|
|
||||||
partCost = 0.0478
|
|
||||||
}
|
|
||||||
printingCosts := float64(actualPageCount) * paperType.Price
|
|
||||||
printingCosts += float64(actualPageCount/2) * PPC
|
|
||||||
printingCosts += partCost * float64(actualPageCount)
|
|
||||||
|
|
||||||
fmt.Printf("Printing Costs per Zine: %v\n", printingCosts)
|
|
||||||
fmt.Printf("Printing Costs Total: %v\n", printingCosts*float64(amount))
|
|
||||||
return printingCosts, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
variantAmount, err := strconv.Atoi(variantAmounts[idx])
|
variantAmount, err := strconv.Atoi(variantAmounts[idx])
|
||||||
@@ -187,26 +154,54 @@ func (rc *printController) PrintHandler(c *gin.Context) {
|
|||||||
|
|
||||||
fmt.Println("Printing Costs:")
|
fmt.Println("Printing Costs:")
|
||||||
|
|
||||||
colored := variant.Name == "Colored"
|
printJob, err := models.NewPrintJob(shopItem, variant, paperType, coverPage, uint(variantAmount))
|
||||||
calculatePrintCosts(shopItem, paperType, coverPage, colored, int(variantAmount))
|
|
||||||
|
|
||||||
printJob, err := models.NewPrintJob(shopItem, variant, doPrintCoverpage, uint(variantAmount))
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.HTML(http.StatusBadRequest, "error.html", gin.H{"data": gin.H{"error": err}})
|
c.HTML(http.StatusBadRequest, "error.html", gin.H{"data": gin.H{"error": err}})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
printJob.CalculatePrintCosts()
|
||||||
|
priceTotal += printJob.PriceTotal
|
||||||
printJobs = append(printJobs, printJob)
|
printJobs = append(printJobs, printJob)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
invoice := models.Invoice{
|
||||||
|
PrintJobs: printJobs,
|
||||||
|
PricePerClick: 0.002604,
|
||||||
|
PartCosts: 0.0067,
|
||||||
|
PriceTotal: priceTotal,
|
||||||
|
}
|
||||||
|
invoice, err := repositories.Invoices.Create(invoice)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
c.HTML(http.StatusBadRequest, "error.html", gin.H{"data": gin.H{"error": err}})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
executeJobs := func() {
|
executeJobs := func() {
|
||||||
for _, printJob := range printJobs {
|
for _, printJob := range printJobs {
|
||||||
printJob.Execute()
|
err := printJob.Execute()
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
printJob.ShopItem.WasPrinted = true
|
||||||
|
_, err = repositories.ShopItems.Update(printJob.ShopItem)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error: %s\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
go executeJobs()
|
go executeJobs()
|
||||||
|
|
||||||
c.HTML(http.StatusOK, "index.html", nil)
|
fmt.Println(invoice)
|
||||||
|
data := CreateSessionData(c, gin.H{
|
||||||
|
"invoice": invoice,
|
||||||
|
})
|
||||||
|
|
||||||
|
c.HTML(http.StatusOK, "printstarted.html", data)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -161,6 +161,7 @@ func (rc *shopItemController) NewShopItemFromForm(ctx *gin.Context) (models.Shop
|
|||||||
Pdf: dstPdf,
|
Pdf: dstPdf,
|
||||||
Variants: variants,
|
Variants: variants,
|
||||||
PrintMode: printMode,
|
PrintMode: printMode,
|
||||||
|
WasPrinted: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("Creating Shopitem: ", shopItem)
|
fmt.Println("Creating Shopitem: ", shopItem)
|
||||||
@@ -400,6 +401,7 @@ func (rc *shopItemController) AddItemsHandler(c *gin.Context) {
|
|||||||
Pdf: dstPdf,
|
Pdf: dstPdf,
|
||||||
Variants: variants,
|
Variants: variants,
|
||||||
PrintMode: "CreateBooklet",
|
PrintMode: "CreateBooklet",
|
||||||
|
WasPrinted: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = repositories.ShopItems.Create(shopItem)
|
_, err = repositories.ShopItems.Create(shopItem)
|
||||||
@@ -537,6 +539,7 @@ func (rc *shopItemController) EditItemHandler(c *gin.Context) {
|
|||||||
newShopItem.Variants = shopItem.Variants
|
newShopItem.Variants = shopItem.Variants
|
||||||
newShopItem.BasePrice = shopItem.BasePrice
|
newShopItem.BasePrice = shopItem.BasePrice
|
||||||
newShopItem.IsPublic = shopItem.IsPublic
|
newShopItem.IsPublic = shopItem.IsPublic
|
||||||
|
newShopItem.WasPrinted = false
|
||||||
|
|
||||||
if len(shopItem.Tags) != 0 {
|
if len(shopItem.Tags) != 0 {
|
||||||
newShopItem.Tags = shopItem.Tags
|
newShopItem.Tags = shopItem.Tags
|
||||||
|
|||||||
15
go.mod
15
go.mod
@@ -6,7 +6,8 @@ require (
|
|||||||
github.com/gin-gonic/gin v1.10.0
|
github.com/gin-gonic/gin v1.10.0
|
||||||
github.com/golang-jwt/jwt/v5 v5.2.1
|
github.com/golang-jwt/jwt/v5 v5.2.1
|
||||||
github.com/joho/godotenv v1.5.1
|
github.com/joho/godotenv v1.5.1
|
||||||
golang.org/x/crypto v0.23.0
|
github.com/pdfcpu/pdfcpu v0.11.0
|
||||||
|
golang.org/x/crypto v0.38.0
|
||||||
gorm.io/driver/sqlite v1.5.7
|
gorm.io/driver/sqlite v1.5.7
|
||||||
gorm.io/gorm v1.25.12
|
gorm.io/gorm v1.25.12
|
||||||
)
|
)
|
||||||
@@ -22,22 +23,30 @@ require (
|
|||||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||||
github.com/go-playground/validator/v10 v10.20.0 // indirect
|
github.com/go-playground/validator/v10 v10.20.0 // indirect
|
||||||
github.com/goccy/go-json v0.10.2 // indirect
|
github.com/goccy/go-json v0.10.2 // indirect
|
||||||
|
github.com/hhrutter/lzw v1.0.0 // indirect
|
||||||
|
github.com/hhrutter/pkcs7 v0.2.0 // indirect
|
||||||
|
github.com/hhrutter/tiff v1.0.2 // indirect
|
||||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||||
github.com/jinzhu/now v1.1.5 // indirect
|
github.com/jinzhu/now v1.1.5 // indirect
|
||||||
github.com/json-iterator/go v1.1.12 // indirect
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
|
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
|
||||||
github.com/leodido/go-urn v1.4.0 // indirect
|
github.com/leodido/go-urn v1.4.0 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
|
github.com/mattn/go-runewidth v0.0.16 // indirect
|
||||||
github.com/mattn/go-sqlite3 v1.14.22 // indirect
|
github.com/mattn/go-sqlite3 v1.14.22 // indirect
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
|
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
|
||||||
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
|
github.com/rivo/uniseg v0.4.7 // indirect
|
||||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||||
github.com/ugorji/go/codec v1.2.12 // indirect
|
github.com/ugorji/go/codec v1.2.12 // indirect
|
||||||
golang.org/x/arch v0.8.0 // indirect
|
golang.org/x/arch v0.8.0 // indirect
|
||||||
|
golang.org/x/image v0.27.0 // indirect
|
||||||
golang.org/x/net v0.25.0 // indirect
|
golang.org/x/net v0.25.0 // indirect
|
||||||
golang.org/x/sys v0.20.0 // indirect
|
golang.org/x/sys v0.33.0 // indirect
|
||||||
golang.org/x/text v0.15.0 // indirect
|
golang.org/x/text v0.25.0 // indirect
|
||||||
google.golang.org/protobuf v1.34.1 // indirect
|
google.golang.org/protobuf v1.34.1 // indirect
|
||||||
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
31
go.sum
31
go.sum
@@ -30,6 +30,12 @@ github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVI
|
|||||||
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
||||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
|
github.com/hhrutter/lzw v1.0.0 h1:laL89Llp86W3rRs83LvKbwYRx6INE8gDn0XNb1oXtm0=
|
||||||
|
github.com/hhrutter/lzw v1.0.0/go.mod h1:2HC6DJSn/n6iAZfgM3Pg+cP1KxeWc3ezG8bBqW5+WEo=
|
||||||
|
github.com/hhrutter/pkcs7 v0.2.0 h1:i4HN2XMbGQpZRnKBLsUwO3dSckzgX142TNqY/KfXg+I=
|
||||||
|
github.com/hhrutter/pkcs7 v0.2.0/go.mod h1:aEzKz0+ZAlz7YaEMY47jDHL14hVWD6iXt0AgqgAvWgE=
|
||||||
|
github.com/hhrutter/tiff v1.0.2 h1:7H3FQQpKu/i5WaSChoD1nnJbGx4MxU5TlNqqpxw55z8=
|
||||||
|
github.com/hhrutter/tiff v1.0.2/go.mod h1:pcOeuK5loFUE7Y/WnzGw20YxUdnqjY1P0Jlcieb/cCw=
|
||||||
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
||||||
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||||
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
|
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
|
||||||
@@ -46,6 +52,8 @@ github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
|
|||||||
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
|
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
|
||||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
|
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
|
||||||
|
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||||
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
|
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
|
||||||
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
@@ -53,10 +61,17 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w
|
|||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||||
|
github.com/pdfcpu/pdfcpu v0.11.0 h1:mL18Y3hSHzSezmnrzA21TqlayBOXuAx7BUzzZyroLGM=
|
||||||
|
github.com/pdfcpu/pdfcpu v0.11.0/go.mod h1:F1ca4GIVFdPtmgvIdvXAycAm88noyNxZwzr9CpTy+Mw=
|
||||||
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
|
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
|
||||||
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
|
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
|
||||||
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||||
|
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
||||||
|
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||||
@@ -76,22 +91,26 @@ github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZ
|
|||||||
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||||
golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc=
|
golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc=
|
||||||
golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
|
golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
|
||||||
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
|
golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8=
|
||||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw=
|
||||||
|
golang.org/x/image v0.27.0 h1:C8gA4oWU/tKkdCfYT6T2u4faJu3MeNS5O8UPWlPF61w=
|
||||||
|
golang.org/x/image v0.27.0/go.mod h1:xbdrClrAUway1MUTEZDq9mz/UpRwYAkFFNUslZtcB+g=
|
||||||
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
|
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
|
||||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
|
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
|
||||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||||
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
|
golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=
|
||||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
|
google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
|
||||||
google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||||
|
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
|||||||
3
main.go
3
main.go
@@ -82,6 +82,9 @@ func main() {
|
|||||||
viewRoutes.GET("/paper/:id", userController.TagView)
|
viewRoutes.GET("/paper/:id", userController.TagView)
|
||||||
viewRoutes.POST("/paper", authValidator.RequireAdmin, configController.AddPaperHandler)
|
viewRoutes.POST("/paper", authValidator.RequireAdmin, configController.AddPaperHandler)
|
||||||
|
|
||||||
|
viewRoutes.GET("/invoice", authValidator.RequireAdmin, configController.InvoiceView)
|
||||||
|
viewRoutes.POST("/invoice/:id", authValidator.RequireAdmin, configController.InvoiceHandler)
|
||||||
|
|
||||||
viewRoutes.GET("/cart", authValidator.RequireAuth, cartItemController.CartItemView)
|
viewRoutes.GET("/cart", authValidator.RequireAuth, cartItemController.CartItemView)
|
||||||
viewRoutes.POST("/cart", authValidator.RequireAuth, cartItemController.AddItemHandler)
|
viewRoutes.POST("/cart", authValidator.RequireAuth, cartItemController.AddItemHandler)
|
||||||
viewRoutes.POST("/cart/delete", authValidator.RequireAuth, cartItemController.DeleteItemHandler)
|
viewRoutes.POST("/cart/delete", authValidator.RequireAuth, cartItemController.DeleteItemHandler)
|
||||||
|
|||||||
@@ -2,6 +2,9 @@ package models
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"git.dynamicdiscord.de/kalipso/zineshop/utils"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
"math"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
@@ -18,12 +21,36 @@ const (
|
|||||||
TriFold PrintOption = "-o Fold=TriFold -o Binding=TopBinding"
|
TriFold PrintOption = "-o Fold=TriFold -o Binding=TopBinding"
|
||||||
)
|
)
|
||||||
|
|
||||||
type PrintJob struct {
|
type OldPrintJob struct {
|
||||||
Pdf string
|
Pdf string
|
||||||
Amount uint
|
Amount uint
|
||||||
Options []PrintOption
|
Options []PrintOption
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Invoice struct {
|
||||||
|
gorm.Model
|
||||||
|
PrintJobs []PrintJob
|
||||||
|
PricePerClick float64
|
||||||
|
PartCosts float64
|
||||||
|
PriceTotal float64
|
||||||
|
}
|
||||||
|
|
||||||
|
type PrintJob struct {
|
||||||
|
gorm.Model
|
||||||
|
ShopItemID uint
|
||||||
|
ShopItem ShopItem
|
||||||
|
VariantID uint
|
||||||
|
Variant ItemVariant
|
||||||
|
PaperTypeId uint
|
||||||
|
PaperType Paper `gorm:"foreignKey:PaperTypeId"`
|
||||||
|
CoverPaperTypeId *uint
|
||||||
|
CoverPaperType *Paper `gorm:"foreignKey:CoverPaperTypeId"`
|
||||||
|
Amount uint
|
||||||
|
PricePerPiece float64
|
||||||
|
PriceTotal float64
|
||||||
|
InvoiceID uint
|
||||||
|
}
|
||||||
|
|
||||||
func GetPrintMode(mode string) PrintOption {
|
func GetPrintMode(mode string) PrintOption {
|
||||||
if mode == "LongEdge" {
|
if mode == "LongEdge" {
|
||||||
return LongEdge
|
return LongEdge
|
||||||
@@ -40,7 +67,7 @@ func GetPrintMode(mode string) PrintOption {
|
|||||||
return CreateBooklet
|
return CreateBooklet
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewPrintJob(shopItem ShopItem, variant ItemVariant, coverPage bool, amount uint) (PrintJob, error) {
|
func NewPrintJob(shopItem ShopItem, variant ItemVariant, paperType Paper, coverPaperType *Paper, amount uint) (PrintJob, error) {
|
||||||
if shopItem.Pdf == "" {
|
if shopItem.Pdf == "" {
|
||||||
return PrintJob{}, fmt.Errorf("ShopItem has no PDF assigned")
|
return PrintJob{}, fmt.Errorf("ShopItem has no PDF assigned")
|
||||||
}
|
}
|
||||||
@@ -49,32 +76,44 @@ func NewPrintJob(shopItem ShopItem, variant ItemVariant, coverPage bool, amount
|
|||||||
return PrintJob{}, fmt.Errorf("Amount to big. This is denied for security reasons")
|
return PrintJob{}, fmt.Errorf("Amount to big. This is denied for security reasons")
|
||||||
}
|
}
|
||||||
|
|
||||||
var result PrintJob
|
result := PrintJob{
|
||||||
result.Pdf = shopItem.Pdf
|
ShopItem: shopItem,
|
||||||
result.Amount = amount
|
Variant: variant,
|
||||||
|
PaperType: paperType,
|
||||||
if variant.Name == "Colored" {
|
CoverPaperType: coverPaperType,
|
||||||
result.Options = append(result.Options, Colored)
|
Amount: amount,
|
||||||
}
|
}
|
||||||
|
|
||||||
if coverPage {
|
|
||||||
result.Options = append(result.Options, CoverPage)
|
|
||||||
}
|
|
||||||
|
|
||||||
result.Options = append(result.Options, GetPrintMode(shopItem.PrintMode))
|
|
||||||
|
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *PrintJob) IsColored() bool {
|
||||||
|
return p.Variant.Name == "Colored"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PrintJob) GeneratePrintOptions() []PrintOption {
|
||||||
|
var result []PrintOption
|
||||||
|
if p.Variant.Name == "Colored" {
|
||||||
|
result = append(result, Colored)
|
||||||
|
}
|
||||||
|
|
||||||
|
if p.CoverPaperType != nil {
|
||||||
|
result = append(result, CoverPage)
|
||||||
|
}
|
||||||
|
|
||||||
|
result = append(result, GetPrintMode(p.ShopItem.PrintMode))
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
func (p *PrintJob) Execute() error {
|
func (p *PrintJob) Execute() error {
|
||||||
baseCommand := "lp -d KonicaBooklet"
|
baseCommand := "lp -d KonicaBooklet"
|
||||||
baseCommand += fmt.Sprintf(" -n %v ", p.Amount)
|
baseCommand += fmt.Sprintf(" -n %v ", p.Amount)
|
||||||
|
|
||||||
for _, option := range p.Options {
|
for _, option := range p.GeneratePrintOptions() {
|
||||||
baseCommand += fmt.Sprintf(" %v ", option)
|
baseCommand += fmt.Sprintf(" %v ", option)
|
||||||
}
|
}
|
||||||
|
|
||||||
baseCommand += fmt.Sprintf(" -- %s", p.Pdf)
|
baseCommand += fmt.Sprintf(" -- %s", p.ShopItem.Pdf)
|
||||||
|
|
||||||
parts := strings.Fields(baseCommand)
|
parts := strings.Fields(baseCommand)
|
||||||
|
|
||||||
@@ -91,3 +130,51 @@ func (p *PrintJob) Execute() error {
|
|||||||
fmt.Printf("Output:\n%s\n", output)
|
fmt.Printf("Output:\n%s\n", output)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *PrintJob) CalculatePrintCosts() (float64, error) {
|
||||||
|
pageCount := utils.CountPagesAtPath(p.ShopItem.Pdf)
|
||||||
|
|
||||||
|
if pageCount == 0 {
|
||||||
|
fmt.Println("Pagecount of 0 - something is wrong here.")
|
||||||
|
return 0, fmt.Errorf("Cant calculate price, pdf seems to be empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
printMode := GetPrintMode(p.ShopItem.PrintMode)
|
||||||
|
|
||||||
|
//Get actual pagecount depending on printmode
|
||||||
|
actualPageCount := pageCount
|
||||||
|
fmt.Println("PagCount: ", actualPageCount)
|
||||||
|
|
||||||
|
if printMode == CreateBooklet {
|
||||||
|
dividedCount := float64(pageCount) / 4.0
|
||||||
|
actualPageCount = int(math.Ceil(dividedCount))
|
||||||
|
}
|
||||||
|
|
||||||
|
if printMode == LongEdge || printMode == ShortEdge {
|
||||||
|
dividedCount := float64(pageCount) / 2.0
|
||||||
|
actualPageCount = int(math.Ceil(dividedCount))
|
||||||
|
}
|
||||||
|
|
||||||
|
PPC := 0.002604
|
||||||
|
partCost := 0.0067
|
||||||
|
if p.IsColored() {
|
||||||
|
partCost = 0.0478
|
||||||
|
}
|
||||||
|
|
||||||
|
printingCosts := float64(actualPageCount-1) * p.PaperType.Price
|
||||||
|
|
||||||
|
if p.CoverPaperType != nil {
|
||||||
|
printingCosts += p.CoverPaperType.Price
|
||||||
|
} else {
|
||||||
|
printingCosts += p.PaperType.Price
|
||||||
|
}
|
||||||
|
|
||||||
|
printingCosts += float64(actualPageCount/2) * PPC
|
||||||
|
printingCosts += partCost * float64(actualPageCount)
|
||||||
|
|
||||||
|
fmt.Printf("Printing Costs per Zine: %v\n", printingCosts)
|
||||||
|
fmt.Printf("Printing Costs Total: %v\n", printingCosts*float64(p.Amount))
|
||||||
|
p.PricePerPiece = printingCosts
|
||||||
|
p.PriceTotal = printingCosts * float64(p.Amount)
|
||||||
|
return printingCosts, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ type ItemVariant struct {
|
|||||||
type ShopItem struct {
|
type ShopItem struct {
|
||||||
gorm.Model
|
gorm.Model
|
||||||
Name string `json:"name" binding:"required" gorm:"unique;not null"`
|
Name string `json:"name" binding:"required" gorm:"unique;not null"`
|
||||||
Abstract string `json:"Abstract" binding:"required"`
|
Abstract string `json:"abstract" binding:"required"`
|
||||||
Description string `json:"description" binding:"required"`
|
Description string `json:"description" binding:"required"`
|
||||||
Category Category `json:"category"`
|
Category Category `json:"category"`
|
||||||
Variants []ItemVariant `json:"variant"`
|
Variants []ItemVariant `json:"variant"`
|
||||||
@@ -53,4 +53,5 @@ type ShopItem struct {
|
|||||||
Image string
|
Image string
|
||||||
Pdf string
|
Pdf string
|
||||||
PrintMode string `json:"printMode" gorm:"default:CreateBooklet"`
|
PrintMode string `json:"printMode" gorm:"default:CreateBooklet"`
|
||||||
|
WasPrinted bool `gorm:"default:false"`
|
||||||
}
|
}
|
||||||
|
|||||||
100
repositories/InvoiceRepository.go
Normal file
100
repositories/InvoiceRepository.go
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
package repositories
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"gorm.io/gorm"
|
||||||
|
|
||||||
|
"git.dynamicdiscord.de/kalipso/zineshop/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
type InvoiceRepository interface {
|
||||||
|
Create(models.Invoice) (models.Invoice, error)
|
||||||
|
GetAll() ([]models.Invoice, error)
|
||||||
|
GetAllSorted(string) ([]models.Invoice, error)
|
||||||
|
GetAllNewestFirst() ([]models.Invoice, error)
|
||||||
|
GetAllNewestLast() ([]models.Invoice, error)
|
||||||
|
GetById(string) (models.Invoice, error)
|
||||||
|
//GetByInvoiceId(string) (models.Invoice, error)
|
||||||
|
Update(models.Invoice) (models.Invoice, error)
|
||||||
|
DeleteById(string) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type GORMInvoiceRepository struct {
|
||||||
|
DB *gorm.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewGORMInvoiceRepository(db *gorm.DB) InvoiceRepository {
|
||||||
|
return &GORMInvoiceRepository{
|
||||||
|
DB: db,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *GORMInvoiceRepository) Create(invoice models.Invoice) (models.Invoice, error) {
|
||||||
|
result := t.DB.Create(&invoice)
|
||||||
|
|
||||||
|
if result.Error != nil {
|
||||||
|
return models.Invoice{}, result.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
return invoice, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *GORMInvoiceRepository) GetAll() ([]models.Invoice, error) {
|
||||||
|
var invoice []models.Invoice
|
||||||
|
result := t.DB.Preload("PrintJobs.ShopItem").Preload("PrintJobs.Variant").Preload("PrintJobs.PaperType").Preload("PrintJobs.CoverPaperType").Preload("PrintJobs").Find(&invoice)
|
||||||
|
|
||||||
|
return invoice, result.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *GORMInvoiceRepository) GetAllSorted(sortString string) ([]models.Invoice, error) {
|
||||||
|
var invoices []models.Invoice
|
||||||
|
result := t.DB.Preload("PrintJobs.ShopItem").Preload("PrintJobs.Variant").Preload("PrintJobs.PaperType").Preload("PrintJobs.CoverPaperType").Preload("PrintJobs").Order(sortString).Find(&invoices)
|
||||||
|
|
||||||
|
return invoices, result.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *GORMInvoiceRepository) GetAllNewestFirst() ([]models.Invoice, error) {
|
||||||
|
return r.GetAllSorted("created_at desc")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *GORMInvoiceRepository) GetAllNewestLast() ([]models.Invoice, error) {
|
||||||
|
return r.GetAllSorted("created_at asc")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *GORMInvoiceRepository) GetById(id string) (models.Invoice, error) {
|
||||||
|
invoiceId, err := strconv.Atoi(id)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return models.Invoice{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var invoice models.Invoice
|
||||||
|
result := t.DB.Preload("PrintJobs").First(&invoice, uint(invoiceId))
|
||||||
|
|
||||||
|
if result.Error != nil {
|
||||||
|
return models.Invoice{}, result.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
return invoice, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *GORMInvoiceRepository) Update(invoice models.Invoice) (models.Invoice, error) {
|
||||||
|
result := t.DB.Save(&invoice)
|
||||||
|
if result.Error != nil {
|
||||||
|
return models.Invoice{}, result.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
return invoice, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *GORMInvoiceRepository) DeleteById(id string) error {
|
||||||
|
invoiceId, err := strconv.Atoi(id)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
result := t.DB.Delete(&models.Invoice{}, invoiceId)
|
||||||
|
return result.Error
|
||||||
|
}
|
||||||
82
repositories/printJobRepository.go
Normal file
82
repositories/printJobRepository.go
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
package repositories
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"gorm.io/gorm"
|
||||||
|
|
||||||
|
"git.dynamicdiscord.de/kalipso/zineshop/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
type PrintJobRepository interface {
|
||||||
|
Create(models.PrintJob) (models.PrintJob, error)
|
||||||
|
GetAll() ([]models.PrintJob, error)
|
||||||
|
GetById(string) (models.PrintJob, error)
|
||||||
|
//GetByShopItemId(string) (models.PrintJob, error)
|
||||||
|
Update(models.PrintJob) (models.PrintJob, error)
|
||||||
|
DeleteById(string) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type GORMPrintJobRepository struct {
|
||||||
|
DB *gorm.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewGORMPrintJobRepository(db *gorm.DB) PrintJobRepository {
|
||||||
|
return &GORMPrintJobRepository{
|
||||||
|
DB: db,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *GORMPrintJobRepository) Create(printJob models.PrintJob) (models.PrintJob, error) {
|
||||||
|
result := t.DB.Create(&printJob)
|
||||||
|
|
||||||
|
if result.Error != nil {
|
||||||
|
return models.PrintJob{}, result.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
return printJob, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *GORMPrintJobRepository) GetAll() ([]models.PrintJob, error) {
|
||||||
|
var printJobs []models.PrintJob
|
||||||
|
result := t.DB.Preload("ShopItem").Preload("Variant").Preload("PaperType").Preload("CoverPaperType").Find(&printJobs)
|
||||||
|
|
||||||
|
return printJobs, result.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *GORMPrintJobRepository) GetById(id string) (models.PrintJob, error) {
|
||||||
|
printJobId, err := strconv.Atoi(id)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return models.PrintJob{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var printJob models.PrintJob
|
||||||
|
result := t.DB.Preload("ShopItem").Preload("Variant").Preload("PaperType").Preload("CoverPaperType").First(&printJob, uint(printJobId))
|
||||||
|
|
||||||
|
if result.Error != nil {
|
||||||
|
return models.PrintJob{}, result.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
return printJob, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *GORMPrintJobRepository) Update(printJob models.PrintJob) (models.PrintJob, error) {
|
||||||
|
result := t.DB.Save(&printJob)
|
||||||
|
if result.Error != nil {
|
||||||
|
return models.PrintJob{}, result.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
return printJob, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *GORMPrintJobRepository) DeleteById(id string) error {
|
||||||
|
printJobId, err := strconv.Atoi(id)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
result := t.DB.Delete(&models.PrintJob{}, printJobId)
|
||||||
|
return result.Error
|
||||||
|
}
|
||||||
@@ -17,6 +17,8 @@ var (
|
|||||||
Tokens RegisterTokenRepository
|
Tokens RegisterTokenRepository
|
||||||
ConfigOptions ConfigRepository
|
ConfigOptions ConfigRepository
|
||||||
Papers PaperRepository
|
Papers PaperRepository
|
||||||
|
PrintJobs PrintJobRepository
|
||||||
|
Invoices InvoiceRepository
|
||||||
)
|
)
|
||||||
|
|
||||||
func InitRepositories() {
|
func InitRepositories() {
|
||||||
@@ -33,6 +35,8 @@ func InitRepositories() {
|
|||||||
&models.Order{},
|
&models.Order{},
|
||||||
&models.Config{},
|
&models.Config{},
|
||||||
&models.Paper{},
|
&models.Paper{},
|
||||||
|
&models.PrintJob{},
|
||||||
|
&models.Invoice{},
|
||||||
&models.RegisterToken{})
|
&models.RegisterToken{})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -47,4 +51,6 @@ func InitRepositories() {
|
|||||||
Tokens = NewGORMRegisterTokenRepository(db)
|
Tokens = NewGORMRegisterTokenRepository(db)
|
||||||
ConfigOptions = NewGORMConfigRepository(db)
|
ConfigOptions = NewGORMConfigRepository(db)
|
||||||
Papers = NewGORMPaperRepository(db)
|
Papers = NewGORMPaperRepository(db)
|
||||||
|
PrintJobs = NewGORMPrintJobRepository(db)
|
||||||
|
Invoices = NewGORMInvoiceRepository(db)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -591,6 +591,10 @@ video {
|
|||||||
grid-column: span 3 / span 3;
|
grid-column: span 3 / span 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.-m-1\.5 {
|
||||||
|
margin: -0.375rem;
|
||||||
|
}
|
||||||
|
|
||||||
.m-2 {
|
.m-2 {
|
||||||
margin: 0.5rem;
|
margin: 0.5rem;
|
||||||
}
|
}
|
||||||
@@ -674,18 +678,22 @@ video {
|
|||||||
margin-top: 1.5rem;
|
margin-top: 1.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mb-3 {
|
|
||||||
margin-bottom: 0.75rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.block {
|
.block {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.inline-block {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
.flex {
|
.flex {
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.inline-flex {
|
||||||
|
display: inline-flex;
|
||||||
|
}
|
||||||
|
|
||||||
.table {
|
.table {
|
||||||
display: table;
|
display: table;
|
||||||
}
|
}
|
||||||
@@ -762,6 +770,10 @@ video {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.min-w-full {
|
||||||
|
min-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.max-w-2xl {
|
.max-w-2xl {
|
||||||
max-width: 42rem;
|
max-width: 42rem;
|
||||||
}
|
}
|
||||||
@@ -770,6 +782,10 @@ video {
|
|||||||
max-width: 48rem;
|
max-width: 48rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.max-w-4xl {
|
||||||
|
max-width: 56rem;
|
||||||
|
}
|
||||||
|
|
||||||
.max-w-6xl {
|
.max-w-6xl {
|
||||||
max-width: 72rem;
|
max-width: 72rem;
|
||||||
}
|
}
|
||||||
@@ -826,10 +842,6 @@ video {
|
|||||||
grid-template-columns: repeat(6, minmax(0, 1fr));
|
grid-template-columns: repeat(6, minmax(0, 1fr));
|
||||||
}
|
}
|
||||||
|
|
||||||
.grid-cols-3 {
|
|
||||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
|
||||||
}
|
|
||||||
|
|
||||||
.flex-col {
|
.flex-col {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
@@ -838,10 +850,6 @@ video {
|
|||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.content-stretch {
|
|
||||||
align-content: stretch;
|
|
||||||
}
|
|
||||||
|
|
||||||
.items-center {
|
.items-center {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
@@ -920,6 +928,10 @@ video {
|
|||||||
border-color: rgb(229 231 235 / var(--tw-divide-opacity, 1));
|
border-color: rgb(229 231 235 / var(--tw-divide-opacity, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.overflow-hidden {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
.overflow-x-auto {
|
.overflow-x-auto {
|
||||||
overflow-x: auto;
|
overflow-x: auto;
|
||||||
}
|
}
|
||||||
@@ -928,6 +940,19 @@ video {
|
|||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.break-normal {
|
||||||
|
overflow-wrap: normal;
|
||||||
|
word-break: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.break-words {
|
||||||
|
overflow-wrap: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
.break-all {
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
|
||||||
.rounded {
|
.rounded {
|
||||||
border-radius: 0.25rem;
|
border-radius: 0.25rem;
|
||||||
}
|
}
|
||||||
@@ -1082,6 +1107,11 @@ video {
|
|||||||
background-color: rgb(220 252 231 / var(--tw-bg-opacity, 1));
|
background-color: rgb(220 252 231 / var(--tw-bg-opacity, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.bg-green-50 {
|
||||||
|
--tw-bg-opacity: 1;
|
||||||
|
background-color: rgb(240 253 244 / var(--tw-bg-opacity, 1));
|
||||||
|
}
|
||||||
|
|
||||||
.bg-green-500 {
|
.bg-green-500 {
|
||||||
--tw-bg-opacity: 1;
|
--tw-bg-opacity: 1;
|
||||||
background-color: rgb(34 197 94 / var(--tw-bg-opacity, 1));
|
background-color: rgb(34 197 94 / var(--tw-bg-opacity, 1));
|
||||||
@@ -1172,6 +1202,11 @@ video {
|
|||||||
background-color: rgb(254 226 226 / var(--tw-bg-opacity, 1));
|
background-color: rgb(254 226 226 / var(--tw-bg-opacity, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.bg-red-50 {
|
||||||
|
--tw-bg-opacity: 1;
|
||||||
|
background-color: rgb(254 242 242 / var(--tw-bg-opacity, 1));
|
||||||
|
}
|
||||||
|
|
||||||
.bg-red-500 {
|
.bg-red-500 {
|
||||||
--tw-bg-opacity: 1;
|
--tw-bg-opacity: 1;
|
||||||
background-color: rgb(239 68 68 / var(--tw-bg-opacity, 1));
|
background-color: rgb(239 68 68 / var(--tw-bg-opacity, 1));
|
||||||
@@ -1272,16 +1307,6 @@ video {
|
|||||||
background-color: rgb(24 24 27 / var(--tw-bg-opacity, 1));
|
background-color: rgb(24 24 27 / var(--tw-bg-opacity, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
.bg-gray-700 {
|
|
||||||
--tw-bg-opacity: 1;
|
|
||||||
background-color: rgb(55 65 81 / var(--tw-bg-opacity, 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
.bg-gray-500 {
|
|
||||||
--tw-bg-opacity: 1;
|
|
||||||
background-color: rgb(107 114 128 / var(--tw-bg-opacity, 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
.fill-red-50 {
|
.fill-red-50 {
|
||||||
fill: #fef2f2;
|
fill: #fef2f2;
|
||||||
}
|
}
|
||||||
@@ -1295,6 +1320,10 @@ video {
|
|||||||
object-fit: cover;
|
object-fit: cover;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.p-1\.5 {
|
||||||
|
padding: 0.375rem;
|
||||||
|
}
|
||||||
|
|
||||||
.p-2 {
|
.p-2 {
|
||||||
padding: 0.5rem;
|
padding: 0.5rem;
|
||||||
}
|
}
|
||||||
@@ -1342,6 +1371,11 @@ video {
|
|||||||
padding-bottom: 0.125rem;
|
padding-bottom: 0.125rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.py-1 {
|
||||||
|
padding-top: 0.25rem;
|
||||||
|
padding-bottom: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
.py-1\.5 {
|
.py-1\.5 {
|
||||||
padding-top: 0.375rem;
|
padding-top: 0.375rem;
|
||||||
padding-bottom: 0.375rem;
|
padding-bottom: 0.375rem;
|
||||||
@@ -1372,6 +1406,11 @@ video {
|
|||||||
padding-bottom: 6rem;
|
padding-bottom: 6rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.py-3 {
|
||||||
|
padding-top: 0.75rem;
|
||||||
|
padding-bottom: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
.py-4 {
|
.py-4 {
|
||||||
padding-top: 1rem;
|
padding-top: 1rem;
|
||||||
padding-bottom: 1rem;
|
padding-bottom: 1rem;
|
||||||
@@ -1382,16 +1421,6 @@ video {
|
|||||||
padding-bottom: 2rem;
|
padding-bottom: 2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.py-20 {
|
|
||||||
padding-top: 5rem;
|
|
||||||
padding-bottom: 5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.px-8 {
|
|
||||||
padding-left: 2rem;
|
|
||||||
padding-right: 2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.pb-3 {
|
.pb-3 {
|
||||||
padding-bottom: 0.75rem;
|
padding-bottom: 0.75rem;
|
||||||
}
|
}
|
||||||
@@ -1416,10 +1445,6 @@ video {
|
|||||||
padding-top: 1.25rem;
|
padding-top: 1.25rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.pb-4 {
|
|
||||||
padding-bottom: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.text-left {
|
.text-left {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
@@ -1432,6 +1457,18 @@ video {
|
|||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.text-start {
|
||||||
|
text-align: start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-end {
|
||||||
|
text-align: end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.align-middle {
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
.text-2xl {
|
.text-2xl {
|
||||||
font-size: 1.5rem;
|
font-size: 1.5rem;
|
||||||
line-height: 2rem;
|
line-height: 2rem;
|
||||||
@@ -1503,6 +1540,10 @@ video {
|
|||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.uppercase {
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
.leading-10 {
|
.leading-10 {
|
||||||
line-height: 2.5rem;
|
line-height: 2.5rem;
|
||||||
}
|
}
|
||||||
@@ -1614,6 +1655,11 @@ video {
|
|||||||
color: rgb(34 197 94 / var(--tw-text-opacity, 1));
|
color: rgb(34 197 94 / var(--tw-text-opacity, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.text-green-700 {
|
||||||
|
--tw-text-opacity: 1;
|
||||||
|
color: rgb(21 128 61 / var(--tw-text-opacity, 1));
|
||||||
|
}
|
||||||
|
|
||||||
.text-green-800 {
|
.text-green-800 {
|
||||||
--tw-text-opacity: 1;
|
--tw-text-opacity: 1;
|
||||||
color: rgb(22 101 52 / var(--tw-text-opacity, 1));
|
color: rgb(22 101 52 / var(--tw-text-opacity, 1));
|
||||||
@@ -1694,6 +1740,11 @@ video {
|
|||||||
color: rgb(239 68 68 / var(--tw-text-opacity, 1));
|
color: rgb(239 68 68 / var(--tw-text-opacity, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.text-red-700 {
|
||||||
|
--tw-text-opacity: 1;
|
||||||
|
color: rgb(185 28 28 / var(--tw-text-opacity, 1));
|
||||||
|
}
|
||||||
|
|
||||||
.text-red-800 {
|
.text-red-800 {
|
||||||
--tw-text-opacity: 1;
|
--tw-text-opacity: 1;
|
||||||
color: rgb(153 27 27 / var(--tw-text-opacity, 1));
|
color: rgb(153 27 27 / var(--tw-text-opacity, 1));
|
||||||
@@ -1784,10 +1835,6 @@ video {
|
|||||||
color: rgb(39 39 42 / var(--tw-text-opacity, 1));
|
color: rgb(39 39 42 / var(--tw-text-opacity, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
.underline {
|
|
||||||
text-decoration-line: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
.antialiased {
|
.antialiased {
|
||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
@@ -1799,24 +1846,18 @@ video {
|
|||||||
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
|
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
|
||||||
}
|
}
|
||||||
|
|
||||||
.shadow-sm {
|
|
||||||
--tw-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05);
|
|
||||||
--tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);
|
|
||||||
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
|
|
||||||
}
|
|
||||||
|
|
||||||
.shadow-xl {
|
|
||||||
--tw-shadow: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1);
|
|
||||||
--tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), 0 8px 10px -6px var(--tw-shadow-color);
|
|
||||||
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
|
|
||||||
}
|
|
||||||
|
|
||||||
.shadow-md {
|
.shadow-md {
|
||||||
--tw-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
|
--tw-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
|
||||||
--tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);
|
--tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);
|
||||||
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
|
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.shadow-sm {
|
||||||
|
--tw-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05);
|
||||||
|
--tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);
|
||||||
|
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
|
||||||
|
}
|
||||||
|
|
||||||
.outline {
|
.outline {
|
||||||
outline-style: solid;
|
outline-style: solid;
|
||||||
}
|
}
|
||||||
@@ -1833,6 +1874,24 @@ video {
|
|||||||
outline-color: #d1d5db;
|
outline-color: #d1d5db;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ring-1 {
|
||||||
|
--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);
|
||||||
|
--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);
|
||||||
|
box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ring-inset {
|
||||||
|
--tw-ring-inset: inset;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ring-green-600\/20 {
|
||||||
|
--tw-ring-color: rgb(22 163 74 / 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ring-red-600\/10 {
|
||||||
|
--tw-ring-color: rgb(220 38 38 / 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
.filter {
|
.filter {
|
||||||
filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
|
filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
|
||||||
}
|
}
|
||||||
@@ -2092,10 +2151,6 @@ video {
|
|||||||
max-width: 24rem;
|
max-width: 24rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sm\:grid-cols-2 {
|
|
||||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
||||||
}
|
|
||||||
|
|
||||||
.sm\:items-center {
|
.sm\:items-center {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
@@ -2139,10 +2194,6 @@ video {
|
|||||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
}
|
}
|
||||||
|
|
||||||
.md\:grid-cols-3 {
|
|
||||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
|
||||||
}
|
|
||||||
|
|
||||||
.md\:flex-row {
|
.md\:flex-row {
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
}
|
}
|
||||||
@@ -2187,18 +2238,14 @@ video {
|
|||||||
max-width: 80rem;
|
max-width: 80rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.lg\:grid-cols-3 {
|
|
||||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
|
||||||
}
|
|
||||||
|
|
||||||
.lg\:grid-cols-4 {
|
|
||||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
|
||||||
}
|
|
||||||
|
|
||||||
.lg\:grid-cols-2 {
|
.lg\:grid-cols-2 {
|
||||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.lg\:grid-cols-3 {
|
||||||
|
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||||
|
}
|
||||||
|
|
||||||
.lg\:p-8 {
|
.lg\:p-8 {
|
||||||
padding: 2rem;
|
padding: 2rem;
|
||||||
}
|
}
|
||||||
@@ -2219,13 +2266,13 @@ video {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@media (min-width: 1280px) {
|
@media (min-width: 1280px) {
|
||||||
.xl\:grid-cols-4 {
|
|
||||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
|
||||||
}
|
|
||||||
|
|
||||||
.xl\:grid-cols-3 {
|
.xl\:grid-cols-3 {
|
||||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.xl\:grid-cols-4 {
|
||||||
|
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (min-width: 1536px) {
|
@media (min-width: 1536px) {
|
||||||
@@ -2249,6 +2296,11 @@ video {
|
|||||||
border-color: rgb(31 41 55 / var(--tw-divide-opacity, 1));
|
border-color: rgb(31 41 55 / var(--tw-divide-opacity, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.dark\:divide-neutral-700 > :not([hidden]) ~ :not([hidden]) {
|
||||||
|
--tw-divide-opacity: 1;
|
||||||
|
border-color: rgb(64 64 64 / var(--tw-divide-opacity, 1));
|
||||||
|
}
|
||||||
|
|
||||||
.dark\:border-gray-600 {
|
.dark\:border-gray-600 {
|
||||||
--tw-border-opacity: 1;
|
--tw-border-opacity: 1;
|
||||||
border-color: rgb(75 85 99 / var(--tw-border-opacity, 1));
|
border-color: rgb(75 85 99 / var(--tw-border-opacity, 1));
|
||||||
@@ -2304,6 +2356,16 @@ video {
|
|||||||
color: rgb(17 24 39 / var(--tw-text-opacity, 1));
|
color: rgb(17 24 39 / var(--tw-text-opacity, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.dark\:text-neutral-200 {
|
||||||
|
--tw-text-opacity: 1;
|
||||||
|
color: rgb(229 229 229 / var(--tw-text-opacity, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark\:text-neutral-500 {
|
||||||
|
--tw-text-opacity: 1;
|
||||||
|
color: rgb(115 115 115 / var(--tw-text-opacity, 1));
|
||||||
|
}
|
||||||
|
|
||||||
.dark\:text-white {
|
.dark\:text-white {
|
||||||
--tw-text-opacity: 1;
|
--tw-text-opacity: 1;
|
||||||
color: rgb(255 255 255 / var(--tw-text-opacity, 1));
|
color: rgb(255 255 255 / var(--tw-text-opacity, 1));
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
package utils
|
package utils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"io"
|
"fmt"
|
||||||
"os"
|
"github.com/pdfcpu/pdfcpu/pkg/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
func GenerateSessionId(length int) string {
|
func GenerateSessionId(length int) string {
|
||||||
@@ -21,40 +20,13 @@ func GenerateToken() string {
|
|||||||
return GenerateSessionId(16)
|
return GenerateSessionId(16)
|
||||||
}
|
}
|
||||||
|
|
||||||
const match = "/Page\x00"
|
|
||||||
|
|
||||||
// Pages reads the given io.ByteReader until EOF is reached, returning the
|
|
||||||
// number of pages encountered.
|
|
||||||
func Pages(reader io.ByteReader) (pages int) {
|
|
||||||
i := 0
|
|
||||||
for {
|
|
||||||
b, err := reader.ReadByte()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
check:
|
|
||||||
switch match[i] {
|
|
||||||
case 0:
|
|
||||||
if !(b >= 'A' && b <= 'Z' || b >= 'a' && b <= 'z') {
|
|
||||||
pages++
|
|
||||||
}
|
|
||||||
i = 0
|
|
||||||
goto check
|
|
||||||
case b:
|
|
||||||
i++
|
|
||||||
default:
|
|
||||||
i = 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// PagesAtPath opens a PDF file at the given file path, returning the number
|
|
||||||
// of pages found.
|
|
||||||
func CountPagesAtPath(path string) (pages int) {
|
func CountPagesAtPath(path string) (pages int) {
|
||||||
if reader, err := os.Open(path); err == nil {
|
ctx, err := api.ReadContextFile(path)
|
||||||
reader.Chdir()
|
if err != nil {
|
||||||
pages = Pages(bufio.NewReader(reader))
|
fmt.Println("Error reading PDF:", err)
|
||||||
reader.Close()
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pages = ctx.PageCount
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,6 +42,8 @@
|
|||||||
hover:text-white">Config</a>
|
hover:text-white">Config</a>
|
||||||
<a href="/paper" class="rounded-md bg-gray-900 m-2 px-3 py-2 text-sm font-medium text-gray-300 hover:bg-gray-700
|
<a href="/paper" class="rounded-md bg-gray-900 m-2 px-3 py-2 text-sm font-medium text-gray-300 hover:bg-gray-700
|
||||||
hover:text-white">Paper</a>
|
hover:text-white">Paper</a>
|
||||||
|
<a href="/invoice" class="rounded-md bg-gray-900 m-2 px-3 py-2 text-sm font-medium text-gray-300 hover:bg-gray-700
|
||||||
|
hover:text-white">Invoices</a>
|
||||||
<a href="/logout" class="rounded-md bg-gray-900 m-2 px-3 py-2 text-sm font-medium text-red-300 hover:bg-gray-700 hover:text-white">Logout</a>
|
<a href="/logout" class="rounded-md bg-gray-900 m-2 px-3 py-2 text-sm font-medium text-red-300 hover:bg-gray-700 hover:text-white">Logout</a>
|
||||||
</div>
|
</div>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
|||||||
55
views/invoice.html
Normal file
55
views/invoice.html
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
<div class="-m-1.5 overflow-x-auto">
|
||||||
|
<div class="p-1.5 min-w-full inline-block align-middle">
|
||||||
|
<div class="overflow-hidden">
|
||||||
|
<table class="min-w-full divide-y divide-gray-200 dark:divide-neutral-700">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th scope="col" class="px-6 py-3 text-start text-xs font-medium text-gray-500 uppercase dark:text-neutral-500"></th>
|
||||||
|
<th scope="col" class="px-6 py-3 text-start text-xs font-medium text-gray-500 uppercase dark:text-neutral-500">Name</th>
|
||||||
|
<th scope="col" class="px-6 py-3 text-end text-xs font-medium text-gray-500 uppercase dark:text-neutral-500">Paper</th>
|
||||||
|
<th scope="col" class="px-6 py-3 text-end text-xs font-medium text-gray-500 uppercase dark:text-neutral-500">Amount</th>
|
||||||
|
<th scope="col" class="px-6 py-3 text-end text-xs font-medium text-gray-500 uppercase dark:text-neutral-500">Price</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody class="divide-y divide-gray-200 dark:divide-neutral-700">
|
||||||
|
{{ range .PrintJobs }}
|
||||||
|
<tr>
|
||||||
|
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-800 dark:text-neutral-200">
|
||||||
|
<a href="/shopitems/{{ .Variant.ShopItemID }}" class="flex items-center aspect-square w-8 h-10 shrink-0">
|
||||||
|
<img class="h-auto w-full max-h-full dark:hidden" src="/{{ .ShopItem.Image }}" alt="imac image" />
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td class="px-6 py-4 text-sm text-gray-800 dark:text-neutral-200">
|
||||||
|
<div class="text-sm break-normal">
|
||||||
|
<p>{{ .ShopItem.Name }}</p>
|
||||||
|
<p>{{ .Variant.Name }}</p>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td class="px-6 py-4 text-sm text-gray-800 dark:text-neutral-200">
|
||||||
|
<div class="text-xs">
|
||||||
|
<p>{{ .PaperType.Brand }} - {{.PaperType.Name }}: {{ .PaperType.Size }} {{ .PaperType.Weight }}g</p>
|
||||||
|
{{ if .CoverPaperType }}
|
||||||
|
<p class="text-red-700">{{ .CoverPaperType.Brand }} - {{.CoverPaperType.Name }}: {{ .CoverPaperType.Size }} {{ .CoverPaperType.Weight }}g</p>
|
||||||
|
{{ end }}
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-800 dark:text-neutral-200">{{ .Amount }}</td>
|
||||||
|
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-800 dark:text-neutral-200">{{ .PriceTotal }}</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-800 dark:text-neutral-200">
|
||||||
|
<b>TOTAL</b>
|
||||||
|
</td>
|
||||||
|
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-800 dark:text-neutral-200"></td>
|
||||||
|
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-800 dark:text-neutral-200"></td>
|
||||||
|
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-800 dark:text-neutral-200"></td>
|
||||||
|
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-800 dark:text-neutral-200"><b>{{ .PriceTotal }}</b></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
29
views/invoiceview.html
Normal file
29
views/invoiceview.html
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
{{ template "header.html" . }}
|
||||||
|
|
||||||
|
|
||||||
|
<div class="flex min-h-full flex-col justify-center px-6 py-12 lg:px-8">
|
||||||
|
<div class="sm:mx-auto sm:w-full sm:max-w-sm">
|
||||||
|
<img class="mx-auto h-10 w-auto" src="/static/img/logo-black.png" alt="Your Company">
|
||||||
|
<h2 class="mt-10 text-center text-2xl/9 font-bold tracking-tight text-gray-900">Invoices</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{ range .data.invoices }}
|
||||||
|
<div class="w-full grid grid-cols-1 gap-4 mx-auto p-4 m-4 flex flex-wrap border rounded shadow-md max-w-4xl">
|
||||||
|
<div class="">
|
||||||
|
<div class="font-bold text-center mb-4">
|
||||||
|
Invoice #{{ .ID }} - {{ .CreatedAt }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col">
|
||||||
|
{{ template "invoice.html" . }}
|
||||||
|
</div>
|
||||||
|
<div class="grid grid-cols-2 mt-4 flex flex-wrap gap-2 w-full">
|
||||||
|
<form action="/invoice/{{ .ID }}" method="POST">
|
||||||
|
<button type="submit" name="action" value="delete" class="bg-red-500 hover:bg-red-700 text-white text-sm/6 font-bold py-2 px-4 rounded">Delete</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{ end }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{ template "footer.html" . }}
|
||||||
22
views/printstarted.html
Normal file
22
views/printstarted.html
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
{{ template "header.html" . }}
|
||||||
|
|
||||||
|
<section class="bg-white py-8 antialiased dark:bg-gray-900 md:py-16">
|
||||||
|
<div class="mx-auto max-w-3xl">
|
||||||
|
<div class="mt-6 sm:mt-8">
|
||||||
|
<div class="relative overflow-x-auto border-b border-gray-200 dark:border-gray-800">
|
||||||
|
<h2 class="title font-manrope font-bold text-4xl leading-10 mb-8 text-center text-black">Print Started
|
||||||
|
</h2>
|
||||||
|
<div class="w-full grid grid-cols-1 gap-4 mx-auto p-4 m-4 flex flex-wrap border rounded shadow-md">
|
||||||
|
<div class="flex flex-col">
|
||||||
|
{{ template "invoice.html" .data.invoice }}
|
||||||
|
</div>
|
||||||
|
<div class="grid grid-cols-2 mt-4 flex flex-wrap gap-2 w-full">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{{ template "footer.html" . }}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
{{ template "header.html" . }}
|
{{ template "header.html" . }}
|
||||||
|
|
||||||
<section class="bg-white py-8 antialiased dark:bg-gray-900 md:py-16">
|
<section class="bg-white py-8 antialiased dark:bg-gray-900 md:py-16">
|
||||||
<div class="mx-auto max-w-3xl">
|
<div class="mx-auto max-w-4xl">
|
||||||
<div class="mt-6 sm:mt-8">
|
<div class="mt-6 sm:mt-8">
|
||||||
<div class="relative overflow-x-auto border-b border-gray-200 dark:border-gray-800">
|
<div class="relative overflow-x-auto border-b border-gray-200 dark:border-gray-800">
|
||||||
<h2 class="title font-manrope font-bold text-4xl leading-10 mb-8 text-center text-black">Zineshop Print
|
<h2 class="title font-manrope font-bold text-4xl leading-10 mb-8 text-center text-black">Zineshop Print
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
<p class="font-normal text-base leading-7 text-gray-500 text-left mb-5 mt-6">
|
<p class="font-normal text-base leading-7 text-gray-500 text-left mb-5 mt-6">
|
||||||
<bold>CoverPage</bold>: If selected, the Printer will take Paper from the BypassTray for the first page. For
|
<bold>CoverPage</bold>: If selected, the Printer will take Paper from the BypassTray for the first page. For
|
||||||
example you can put colored paper there to have a nice looking front page, and the rest will be normal paper.
|
example you can put colored paper there to have a nice looking front page, and the rest will be normal paper.
|
||||||
Makue sure you put paper in that tray when selecting this option.<br><br>
|
Make sure you put paper in that tray when selecting this option.<br><br>
|
||||||
|
|
||||||
Print Order: The Zines will be printed from top to bottom as seen in this list.
|
Print Order: The Zines will be printed from top to bottom as seen in this list.
|
||||||
|
|
||||||
@@ -33,6 +33,12 @@
|
|||||||
<a href="/shopitems/{{ .ItemVariant.ShopItemID }}" class="flex items-center aspect-square w-8 h-10 shrink-0">
|
<a href="/shopitems/{{ .ItemVariant.ShopItemID }}" class="flex items-center aspect-square w-8 h-10 shrink-0">
|
||||||
<img class="h-auto w-full max-h-full dark:hidden" src="/{{ .ShopItem.Image }}" alt="imac image" />
|
<img class="h-auto w-full max-h-full dark:hidden" src="/{{ .ShopItem.Image }}" alt="imac image" />
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
|
{{ if .ShopItem.WasPrinted }}
|
||||||
|
<span class="inline-flex items-center rounded-md bg-green-50 px-2 py-1 text-xs font-medium text-green-700 ring-1 ring-green-600/20 ring-inset">Tested</span>
|
||||||
|
{{ else }}
|
||||||
|
<span class="inline-flex items-center rounded-md bg-red-50 px-2 py-1 text-xs font-medium text-red-700 ring-1 ring-red-600/10 ring-inset">NOT TESTED</span>
|
||||||
|
{{ end }}
|
||||||
<a href="/shopitems/{{ .ItemVariant.ShopItemID }}" class="hover:underline">{{ .ShopItem.Name }} - {{ .ItemVariant.Name }}</a>
|
<a href="/shopitems/{{ .ItemVariant.ShopItemID }}" class="hover:underline">{{ .ShopItem.Name }} - {{ .ItemVariant.Name }}</a>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
@@ -47,7 +53,7 @@
|
|||||||
|
|
||||||
<td class="whitespace-nowrap py-4">
|
<td class="whitespace-nowrap py-4">
|
||||||
<select name="variant-coverpage[]" required class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500">
|
<select name="variant-coverpage[]" required class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500">
|
||||||
<option selected value="0">None</option>
|
<option selected value="0">CoverPage: None</option>
|
||||||
{{ range $.data.paper }}
|
{{ range $.data.paper }}
|
||||||
<option value="{{ .ID }}">{{ .Brand }} - {{ .Name }}: {{ .Size }} {{ .Weight }}g/m2</option>
|
<option value="{{ .ID }}">{{ .Brand }} - {{ .Name }}: {{ .Size }} {{ .Weight }}g/m2</option>
|
||||||
{{ end}}
|
{{ end}}
|
||||||
|
|||||||
Reference in New Issue
Block a user