Compare commits
9 Commits
a52b108bf8
...
cb60cb39d5
Author | SHA1 | Date | |
---|---|---|---|
cb60cb39d5 | |||
3ce1c5c2d0 | |||
9cd9b20163 | |||
81b379afbd | |||
4244e397f3 | |||
dbe140ecaf | |||
b5747c9d9d | |||
bd2005bf5d | |||
953394335b |
|
@ -123,6 +123,10 @@ func main() {
|
|||
{
|
||||
metricRoutes.GET("/all", handlers.MetricGetAll)
|
||||
}
|
||||
paymentRoutes := api.Group("/payment", middleware.AuthMiddleware())
|
||||
{
|
||||
paymentRoutes.POST("/add", handlers.PaymentAdd)
|
||||
}
|
||||
}
|
||||
|
||||
r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
|
||||
|
|
|
@ -10,3 +10,7 @@ type UserIdentifiable interface {
|
|||
GetUserID() uint
|
||||
SetUserID(userID uint)
|
||||
}
|
||||
|
||||
type PaymentGroup interface {
|
||||
__internalBelogingToPayment()
|
||||
}
|
||||
|
|
43
db/item.go
43
db/item.go
|
@ -1,11 +1,16 @@
|
|||
package db
|
||||
|
||||
import "gorm.io/gorm"
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type Item struct {
|
||||
gorm.Model
|
||||
Name string
|
||||
Comment string
|
||||
Price uint64
|
||||
MetricType uint8
|
||||
MetricValue uint64
|
||||
//
|
||||
|
@ -16,7 +21,7 @@ type Item struct {
|
|||
Carbs uint64
|
||||
Fats uint64
|
||||
//
|
||||
Prices []ItemPrice
|
||||
Prices []ItemPrice `gorm:"constraint:OnDelete:CASCADE;"`
|
||||
CurrentPriceID uint
|
||||
CurrentPrice *ItemPrice
|
||||
//
|
||||
|
@ -26,6 +31,8 @@ type Item struct {
|
|||
User *User
|
||||
}
|
||||
|
||||
func (i Item) __internalBelogingToPayment() {}
|
||||
|
||||
// Implements db.UserIdentifiable:1
|
||||
func (i Item) GetID() uint {
|
||||
return i.ID
|
||||
|
@ -70,3 +77,35 @@ func GetItemToRootCat(id uint, preloadPrices bool) (*Item, error) {
|
|||
}).Preload("CurrentPrice").First(&item, id).Error
|
||||
return &item, err
|
||||
}
|
||||
|
||||
var (
|
||||
ERROR_ITEM_PRICE_ISZERO = errors.New("Item's Price is zero")
|
||||
ERROR_ITEM_ITEMPRICE_INTERR = errors.New("Item's ItemPrice ID is zero after creating")
|
||||
)
|
||||
|
||||
func (i *Item) BeforeCreate(tx *gorm.DB) error {
|
||||
if i.Price == 0 {
|
||||
return ERROR_ITEM_PRICE_ISZERO
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *Item) AfterCreate(tx *gorm.DB) error {
|
||||
if i.CurrentPriceID == 0 {
|
||||
itemPrice := &ItemPrice{
|
||||
ItemID: i.ID,
|
||||
Price: i.Price,
|
||||
}
|
||||
if err := tx.Create(itemPrice).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if itemPrice.ID == 0 {
|
||||
return ERROR_ITEM_ITEMPRICE_INTERR
|
||||
}
|
||||
i.CurrentPriceID = itemPrice.ID
|
||||
if err := tx.Save(i).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -15,3 +15,5 @@ type ItemBought struct {
|
|||
MetricType uint8
|
||||
MetricValue uint64
|
||||
}
|
||||
|
||||
func (i ItemBought) __internalBelogingToPayment() {}
|
||||
|
|
|
@ -18,6 +18,8 @@ type Payment struct {
|
|||
Title string
|
||||
Descr string
|
||||
Note string
|
||||
Items []ItemBought
|
||||
Items []ItemBought `gorm:"constraint:OnDelete:CASCADE;"`
|
||||
Date time.Time
|
||||
}
|
||||
|
||||
func (p Payment) __internalBelogingToPayment() {}
|
||||
|
|
|
@ -21,7 +21,7 @@ var itemTransform func(inp *db.Item) types.DbItem = func(inp *db.Item) types.DbI
|
|||
Proteins: inp.Proteins,
|
||||
Carbs: inp.Carbs,
|
||||
Fats: inp.Fats,
|
||||
Price: inp.CurrentPrice.Price,
|
||||
Price: inp.Price,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
146
handlers/payment.go
Normal file
146
handlers/payment.go
Normal file
|
@ -0,0 +1,146 @@
|
|||
package handlers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"git.qowevisa.me/Qowevisa/fin-check-api/db"
|
||||
"git.qowevisa.me/Qowevisa/fin-check-api/types"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
var itemBoughtTransform func(inp *db.ItemBought) types.ItemBought = func(inp *db.ItemBought) types.ItemBought {
|
||||
return types.ItemBought{}
|
||||
}
|
||||
|
||||
var paymentTransform func(inp *db.Payment) types.Payment = func(inp *db.Payment) types.Payment {
|
||||
var items []types.ItemBought
|
||||
for _, item := range inp.Items {
|
||||
items = append(items, itemBoughtTransform(&item))
|
||||
}
|
||||
return types.Payment{
|
||||
ID: inp.ID,
|
||||
CardID: inp.CardID,
|
||||
CategoryID: inp.CategoryID,
|
||||
Title: inp.Title,
|
||||
Description: inp.Descr,
|
||||
Note: inp.Note,
|
||||
Date: inp.Date,
|
||||
Items: items,
|
||||
}
|
||||
}
|
||||
|
||||
// @Summary Add payment
|
||||
// @Description Add payment
|
||||
// @Tags payment
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param Authorization header string true "Bearer token"
|
||||
// @Param payment body types.Payment true "Payment"
|
||||
// @Success 200 {object} types.Message
|
||||
// @Failure 400 {object} types.ErrorResponse
|
||||
// @Failure 500 {object} types.ErrorResponse
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /payment/add [post]
|
||||
func PaymentAdd(c *gin.Context) {
|
||||
userID, err := GetUserID(c)
|
||||
if err != nil {
|
||||
c.JSON(500, types.ErrorResponse{Message: err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
var updates types.Payment
|
||||
if err := c.ShouldBindJSON(&updates); err != nil {
|
||||
log.Printf("err is %v\n", err)
|
||||
c.JSON(400, types.ErrorResponse{Message: "Invalid request"})
|
||||
return
|
||||
}
|
||||
// As this handler will likely create more than one row in database we need to
|
||||
// create some sort of defer func that will rollback all created rows
|
||||
weNeedRollback := false
|
||||
var deletableIfRollback []db.PaymentGroup
|
||||
defer func() {
|
||||
if weNeedRollback {
|
||||
dbc := db.Connect()
|
||||
for _, deleteIt := range deletableIfRollback {
|
||||
if err := dbc.Debug().Delete(deleteIt).Error; err != nil {
|
||||
log.Printf("ERROR: dbc.Delete: %v\n", err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
dbc := db.Connect()
|
||||
|
||||
payment := &db.Payment{
|
||||
CardID: updates.CardID,
|
||||
CategoryID: updates.CategoryID,
|
||||
UserID: userID,
|
||||
Title: updates.Title,
|
||||
Descr: updates.Description,
|
||||
Note: updates.Note,
|
||||
Date: updates.Date,
|
||||
}
|
||||
if err := dbc.Debug().Create(payment).Error; err != nil {
|
||||
c.JSON(500, types.ErrorResponse{Message: err.Error()})
|
||||
weNeedRollback = true
|
||||
return
|
||||
}
|
||||
if payment.ID == 0 {
|
||||
c.JSON(500, types.ErrorResponse{Message: "Internal error: ERR.P.A.1"})
|
||||
weNeedRollback = true
|
||||
return
|
||||
}
|
||||
deletableIfRollback = append(deletableIfRollback, payment)
|
||||
for _, uItemBought := range updates.Items {
|
||||
// Creating item and adding it to rollback if itemID is set to 0
|
||||
if uItemBought.ItemID == 0 {
|
||||
newItem := &db.Item{
|
||||
Name: uItemBought.NewName,
|
||||
Comment: uItemBought.NewComment,
|
||||
Price: uItemBought.Price,
|
||||
MetricType: uItemBought.MetricType,
|
||||
MetricValue: uItemBought.MetricValue,
|
||||
CategoryID: updates.CategoryID,
|
||||
TypeID: uItemBought.TypeID,
|
||||
UserID: userID,
|
||||
}
|
||||
if err := dbc.Create(newItem).Error; err != nil {
|
||||
c.JSON(500, types.ErrorResponse{Message: err.Error()})
|
||||
weNeedRollback = true
|
||||
return
|
||||
}
|
||||
if newItem.ID == 0 {
|
||||
c.JSON(500, types.ErrorResponse{Message: "Internal error: ERR.P.A.2"})
|
||||
weNeedRollback = true
|
||||
return
|
||||
}
|
||||
deletableIfRollback = append(deletableIfRollback, newItem)
|
||||
newItemBought := &db.ItemBought{
|
||||
ItemID: newItem.ID,
|
||||
PaymentID: payment.ID,
|
||||
TypeID: uItemBought.TypeID,
|
||||
Quantity: uItemBought.Quantity,
|
||||
TotalCost: newItem.Price * uint64(uItemBought.Quantity),
|
||||
MetricType: uItemBought.MetricType,
|
||||
MetricValue: uItemBought.MetricValue,
|
||||
}
|
||||
if err := dbc.Create(newItemBought).Error; err != nil {
|
||||
c.JSON(500, types.ErrorResponse{Message: err.Error()})
|
||||
weNeedRollback = true
|
||||
return
|
||||
}
|
||||
if newItemBought.ID == 0 {
|
||||
c.JSON(500, types.ErrorResponse{Message: "Internal error: ERR.P.A.3"})
|
||||
weNeedRollback = true
|
||||
return
|
||||
}
|
||||
deletableIfRollback = append(deletableIfRollback, newItemBought)
|
||||
newItemBought.Item = newItem
|
||||
} else {
|
||||
// TODO: check if Item has same userID and potentially update Item
|
||||
}
|
||||
}
|
||||
|
||||
c.JSON(200, types.Message{Info: fmt.Sprintf("Entity with %d ID is created successfully!", payment.ID)})
|
||||
}
|
|
@ -65,16 +65,6 @@ type DbType struct {
|
|||
Color string `json:"color" example:"red"`
|
||||
}
|
||||
|
||||
type DbPayment struct {
|
||||
ID uint `json:"id" example:"1"`
|
||||
CardID uint `json:"card_id" example:"1"`
|
||||
CategoryID uint `json:"category_id" example:"1"`
|
||||
Title string `json:"title" example:"Veggies"`
|
||||
Descr string `json:"description" example:""`
|
||||
Note string `json:"not" example:"I'm a teapot"`
|
||||
Date time.Time `json:"date" example:"29/11/2001 12:00"`
|
||||
}
|
||||
|
||||
type Session struct {
|
||||
ID string `json:"id"`
|
||||
UserID uint `json:"user_id" example:"1"`
|
||||
|
@ -122,3 +112,28 @@ type DbMetric struct {
|
|||
Name string `json:"name" example:"Kilogram"`
|
||||
Short string `json:"short" example:"kg"`
|
||||
}
|
||||
|
||||
type Payment struct {
|
||||
ID uint `json:"id" example:"1"`
|
||||
CardID uint `json:"card_id" example:"1"`
|
||||
CategoryID uint `json:"category_id" example:"1"`
|
||||
Title string `json:"title" example:"some title"`
|
||||
Description string `json:"descr" example:"i bought some title for 20$"`
|
||||
Note string `json:"note" example:"no i did not hit domain"`
|
||||
Date time.Time `json:"date" example:"29/11/2001 12:00"`
|
||||
Items []ItemBought `json:"items" example:"[]"`
|
||||
}
|
||||
|
||||
type ItemBought struct {
|
||||
ID uint `json:"id" example:"1"`
|
||||
NewName string `json:"new_name" example:"itemName"`
|
||||
NewComment string `json:"new_comment" example:"itemName"`
|
||||
ItemID uint `json:"item_id" example:"0"`
|
||||
PaymentID uint `json:"payment_id" example:"1"`
|
||||
TypeID uint `json:"type_id" example:"1"`
|
||||
Price uint64 `json:"price" example:"1025"`
|
||||
Quantity uint `json:"quantity" example:"2"`
|
||||
TotalCost uint64 `json:"total_cost" example:"2050"`
|
||||
MetricType uint8 `json:"metric_type" example:"0"`
|
||||
MetricValue uint64 `json:"metric_value" example:"100"`
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user