diff options
| author | Vidhu Kant Sharma <vidhukant@vidhukant.com> | 2024-07-09 07:58:34 +0530 | 
|---|---|---|
| committer | Vidhu Kant Sharma <vidhukant@vidhukant.com> | 2024-07-09 07:58:34 +0530 | 
| commit | d0a44ff5cfad5d063929426e2420f6f0d55b1dbe (patch) | |
| tree | 476ad4ff14e39bed40049b4d1cba296c6d395c1b /invoice | |
| parent | 908fb4b2b0fd1c31aa8c1cc87f56d490b42aca7a (diff) | |
added custom fields support
Diffstat (limited to 'invoice')
| -rw-r--r-- | invoice/controller.go | 124 | ||||
| -rw-r--r-- | invoice/hooks.go | 32 | ||||
| -rw-r--r-- | invoice/invoice.go | 16 | ||||
| -rw-r--r-- | invoice/router.go | 4 | ||||
| -rw-r--r-- | invoice/service.go | 66 | 
5 files changed, 234 insertions, 8 deletions
diff --git a/invoice/controller.go b/invoice/controller.go index d3dd51c..ad6df3e 100644 --- a/invoice/controller.go +++ b/invoice/controller.go @@ -210,7 +210,6 @@ func handleGetInvoiceItems (ctx *gin.Context) {  	userId := uId.(uint) -  	err = checkInvoiceOwnership(uint(id), userId)  	if err != nil {  		ctx.Error(err) @@ -315,3 +314,126 @@ func removeItem (ctx *gin.Context) {  		"data": item,  	})  } + +// get custom fields belonging to a certain invoice +func handleGetInvoiceCustomFields (ctx *gin.Context) { +	id, err := strconv.ParseUint(ctx.Param("id"), 10, 64) +	if err != nil { +		ctx.Error(e.ErrInvalidID) +		ctx.Abort() +		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 { +		ctx.Error(err) +		ctx.Abort() +		return +	} + +	ctx.JSON(http.StatusOK, gin.H{ +		"message": "success", +		"data": cf, +	}) +} + +func addCustomField (ctx *gin.Context) { +	id, err := strconv.ParseUint(ctx.Param("id"), 10, 64) +	if err != nil { +		ctx.Error(e.ErrInvalidID) +		ctx.Abort() +		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) +		ctx.Abort() +		return +	} + +	ctx.JSON(http.StatusOK, gin.H{ +		"message": "success", +		"data": cf, +	}) +} + +func removeCustomField (ctx *gin.Context) { +	id, err := strconv.ParseUint(ctx.Param("id"), 10, 64) +	if err != nil { +		ctx.Error(e.ErrInvalidID) +		ctx.Abort() +		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) +		ctx.Abort() +		return +	} + +	ctx.JSON(http.StatusOK, gin.H{ +		"message": "success", +		"data": cf, +	}) +} diff --git a/invoice/hooks.go b/invoice/hooks.go index 7a59352..b0ec877 100644 --- a/invoice/hooks.go +++ b/invoice/hooks.go @@ -85,3 +85,35 @@ func (i *InvoiceItem) BeforeDelete(tx *gorm.DB) error {  	return nil  } + +func (cf *CustomField) BeforeSave(tx *gorm.DB) error { +	var err error + +	isDraft, err := isDraft(cf.InvoiceID) +	if err != nil { +		return err +	} + +	if !isDraft { +		return errors.ErrCannotEditInvoice +	} + +	// TODO: check if field is duplicate + +	return nil +} + +func (cf *CustomField) BeforeDelete(tx *gorm.DB) error { +	var err error + +	isDraft, err := isDraft(cf.InvoiceID) +	if err != nil { +		return err +	} + +	if !isDraft { +		return errors.ErrCannotEditInvoice +	} + +	return nil +} diff --git a/invoice/invoice.go b/invoice/invoice.go index 4b93ee4..4397710 100644 --- a/invoice/invoice.go +++ b/invoice/invoice.go @@ -30,7 +30,7 @@ var db *gorm.DB  func init() {  	db = d.DB -	db.AutoMigrate(&Invoice{}, &InvoiceItem{}, &InvoiceBillingAddress{}, &InvoiceShippingAddress{}) +	db.AutoMigrate(&Invoice{}, &InvoiceItem{}, &InvoiceBillingAddress{}, &InvoiceShippingAddress{}, &CustomField{})  }  type InvoiceBillingAddress struct { @@ -46,13 +46,21 @@ type InvoiceShippingAddress struct {  }  type InvoiceItem struct { -	gorm.Model  	i.Item +	ID        uint  	InvoiceID uint  	BrandName string  	Quantity  string // float  } +// user can add as many custom fields as they like +type CustomField struct { +	ID        uint +	InvoiceID uint +	Key       string +	Value     string +} +  type Invoice struct {  	gorm.Model  	UserID          uint      `json:"-"` @@ -64,6 +72,7 @@ type Invoice struct {  	IsDraft         bool  	Note            string  	Items           []InvoiceItem +	CustomFields    []CustomField    // issuer and customer details are stored here     // because they are NOT intended to ever change @@ -80,7 +89,4 @@ type Invoice struct {  	CustomerPhone       string  	CustomerEmail       string  	CustomerWebsite     string - -	// Transporter     Transporter -	// TransactionID   string  } diff --git a/invoice/router.go b/invoice/router.go index 290eacb..febd8fd 100644 --- a/invoice/router.go +++ b/invoice/router.go @@ -32,5 +32,9 @@ func Routes(route *gin.RouterGroup) {  		g.GET("/:id/item", handleGetInvoiceItems)  		g.POST("/:id/item", addItem)  		g.DELETE("/item/:id", removeItem) +		g.GET("/:id/custom", handleGetInvoiceCustomFields) +		g.POST("/:id/custom", addCustomField) +		g.DELETE("/custom/:id", removeCustomField) +		//g.PUT("/custom/:id", editCustomField)  	}  } diff --git a/invoice/service.go b/invoice/service.go index 91579c6..163b21e 100644 --- a/invoice/service.go +++ b/invoice/service.go @@ -52,7 +52,7 @@ func getNewInvoiceNumber(userId uint) (uint, error) {  }  func getInvoice(invoice *Invoice, id uint) error { -	res := db.Preload("BillingAddress").Preload("ShippingAddress").Preload("Items").Find(&invoice, id) +	res := db.Preload("BillingAddress").Preload("ShippingAddress").Preload("Items").Preload("CustomFields").Find(&invoice, id)  	// TODO: handle potential errors  	if res.Error != nil { @@ -96,7 +96,20 @@ func getInvoiceItems(items *[]InvoiceItem, invoiceId uint) error {  	return nil  } -// TODO: route to only get the invouce's items +func getInvoiceCustomFields(customFields *[]CustomField, invoiceId uint) error { +	res := db.Where("invoice_id = ?", invoiceId).Find(&customFields) + +	// TODO: handle potential errors +	if res.Error != nil { +		return res.Error +	} + +	if res.RowsAffected == 0 { +		return e.ErrEmptyResponse +	} + +	return nil +}  func (i *Invoice) upsert() error {  	res := db.Save(i) @@ -147,6 +160,33 @@ func getItemInvoice(itemId, userId uint) (uint, error) {  	return invoiceId, nil  } +// also checks for ownership +func getCustomFieldInvoice(fieldId, userId uint) (uint, error) { +	var invoiceId uint +	res := db. +		Model(&CustomField{}). +		Select("invoice_id"). +		Where("id = ?", fieldId). +		Find(&invoiceId) + +	// TODO: handle potential errors +	if res.Error != nil { +		return invoiceId, res.Error +	} + +	if res.RowsAffected == 0 { +		return invoiceId, e.ErrNotFound +	} + +	err := checkInvoiceOwnership(invoiceId, userId) + +	if err != nil { +		return invoiceId, err +	} + +	return invoiceId, nil +} +  func (i *InvoiceItem) del() error {  	res := db.Delete(i) @@ -163,8 +203,30 @@ func (i *InvoiceItem) del() error {  	return nil  } +func (c *CustomField) del() error { +	res := db.Delete(c) + +	// 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 +	} + +	return nil +} +  func (i *InvoiceItem) upsert() error {  	res := db.Save(i)  	// TODO: handle potential errors  	return res.Error  } + +func (c *CustomField) upsert() error { +	res := db.Save(c) +	// TODO: handle potential errors +	return res.Error +}  |