aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/invoice
diff options
context:
space:
mode:
authorVidhu Kant Sharma <vidhukant@vidhukant.com>2025-10-11 20:55:48 +0530
committerVidhu Kant Sharma <vidhukant@vidhukant.com>2025-10-11 20:55:48 +0530
commitbc154857fb5569d7c1fa9785cc891cb927a6a156 (patch)
tree590c9f6a00a1b97b2ee45cfa5a767558089affe0 /invoice
parent8a47978ca17d2f251d67d12b0e34fa26bb1e4ace (diff)
removed per-user itemsv0.17.0
Diffstat (limited to 'invoice')
-rw-r--r--invoice/controller.go229
-rw-r--r--invoice/invoice.go3
-rw-r--r--invoice/router.go4
-rw-r--r--invoice/service.go42
-rw-r--r--invoice/validators.go28
5 files changed, 35 insertions, 271 deletions
diff --git a/invoice/controller.go b/invoice/controller.go
index ad6df3e..b03ec22 100644
--- a/invoice/controller.go
+++ b/invoice/controller.go
@@ -32,17 +32,7 @@ func handleGetSingleInvoice (ctx *gin.Context) {
return
}
- uId, ok := ctx.Get("UserID")
- if !ok {
- ctx.Error(e.ErrUnauthorized)
- ctx.Abort()
- return
- }
-
- userId := uId.(uint)
-
var invoice Invoice
-
err = getInvoice(&invoice, uint(id))
if err != nil {
ctx.Error(err)
@@ -50,85 +40,36 @@ func handleGetSingleInvoice (ctx *gin.Context) {
return
}
- if invoice.UserID != userId {
- ctx.Error(e.ErrForbidden)
- ctx.Abort()
- return
- }
-
ctx.JSON(http.StatusOK, gin.H{
- "message": "success",
"data": invoice,
})
}
-func handleGetInvoices (ctx *gin.Context) {
- var invoices []Invoice
-
- uId, ok := ctx.Get("UserID")
- if !ok {
- ctx.Error(e.ErrUnauthorized)
- ctx.Abort()
- return
- }
-
- userId := uId.(uint)
-
- err := getInvoices(&invoices, userId, false)
- if err != nil {
- ctx.Error(err)
- ctx.Abort()
- return
- }
-
- ctx.JSON(http.StatusOK, gin.H{
- "message": "success",
- "data": invoices,
- })
-}
-
-func handleGetDrafts (ctx *gin.Context) {
- var invoices []Invoice
-
- uId, ok := ctx.Get("UserID")
- if !ok {
- ctx.Error(e.ErrUnauthorized)
- ctx.Abort()
- return
- }
+func handleGetInvoices(getDrafts bool) func(*gin.Context) {
+ return func(ctx *gin.Context) {
+ var invoices []Invoice
- userId := uId.(uint)
+ err := getInvoices(&invoices, getDrafts)
+ if err != nil {
+ ctx.Error(err)
+ ctx.Abort()
+ return
+ }
- err := getInvoices(&invoices, userId, true)
- if err != nil {
- ctx.Error(err)
- ctx.Abort()
- return
+ ctx.JSON(http.StatusOK, gin.H{
+ "data": invoices,
+ })
}
-
- ctx.JSON(http.StatusOK, gin.H{
- "message": "success",
- "data": invoices,
- })
}
func handleSaveInvoice (ctx *gin.Context) {
var invoice Invoice
ctx.Bind(&invoice)
- uId, ok := ctx.Get("UserID")
- if !ok {
- ctx.Error(e.ErrUnauthorized)
- ctx.Abort()
- return
- }
-
- userId := uId.(uint)
- invoice.UserID = userId
-
// if invoice number is 0, generate one!
+ // (maybe the client didn't give us one)
if invoice.InvoiceNumber == 0 {
- n, err := getNewInvoiceNumber(invoice.UserID)
+ n, err := getNewInvoiceNumber()
if err != nil {
ctx.Error(err)
@@ -147,12 +88,12 @@ func handleSaveInvoice (ctx *gin.Context) {
}
ctx.JSON(http.StatusOK, gin.H{
- "message": "success",
"data": invoice,
})
}
func handleDelInvoice (ctx *gin.Context) {
+ // TODO: only drafts can be deleted, non-drafts should be "cancelled"
id, err := strconv.ParseUint(ctx.Param("id"), 10, 64)
if err != nil {
ctx.Error(e.ErrInvalidID)
@@ -163,23 +104,6 @@ func handleDelInvoice (ctx *gin.Context) {
var invoice Invoice
invoice.ID = uint(id)
- uId, ok := ctx.Get("UserID")
- if !ok {
- ctx.Error(e.ErrUnauthorized)
- ctx.Abort()
- return
- }
-
- userId := uId.(uint)
- invoice.UserID = userId
-
- err = checkInvoiceOwnership(invoice.ID, invoice.UserID)
- if err != nil {
- ctx.Error(err)
- ctx.Abort()
- return
- }
-
err = invoice.del()
if err != nil {
ctx.Error(err)
@@ -187,9 +111,7 @@ func handleDelInvoice (ctx *gin.Context) {
return
}
- ctx.JSON(http.StatusOK, gin.H{
- "message": "success",
- })
+ ctx.JSON(http.StatusOK, nil)
}
// get items belonging to a certain invoice
@@ -201,22 +123,6 @@ func handleGetInvoiceItems (ctx *gin.Context) {
return
}
- uId, ok := ctx.Get("UserID")
- if !ok {
- ctx.Error(e.ErrUnauthorized)
- ctx.Abort()
- return
- }
-
- userId := uId.(uint)
-
- err = checkInvoiceOwnership(uint(id), userId)
- if err != nil {
- ctx.Error(err)
- ctx.Abort()
- return
- }
-
var items []InvoiceItem
err = getInvoiceItems(&items, uint(id))
if err != nil {
@@ -226,12 +132,12 @@ func handleGetInvoiceItems (ctx *gin.Context) {
}
ctx.JSON(http.StatusOK, gin.H{
- "message": "success",
"data": items,
})
}
func addItem (ctx *gin.Context) {
+ // TODO: only drafts can be edited
id, err := strconv.ParseUint(ctx.Param("id"), 10, 64)
if err != nil {
ctx.Error(e.ErrInvalidID)
@@ -239,27 +145,11 @@ func addItem (ctx *gin.Context) {
return
}
- uId, ok := ctx.Get("UserID")
- if !ok {
- ctx.Error(e.ErrUnauthorized)
- ctx.Abort()
- return
- }
-
- userId := uId.(uint)
-
var item InvoiceItem
ctx.Bind(&item)
item.InvoiceID = uint(id)
- err = checkInvoiceOwnership(item.InvoiceID, userId)
- if err != nil {
- ctx.Error(err)
- ctx.Abort()
- return
- }
-
err = item.upsert()
if err != nil {
ctx.Error(err)
@@ -267,13 +157,11 @@ func addItem (ctx *gin.Context) {
return
}
- ctx.JSON(http.StatusOK, gin.H{
- "message": "success",
- "data": item,
- })
+ ctx.JSON(http.StatusOK, nil)
}
func removeItem (ctx *gin.Context) {
+ // TODO: only drafts can be edited
id, err := strconv.ParseUint(ctx.Param("id"), 10, 64)
if err != nil {
ctx.Error(e.ErrInvalidID)
@@ -281,27 +169,9 @@ func removeItem (ctx *gin.Context) {
return
}
- uId, ok := ctx.Get("UserID")
- if !ok {
- ctx.Error(e.ErrUnauthorized)
- ctx.Abort()
- return
- }
-
- userId := uId.(uint)
-
var item InvoiceItem
item.ID = uint(id)
- invoiceId, err := getItemInvoice(item.ID, userId)
- if err != nil {
- ctx.Error(err)
- ctx.Abort()
- return
- }
-
- item.InvoiceID = invoiceId
-
err = item.del()
if err != nil {
ctx.Error(err)
@@ -309,10 +179,7 @@ func removeItem (ctx *gin.Context) {
return
}
- ctx.JSON(http.StatusOK, gin.H{
- "message": "success",
- "data": item,
- })
+ ctx.JSON(http.StatusOK, nil)
}
// get custom fields belonging to a certain invoice
@@ -324,22 +191,6 @@ func handleGetInvoiceCustomFields (ctx *gin.Context) {
return
}
- uId, ok := ctx.Get("UserID")
- if !ok {
- ctx.Error(e.ErrUnauthorized)
- ctx.Abort()
- return
- }
-
- userId := uId.(uint)
-
- err = checkInvoiceOwnership(uint(id), userId)
- if err != nil {
- ctx.Error(err)
- ctx.Abort()
- return
- }
-
var cf []CustomField
err = getInvoiceCustomFields(&cf, uint(id))
if err != nil {
@@ -349,12 +200,12 @@ func handleGetInvoiceCustomFields (ctx *gin.Context) {
}
ctx.JSON(http.StatusOK, gin.H{
- "message": "success",
"data": cf,
})
}
func addCustomField (ctx *gin.Context) {
+ // TODO: only drafts can be edited
id, err := strconv.ParseUint(ctx.Param("id"), 10, 64)
if err != nil {
ctx.Error(e.ErrInvalidID)
@@ -362,27 +213,10 @@ func addCustomField (ctx *gin.Context) {
return
}
- uId, ok := ctx.Get("UserID")
- if !ok {
- ctx.Error(e.ErrUnauthorized)
- ctx.Abort()
- return
- }
-
- userId := uId.(uint)
-
var cf CustomField
ctx.Bind(&cf)
-
cf.InvoiceID = uint(id)
- err = checkInvoiceOwnership(cf.InvoiceID, userId)
- if err != nil {
- ctx.Error(err)
- ctx.Abort()
- return
- }
-
err = cf.upsert()
if err != nil {
ctx.Error(err)
@@ -391,12 +225,12 @@ func addCustomField (ctx *gin.Context) {
}
ctx.JSON(http.StatusOK, gin.H{
- "message": "success",
"data": cf,
})
}
func removeCustomField (ctx *gin.Context) {
+ // TODO: only drafts can be edited
id, err := strconv.ParseUint(ctx.Param("id"), 10, 64)
if err != nil {
ctx.Error(e.ErrInvalidID)
@@ -404,27 +238,9 @@ func removeCustomField (ctx *gin.Context) {
return
}
- uId, ok := ctx.Get("UserID")
- if !ok {
- ctx.Error(e.ErrUnauthorized)
- ctx.Abort()
- return
- }
-
- userId := uId.(uint)
-
var cf CustomField
cf.ID = uint(id)
- invoiceId, err := getCustomFieldInvoice(cf.ID, userId)
- if err != nil {
- ctx.Error(err)
- ctx.Abort()
- return
- }
-
- cf.InvoiceID = invoiceId
-
err = cf.del()
if err != nil {
ctx.Error(err)
@@ -433,7 +249,6 @@ func removeCustomField (ctx *gin.Context) {
}
ctx.JSON(http.StatusOK, gin.H{
- "message": "success",
"data": cf,
})
}
diff --git a/invoice/invoice.go b/invoice/invoice.go
index 4397710..9fa931b 100644
--- a/invoice/invoice.go
+++ b/invoice/invoice.go
@@ -20,7 +20,6 @@ package invoice
import (
"gorm.io/gorm"
d "vidhukant.com/openbills/db"
- "vidhukant.com/openbills/user"
u "vidhukant.com/openbills/util"
i "vidhukant.com/openbills/item"
"time"
@@ -63,8 +62,6 @@ type CustomField struct {
type Invoice struct {
gorm.Model
- UserID uint `json:"-"`
- User user.User `json:"-"`
InvoiceDate time.Time
InvoiceNumber uint
BillingAddress InvoiceBillingAddress
diff --git a/invoice/router.go b/invoice/router.go
index febd8fd..f406786 100644
--- a/invoice/router.go
+++ b/invoice/router.go
@@ -24,8 +24,8 @@ import (
func Routes(route *gin.RouterGroup) {
g := route.Group("/invoice")
{
- g.GET("/", handleGetInvoices)
- g.GET("/draft", handleGetDrafts)
+ g.GET("/", handleGetInvoices(false))
+ g.GET("/draft", handleGetInvoices(true))
g.GET("/:id", handleGetSingleInvoice)
g.POST("/", handleSaveInvoice)
g.DELETE("/:id", handleDelInvoice)
diff --git a/invoice/service.go b/invoice/service.go
index 163b21e..55b1319 100644
--- a/invoice/service.go
+++ b/invoice/service.go
@@ -22,18 +22,12 @@ import (
)
// returns greatest invoice number + 1
-func getNewInvoiceNumber(userId uint) (uint, error) {
- var i uint
-
+func getNewInvoiceNumber() (uint, error) {
// check if number of invoices is 0
var count int64
- err := db.Model(&Invoice{}).
- Where("user_id = ?", userId).
- Count(&count).
- Error
-
+ err := db.Model(&Invoice{}).Count(&count).Error
if err != nil {
- return i, err
+ return 0, err
}
// if no records exist, then invoice number should be 1
@@ -45,7 +39,8 @@ func getNewInvoiceNumber(userId uint) (uint, error) {
// NOTE: if there are gaps in invoice numbers,
// they won't be filled and the series would continue
// from the greatest invoice number.
- row := db.Model(&Invoice{}).Where("user_id = ?", userId).Select("max(invoice_number)").Row()
+ var i uint
+ row := db.Model(&Invoice{}).Select("max(invoice_number)").Row()
err = row.Scan(&i)
return i + 1, err
@@ -66,8 +61,8 @@ func getInvoice(invoice *Invoice, id uint) error {
return nil
}
-func getInvoices(invoices *[]Invoice, userId uint, isDraft bool) error {
- res := db.Where("user_id = ? and is_draft = ?", userId, isDraft).Find(&invoices)
+func getInvoices(invoices *[]Invoice, isDraft bool) error {
+ res := db.Where("is_draft = ?", isDraft).Find(&invoices)
// TODO: handle potential errors
if res.Error != nil {
@@ -118,14 +113,13 @@ func (i *Invoice) upsert() error {
}
func (i *Invoice) del() error {
- res := db.Where("id = ? and user_id = ?", i.ID, i.UserID).Delete(i)
+ res := db.Where("id = ?", i.ID).Delete(i)
// TODO: handle potential errors
if res.Error != nil {
return res.Error
}
- // returns 404 if either row doesn't exist or if the user doesn't own it
if res.RowsAffected == 0 {
return e.ErrNotFound
}
@@ -133,8 +127,7 @@ func (i *Invoice) del() error {
return nil
}
-// also checks for ownership
-func getItemInvoice(itemId, userId uint) (uint, error) {
+func getItemInvoice(itemId uint) (uint, error) {
var invoiceId uint
res := db.
Model(&InvoiceItem{}).
@@ -151,17 +144,10 @@ func getItemInvoice(itemId, userId uint) (uint, error) {
return invoiceId, e.ErrNotFound
}
- err := checkInvoiceOwnership(invoiceId, userId)
-
- if err != nil {
- return invoiceId, err
- }
-
return invoiceId, nil
}
-// also checks for ownership
-func getCustomFieldInvoice(fieldId, userId uint) (uint, error) {
+func getCustomFieldInvoice(fieldId uint) (uint, error) {
var invoiceId uint
res := db.
Model(&CustomField{}).
@@ -178,12 +164,6 @@ func getCustomFieldInvoice(fieldId, userId uint) (uint, error) {
return invoiceId, e.ErrNotFound
}
- err := checkInvoiceOwnership(invoiceId, userId)
-
- if err != nil {
- return invoiceId, err
- }
-
return invoiceId, nil
}
@@ -195,7 +175,6 @@ func (i *InvoiceItem) del() error {
return res.Error
}
- // returns 404 if either row doesn't exist or if the user doesn't own it
if res.RowsAffected == 0 {
return e.ErrNotFound
}
@@ -211,7 +190,6 @@ func (c *CustomField) del() error {
return res.Error
}
- // returns 404 if either row doesn't exist or if the user doesn't own it
if res.RowsAffected == 0 {
return e.ErrNotFound
}
diff --git a/invoice/validators.go b/invoice/validators.go
index 9f145dc..1c39cbe 100644
--- a/invoice/validators.go
+++ b/invoice/validators.go
@@ -24,7 +24,7 @@ import (
func (i *Invoice) validate() error {
var count int64
err := db.Model(&Invoice{}).
- Where("user_id = ? and invoice_number = ?", i.UserID, i.InvoiceNumber).
+ Where("invoice_number = ?", i.InvoiceNumber).
Count(&count).
Error
@@ -59,29 +59,3 @@ func isDraft(invoiceId uint) (bool, error) {
return invoice.IsDraft, nil
}
-
-func checkInvoiceOwnership(invoiceId, userId uint) error {
- var invoice Invoice
- err := db.
- Select("id", "user_id").
- Where("id = ?", invoiceId).
- Find(&invoice).
- Error
-
- // TODO: handle potential errors
- if err != nil {
- return err
- }
-
- // invoice doesn't exist
- if invoice.ID == 0 {
- return errors.ErrNotFound
- }
-
- // user doesn't own this invoice
- if invoice.UserID != userId {
- return errors.ErrForbidden
- }
-
- return nil
-}