This commit is contained in:
@@ -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.GetAll()
|
||||||
|
|
||||||
|
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")
|
||||||
|
|||||||
@@ -113,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])
|
||||||
|
|
||||||
@@ -160,13 +161,7 @@ func (rc *printController) PrintHandler(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
printJob.CalculatePrintCosts()
|
printJob.CalculatePrintCosts()
|
||||||
printJob, err = repositories.PrintJobs.Create(printJob)
|
priceTotal += printJob.PriceTotal
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
c.HTML(http.StatusBadRequest, "error.html", gin.H{"data": gin.H{"error": err}})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
printJobs = append(printJobs, printJob)
|
printJobs = append(printJobs, printJob)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -174,6 +169,7 @@ func (rc *printController) PrintHandler(c *gin.Context) {
|
|||||||
PrintJobs: printJobs,
|
PrintJobs: printJobs,
|
||||||
PricePerClick: 0.002604,
|
PricePerClick: 0.002604,
|
||||||
PartCosts: 0.0067,
|
PartCosts: 0.0067,
|
||||||
|
PriceTotal: priceTotal,
|
||||||
}
|
}
|
||||||
invoice, err := repositories.Invoices.Create(invoice)
|
invoice, err := repositories.Invoices.Create(invoice)
|
||||||
|
|
||||||
|
|||||||
1
go.mod
1
go.mod
@@ -3,6 +3,7 @@ module git.dynamicdiscord.de/kalipso/zineshop
|
|||||||
go 1.23.3
|
go 1.23.3
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/dslipak/pdf v0.0.2
|
||||||
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
|
||||||
|
|||||||
2
go.sum
2
go.sum
@@ -9,6 +9,8 @@ github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQ
|
|||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/dslipak/pdf v0.0.2 h1:djAvcM5neg9Ush+zR6QXB+VMJzR6TdnX766HPIg1JmI=
|
||||||
|
github.com/dslipak/pdf v0.0.2/go.mod h1:2L3SnkI9cQwnAS9gfPz2iUoLC0rUZwbucpbKi5R1mUo=
|
||||||
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
|
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
|
||||||
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
|
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
|
||||||
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
||||||
|
|||||||
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)
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ type Invoice struct {
|
|||||||
PrintJobs []PrintJob
|
PrintJobs []PrintJob
|
||||||
PricePerClick float64
|
PricePerClick float64
|
||||||
PartCosts float64
|
PartCosts float64
|
||||||
|
PriceTotal float64
|
||||||
}
|
}
|
||||||
|
|
||||||
type PrintJob struct {
|
type PrintJob struct {
|
||||||
@@ -45,6 +46,8 @@ type PrintJob struct {
|
|||||||
CoverPaperTypeId *uint
|
CoverPaperTypeId *uint
|
||||||
CoverPaperType *Paper `gorm:"foreignKey:CoverPaperTypeId"`
|
CoverPaperType *Paper `gorm:"foreignKey:CoverPaperTypeId"`
|
||||||
Amount uint
|
Amount uint
|
||||||
|
PricePerPiece float64
|
||||||
|
PriceTotal float64
|
||||||
InvoiceID uint
|
InvoiceID uint
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -134,6 +137,7 @@ func (p *PrintJob) CalculatePrintCosts() (float64, error) {
|
|||||||
|
|
||||||
//Get actual pagecount depending on printmode
|
//Get actual pagecount depending on printmode
|
||||||
actualPageCount := pageCount
|
actualPageCount := pageCount
|
||||||
|
fmt.Println("PagCount: ", actualPageCount)
|
||||||
|
|
||||||
if printMode == CreateBooklet {
|
if printMode == CreateBooklet {
|
||||||
dividedCount := float64(pageCount) / 4.0
|
dividedCount := float64(pageCount) / 4.0
|
||||||
@@ -156,5 +160,7 @@ func (p *PrintJob) CalculatePrintCosts() (float64, error) {
|
|||||||
|
|
||||||
fmt.Printf("Printing Costs per Zine: %v\n", printingCosts)
|
fmt.Printf("Printing Costs per Zine: %v\n", printingCosts)
|
||||||
fmt.Printf("Printing Costs Total: %v\n", printingCosts*float64(p.Amount))
|
fmt.Printf("Printing Costs Total: %v\n", printingCosts*float64(p.Amount))
|
||||||
|
p.PricePerPiece = printingCosts
|
||||||
|
p.PriceTotal = printingCosts * float64(p.Amount)
|
||||||
return printingCosts, nil
|
return printingCosts, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ func NewGORMInvoiceRepository(db *gorm.DB) InvoiceRepository {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *GORMInvoiceRepository) Create(invoice models.Invoice) (models.Invoice, error) {
|
func (t *GORMInvoiceRepository) Create(invoice models.Invoice) (models.Invoice, error) {
|
||||||
result := t.DB.Omit("PrintJobs").Create(&invoice)
|
result := t.DB.Create(&invoice)
|
||||||
|
|
||||||
if result.Error != nil {
|
if result.Error != nil {
|
||||||
return models.Invoice{}, result.Error
|
return models.Invoice{}, result.Error
|
||||||
@@ -39,7 +39,7 @@ func (t *GORMInvoiceRepository) Create(invoice models.Invoice) (models.Invoice,
|
|||||||
|
|
||||||
func (t *GORMInvoiceRepository) GetAll() ([]models.Invoice, error) {
|
func (t *GORMInvoiceRepository) GetAll() ([]models.Invoice, error) {
|
||||||
var invoice []models.Invoice
|
var invoice []models.Invoice
|
||||||
result := t.DB.Preload("PrintJobs").Find(&invoice)
|
result := t.DB.Preload("PrintJobs.ShopItem").Preload("PrintJobs.Variant").Preload("PrintJobs.PaperType").Preload("PrintJobs.CoverPaperType").Preload("PrintJobs").Find(&invoice)
|
||||||
|
|
||||||
return invoice, result.Error
|
return invoice, result.Error
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -599,6 +599,10 @@ video {
|
|||||||
margin: 1rem;
|
margin: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.-m-1\.5 {
|
||||||
|
margin: -0.375rem;
|
||||||
|
}
|
||||||
|
|
||||||
.-mx-2 {
|
.-mx-2 {
|
||||||
margin-left: -0.5rem;
|
margin-left: -0.5rem;
|
||||||
margin-right: -0.5rem;
|
margin-right: -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;
|
||||||
}
|
}
|
||||||
@@ -826,10 +838,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 +846,6 @@ video {
|
|||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.content-stretch {
|
|
||||||
align-content: stretch;
|
|
||||||
}
|
|
||||||
|
|
||||||
.items-center {
|
.items-center {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
@@ -879,6 +883,11 @@ video {
|
|||||||
row-gap: 1rem;
|
row-gap: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.gap-x-2 {
|
||||||
|
-moz-column-gap: 0.5rem;
|
||||||
|
column-gap: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
.space-x-4 > :not([hidden]) ~ :not([hidden]) {
|
.space-x-4 > :not([hidden]) ~ :not([hidden]) {
|
||||||
--tw-space-x-reverse: 0;
|
--tw-space-x-reverse: 0;
|
||||||
margin-right: calc(1rem * var(--tw-space-x-reverse));
|
margin-right: calc(1rem * var(--tw-space-x-reverse));
|
||||||
@@ -920,6 +929,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;
|
||||||
}
|
}
|
||||||
@@ -987,6 +1000,10 @@ video {
|
|||||||
border-color: rgb(209 213 219 / var(--tw-border-opacity, 1));
|
border-color: rgb(209 213 219 / var(--tw-border-opacity, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.border-transparent {
|
||||||
|
border-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
.bg-amber-100 {
|
.bg-amber-100 {
|
||||||
--tw-bg-opacity: 1;
|
--tw-bg-opacity: 1;
|
||||||
background-color: rgb(254 243 199 / var(--tw-bg-opacity, 1));
|
background-color: rgb(254 243 199 / var(--tw-bg-opacity, 1));
|
||||||
@@ -1272,16 +1289,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;
|
||||||
}
|
}
|
||||||
@@ -1307,6 +1314,10 @@ video {
|
|||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.p-1\.5 {
|
||||||
|
padding: 0.375rem;
|
||||||
|
}
|
||||||
|
|
||||||
.px-2 {
|
.px-2 {
|
||||||
padding-left: 0.5rem;
|
padding-left: 0.5rem;
|
||||||
padding-right: 0.5rem;
|
padding-right: 0.5rem;
|
||||||
@@ -1382,14 +1393,9 @@ video {
|
|||||||
padding-bottom: 2rem;
|
padding-bottom: 2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.py-20 {
|
.py-3 {
|
||||||
padding-top: 5rem;
|
padding-top: 0.75rem;
|
||||||
padding-bottom: 5rem;
|
padding-bottom: 0.75rem;
|
||||||
}
|
|
||||||
|
|
||||||
.px-8 {
|
|
||||||
padding-left: 2rem;
|
|
||||||
padding-right: 2rem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.pb-3 {
|
.pb-3 {
|
||||||
@@ -1416,10 +1422,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 +1434,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 +1517,10 @@ video {
|
|||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.uppercase {
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
.leading-10 {
|
.leading-10 {
|
||||||
line-height: 2.5rem;
|
line-height: 2.5rem;
|
||||||
}
|
}
|
||||||
@@ -1784,8 +1802,9 @@ video {
|
|||||||
color: rgb(39 39 42 / var(--tw-text-opacity, 1));
|
color: rgb(39 39 42 / var(--tw-text-opacity, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
.underline {
|
.text-blue-600 {
|
||||||
text-decoration-line: underline;
|
--tw-text-opacity: 1;
|
||||||
|
color: rgb(37 99 235 / var(--tw-text-opacity, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
.antialiased {
|
.antialiased {
|
||||||
@@ -1799,24 +1818,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;
|
||||||
}
|
}
|
||||||
@@ -1941,6 +1954,11 @@ video {
|
|||||||
color: rgb(255 255 255 / var(--tw-text-opacity, 1));
|
color: rgb(255 255 255 / var(--tw-text-opacity, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.hover\:text-blue-800:hover {
|
||||||
|
--tw-text-opacity: 1;
|
||||||
|
color: rgb(30 64 175 / var(--tw-text-opacity, 1));
|
||||||
|
}
|
||||||
|
|
||||||
.hover\:underline:hover {
|
.hover\:underline:hover {
|
||||||
text-decoration-line: underline;
|
text-decoration-line: underline;
|
||||||
}
|
}
|
||||||
@@ -1954,6 +1972,11 @@ video {
|
|||||||
border-color: rgb(59 130 246 / var(--tw-border-opacity, 1));
|
border-color: rgb(59 130 246 / var(--tw-border-opacity, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.focus\:text-blue-800:focus {
|
||||||
|
--tw-text-opacity: 1;
|
||||||
|
color: rgb(30 64 175 / var(--tw-text-opacity, 1));
|
||||||
|
}
|
||||||
|
|
||||||
.focus\:outline-none:focus {
|
.focus\:outline-none:focus {
|
||||||
outline: 2px solid transparent;
|
outline: 2px solid transparent;
|
||||||
outline-offset: 2px;
|
outline-offset: 2px;
|
||||||
@@ -2013,6 +2036,14 @@ video {
|
|||||||
outline-color: #4f46e5;
|
outline-color: #4f46e5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.disabled\:pointer-events-none:disabled {
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.disabled\:opacity-50:disabled {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
.group:hover .group-hover\:fill-red-400 {
|
.group:hover .group-hover\:fill-red-400 {
|
||||||
fill: #f87171;
|
fill: #f87171;
|
||||||
}
|
}
|
||||||
@@ -2092,10 +2123,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 +2166,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 +2210,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 +2238,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 +2268,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));
|
||||||
@@ -2309,6 +2333,21 @@ video {
|
|||||||
color: rgb(255 255 255 / var(--tw-text-opacity, 1));
|
color: rgb(255 255 255 / var(--tw-text-opacity, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.dark\:text-blue-500 {
|
||||||
|
--tw-text-opacity: 1;
|
||||||
|
color: rgb(59 130 246 / 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\:placeholder-gray-400::-moz-placeholder {
|
.dark\:placeholder-gray-400::-moz-placeholder {
|
||||||
--tw-placeholder-opacity: 1;
|
--tw-placeholder-opacity: 1;
|
||||||
color: rgb(156 163 175 / var(--tw-placeholder-opacity, 1));
|
color: rgb(156 163 175 / var(--tw-placeholder-opacity, 1));
|
||||||
@@ -2334,11 +2373,21 @@ video {
|
|||||||
color: rgb(255 255 255 / var(--tw-text-opacity, 1));
|
color: rgb(255 255 255 / var(--tw-text-opacity, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.dark\:hover\:text-blue-400:hover {
|
||||||
|
--tw-text-opacity: 1;
|
||||||
|
color: rgb(96 165 250 / var(--tw-text-opacity, 1));
|
||||||
|
}
|
||||||
|
|
||||||
.dark\:focus\:border-blue-500:focus {
|
.dark\:focus\:border-blue-500:focus {
|
||||||
--tw-border-opacity: 1;
|
--tw-border-opacity: 1;
|
||||||
border-color: rgb(59 130 246 / var(--tw-border-opacity, 1));
|
border-color: rgb(59 130 246 / var(--tw-border-opacity, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.dark\:focus\:text-blue-400:focus {
|
||||||
|
--tw-text-opacity: 1;
|
||||||
|
color: rgb(96 165 250 / var(--tw-text-opacity, 1));
|
||||||
|
}
|
||||||
|
|
||||||
.dark\:focus\:ring-blue-500:focus {
|
.dark\:focus\:ring-blue-500:focus {
|
||||||
--tw-ring-opacity: 1;
|
--tw-ring-opacity: 1;
|
||||||
--tw-ring-color: rgb(59 130 246 / var(--tw-ring-opacity, 1));
|
--tw-ring-color: rgb(59 130 246 / var(--tw-ring-opacity, 1));
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
package utils
|
package utils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
|
"fmt"
|
||||||
|
"github.com/dslipak/pdf"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func GenerateSessionId(length int) string {
|
func GenerateSessionId(length int) string {
|
||||||
@@ -30,6 +30,7 @@ func Pages(reader io.ByteReader) (pages int) {
|
|||||||
for {
|
for {
|
||||||
b, err := reader.ReadByte()
|
b, err := reader.ReadByte()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
check:
|
check:
|
||||||
@@ -51,10 +52,15 @@ func Pages(reader io.ByteReader) (pages int) {
|
|||||||
// PagesAtPath opens a PDF file at the given file path, returning the number
|
// PagesAtPath opens a PDF file at the given file path, returning the number
|
||||||
// of pages found.
|
// of pages found.
|
||||||
func CountPagesAtPath(path string) (pages int) {
|
func CountPagesAtPath(path string) (pages int) {
|
||||||
if reader, err := os.Open(path); err == nil {
|
r, err := pdf.Open(path)
|
||||||
reader.Chdir()
|
|
||||||
pages = Pages(bufio.NewReader(reader))
|
if err != nil {
|
||||||
reader.Close()
|
fmt.Println("LOL")
|
||||||
|
fmt.Println(err)
|
||||||
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pages = r.NumPage()
|
||||||
|
|
||||||
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 }}
|
||||||
|
|||||||
77
views/invoiceview.html
Normal file
77
views/invoiceview.html
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
{{ 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">
|
||||||
|
<div class="">
|
||||||
|
<div class="font-bold text-center mb-4">
|
||||||
|
Invoice #{{ .ID }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<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">Image</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-start text-xs font-medium text-gray-500 uppercase dark:text-neutral-500">Variant</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">CoverPaper</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 whitespace-nowrap text-sm text-gray-800 dark:text-neutral-200">{{ .ShopItem.Name }}</td>
|
||||||
|
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-800 dark:text-neutral-200">{{ .Variant.Name}}</td>
|
||||||
|
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-800 dark:text-neutral-200">{{ .PaperType.Brand }} - {{.PaperType.Name }}: {{ .PaperType.Size }} {{ .PaperType.Weight }}g/m2</td>
|
||||||
|
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-800 dark:text-neutral-200">{{ .PaperType.Brand }} - {{.PaperType.Name }}: {{ .PaperType.Size }} {{ .PaperType.Weight }}g/m2</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"></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>
|
||||||
|
</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" . }}
|
||||||
Reference in New Issue
Block a user