diff --git a/wagfarm-api/Schlagkartei52.xlsm b/wagfarm-api/Schlagkartei52.xlsm deleted file mode 100755 index 8401b7a..0000000 Binary files a/wagfarm-api/Schlagkartei52.xlsm and /dev/null differ diff --git a/wagfarm-api/asset/asset.go b/wagfarm-api/asset/asset.go deleted file mode 100644 index 8213a4b..0000000 --- a/wagfarm-api/asset/asset.go +++ /dev/null @@ -1,28 +0,0 @@ -package asset - -import ( - "wagfarm-api/asset/fertilizer" - "wagfarm-api/asset/land" - "wagfarm-api/asset/machine" - "wagfarm-api/asset/pesticide" - "wagfarm-api/asset/plant" - "wagfarm-api/asset/product" - "wagfarm-api/asset/seed" - - "github.com/gin-gonic/gin" -) - -const Models []interface{} { - -} - -func RegisterRoutes(rg *gin.RouterGroup) { - group := rg.Group("/asset") - fertilizer.RegisterRoutes(group) - land.RegisterRoutes(group) - machine.RegisterRoutes(group) - pesticide.RegisterRoutes(group) - plant.RegisterRoutes(group) - product.RegisterRoutes(group) - seed.RegisterRoutes(group) -} diff --git a/wagfarm-api/asset/fertilizer/model.go b/wagfarm-api/asset/fertilizer/model.go deleted file mode 100644 index d607f42..0000000 --- a/wagfarm-api/asset/fertilizer/model.go +++ /dev/null @@ -1,20 +0,0 @@ -package fertilizer - -import "wagfarm-api/asset/base" - -type Fertilizer struct { - base.BoughtResource - FertilizerTypeID uint `gorm:"not null"` - FertilizerType FertilizerType `gorm:"not null; constraint:OnUpdate:CASCADE,OnDelete:CASCADE;"` - // Association to the ingredients. This represents the composition. - Ingredients []FertilizerIngredient `gorm:"not null; many2many:fertilizer_ingredient"` -} - -type FertilizerIngredient struct { - FertilizerAssetID uint `gorm:"primaryKey"` // foreign key to the fertilizer asset - IngredientID uint `gorm:"primaryKey"` // foreign key to the ingredient - Amount float64 `gorm:"not null"` // amount of the ingredient - - // Preload the ingredient details if needed. - Ingredient Ingredient `gorm:"not null"` -} diff --git a/wagfarm-api/asset/machine/model.go b/wagfarm-api/asset/machine/model.go deleted file mode 100644 index 7f23b33..0000000 --- a/wagfarm-api/asset/machine/model.go +++ /dev/null @@ -1,9 +0,0 @@ -package machine - -import ( - "wagfarm-api/asset/base" -) - -type Machine struct { - base.Resource -} diff --git a/wagfarm-api/asset/pesticide/model.go b/wagfarm-api/asset/pesticide/model.go deleted file mode 100644 index 85be35a..0000000 --- a/wagfarm-api/asset/pesticide/model.go +++ /dev/null @@ -1,9 +0,0 @@ -package pesticide - -import "wagfarm-api/asset/base" - -type Pesticide struct { - base.BoughtResource - PesticideTypeID uint `gorm:"not null"` - PesticideType PesticideType `gorm:"not null; constraint:OnUpdate:CASCADE,OnDelete:CASCADE;"` -} diff --git a/wagfarm-api/asset/product/model.go b/wagfarm-api/asset/product/model.go deleted file mode 100644 index dd71d30..0000000 --- a/wagfarm-api/asset/product/model.go +++ /dev/null @@ -1,9 +0,0 @@ -package product - -import "wagfarm-api/asset/base" - -type Product struct { - base.SoldResource - ProductTypeID uint `gorm:"not null"` - ProductType ProductType `gorm:"not null; constraint:OnUpdate:CASCADE,OnDelete:CASCADE;"` -} diff --git a/wagfarm-api/asset/seed/model.go b/wagfarm-api/asset/seed/model.go deleted file mode 100644 index b5dc3ea..0000000 --- a/wagfarm-api/asset/seed/model.go +++ /dev/null @@ -1,11 +0,0 @@ -package seed - -import ( - "wagfarm-api/asset/base" -) - -type Seed struct { - base.BoughtResource - SeedTypeID uint `gorm:"not null"` - SeedType SeedType `gorm:"not null; constraint:OnUpdate:CASCADE,OnDelete:CASCADE;"` -} diff --git a/wagfarm-api/assets/assets.go b/wagfarm-api/assets/assets.go new file mode 100644 index 0000000..97dc921 --- /dev/null +++ b/wagfarm-api/assets/assets.go @@ -0,0 +1,36 @@ +package assets + +import ( + "wagfarm-api/assets/fertilizer" + "wagfarm-api/assets/land" + "wagfarm-api/assets/machine" + "wagfarm-api/assets/pesticide" + "wagfarm-api/assets/plant" + "wagfarm-api/assets/product" + "wagfarm-api/assets/seed" + + "github.com/gin-gonic/gin" +) + +var Models = []any{} + +func RegisterModels() { + fertilizer.RegisterModels() + land.RegisterModels() + machine.RegisterModels() + pesticide.RegisterModels() + plant.RegisterModels() + product.RegisterModels() + seed.RegisterModels() +} + +func RegisterRoutes(rg *gin.RouterGroup) { + group := rg.Group("/assets") + fertilizer.RegisterRoutes(group) + land.RegisterRoutes(group) + machine.RegisterRoutes(group) + pesticide.RegisterRoutes(group) + plant.RegisterRoutes(group) + product.RegisterRoutes(group) + seed.RegisterRoutes(group) +} diff --git a/wagfarm-api/asset/base/model.go b/wagfarm-api/assets/base/model.go similarity index 55% rename from wagfarm-api/asset/base/model.go rename to wagfarm-api/assets/base/model.go index f32bd6c..c462d9a 100644 --- a/wagfarm-api/asset/base/model.go +++ b/wagfarm-api/assets/base/model.go @@ -1,5 +1,14 @@ package base +import ( + "time" + "wagfarm-api/taxonomy/customer" + "wagfarm-api/taxonomy/seller" + "wagfarm-api/taxonomy/unit" + + "github.com/shopspring/decimal" +) + type Asset struct { ID uint `gorm:"primaryKey` Name string `gorm:"not null"` @@ -17,14 +26,14 @@ type Resource struct { type BoughtResource struct { Resource - BuyDate Datetime.Time `gorm:"type:date;default:CURRENT_DATE"` + BuyDate time.Time `gorm:"not null"` BoughtFromID uint `gorm:"not null"` - BoughtFrom Seller `gorm:"not null; constraint:OnUpdate:CASCADE,OnDelete:CASCADE;"` + BoughtFrom seller.Seller `gorm:"not null; constraint:OnUpdate:CASCADE,OnDelete:CASCADE;"` } type SoldResource struct { Resource - SaleDate Datetime.Time `gorm:"type:date;default:CURRENT_DATE"` - SoldToID uint `gorm:"not null"` - SoldTo Customer `gorm:"not null; constraint:OnUpdate:CASCADE,OnDelete:CASCADE;"` + SaleDate time.Time `gorm:"not null"` + SoldToID uint `gorm:"not null"` + SoldTo customer.Customer `gorm:"not null; constraint:OnUpdate:CASCADE,OnDelete:CASCADE;"` } diff --git a/wagfarm-api/assets/fertilizer/model.go b/wagfarm-api/assets/fertilizer/model.go new file mode 100644 index 0000000..18b33e9 --- /dev/null +++ b/wagfarm-api/assets/fertilizer/model.go @@ -0,0 +1,30 @@ +package fertilizer + +import ( + "wagfarm-api/assets/base" + "wagfarm-api/database" + "wagfarm-api/taxonomy/fertilizertype" + "wagfarm-api/taxonomy/ingredient" +) + +type Fertilizer struct { + base.BoughtResource + FertilizerTypeID uint `gorm:"not null"` + FertilizerType fertilizertype.FertilizerType `gorm:"not null; constraint:OnUpdate:CASCADE,OnDelete:CASCADE;"` + // Association to the ingredients. This represents the composition. + Ingredients []FertilizerIngredient `gorm:"not null; many2many:fertilizer_ingredient"` +} + +type FertilizerIngredient struct { + FertilizerAssetID uint `gorm:"primaryKey"` // foreign key to the fertilizer assets + IngredientID uint `gorm:"primaryKey"` // foreign key to the ingredient + Amount float64 `gorm:"not null"` // amount of the ingredient + + // Preload the ingredient details if needed. + Ingredient ingredient.Ingredient `gorm:"not null"` +} + +func RegisterModels() { + database.RegisterModel(&Fertilizer{}) + database.RegisterJoinTable(&Fertilizer{}, "Ingredients", &FertilizerIngredient{}) +} diff --git a/wagfarm-api/asset/fertilizer/route.go b/wagfarm-api/assets/fertilizer/route.go similarity index 100% rename from wagfarm-api/asset/fertilizer/route.go rename to wagfarm-api/assets/fertilizer/route.go diff --git a/wagfarm-api/asset/land/model.go b/wagfarm-api/assets/land/model.go similarity index 66% rename from wagfarm-api/asset/land/model.go rename to wagfarm-api/assets/land/model.go index 9d73b2f..0072b32 100644 --- a/wagfarm-api/asset/land/model.go +++ b/wagfarm-api/assets/land/model.go @@ -1,6 +1,9 @@ package land -import "wagfarm-api/asset/base" +import ( + "wagfarm-api/assets/base" + "wagfarm-api/database" +) type Land struct { base.Asset @@ -9,3 +12,5 @@ type Land struct { IsRedArea bool `gorm:"not null"` Area float64 `gorm:"not null"` } + +func RegisterModels() { database.RegisterModel(&Land{}) } diff --git a/wagfarm-api/asset/land/route.go b/wagfarm-api/assets/land/route.go similarity index 100% rename from wagfarm-api/asset/land/route.go rename to wagfarm-api/assets/land/route.go diff --git a/wagfarm-api/assets/machine/model.go b/wagfarm-api/assets/machine/model.go new file mode 100644 index 0000000..0d13bad --- /dev/null +++ b/wagfarm-api/assets/machine/model.go @@ -0,0 +1,12 @@ +package machine + +import ( + "wagfarm-api/assets/base" + "wagfarm-api/database" +) + +type Machine struct { + base.Resource +} + +func RegisterModels() { database.RegisterModel(&Machine{}) } diff --git a/wagfarm-api/asset/machine/route.go b/wagfarm-api/assets/machine/route.go similarity index 100% rename from wagfarm-api/asset/machine/route.go rename to wagfarm-api/assets/machine/route.go diff --git a/wagfarm-api/assets/pesticide/model.go b/wagfarm-api/assets/pesticide/model.go new file mode 100644 index 0000000..b6da992 --- /dev/null +++ b/wagfarm-api/assets/pesticide/model.go @@ -0,0 +1,15 @@ +package pesticide + +import ( + "wagfarm-api/assets/base" + "wagfarm-api/database" + "wagfarm-api/taxonomy/pesticidetype" +) + +type Pesticide struct { + base.BoughtResource + PesticideTypeID uint `gorm:"not null"` + PesticideType pesticidetype.PesticideType `gorm:"not null; constraint:OnUpdate:CASCADE,OnDelete:CASCADE;"` +} + +func RegisterModels() { database.RegisterModel(&Pesticide{}) } diff --git a/wagfarm-api/asset/pesticide/route.go b/wagfarm-api/assets/pesticide/route.go similarity index 100% rename from wagfarm-api/asset/pesticide/route.go rename to wagfarm-api/assets/pesticide/route.go diff --git a/wagfarm-api/asset/plant/model.go b/wagfarm-api/assets/plant/model.go similarity index 76% rename from wagfarm-api/asset/plant/model.go rename to wagfarm-api/assets/plant/model.go index b4f1b49..ae1670f 100644 --- a/wagfarm-api/asset/plant/model.go +++ b/wagfarm-api/assets/plant/model.go @@ -1,8 +1,10 @@ package plant import ( - "wagfarm-api/asset/base" - "wagfarm-api/asset/land" + "wagfarm-api/assets/base" + "wagfarm-api/assets/land" + "wagfarm-api/database" + "wagfarm-api/taxonomy/crop" ) type Plant struct { @@ -16,3 +18,5 @@ type Plant struct { Year uint `gorm:"not null"` AreaPercentage float64 `gorm:"not null"` } + +func RegisterModels() { database.RegisterModel(&Plant{}) } diff --git a/wagfarm-api/asset/plant/route.go b/wagfarm-api/assets/plant/route.go similarity index 100% rename from wagfarm-api/asset/plant/route.go rename to wagfarm-api/assets/plant/route.go diff --git a/wagfarm-api/assets/product/model.go b/wagfarm-api/assets/product/model.go new file mode 100644 index 0000000..6d34d06 --- /dev/null +++ b/wagfarm-api/assets/product/model.go @@ -0,0 +1,15 @@ +package product + +import ( + "wagfarm-api/assets/base" + "wagfarm-api/database" + "wagfarm-api/taxonomy/producttype" +) + +type Product struct { + base.SoldResource + ProductTypeID uint `gorm:"not null"` + ProductType producttype.ProductType `gorm:"not null; constraint:OnUpdate:CASCADE,OnDelete:CASCADE;"` +} + +func RegisterModels() { database.RegisterModel(&Product{}) } diff --git a/wagfarm-api/asset/product/route.go b/wagfarm-api/assets/product/route.go similarity index 100% rename from wagfarm-api/asset/product/route.go rename to wagfarm-api/assets/product/route.go diff --git a/wagfarm-api/assets/seed/model.go b/wagfarm-api/assets/seed/model.go new file mode 100644 index 0000000..2b332ac --- /dev/null +++ b/wagfarm-api/assets/seed/model.go @@ -0,0 +1,15 @@ +package seed + +import ( + "wagfarm-api/assets/base" + "wagfarm-api/database" + "wagfarm-api/taxonomy/seedtype" +) + +type Seed struct { + base.BoughtResource + SeedTypeID uint `gorm:"not null"` + SeedType seedtype.SeedType `gorm:"not null; constraint:OnUpdate:CASCADE,OnDelete:CASCADE;"` +} + +func RegisterModels() { database.RegisterModel(&Seed{}) } diff --git a/wagfarm-api/asset/seed/route.go b/wagfarm-api/assets/seed/route.go similarity index 100% rename from wagfarm-api/asset/seed/route.go rename to wagfarm-api/assets/seed/route.go diff --git a/wagfarm-api/database/db.go b/wagfarm-api/database/db.go index df7fdb2..d48b405 100644 --- a/wagfarm-api/database/db.go +++ b/wagfarm-api/database/db.go @@ -3,8 +3,6 @@ package database import ( "fmt" "os" - "slices" - "wagfarm-api/models" "gorm.io/driver/mysql" "gorm.io/gorm" @@ -35,17 +33,40 @@ func Connect() error { DB = db return nil } + +var allModels []any + +func RegisterModel(model any) { + allModels = append(allModels, model) +} + +type JoinTable struct { + model any + field string + joinTable any +} + +var allJoinTables []JoinTable + +func RegisterJoinTable(model any, field string, joinTable any) { + newJoin := JoinTable{ + model: model, + field: field, + joinTable: joinTable, + } + allJoinTables = append(allJoinTables, newJoin) +} + func Migrate() error { - var err error - err = DB.AutoMigrate(slices.Concat( - log.Models, asset.Models, taxonomy.Models)) - if err != nil { + // Run migrations + if err := DB.AutoMigrate(allModels...); err != nil { return fmt.Errorf("auto migration failed: %w", err) } - err = DB.SetupJoinTable(&models.Fertilizer{}, "Ingredients", &models.FertilizerIngredient{}) - if err != nil { - return fmt.Errorf("failed to setup join table for FertilizerAsset and Ingredients: %w", err) + for _, table := range allJoinTables { + if err := DB.SetupJoinTable(table.model, table.field, table.joinTable); err != nil { + return fmt.Errorf("creating custom join tables failed: %w", err) + } } return nil diff --git a/wagfarm-api/generic/controller.go b/wagfarm-api/generic/controller.go index be999bd..ec79d82 100644 --- a/wagfarm-api/generic/controller.go +++ b/wagfarm-api/generic/controller.go @@ -36,99 +36,99 @@ func DefaultCRUDController[T Model]() CRUDController { } } -// GetLogs handles GET /logs and returns all log records. +// GetLogs handles GET /records and returns all record records. func GetAll[T Model](c *gin.Context) { - var logs []T + var records []T - if err := database.Preload().Find(&logs).Error; err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": "Error fetching logs: " + err.Error()}) + if err := database.Preload().Find(&records).Error; err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": "Error fetching records: " + err.Error()}) return } - c.JSON(http.StatusOK, logs) + c.JSON(http.StatusOK, records) } -// GetLog handles GET /logs/:id and returns a single log record. +// GetLog handles GET /records/:id and returns a single record record. func GetOne[T Model](c *gin.Context) { idParam := c.Param("id") id, err := strconv.Atoi(idParam) if err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid log ID"}) + c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid record ID"}) return } - var log T - if err := database.Preload().First(&log, id).Error; err != nil { - c.JSON(http.StatusNotFound, gin.H{"error": "Log not found"}) + var record T + if err := database.Preload().First(&record, id).Error; err != nil { + c.JSON(http.StatusNotFound, gin.H{"error": "Record not found"}) return } - c.JSON(http.StatusOK, log) + c.JSON(http.StatusOK, record) } -// CreateLog handles POST /logs and creates a new log record. +// CreateLog handles POST /records and creates a new record record. func Create[T Model](c *gin.Context) { - var log T - if err := c.ShouldBindJSON(&log); err != nil { + var record T + if err := c.ShouldBindJSON(&record); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } - if err := database.DB.Create(&log).Error; err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create log: " + err.Error()}) + if err := database.DB.Create(&record).Error; err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create record: " + err.Error()}) return } // Optionally preload visibility before returning. - database.Preload().First(&log, log.GetID()) - c.JSON(http.StatusCreated, log) + database.Preload().First(&record, record.GetID()) + c.JSON(http.StatusCreated, record) } -// UpdateLog handles PUT /logs/:id and updates an existing log record. +// UpdateLog handles PUT /records/:id and updates an existing record record. func Update[T Model](c *gin.Context) { idParam := c.Param("id") id, err := strconv.Atoi(idParam) if err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid log ID"}) + c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid record ID"}) return } var existing T if err := database.DB.First(&existing, id).Error; err != nil { - c.JSON(http.StatusNotFound, gin.H{"error": "Log not found"}) + c.JSON(http.StatusNotFound, gin.H{"error": "Record not found"}) return } - var log T - if err := c.ShouldBindJSON(&log); err != nil { + var record T + if err := c.ShouldBindJSON(&record); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } - if err := database.DB.Model(&existing).Updates(log).Error; err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to update log: " + err.Error()}) + if err := database.DB.Model(&existing).Updates(record).Error; err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to update record: " + err.Error()}) return } - database.Preload().First(&existing, log.GetID()) + database.Preload().First(&existing, record.GetID()) c.JSON(http.StatusOK, existing) } -// DeleteLog handles DELETE /logs/:id and deletes a log record. +// DeleteLog handles DELETE /records/:id and deletes a record record. func Delete[T Model](c *gin.Context) { idParam := c.Param("id") id, err := strconv.Atoi(idParam) if err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid log ID"}) + c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid record ID"}) return } - var log T - if err := database.DB.First(&log, id).Error; err != nil { - c.JSON(http.StatusNotFound, gin.H{"error": "Log not found"}) + var record T + if err := database.DB.First(&record, id).Error; err != nil { + c.JSON(http.StatusNotFound, gin.H{"error": "Record not found"}) return } - if err := database.DB.Delete(&log).Error; err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to delete log: " + err.Error()}) + if err := database.DB.Delete(&record).Error; err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to delete record: " + err.Error()}) return } - c.JSON(http.StatusOK, gin.H{"message": "Log deleted successfully"}) + c.JSON(http.StatusOK, gin.H{"message": "Record deleted successfully"}) } diff --git a/wagfarm-api/go.mod b/wagfarm-api/go.mod index 7fe037f..3fed03e 100644 --- a/wagfarm-api/go.mod +++ b/wagfarm-api/go.mod @@ -6,6 +6,7 @@ require ( github.com/gin-gonic/gin v1.10.0 gorm.io/driver/mysql v1.5.7 gorm.io/gorm v1.25.12 + github.com/shopspring/decimal v1.4.0 ) require ( diff --git a/wagfarm-api/go.sum b/wagfarm-api/go.sum index b8d52d1..391309e 100644 --- a/wagfarm-api/go.sum +++ b/wagfarm-api/go.sum @@ -47,6 +47,8 @@ github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjY github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= +github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= diff --git a/wagfarm-api/log/base/model.go b/wagfarm-api/log/base/model.go deleted file mode 100644 index d055585..0000000 --- a/wagfarm-api/log/base/model.go +++ /dev/null @@ -1,31 +0,0 @@ -package base - -import "time" - -type BaseLog struct { - ID uint `gorm:"primaryKey"` - Name string `gorm:"not null"` - Notes string `gorm:"not null"` - LogType string `gorm:"not null"` - Date time.Time `gorm:"default:CURRENT_TIME"` - Duration float64 `gorm:"not null"` // in hours - VisibiltyID uint `gorm:"not null"` - Visibility taxonomy.Visibility `gorm:"constraint:OnUpdate:CASCADE,OnDelete:CASCADE;not null"` -} - -func (l BaseLog) GetID() uint { return l.ID } - -type ExtendedLog struct { - ID uint `gorm:"primaryKey"` - LogID uint `gorm:"not null"` - BaseLog BaseLog `gorm:"foreignKey:LogID;constraint:OnUpdate:CASCADE,OnDelete:CASCADE;not null"` -} - -func (l ExtendedLog) GetID() uint { return l.ID } - -type FieldWorkLog struct { - ExtendedLog - WorkedAreaPercentage float64 `gorm:"not null"` - MachineID uint `gorm:"not null"` - Machine asset.Machine `gorm:"constraint:OnUpdate:CASCADE,OnDelete:CASCADE;not null"` -} diff --git a/wagfarm-api/log/cropprotection/model.go b/wagfarm-api/log/cropprotection/model.go deleted file mode 100644 index 926f479..0000000 --- a/wagfarm-api/log/cropprotection/model.go +++ /dev/null @@ -1,12 +0,0 @@ -package cropprotection - -import "wagfarm-api/log/base" - -type CropProtectionLog struct { - base.FieldWorkLog - PesticideID uint `gorm:"not null"` - Pesticide taxonomy.Pesticide `gorm:"constraint:OnUpdate:CASCADE,OnDelete:CASCADE;not null"` - Amount float64 `gorm:"not null"` // in units of the pesticide - PerformedByID uint `gorm:"not null"` - PerformedBy taxonomy.Worker `gorm:"constraint:OnUpdate:CASCADE,OnDelete:CASCADE;not null"` -} diff --git a/wagfarm-api/log/fertilizing/model.go b/wagfarm-api/log/fertilizing/model.go deleted file mode 100644 index 946648f..0000000 --- a/wagfarm-api/log/fertilizing/model.go +++ /dev/null @@ -1,12 +0,0 @@ -package fertilizing - -import ( - "wagfarm-api/log/base" -) - -type FertilizingLog struct { - base.ExtendedLog - FertilizerID uint `gorm:"not null"` - Fertilizer asset.Fertilizer `gorm:"constraint:OnUpdate:CASCADE,OnDelete:CASCADE;not null"` - Amount float64 `gorm:"not null"` // in units of the fertilizer -} diff --git a/wagfarm-api/log/harvest/model.go b/wagfarm-api/log/harvest/model.go deleted file mode 100644 index 39c6908..0000000 --- a/wagfarm-api/log/harvest/model.go +++ /dev/null @@ -1,9 +0,0 @@ -package harvest - -import base "wagfarm-api/log/seeding" - -type HarvestLog struct { - base.FieldWorkLog - Product asset.Product `gorm:"constraint:OnUpdate:CASCADE,OnDelete:CASCADE;not null"` - Amount float64 `gorm:"not null"` // in units of the product -} diff --git a/wagfarm-api/log/seeding/model.go b/wagfarm-api/log/seeding/model.go deleted file mode 100644 index 31fa698..0000000 --- a/wagfarm-api/log/seeding/model.go +++ /dev/null @@ -1,14 +0,0 @@ -package seeding - -import "wagfarm-api/log/base" - -type SeedingLog struct { - base.FieldWorkLog - SeedID uint `gorm:"not null"` - Seed asset.Seed `gorm:"constraint:OnUpdate:CASCADE,OnDelete:CASCADE;not null"` - TechniqueID uint `gorm:"not null"` - Technique taxonomy.SeedingTechnique `gorm:"constraint:OnUpdate:CASCADE,OnDelete:CASCADE;not null"` - Amount float64 `gorm:"not null"` // in units/ha - ConditionsID uint `gorm:"not null"` - Conditions taxonomy.SeedingCondition `gorm:"constraint:OnUpdate:CASCADE,OnDelete:CASCADE;not null"` -} diff --git a/wagfarm-api/logs/base/model.go b/wagfarm-api/logs/base/model.go new file mode 100644 index 0000000..839d307 --- /dev/null +++ b/wagfarm-api/logs/base/model.go @@ -0,0 +1,48 @@ +package base + +import ( + "time" + "wagfarm-api/assets/machine" + "wagfarm-api/database" + "wagfarm-api/taxonomy/visibility" + + "github.com/shopspring/decimal" + "gorm.io/gorm" +) + +type BaseLog struct { + ID uint `gorm:"primaryKey"` + Name string `gorm:"not null"` + Notes string `gorm:"not null"` + LogType string `gorm:"not null"` + Date time.Time `gorm:"not null"` + Duration float64 `gorm:"not null"` // in hours + VisibiltyID uint `gorm:"not null"` + Visibility visibility.Visibility `gorm:"constraint:OnUpdate:CASCADE,OnDelete:CASCADE;not null"` + Cost decimal.Decimal `gorm:"not null;type:decimal(10,2);"` // in euro +} + +func (l BaseLog) GetID() uint { return l.ID } + +type ExtendedLog struct { + ID uint `gorm:"primaryKey"` + BaseLogID uint `gorm:"not null"` + BaseLog BaseLog `gorm:"constraint:OnUpdate:CASCADE,OnDelete:CASCADE;not null"` +} + +func (l ExtendedLog) GetID() uint { return l.ID } +func (l *ExtendedLog) UpdateCost(db *gorm.DB, newCost decimal.Decimal) (err error) { + err = db.Model(&BaseLog{}). + Where("id = ?", l.BaseLogID). + Update("cost", newCost).Error + return +} + +type FieldWorkLog struct { + ExtendedLog + WorkedAreaPercentage float64 `gorm:"not null"` + MachineID uint `gorm:"not null"` + Machine machine.Machine `gorm:"constraint:OnUpdate:CASCADE,OnDelete:CASCADE;not null"` +} + +func RegisterModels() { database.RegisterModel(&BaseLog{}) } diff --git a/wagfarm-api/log/base/route.go b/wagfarm-api/logs/base/route.go similarity index 100% rename from wagfarm-api/log/base/route.go rename to wagfarm-api/logs/base/route.go diff --git a/wagfarm-api/logs/cropprotection/model.go b/wagfarm-api/logs/cropprotection/model.go new file mode 100644 index 0000000..b498b1d --- /dev/null +++ b/wagfarm-api/logs/cropprotection/model.go @@ -0,0 +1,36 @@ +package cropprotection + +import ( + "wagfarm-api/assets/pesticide" + "wagfarm-api/database" + "wagfarm-api/logs/base" + "wagfarm-api/taxonomy/worker" + + "github.com/shopspring/decimal" + "gorm.io/gorm" +) + +type CropProtectionLog struct { + base.FieldWorkLog + PesticideID uint `gorm:"not null"` + Pesticide pesticide.Pesticide `gorm:"constraint:OnUpdate:CASCADE,OnDelete:CASCADE;not null"` + Amount float64 `gorm:"not null"` // in units of the pesticide + PerformedByID uint `gorm:"not null"` + PerformedBy worker.Worker `gorm:"constraint:OnUpdate:CASCADE,OnDelete:CASCADE;not null"` +} + +func (l *CropProtectionLog) AfterSave(db *gorm.DB) (err error) { + // Example: compute cost as Amount * UnitPrice + if l.Pesticide.ID == 0 { + if err := db.First(&l.Pesticide, l.PesticideID).Error; err != nil { + return err + } + } + + unitPrice := l.Pesticide.Cost + totalCost := unitPrice.Mul(decimal.NewFromFloat(l.Amount)) + l.UpdateCost(db, totalCost) + return +} + +func RegisterModels() { database.RegisterModel(&CropProtectionLog{}) } diff --git a/wagfarm-api/log/cropprotection/route.go b/wagfarm-api/logs/cropprotection/route.go similarity index 100% rename from wagfarm-api/log/cropprotection/route.go rename to wagfarm-api/logs/cropprotection/route.go diff --git a/wagfarm-api/logs/fertilizing/model.go b/wagfarm-api/logs/fertilizing/model.go new file mode 100644 index 0000000..575d98d --- /dev/null +++ b/wagfarm-api/logs/fertilizing/model.go @@ -0,0 +1,34 @@ +package fertilizing + +import ( + "wagfarm-api/assets/fertilizer" + "wagfarm-api/database" + "wagfarm-api/logs/base" + + "github.com/shopspring/decimal" + "gorm.io/gorm" +) + +type FertilizingLog struct { + base.ExtendedLog + FertilizerID uint `gorm:"not null"` + Fertilizer fertilizer.Fertilizer `gorm:"constraint:OnUpdate:CASCADE,OnDelete:CASCADE;not null"` + Amount float64 `gorm:"not null"` // in units of the fertilizer +} + +func (l *FertilizingLog) AfterSave(db *gorm.DB) (err error) { + // Example: compute cost as Amount * UnitPrice + if l.FertilizerID == 0 { + if err := db.First(&l.Fertilizer, l.FertilizerID).Error; err != nil { + return err + } + } + + unitPrice := l.Fertilizer.Cost + totalCost := unitPrice.Mul(decimal.NewFromFloat(l.Amount)) + l.UpdateCost(db, totalCost) + + return +} + +func RegisterModels() { database.RegisterModel(&FertilizingLog{}) } diff --git a/wagfarm-api/log/fertilizing/route.go b/wagfarm-api/logs/fertilizing/route.go similarity index 100% rename from wagfarm-api/log/fertilizing/route.go rename to wagfarm-api/logs/fertilizing/route.go diff --git a/wagfarm-api/logs/harvest/model.go b/wagfarm-api/logs/harvest/model.go new file mode 100644 index 0000000..9ef43c9 --- /dev/null +++ b/wagfarm-api/logs/harvest/model.go @@ -0,0 +1,34 @@ +package harvest + +import ( + "wagfarm-api/assets/product" + "wagfarm-api/database" + "wagfarm-api/logs/base" + + "github.com/shopspring/decimal" + "gorm.io/gorm" +) + +type HarvestLog struct { + base.FieldWorkLog + ProductID uint `gorm:"not null"` + Product product.Product `gorm:"constraint:OnUpdate:CASCADE,OnDelete:CASCADE;not null"` + Amount float64 `gorm:"not null"` // in units of the product +} + +func (l *HarvestLog) AfterSave(db *gorm.DB) (err error) { + // Example: compute cost as Amount * UnitPrice + if l.ProductID == 0 { + if err := db.First(&l.Product, l.ProductID).Error; err != nil { + return err + } + } + + unitPrice := l.Product.Cost + totalCost := unitPrice.Mul(decimal.NewFromFloat(l.Amount)) + l.UpdateCost(db, totalCost) + + return +} + +func RegisterModels() { database.RegisterModel(&HarvestLog{}) } diff --git a/wagfarm-api/log/harvest/route.go b/wagfarm-api/logs/harvest/route.go similarity index 100% rename from wagfarm-api/log/harvest/route.go rename to wagfarm-api/logs/harvest/route.go diff --git a/wagfarm-api/logs/logs.go b/wagfarm-api/logs/logs.go new file mode 100644 index 0000000..dc036f0 --- /dev/null +++ b/wagfarm-api/logs/logs.go @@ -0,0 +1,28 @@ +package logs + +import ( + "wagfarm-api/logs/base" + "wagfarm-api/logs/cropprotection" + "wagfarm-api/logs/fertilizing" + "wagfarm-api/logs/harvest" + "wagfarm-api/logs/seeding" + + "github.com/gin-gonic/gin" +) + +func RegisterModels() { + base.RegisterModels() + cropprotection.RegisterModels() + fertilizing.RegisterModels() + harvest.RegisterModels() + seeding.RegisterModels() +} + +func RegisterRoutes(rg *gin.RouterGroup) { + group := rg.Group("/logs") + base.RegisterRoutes(group) + cropprotection.RegisterRoutes(group) + fertilizing.RegisterRoutes(group) + harvest.RegisterRoutes(group) + seeding.RegisterRoutes(group) +} diff --git a/wagfarm-api/logs/seeding/model.go b/wagfarm-api/logs/seeding/model.go new file mode 100644 index 0000000..30c0567 --- /dev/null +++ b/wagfarm-api/logs/seeding/model.go @@ -0,0 +1,40 @@ +package seeding + +import ( + "wagfarm-api/assets/seed" + "wagfarm-api/database" + "wagfarm-api/logs/base" + "wagfarm-api/taxonomy/seedingcondition" + "wagfarm-api/taxonomy/seedingtechnique" + + "github.com/shopspring/decimal" + "gorm.io/gorm" +) + +type SeedingLog struct { + base.FieldWorkLog + SeedID uint `gorm:"not null"` + Seed seed.Seed `gorm:"constraint:OnUpdate:CASCADE,OnDelete:CASCADE;not null"` + TechniqueID uint `gorm:"not null"` + Technique seedingtechnique.SeedingTechnique `gorm:"constraint:OnUpdate:CASCADE,OnDelete:CASCADE;not null"` + Amount float64 `gorm:"not null"` // in units/ha + ConditionsID uint `gorm:"not null"` + Conditions seedingcondition.SeedingCondition `gorm:"constraint:OnUpdate:CASCADE,OnDelete:CASCADE;not null"` +} + +func (l *SeedingLog) AfterSave(db *gorm.DB) (err error) { + // Example: compute cost as Amount * UnitPrice + if l.SeedID == 0 { + if err := db.First(&l.Seed, l.SeedID).Error; err != nil { + return err + } + } + + unitPrice := l.Seed.Cost + totalCost := unitPrice.Mul(decimal.NewFromFloat(l.Amount)) + l.UpdateCost(db, totalCost) + + return +} + +func RegisterModels() { database.RegisterModel(&SeedingLog{}) } diff --git a/wagfarm-api/log/seeding/route.go b/wagfarm-api/logs/seeding/route.go similarity index 100% rename from wagfarm-api/log/seeding/route.go rename to wagfarm-api/logs/seeding/route.go diff --git a/wagfarm-api/main.go b/wagfarm-api/main.go index e3ad232..e89b53f 100644 --- a/wagfarm-api/main.go +++ b/wagfarm-api/main.go @@ -3,7 +3,10 @@ package main import ( "log" "os" + "wagfarm-api/assets" "wagfarm-api/database" + "wagfarm-api/logs" + "wagfarm-api/taxonomy" "github.com/gin-gonic/gin" ) @@ -25,8 +28,17 @@ func initLogging() { gin.DefaultWriter = f // capture Gin logs too } -func RegisterRoutes(r *gin.Engine) { +func RegisterModels() { + assets.RegisterModels() + logs.RegisterModels() + taxonomy.RegisterModels() +} +func RegisterRoutes(r *gin.Engine) { + group := r.Group("/v1") + assets.RegisterRoutes(group) + logs.RegisterRoutes(group) + taxonomy.RegisterRoutes(group) } func main() { @@ -39,6 +51,8 @@ func main() { log.Fatalf("Database connection error: %v", err) } + RegisterModels() + // Run migrations. if err := database.Migrate(); err != nil { log.Fatalf("Migration failed: %v", err) diff --git a/wagfarm-api/taxonomy/crop/model.go b/wagfarm-api/taxonomy/crop/model.go index 67199e3..effd942 100644 --- a/wagfarm-api/taxonomy/crop/model.go +++ b/wagfarm-api/taxonomy/crop/model.go @@ -1,5 +1,10 @@ package crop -import "wagfarm-api/taxonomy/base" +import ( + "wagfarm-api/database" + "wagfarm-api/taxonomy/base" +) type Crop struct{ base.Taxonomy } + +func RegisterModels() { database.RegisterModel(&Crop{}) } diff --git a/wagfarm-api/taxonomy/customer/model.go b/wagfarm-api/taxonomy/customer/model.go index a58f2ce..3671ac2 100644 --- a/wagfarm-api/taxonomy/customer/model.go +++ b/wagfarm-api/taxonomy/customer/model.go @@ -1,5 +1,10 @@ package customer -import "wagfarm-api/taxonomy/base" +import ( + "wagfarm-api/database" + "wagfarm-api/taxonomy/base" +) type Customer struct{ base.Taxonomy } + +func RegisterModels() { database.RegisterModel(&Customer{}) } diff --git a/wagfarm-api/taxonomy/fertilizertype/model.go b/wagfarm-api/taxonomy/fertilizertype/model.go index c4dbfb0..69ffd2d 100644 --- a/wagfarm-api/taxonomy/fertilizertype/model.go +++ b/wagfarm-api/taxonomy/fertilizertype/model.go @@ -1,5 +1,10 @@ package fertilizertype -import "wagfarm-api/taxonomy/base" +import ( + "wagfarm-api/database" + "wagfarm-api/taxonomy/base" +) type FertilizerType struct{ base.Taxonomy } + +func RegisterModels() { database.RegisterModel(&FertilizerType{}) } diff --git a/wagfarm-api/taxonomy/ingredient/model.go b/wagfarm-api/taxonomy/ingredient/model.go index 2758f3d..9911730 100644 --- a/wagfarm-api/taxonomy/ingredient/model.go +++ b/wagfarm-api/taxonomy/ingredient/model.go @@ -1,6 +1,7 @@ package ingredient import ( + "wagfarm-api/database" "wagfarm-api/taxonomy/base" "wagfarm-api/taxonomy/unit" ) @@ -10,3 +11,5 @@ type Ingredient struct { UnitID uint `gorm:"not null"` Unit unit.Unit `gorm:"not null"` } + +func RegisterModels() { database.RegisterModel(&Ingredient{}) } diff --git a/wagfarm-api/taxonomy/pesticidetype/model.go b/wagfarm-api/taxonomy/pesticidetype/model.go index e834c9f..e5f68df 100644 --- a/wagfarm-api/taxonomy/pesticidetype/model.go +++ b/wagfarm-api/taxonomy/pesticidetype/model.go @@ -1,5 +1,10 @@ package pesticidetype -import "wagfarm-api/taxonomy/base" +import ( + "wagfarm-api/database" + "wagfarm-api/taxonomy/base" +) type PesticideType struct{ base.Taxonomy } + +func RegisterModels() { database.RegisterModel(&PesticideType{}) } diff --git a/wagfarm-api/taxonomy/producttype/model.go b/wagfarm-api/taxonomy/producttype/model.go index 22f5b15..55a88c7 100644 --- a/wagfarm-api/taxonomy/producttype/model.go +++ b/wagfarm-api/taxonomy/producttype/model.go @@ -1,5 +1,10 @@ package producttype -import "wagfarm-api/taxonomy/base" +import ( + "wagfarm-api/database" + "wagfarm-api/taxonomy/base" +) type ProductType struct{ base.Taxonomy } + +func RegisterModels() { database.RegisterModel(&ProductType{}) } diff --git a/wagfarm-api/taxonomy/seedingcondition/model.go b/wagfarm-api/taxonomy/seedingcondition/model.go index 2b3c891..5857335 100644 --- a/wagfarm-api/taxonomy/seedingcondition/model.go +++ b/wagfarm-api/taxonomy/seedingcondition/model.go @@ -1,5 +1,10 @@ package seedingcondition -import "wagfarm-api/taxonomy/base" +import ( + "wagfarm-api/database" + "wagfarm-api/taxonomy/base" +) type SeedingCondition struct{ base.Taxonomy } + +func RegisterModels() { database.RegisterModel(&SeedingCondition{}) } diff --git a/wagfarm-api/taxonomy/seedingtechnique/model.go b/wagfarm-api/taxonomy/seedingtechnique/model.go index 2556abe..5c2971d 100644 --- a/wagfarm-api/taxonomy/seedingtechnique/model.go +++ b/wagfarm-api/taxonomy/seedingtechnique/model.go @@ -1,5 +1,10 @@ package seedingtechnique -import "wagfarm-api/taxonomy/base" +import ( + "wagfarm-api/database" + "wagfarm-api/taxonomy/base" +) type SeedingTechnique struct{ base.Taxonomy } + +func RegisterModels() { database.RegisterModel(&SeedingTechnique{}) } diff --git a/wagfarm-api/taxonomy/seedtype/model.go b/wagfarm-api/taxonomy/seedtype/model.go index 324d2b5..7cb32b3 100644 --- a/wagfarm-api/taxonomy/seedtype/model.go +++ b/wagfarm-api/taxonomy/seedtype/model.go @@ -1,6 +1,7 @@ package seedtype import ( + "wagfarm-api/database" "wagfarm-api/taxonomy/base" "wagfarm-api/taxonomy/crop" ) @@ -10,3 +11,5 @@ type SeedType struct { CropID uint `gorm:"not null"` Crop crop.Crop `gorm:"not null; constraint:OnUpdate:CASCADE,OnDelete:CASCADE;"` } + +func RegisterModels() { database.RegisterModel(&SeedType{}) } diff --git a/wagfarm-api/taxonomy/seller/model.go b/wagfarm-api/taxonomy/seller/model.go index 4954dcf..b05ec9d 100644 --- a/wagfarm-api/taxonomy/seller/model.go +++ b/wagfarm-api/taxonomy/seller/model.go @@ -1,5 +1,10 @@ package seller -import "wagfarm-api/taxonomy/base" +import ( + "wagfarm-api/database" + "wagfarm-api/taxonomy/base" +) type Seller struct{ base.Taxonomy } + +func RegisterModels() { database.RegisterModel(&Seller{}) } diff --git a/wagfarm-api/taxonomy/taxonomy.go b/wagfarm-api/taxonomy/taxonomy.go new file mode 100644 index 0000000..ca03745 --- /dev/null +++ b/wagfarm-api/taxonomy/taxonomy.go @@ -0,0 +1,52 @@ +package taxonomy + +import ( + "wagfarm-api/taxonomy/crop" + "wagfarm-api/taxonomy/customer" + "wagfarm-api/taxonomy/fertilizertype" + "wagfarm-api/taxonomy/ingredient" + "wagfarm-api/taxonomy/pesticidetype" + "wagfarm-api/taxonomy/producttype" + "wagfarm-api/taxonomy/seedingcondition" + "wagfarm-api/taxonomy/seedingtechnique" + "wagfarm-api/taxonomy/seedtype" + "wagfarm-api/taxonomy/seller" + "wagfarm-api/taxonomy/unit" + "wagfarm-api/taxonomy/visibility" + "wagfarm-api/taxonomy/worker" + + "github.com/gin-gonic/gin" +) + +func RegisterModels() { + crop.RegisterModels() + customer.RegisterModels() + fertilizertype.RegisterModels() + ingredient.RegisterModels() + pesticidetype.RegisterModels() + producttype.RegisterModels() + seedingcondition.RegisterModels() + seedingtechnique.RegisterModels() + seedtype.RegisterModels() + seller.RegisterModels() + unit.RegisterModels() + visibility.RegisterModels() + worker.RegisterModels() +} + +func RegisterRoutes(rg *gin.RouterGroup) { + group := rg.Group("/taxonomy") + crop.RegisterRoutes(group) + customer.RegisterRoutes(group) + fertilizertype.RegisterRoutes(group) + ingredient.RegisterRoutes(group) + pesticidetype.RegisterRoutes(group) + producttype.RegisterRoutes(group) + seedingcondition.RegisterRoutes(group) + seedingtechnique.RegisterRoutes(group) + seedtype.RegisterRoutes(group) + seller.RegisterRoutes(group) + unit.RegisterRoutes(group) + visibility.RegisterRoutes(group) + worker.RegisterRoutes(group) +} diff --git a/wagfarm-api/taxonomy/unit/model.go b/wagfarm-api/taxonomy/unit/model.go index 3a4811b..2de6a13 100644 --- a/wagfarm-api/taxonomy/unit/model.go +++ b/wagfarm-api/taxonomy/unit/model.go @@ -1,5 +1,10 @@ package unit -import "wagfarm-api/taxonomy/base" +import ( + "wagfarm-api/database" + "wagfarm-api/taxonomy/base" +) type Unit struct{ base.Taxonomy } + +func RegisterModels() { database.RegisterModel(&Unit{}) } diff --git a/wagfarm-api/taxonomy/visibility/model.go b/wagfarm-api/taxonomy/visibility/model.go index c027db0..7d8eb2b 100644 --- a/wagfarm-api/taxonomy/visibility/model.go +++ b/wagfarm-api/taxonomy/visibility/model.go @@ -1,5 +1,10 @@ package visibility -import "wagfarm-api/taxonomy/base" +import ( + "wagfarm-api/database" + "wagfarm-api/taxonomy/base" +) type Visibility struct{ base.Taxonomy } + +func RegisterModels() { database.RegisterModel(&Visibility{}) } diff --git a/wagfarm-api/taxonomy/worker/model.go b/wagfarm-api/taxonomy/worker/model.go index b7245e6..60cc785 100644 --- a/wagfarm-api/taxonomy/worker/model.go +++ b/wagfarm-api/taxonomy/worker/model.go @@ -1,5 +1,10 @@ package worker -import "wagfarm-api/taxonomy/base" +import ( + "wagfarm-api/database" + "wagfarm-api/taxonomy/base" +) type Worker struct{ base.Taxonomy } + +func RegisterModels() { database.RegisterModel(&Worker{}) }