diff options
| author | Vidhu Kant Sharma <vidhukant@vidhukant.com> | 2023-09-02 20:12:53 +0530 | 
|---|---|---|
| committer | Vidhu Kant Sharma <vidhukant@vidhukant.com> | 2023-09-02 20:12:53 +0530 | 
| commit | 127d4fb8ee7f8b141f9fb2f1a8fda45d350f34fc (patch) | |
| tree | 071e5e3cc928c7f0ad45430a971f8c9f9a856d96 /item | |
first commit
Diffstat (limited to 'item')
| -rw-r--r-- | item/controller.go | 156 | ||||
| -rw-r--r-- | item/hooks.go | 57 | ||||
| -rw-r--r-- | item/item.go | 52 | ||||
| -rw-r--r-- | item/router.go | 40 | ||||
| -rw-r--r-- | item/service.go | 126 | ||||
| -rw-r--r-- | item/validators.go | 111 | 
6 files changed, 542 insertions, 0 deletions
diff --git a/item/controller.go b/item/controller.go new file mode 100644 index 0000000..b4e27c1 --- /dev/null +++ b/item/controller.go @@ -0,0 +1,156 @@ +/* openbills - Server for web based Libre Billing Software + * Copyright (C) 2023  Vidhu Kant Sharma <vidhukant@vidhukant.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <https://www.gnu.org/licenses/>. + */ + +package item + +import ( +	e "vidhukant.com/openbills/errors" +	"github.com/gin-gonic/gin" +	"net/http" +	"strconv" +) + +func handleGetBrandItems (ctx *gin.Context) { +	id, err := strconv.ParseUint(ctx.Param("id"), 10, 64) +	if err != nil { +		ctx.Error(e.ErrInvalidID) +		return +	} + +	var items []SavedItem +	err = getBrandItems(&items, uint(id)) +	if err != nil { +		ctx.Error(err) +		ctx.Abort() +		return +	} + +	ctx.JSON(http.StatusOK, gin.H{ +		"message": "success", +		"data": items, +	}) +} + +func handleGetBrands (ctx *gin.Context) { +	var brands []Brand + +	err := getBrands(&brands) +	if err != nil { +		ctx.Error(err) +		ctx.Abort() +		return +	} + +	ctx.JSON(http.StatusOK, gin.H{ +		"message": "success", +		"data": brands, +	}) +} + +func handleSaveBrand (ctx *gin.Context) { +	var brand Brand +	ctx.Bind(&brand) + +	err := brand.upsert() +	if err != nil { +		ctx.Error(err) +		ctx.Abort() +		return +	} + +	ctx.JSON(http.StatusOK, gin.H{ +		"message": "success", +		"data": brand, +	}) +} + +func handleDelBrand (ctx *gin.Context) { +	id, err := strconv.ParseUint(ctx.Param("id"), 10, 64) +	if err != nil { +		ctx.Error(e.ErrInvalidID) +		return +	} + +	var brand Brand +	brand.ID = uint(id) + +	err = brand.del() +	if err != nil { +		ctx.Error(err) +		ctx.Abort() +		return +	} + +	ctx.JSON(http.StatusOK, gin.H{ +		"message": "success", +	}) +} + +func handleGetItems (ctx *gin.Context) { +	var items []SavedItem + +	err := getItems(&items) +	if err != nil { +		ctx.Error(err) +		ctx.Abort() +		return +	} + +	ctx.JSON(http.StatusOK, gin.H{ +		"message": "success", +		"data": items, +	}) +} + +func handleSaveItem (ctx *gin.Context) { +	var item SavedItem +	ctx.Bind(&item) + +	err := item.upsert() +	if err != nil { +		ctx.Error(err) +		ctx.Abort() +		return +	} + +	ctx.JSON(http.StatusOK, gin.H{ +		"message": "success", +		"data": item, +	}) +} + +func handleDelItem (ctx *gin.Context) { +	id, err := strconv.ParseUint(ctx.Param("id"), 10, 64) +	if err != nil { +		ctx.Error(e.ErrInvalidID) +		return +	} + +	var item SavedItem +	item.ID = uint(id) + +	err = item.del() +	if err != nil { +		ctx.Error(err) +		ctx.Abort() +		return +	} + +	ctx.JSON(http.StatusOK, gin.H{ +		"message": "success", +	}) +} diff --git a/item/hooks.go b/item/hooks.go new file mode 100644 index 0000000..ddb9a44 --- /dev/null +++ b/item/hooks.go @@ -0,0 +1,57 @@ +/* openbills - Server for web based Libre Billing Software + * Copyright (C) 2023  Vidhu Kant Sharma <vidhukant@vidhukant.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <https://www.gnu.org/licenses/>. + */ + +package item + +import ( +	"gorm.io/gorm" +	"vidhukant.com/openbills/errors" +) + +func (i *SavedItem) BeforeSave(tx *gorm.DB) error { +	var err error + +	err = checkIfBrandExists(i.BrandID) +	if err != nil { +		return err +	} + +	err = i.validate() +	if err != nil { +		return err +	} + +	return nil +} + +func (b *Brand) BeforeSave(tx *gorm.DB) error { +	err := b.validate() +	if err != nil { +		return err +	} + +	return nil +} + +func (b *Brand) BeforeDelete(tx *gorm.DB) error { +  // if ID is 0, brand won't be deleted +	if b.ID == 0 { +		return errors.ErrNoWhereCondition +	} + +	return nil +} diff --git a/item/item.go b/item/item.go new file mode 100644 index 0000000..4da9c78 --- /dev/null +++ b/item/item.go @@ -0,0 +1,52 @@ +/* openbills - Server for web based Libre Billing Software + * Copyright (C) 2023  Vidhu Kant Sharma <vidhukant@vidhukant.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <https://www.gnu.org/licenses/>. + */ + +package item + +import ( +	"gorm.io/gorm" +	d "vidhukant.com/openbills/db" +) + +var db *gorm.DB +func init() { +	db = d.DB + +	db.AutoMigrate(&SavedItem{}, &Brand{}) +} + +type Brand struct { +	gorm.Model +	Name  string +} + +type Item struct { +	BrandID            uint +	Brand              Brand +	UnitOfMeasure      string // TODO: probably has to be a custom type +	HasDecimalQuantity bool +	Name               string +	Description        string +	HSN                string +	UnitPrice          string // float +	GSTPercentage      string // float +} + +type SavedItem struct { +	gorm.Model +	Item +} diff --git a/item/router.go b/item/router.go new file mode 100644 index 0000000..fab973f --- /dev/null +++ b/item/router.go @@ -0,0 +1,40 @@ +/* openbills - Server for web based Libre Billing Software + * Copyright (C) 2023  Vidhu Kant Sharma <vidhukant@vidhukant.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <https://www.gnu.org/licenses/>. + */ + +package item + +import ( +	"github.com/gin-gonic/gin" +) + +func Routes(route *gin.RouterGroup) { +	b := route.Group("/brand") +	{ +		b.GET("/", handleGetBrands) +		b.GET("/:id/items", handleGetBrandItems) +		b.POST("/", handleSaveBrand) +		b.DELETE("/:id", handleDelBrand) +	} + +	i := route.Group("/item") +	{ +		i.GET("/", handleGetItems) +		//i.GET("/:id", handleGetBrandItems) +		i.POST("/", handleSaveItem) +		i.DELETE("/:id", handleDelItem) +	} +} diff --git a/item/service.go b/item/service.go new file mode 100644 index 0000000..c8a72f6 --- /dev/null +++ b/item/service.go @@ -0,0 +1,126 @@ +/* openbills - Server for web based Libre Billing Software + * Copyright (C) 2023  Vidhu Kant Sharma <vidhukant@vidhukant.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <https://www.gnu.org/licenses/>. + */ + +package item + +import ( +	"vidhukant.com/openbills/errors" +	e "vidhukant.com/openbills/errors" +) + +func getBrandItems(items *[]SavedItem, id uint) error { +	// check if id is valid +	var count int64 +	err := db.Model(&Brand{}). +		Select("id"). +		Where("id = ?", id). +		Count(&count). +		Error + +	if err != nil { +		return err +  } + +	if count == 0 { +		return errors.ErrBrandNotFound +	} + +	res := db.Model(&SavedItem{}).Where("brand_id = ?", id).Find(&items) + +	// TODO: handle potential errors +	if res.Error != nil { +		return res.Error +	} + +	if res.RowsAffected == 0 { +		return e.ErrEmptyResponse +	} + +	return nil +} + +func getBrands(brands *[]Brand) error { +	res := db.Find(&brands) + +	// TODO: handle potential errors +	if res.Error != nil { +		return res.Error +	} + +	if res.RowsAffected == 0 { +		return e.ErrEmptyResponse +	} + +	return nil +} + +func (b *Brand) upsert() error { +	res := db.Save(b) +	// TODO: handle potential errors +	return res.Error +} + +func (b *Brand) del() error { +	res := db.Delete(b) + +	// TODO: handle potential errors +	if res.Error != nil { +		return res.Error +	} + +	if res.RowsAffected == 0 { +		return e.ErrNotFound +	} + +	return nil +} + +func getItems(items *[]SavedItem) error { +	res := db.Preload("Brand").Find(&items) + +	// TODO: handle potential errors +	if res.Error != nil { +		return res.Error +	} + +	if res.RowsAffected == 0 { +		return e.ErrEmptyResponse +	} + +	return nil +} + +func (i *SavedItem) upsert() error { +	res := db.Save(i) +	// TODO: handle potential errors +	return res.Error +} + +func (i *SavedItem) del() error { +	res := db.Delete(i) + +	// TODO: handle potential errors +	if res.Error != nil { +		return res.Error +	} + +	if res.RowsAffected == 0 { +		return e.ErrNotFound +	} + +	return nil +} diff --git a/item/validators.go b/item/validators.go new file mode 100644 index 0000000..09162ab --- /dev/null +++ b/item/validators.go @@ -0,0 +1,111 @@ +/* openbills - Server for web based Libre Billing Software + * Copyright (C) 2023  Vidhu Kant Sharma <vidhukant@vidhukant.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <https://www.gnu.org/licenses/>. + */ + +package item + +import ( +	"strconv" +	"strings" + +	"vidhukant.com/openbills/errors" +) + +func (b *Brand) validate() error { +	// trim whitespaces +	b.Name = strings.TrimSpace(b.Name) + +	if b.Name == "" { +		return errors.ErrEmptyBrandName +	} + +	// make sure GSTIN is unique +	var count int64 +	err := db.Model(&Brand{}). +		Select("name"). +		Where("name = ?", b.Name). +		Count(&count). +		Error + +	if err != nil { +		return err +	} + +	if count > 0 { +		return errors.ErrNonUniqueBrandName +	} + +	return nil +} + +func checkIfBrandExists(id uint) error { +	// check if brand id is valid +	var count int64 +	err := db.Model(&Brand{}). +		Select("id"). +		Where("id = ?", id). +		Count(&count). +		Error + +	if err != nil { +		return err +  } + +	if count == 0 { +		return errors.ErrBrandNotFound +	} + +	return nil +} + +func (i *SavedItem) validate() error { +	// trim whitespaces +	i.Name = strings.TrimSpace(i.Name) +	i.Description = strings.TrimSpace(i.Description) +	i.HSN = strings.TrimSpace(i.HSN) + +	var err error + +	// check if UnitPrice is float +	_, err = strconv.ParseFloat(i.UnitPrice, 64) +	if err != nil && strings.TrimSpace(i.UnitPrice) != "" { +		return errors.ErrInvalidUnitPrice +	} + +	// check if GSTPercentage is float +	_, err = strconv.ParseFloat(i.GSTPercentage, 64) +	if err != nil && strings.TrimSpace(i.GSTPercentage) != "" { +		return errors.ErrInvalidGSTPercentage +	} + +	// check if item with same name and brand already exists +	var count int64 +	err = db.Model(&SavedItem{}). +		Select("name, brand_id"). +		Where("brand_id = ? and name = ?", i.BrandID, i.Name). +		Count(&count). +		Error + +	if err != nil { +		return err +  } + +	if count != 0 { +		return errors.ErrNonUniqueBrandItem +	} + +	return nil +}  |