fix(BE-273): add object nonstock and supplier in response get one and fix name base to relation in dto

This commit is contained in:
Hafizh A. Y
2025-11-20 14:59:50 +07:00
parent b4b860b9d4
commit 228aedc215
64 changed files with 964 additions and 3576 deletions
+1 -9
View File
@@ -5,12 +5,10 @@ go 1.23
require ( require (
github.com/MicahParks/keyfunc/v2 v2.1.0 github.com/MicahParks/keyfunc/v2 v2.1.0
github.com/bytedance/sonic v1.12.1 github.com/bytedance/sonic v1.12.1
github.com/glebarez/sqlite v1.11.0
github.com/go-playground/validator/v10 v10.27.0 github.com/go-playground/validator/v10 v10.27.0
github.com/gofiber/contrib/jwt v1.0.10 github.com/gofiber/contrib/jwt v1.0.10
github.com/gofiber/fiber/v2 v2.52.5 github.com/gofiber/fiber/v2 v2.52.5
github.com/golang-jwt/jwt/v5 v5.2.1 github.com/golang-jwt/jwt/v5 v5.2.1
github.com/google/uuid v1.6.0
github.com/jackc/pgconn v1.14.1 github.com/jackc/pgconn v1.14.1
github.com/redis/go-redis/v9 v9.14.0 github.com/redis/go-redis/v9 v9.14.0
github.com/sirupsen/logrus v1.9.3 github.com/sirupsen/logrus v1.9.3
@@ -27,13 +25,12 @@ require (
github.com/cloudwego/base64x v0.1.4 // indirect github.com/cloudwego/base64x v0.1.4 // indirect
github.com/cloudwego/iasm v0.2.0 // indirect github.com/cloudwego/iasm v0.2.0 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.8 // indirect github.com/gabriel-vasile/mimetype v1.4.8 // indirect
github.com/glebarez/go-sqlite v1.21.2 // indirect
github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/google/go-cmp v0.6.0 // indirect github.com/google/go-cmp v0.6.0 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect
github.com/jackc/chunkreader/v2 v2.0.1 // indirect github.com/jackc/chunkreader/v2 v2.0.1 // indirect
github.com/jackc/pgio v1.0.0 // indirect github.com/jackc/pgio v1.0.0 // indirect
@@ -54,7 +51,6 @@ require (
github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/pelletier/go-toml/v2 v2.2.2 // indirect github.com/pelletier/go-toml/v2 v2.2.2 // indirect
github.com/philhofer/fwd v1.1.2 // indirect github.com/philhofer/fwd v1.1.2 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/rivo/uniseg v0.4.7 // indirect github.com/rivo/uniseg v0.4.7 // indirect
github.com/rogpeppe/go-internal v1.11.0 // indirect github.com/rogpeppe/go-internal v1.11.0 // indirect
github.com/sagikazarmark/locafero v0.4.0 // indirect github.com/sagikazarmark/locafero v0.4.0 // indirect
@@ -79,8 +75,4 @@ require (
golang.org/x/text v0.22.0 // indirect golang.org/x/text v0.22.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect
modernc.org/libc v1.22.5 // indirect
modernc.org/mathutil v1.5.0 // indirect
modernc.org/memory v1.5.0 // indirect
modernc.org/sqlite v1.23.1 // indirect
) )
-19
View File
@@ -27,18 +27,12 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM= github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM=
github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8= github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8=
github.com/glebarez/go-sqlite v1.21.2 h1:3a6LFC4sKahUunAmynQKLZceZCOzUthkRkEAl9gAXWo=
github.com/glebarez/go-sqlite v1.21.2/go.mod h1:sfxdZyhQjTM2Wry3gVYWaW072Ri1WMdWJi0k6+3382k=
github.com/glebarez/sqlite v1.11.0 h1:wSG0irqzP6VurnMEpFGer5Li19RpIRi2qvQz++w0GMw=
github.com/glebarez/sqlite v1.11.0/go.mod h1:h8/o8j5wiAsqSPoWELDUdJXhjAhsVliSn7bWZjOhrgQ=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
@@ -56,8 +50,6 @@ github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17w
github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ=
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
@@ -154,9 +146,6 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRI
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/redis/go-redis/v9 v9.14.0 h1:u4tNCjXOyzfgeLN+vAZaW1xUooqWDqVEsZN0U01jfAE= github.com/redis/go-redis/v9 v9.14.0 h1:u4tNCjXOyzfgeLN+vAZaW1xUooqWDqVEsZN0U01jfAE=
github.com/redis/go-redis/v9 v9.14.0/go.mod h1:huWgSWd8mW6+m0VPhJjSSQ+d6Nh1VICQ6Q5lHuCH/Iw= github.com/redis/go-redis/v9 v9.14.0/go.mod h1:huWgSWd8mW6+m0VPhJjSSQ+d6Nh1VICQ6Q5lHuCH/Iw=
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
@@ -317,12 +306,4 @@ gorm.io/driver/postgres v1.5.9 h1:DkegyItji119OlcaLjqN11kHoUgZ/j13E0jkJZgD6A8=
gorm.io/driver/postgres v1.5.9/go.mod h1:DX3GReXH+3FPWGrrgffdvCk3DQ1dwDPdmbenSkweRGI= gorm.io/driver/postgres v1.5.9/go.mod h1:DX3GReXH+3FPWGrrgffdvCk3DQ1dwDPdmbenSkweRGI=
gorm.io/gorm v1.25.11 h1:/Wfyg1B/je1hnDx3sMkX+gAlxrlZpn6X0BXRlwXlvHg= gorm.io/gorm v1.25.11 h1:/Wfyg1B/je1hnDx3sMkX+gAlxrlZpn6X0BXRlwXlvHg=
gorm.io/gorm v1.25.11/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ= gorm.io/gorm v1.25.11/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ=
modernc.org/libc v1.22.5 h1:91BNch/e5B0uPbJFgqbxXuOnxBQjlS//icfQEGmvyjE=
modernc.org/libc v1.22.5/go.mod h1:jj+Z7dTNX8fBScMVNRAYZ/jF91K8fdT2hYMThc3YjBY=
modernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ=
modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
modernc.org/memory v1.5.0 h1:N+/8c5rE6EqugZwHii4IFsaJ7MUhoWX07J5tC/iI5Ds=
modernc.org/memory v1.5.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU=
modernc.org/sqlite v1.23.1 h1:nrSBg4aRQQwq59JpvGEQ15tNxoO5pX/kUjcRNwSAGQM=
modernc.org/sqlite v1.23.1/go.mod h1:OrDj17Mggn6MhE+iPbBNf7RGKODDE9NFT0f3EwDzJqk=
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
+4 -4
View File
@@ -82,7 +82,7 @@ func Run(db *gorm.DB) error {
return err return err
} }
if err := seedTransferStock(tx, adminID); err != nil { if err := seedTransferStock(tx); err != nil {
return err return err
} }
fmt.Println("✅ Master data seeding completed") fmt.Println("✅ Master data seeding completed")
@@ -692,7 +692,7 @@ func seedProducts(tx *gorm.DB, createdBy uint, uoms map[string]uint, categories
var existing entity.ProductSupplier var existing entity.ProductSupplier
err := tx.Where("product_id = ? AND supplier_id = ?", product.Id, supplierID).First(&existing).Error err := tx.Where("product_id = ? AND supplier_id = ?", product.Id, supplierID).First(&existing).Error
if errors.Is(err, gorm.ErrRecordNotFound) { if errors.Is(err, gorm.ErrRecordNotFound) {
link := entity.ProductSupplier{ProductID: product.Id, SupplierID: supplierID} link := entity.ProductSupplier{ProductId: product.Id, SupplierId: supplierID}
if err := tx.Create(&link).Error; err != nil { if err := tx.Create(&link).Error; err != nil {
return err return err
} }
@@ -765,7 +765,7 @@ func seedNonstocks(tx *gorm.DB, createdBy uint, uoms map[string]uint, suppliers
var existing entity.NonstockSupplier var existing entity.NonstockSupplier
err := tx.Where("nonstock_id = ? AND supplier_id = ?", nonstock.Id, supplierID).First(&existing).Error err := tx.Where("nonstock_id = ? AND supplier_id = ?", nonstock.Id, supplierID).First(&existing).Error
if errors.Is(err, gorm.ErrRecordNotFound) { if errors.Is(err, gorm.ErrRecordNotFound) {
link := entity.NonstockSupplier{NonstockID: nonstock.Id, SupplierID: supplierID} link := entity.NonstockSupplier{NonstockId: nonstock.Id, SupplierId: supplierID}
if err := tx.Create(&link).Error; err != nil { if err := tx.Create(&link).Error; err != nil {
return err return err
} }
@@ -929,7 +929,7 @@ func seedProductWarehouse(tx *gorm.DB, createdBy uint) error {
return nil return nil
} }
func seedTransferStock(tx *gorm.DB, createdBy uint) error { func seedTransferStock(tx *gorm.DB) error {
transfer := entity.StockTransfer{ transfer := entity.StockTransfer{
FromWarehouseId: 1, FromWarehouseId: 1,
+4 -4
View File
@@ -15,8 +15,8 @@ type Nonstock struct {
UpdatedAt time.Time `gorm:"autoUpdateTime"` UpdatedAt time.Time `gorm:"autoUpdateTime"`
DeletedAt gorm.DeletedAt `gorm:"index" json:"-"` DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
CreatedUser User `gorm:"foreignKey:CreatedBy;references:Id"` CreatedUser User `gorm:"foreignKey:CreatedBy;references:Id"`
Uom Uom `gorm:"foreignKey:UomId;references:Id"` Uom Uom `gorm:"foreignKey:UomId;references:Id"`
Suppliers []Supplier `gorm:"many2many:nonstock_suppliers;joinForeignKey:NonstockID;joinReferences:SupplierID"` NonstockSuppliers []NonstockSupplier `gorm:"foreignKey:NonstockId;references:Id"`
Flags []Flag `gorm:"polymorphic:Flagable;polymorphicValue:nonstocks"` Flags []Flag `gorm:"polymorphic:Flagable;polymorphicValue:nonstocks"`
} }
+5 -2
View File
@@ -3,7 +3,10 @@ package entities
import "time" import "time"
type NonstockSupplier struct { type NonstockSupplier struct {
NonstockID uint `gorm:"primaryKey"` NonstockId uint `gorm:"not null"`
SupplierID uint `gorm:"primaryKey"` SupplierId uint `gorm:"not null"`
CreatedAt time.Time `gorm:"autoCreateTime"` CreatedAt time.Time `gorm:"autoCreateTime"`
Nonstock Nonstock `gorm:"foreignKey:NonstockId;references:Id"`
Supplier Supplier `gorm:"foreignKey:SupplierId;references:Id"`
} }
+5 -5
View File
@@ -22,9 +22,9 @@ type Product struct {
UpdatedAt time.Time `gorm:"autoUpdateTime"` UpdatedAt time.Time `gorm:"autoUpdateTime"`
DeletedAt gorm.DeletedAt `gorm:"index" json:"-"` DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
CreatedUser User `gorm:"foreignKey:CreatedBy;references:Id"` CreatedUser User `gorm:"foreignKey:CreatedBy;references:Id"`
Uom Uom `gorm:"foreignKey:UomId;references:Id"` Uom Uom `gorm:"foreignKey:UomId;references:Id"`
ProductCategory ProductCategory `gorm:"foreignKey:ProductCategoryId;references:Id"` ProductCategory ProductCategory `gorm:"foreignKey:ProductCategoryId;references:Id"`
Suppliers []Supplier `gorm:"many2many:product_suppliers;joinForeignKey:ProductID;joinReferences:SupplierID"` ProductSuppliers []ProductSupplier `gorm:"foreignKey:ProductId;references:Id"`
Flags []Flag `gorm:"polymorphic:Flagable;polymorphicValue:products"` Flags []Flag `gorm:"polymorphic:Flagable;polymorphicValue:products"`
} }
+5 -2
View File
@@ -3,7 +3,10 @@ package entities
import "time" import "time"
type ProductSupplier struct { type ProductSupplier struct {
ProductID uint `gorm:"primaryKey"` ProductId uint `gorm:"not null"`
SupplierID uint `gorm:"primaryKey"` SupplierId uint `gorm:"not null"`
CreatedAt time.Time `gorm:"autoCreateTime"` CreatedAt time.Time `gorm:"autoCreateTime"`
Product Product `gorm:"foreignKey:ProductId;references:Id"`
Supplier Supplier `gorm:"foreignKey:SupplierId;references:Id"`
} }
+3 -1
View File
@@ -26,5 +26,7 @@ type Supplier struct {
UpdatedAt time.Time `gorm:"autoUpdateTime"` UpdatedAt time.Time `gorm:"autoUpdateTime"`
DeletedAt gorm.DeletedAt `gorm:"index" json:"-"` DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
CreatedUser User `gorm:"foreignKey:CreatedBy;references:Id"` CreatedUser User `gorm:"foreignKey:CreatedBy;references:Id"`
ProductSuppliers []ProductSupplier `gorm:"foreignKey:SupplierId;references:Id"`
NonstockSuppliers []NonstockSupplier `gorm:"foreignKey:SupplierId;references:Id"`
} }
@@ -85,7 +85,7 @@ func (u *ApprovalController) GetAll(c *fiber.Ctx) error {
flat := dto.ToApprovalDTOs(records) flat := dto.ToApprovalDTOs(records)
return c.Status(fiber.StatusOK). return c.Status(fiber.StatusOK).
JSON(response.SuccessWithPaginate[dto.ApprovalBaseDTO]{ JSON(response.SuccessWithPaginate[dto.ApprovalRelationDTO]{
Code: fiber.StatusOK, Code: fiber.StatusOK,
Status: "success", Status: "success",
Message: "Get All approvals successfully", Message: "Get All approvals successfully",
+18 -18
View File
@@ -10,24 +10,24 @@ import (
approvalutils "gitlab.com/mbugroup/lti-api.git/internal/utils/approvals" approvalutils "gitlab.com/mbugroup/lti-api.git/internal/utils/approvals"
) )
type ApprovalBaseDTO struct { type ApprovalRelationDTO struct {
Id uint `json:"id"` Id uint `json:"id"`
StepNumber uint16 `json:"step_number"` StepNumber uint16 `json:"step_number"`
StepName string `json:"step_name"` StepName string `json:"step_name"`
Action *string `json:"action"` Action *string `json:"action"`
Notes *string `json:"notes"` Notes *string `json:"notes"`
ActionBy userDTO.UserBaseDTO `json:"action_by"` ActionBy userDTO.UserRelationDTO `json:"action_by"`
ActionAt time.Time `json:"action_at"` ActionAt time.Time `json:"action_at"`
} }
type ApprovalGroupDTO struct { type ApprovalGroupDTO struct {
StepNumber uint16 `json:"step_number"` StepNumber uint16 `json:"step_number"`
StepName string `json:"step_name"` StepName string `json:"step_name"`
Approvals []ApprovalBaseDTO `json:"approvals"` Approvals []ApprovalRelationDTO `json:"approvals"`
} }
func ToApprovalDTO(e entity.Approval) ApprovalBaseDTO { func ToApprovalDTO(e entity.Approval) ApprovalRelationDTO {
dto := ApprovalBaseDTO{ dto := ApprovalRelationDTO{
Id: e.Id, Id: e.Id,
Notes: e.Notes, Notes: e.Notes,
} }
@@ -54,10 +54,10 @@ func ToApprovalDTO(e entity.Approval) ApprovalBaseDTO {
} }
if e.ActionUser != nil && e.ActionUser.Id != 0 { if e.ActionUser != nil && e.ActionUser.Id != 0 {
user := userDTO.ToUserBaseDTO(*e.ActionUser) user := userDTO.ToUserRelationDTO(*e.ActionUser)
dto.ActionBy = user dto.ActionBy = user
} else if e.ActionBy != nil && *e.ActionBy != 0 { } else if e.ActionBy != nil && *e.ActionBy != 0 {
dto.ActionBy = userDTO.UserBaseDTO{ dto.ActionBy = userDTO.UserRelationDTO{
Id: *e.ActionBy, Id: *e.ActionBy,
IdUser: int64(*e.ActionBy), IdUser: int64(*e.ActionBy),
} }
@@ -71,8 +71,8 @@ func ToApprovalDTO(e entity.Approval) ApprovalBaseDTO {
return dto return dto
} }
func ToApprovalDTOs(items []entity.Approval) []ApprovalBaseDTO { func ToApprovalDTOs(items []entity.Approval) []ApprovalRelationDTO {
result := make([]ApprovalBaseDTO, len(items)) result := make([]ApprovalRelationDTO, len(items))
for i, item := range items { for i, item := range items {
result[i] = ToApprovalDTO(item) result[i] = ToApprovalDTO(item)
} }
@@ -86,7 +86,7 @@ func ToApprovalGroupDTOs(items []entity.Approval) []ApprovalGroupDTO {
type groupAccumulator struct { type groupAccumulator struct {
StepName string StepName string
Approvals []ApprovalBaseDTO Approvals []ApprovalRelationDTO
} }
groups := make(map[uint16]*groupAccumulator) groups := make(map[uint16]*groupAccumulator)
+14 -14
View File
@@ -9,7 +9,7 @@ import (
// === DTO Structs === // === DTO Structs ===
type ExpenseBaseDTO struct { type ExpenseRelationDTO struct {
Id uint64 `json:"id"` Id uint64 `json:"id"`
PoNumber string `json:"po_number"` PoNumber string `json:"po_number"`
ExpenseDate time.Time `json:"expense_date"` ExpenseDate time.Time `json:"expense_date"`
@@ -17,21 +17,21 @@ type ExpenseBaseDTO struct {
} }
type ExpenseListDTO struct { type ExpenseListDTO struct {
Id uint64 `json:"id"` Id uint64 `json:"id"`
ReferenceNumber string `json:"reference_number"` ReferenceNumber string `json:"reference_number"`
PoNumber string `json:"po_number"` PoNumber string `json:"po_number"`
Category string `json:"category"` Category string `json:"category"`
ExpenseDate time.Time `json:"expense_date"` ExpenseDate time.Time `json:"expense_date"`
GrandTotal float64 `json:"grand_total"` GrandTotal float64 `json:"grand_total"`
CreatedUser *userDTO.UserBaseDTO `json:"created_user,omitempty"` CreatedUser *userDTO.UserRelationDTO `json:"created_user,omitempty"`
CreatedAt time.Time `json:"created_at"` CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"` UpdatedAt time.Time `json:"updated_at"`
} }
// === Mapper Functions === // === Mapper Functions ===
func ToExpenseBaseDTO(e entity.Expense) ExpenseBaseDTO { func ToExpenseRelationDTO(e entity.Expense) ExpenseRelationDTO {
return ExpenseBaseDTO{ return ExpenseRelationDTO{
Id: e.Id, Id: e.Id,
PoNumber: e.PoNumber, PoNumber: e.PoNumber,
ExpenseDate: e.ExpenseDate, ExpenseDate: e.ExpenseDate,
@@ -40,9 +40,9 @@ func ToExpenseBaseDTO(e entity.Expense) ExpenseBaseDTO {
} }
func ToExpenseListDTO(e entity.Expense) ExpenseListDTO { func ToExpenseListDTO(e entity.Expense) ExpenseListDTO {
var createdUser *userDTO.UserBaseDTO var createdUser *userDTO.UserRelationDTO
if e.CreatedUser.Id != 0 { if e.CreatedUser.Id != 0 {
mapped := userDTO.ToUserBaseDTO(*e.CreatedUser) mapped := userDTO.ToUserRelationDTO(*e.CreatedUser)
createdUser = &mapped createdUser = &mapped
} }
@@ -10,28 +10,28 @@ import (
// === DTO Structs === // === DTO Structs ===
type ProductBaseDTO struct { type ProductRelationDTO struct {
Id uint `json:"id"` Id uint `json:"id"`
Name string `json:"name"` Name string `json:"name"`
SKU string `json:"sku"` SKU string `json:"sku"`
ProductCategory *productCategoryDTO.ProductCategoryBaseDTO `json:"product_category,omitempty"` ProductCategory *productCategoryDTO.ProductCategoryRelationDTO `json:"product_category,omitempty"`
} }
type WarehouseBaseDTO struct { type WarehouseRelationDTO struct {
Id uint `json:"id"` Id uint `json:"id"`
Name string `json:"name"` Name string `json:"name"`
} }
type ProductWarehouseDTO struct { type ProductWarehouseDTO struct {
Id uint `json:"id"` Id uint `json:"id"`
ProductId uint `json:"product_id"` ProductId uint `json:"product_id"`
WarehouseId uint `json:"warehouse_id"` WarehouseId uint `json:"warehouse_id"`
Quantity float64 `json:"quantity"` Quantity float64 `json:"quantity"`
Product *ProductBaseDTO `json:"product,omitempty"` Product *ProductRelationDTO `json:"product,omitempty"`
Warehouse *WarehouseBaseDTO `json:"warehouse,omitempty"` Warehouse *WarehouseRelationDTO `json:"warehouse,omitempty"`
} }
type AdjustmentBaseDTO struct { type AdjustmentRelationDTO struct {
Id uint `json:"id"` Id uint `json:"id"`
TransactionType string `json:"transaction_type"` TransactionType string `json:"transaction_type"`
Quantity float64 `json:"quantity"` Quantity float64 `json:"quantity"`
@@ -43,9 +43,9 @@ type AdjustmentBaseDTO struct {
} }
type AdjustmentListDTO struct { type AdjustmentListDTO struct {
AdjustmentBaseDTO AdjustmentRelationDTO
CreatedUser *userDTO.UserBaseDTO `json:"created_user,omitempty"` CreatedUser *userDTO.UserRelationDTO `json:"created_user,omitempty"`
CreatedAt time.Time `json:"created_at"` CreatedAt time.Time `json:"created_at"`
} }
type AdjustmentDetailDTO struct { type AdjustmentDetailDTO struct {
@@ -55,7 +55,7 @@ type AdjustmentDetailDTO struct {
// === Mapper Functions === // === Mapper Functions ===
func ToProductBaseDTO(e *entity.Product) *ProductBaseDTO { func ToProductRelationDTO(e *entity.Product) *ProductRelationDTO {
if e == nil { if e == nil {
return nil return nil
} }
@@ -64,13 +64,13 @@ func ToProductBaseDTO(e *entity.Product) *ProductBaseDTO {
sku = *e.Sku sku = *e.Sku
} }
var category *productCategoryDTO.ProductCategoryBaseDTO var category *productCategoryDTO.ProductCategoryRelationDTO
if e.ProductCategory.Id != 0 { if e.ProductCategory.Id != 0 {
mapped := productCategoryDTO.ToProductCategoryBaseDTO(e.ProductCategory) mapped := productCategoryDTO.ToProductCategoryRelationDTO(e.ProductCategory)
category = &mapped category = &mapped
} }
return &ProductBaseDTO{ return &ProductRelationDTO{
Id: e.Id, Id: e.Id,
Name: e.Name, Name: e.Name,
SKU: sku, SKU: sku,
@@ -78,11 +78,11 @@ func ToProductBaseDTO(e *entity.Product) *ProductBaseDTO {
} }
} }
func ToWarehouseBaseDTO(e *entity.Warehouse) *WarehouseBaseDTO { func ToWarehouseRelationDTO(e *entity.Warehouse) *WarehouseRelationDTO {
if e == nil { if e == nil {
return nil return nil
} }
return &WarehouseBaseDTO{ return &WarehouseRelationDTO{
Id: e.Id, Id: e.Id,
Name: e.Name, Name: e.Name,
} }
@@ -97,13 +97,13 @@ func ToProductWarehouseDTO(e *entity.ProductWarehouse) *ProductWarehouseDTO {
ProductId: e.ProductId, ProductId: e.ProductId,
WarehouseId: e.WarehouseId, WarehouseId: e.WarehouseId,
Quantity: e.Quantity, Quantity: e.Quantity,
Product: ToProductBaseDTO(&e.Product), Product: ToProductRelationDTO(&e.Product),
Warehouse: ToWarehouseBaseDTO(&e.Warehouse), Warehouse: ToWarehouseRelationDTO(&e.Warehouse),
} }
} }
func ToAdjustmentBaseDTO(e *entity.StockLog) AdjustmentBaseDTO { func ToAdjustmentRelationDTO(e *entity.StockLog) AdjustmentRelationDTO {
return AdjustmentBaseDTO{ return AdjustmentRelationDTO{
Id: e.Id, Id: e.Id,
TransactionType: e.TransactionType, TransactionType: e.TransactionType,
Quantity: e.Quantity, Quantity: e.Quantity,
@@ -116,9 +116,9 @@ func ToAdjustmentBaseDTO(e *entity.StockLog) AdjustmentBaseDTO {
} }
func ToAdjustmentListDTO(e *entity.StockLog) AdjustmentListDTO { func ToAdjustmentListDTO(e *entity.StockLog) AdjustmentListDTO {
var createdUser *userDTO.UserBaseDTO var createdUser *userDTO.UserRelationDTO
if e.CreatedUser != nil { if e.CreatedUser != nil {
createdUser = &userDTO.UserBaseDTO{ createdUser = &userDTO.UserRelationDTO{
Id: e.CreatedUser.Id, Id: e.CreatedUser.Id,
IdUser: e.CreatedUser.IdUser, IdUser: e.CreatedUser.IdUser,
Email: e.CreatedUser.Email, Email: e.CreatedUser.Email,
@@ -127,9 +127,9 @@ func ToAdjustmentListDTO(e *entity.StockLog) AdjustmentListDTO {
} }
return AdjustmentListDTO{ return AdjustmentListDTO{
AdjustmentBaseDTO: ToAdjustmentBaseDTO(e), AdjustmentRelationDTO: ToAdjustmentRelationDTO(e),
CreatedUser: createdUser, CreatedUser: createdUser,
CreatedAt: e.CreatedAt, CreatedAt: e.CreatedAt,
} }
} }
@@ -9,7 +9,7 @@ import (
// === DTO Structs === // === DTO Structs ===
type ProductWarehouseBaseDTO struct { type ProductWarehouseRelationDTO struct {
Id uint `json:"id"` Id uint `json:"id"`
ProductId uint `json:"product_id"` ProductId uint `json:"product_id"`
WarehouseId uint `json:"warehouse_id"` WarehouseId uint `json:"warehouse_id"`
@@ -17,21 +17,21 @@ type ProductWarehouseBaseDTO struct {
} }
type ProductWarehousNestedDTO struct { type ProductWarehousNestedDTO struct {
Id uint `json:"id"` Id uint `json:"id"`
Product *productDTO.ProductBaseDTO `json:"product,omitempty"` Product *productDTO.ProductRelationDTO `json:"product,omitempty"`
Warehouse *WarehouseBaseDTO `json:"warehouse,omitempty"` Warehouse *WarehouseRelationDTO `json:"warehouse,omitempty"`
} }
type ProductWarehouseListDTO struct { type ProductWarehouseListDTO struct {
ProductWarehouseBaseDTO ProductWarehouseRelationDTO
Product *productDTO.ProductBaseDTO `json:"product,omitempty"` Product *productDTO.ProductRelationDTO `json:"product,omitempty"`
Warehouse *WarehouseBaseDTO `json:"warehouse,omitempty"` Warehouse *WarehouseRelationDTO `json:"warehouse,omitempty"`
CreatedUser *UserBaseDTO `json:"created_user,omitempty"` CreatedUser *UserRelationDTO `json:"created_user,omitempty"`
CreatedAt time.Time `json:"created_at"` CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"` UpdatedAt time.Time `json:"updated_at"`
} }
type UserBaseDTO struct { type UserRelationDTO struct {
Id uint `json:"id"` Id uint `json:"id"`
Username string `json:"username"` Username string `json:"username"`
} }
@@ -41,40 +41,40 @@ type ProductWarehouseDetailDTO struct {
} }
// Nested DTOs for relations // Nested DTOs for relations
type ProductBaseDTO struct { type ProductRelationDTO struct {
Id uint `json:"id"` Id uint `json:"id"`
Name string `json:"name"` Name string `json:"name"`
Sku string `json:"sku"` Sku string `json:"sku"`
Flags []string `json:"flags"` Flags []string `json:"flags"`
} }
type WarehouseBaseDTO struct { type WarehouseRelationDTO struct {
Id uint `json:"id"` Id uint `json:"id"`
Name string `json:"name"` Name string `json:"name"`
Kandang *KandangBaseDTO `json:"kandang,omitempty"` Kandang *KandangRelationDTO `json:"kandang,omitempty"`
Location *LocationBaseDTO `json:"location,omitempty"` Location *LocationRelationDTO `json:"location,omitempty"`
Area *AreaBaseDTO `json:"area,omitempty"` Area *AreaRelationDTO `json:"area,omitempty"`
} }
type KandangBaseDTO struct { type KandangRelationDTO struct {
Id uint `json:"id"` Id uint `json:"id"`
Name string `json:"name"` Name string `json:"name"`
} }
type LocationBaseDTO struct { type LocationRelationDTO struct {
Id uint `json:"id"` Id uint `json:"id"`
Name string `json:"name"` Name string `json:"name"`
} }
type AreaBaseDTO struct { type AreaRelationDTO struct {
Id uint `json:"id"` Id uint `json:"id"`
Name string `json:"name"` Name string `json:"name"`
} }
// === Mapper Functions === // === Mapper Functions ===
func ToProductWarehouseBaseDTO(e entity.ProductWarehouse) ProductWarehouseBaseDTO { func ToProductWarehouseRelationDTO(e entity.ProductWarehouse) ProductWarehouseRelationDTO {
return ProductWarehouseBaseDTO{ return ProductWarehouseRelationDTO{
Id: e.Id, Id: e.Id,
ProductId: e.ProductId, // Field yang benar dari entity ProductId: e.ProductId, // Field yang benar dari entity
WarehouseId: e.WarehouseId, // Field yang benar dari entity WarehouseId: e.WarehouseId, // Field yang benar dari entity
@@ -83,12 +83,12 @@ func ToProductWarehouseBaseDTO(e entity.ProductWarehouse) ProductWarehouseBaseDT
} }
func ToProductWarehouseNestedDTO(e entity.ProductWarehouse) ProductWarehousNestedDTO { func ToProductWarehouseNestedDTO(e entity.ProductWarehouse) ProductWarehousNestedDTO {
product := productDTO.ToProductBaseDTO(e.Product) product := productDTO.ToProductRelationDTO(e.Product)
return ProductWarehousNestedDTO{ return ProductWarehousNestedDTO{
Id: e.Id, Id: e.Id,
Product: &product, Product: &product,
Warehouse: &WarehouseBaseDTO{ Warehouse: &WarehouseRelationDTO{
Id: e.Warehouse.Id, Id: e.Warehouse.Id,
Name: e.Warehouse.Name, Name: e.Warehouse.Name,
}, },
@@ -97,40 +97,40 @@ func ToProductWarehouseNestedDTO(e entity.ProductWarehouse) ProductWarehousNeste
func ToProductWarehouseListDTO(e entity.ProductWarehouse) ProductWarehouseListDTO { func ToProductWarehouseListDTO(e entity.ProductWarehouse) ProductWarehouseListDTO {
dto := ProductWarehouseListDTO{ dto := ProductWarehouseListDTO{
ProductWarehouseBaseDTO: ToProductWarehouseBaseDTO(e), ProductWarehouseRelationDTO: ToProductWarehouseRelationDTO(e),
CreatedAt: e.CreatedAt, CreatedAt: e.CreatedAt,
UpdatedAt: e.UpdatedAt, UpdatedAt: e.UpdatedAt,
} }
// Map Product relation jika ada // Map Product relation jika ada
if e.Product.Id != 0 { if e.Product.Id != 0 {
product := productDTO.ToProductBaseDTO(e.Product) product := productDTO.ToProductRelationDTO(e.Product)
dto.Product = &product dto.Product = &product
} }
// Map Warehouse relation jika ada // Map Warehouse relation jika ada
if e.Warehouse.Id != 0 { if e.Warehouse.Id != 0 {
warehouse := WarehouseBaseDTO{ warehouse := WarehouseRelationDTO{
Id: e.Warehouse.Id, Id: e.Warehouse.Id,
Name: e.Warehouse.Name, Name: e.Warehouse.Name,
} }
// Map Kandang jika ada // Map Kandang jika ada
if e.Warehouse.Kandang != nil && e.Warehouse.Kandang.Id != 0 { if e.Warehouse.Kandang != nil && e.Warehouse.Kandang.Id != 0 {
warehouse.Kandang = &KandangBaseDTO{ warehouse.Kandang = &KandangRelationDTO{
Id: e.Warehouse.Kandang.Id, Id: e.Warehouse.Kandang.Id,
Name: e.Warehouse.Kandang.Name, Name: e.Warehouse.Kandang.Name,
} }
} }
// Map Location jika ada // Map Location jika ada
if e.Warehouse.Location != nil && e.Warehouse.Location.Id != 0 { if e.Warehouse.Location != nil && e.Warehouse.Location.Id != 0 {
warehouse.Location = &LocationBaseDTO{ warehouse.Location = &LocationRelationDTO{
Id: e.Warehouse.Location.Id, Id: e.Warehouse.Location.Id,
Name: e.Warehouse.Location.Name, Name: e.Warehouse.Location.Name,
} }
} }
if e.Warehouse.Area.Id != 0 { if e.Warehouse.Area.Id != 0 {
warehouse.Area = &AreaBaseDTO{ warehouse.Area = &AreaRelationDTO{
Id: e.Warehouse.Area.Id, Id: e.Warehouse.Area.Id,
Name: e.Warehouse.Area.Name, Name: e.Warehouse.Area.Name,
} }
@@ -141,7 +141,7 @@ func ToProductWarehouseListDTO(e entity.ProductWarehouse) ProductWarehouseListDT
// Map CreatedUser relation jika ada // Map CreatedUser relation jika ada
if e.CreatedUser.Id != 0 { if e.CreatedUser.Id != 0 {
user := UserBaseDTO{ user := UserRelationDTO{
Id: e.CreatedUser.Id, Id: e.CreatedUser.Id,
Username: e.CreatedUser.Name, Username: e.CreatedUser.Name,
} }
@@ -165,22 +165,22 @@ func ToProductWarehouseDetailDTO(e entity.ProductWarehouse) ProductWarehouseDeta
} }
} }
func ToKandangBaseDTO(e entity.Kandang) KandangBaseDTO { func ToKandangRelationDTO(e entity.Kandang) KandangRelationDTO {
return KandangBaseDTO{ return KandangRelationDTO{
Id: e.Id, Id: e.Id,
Name: e.Name, Name: e.Name,
} }
} }
func ToLocationBaseDTO(e entity.Location) LocationBaseDTO { func ToLocationRelationDTO(e entity.Location) LocationRelationDTO {
return LocationBaseDTO{ return LocationRelationDTO{
Id: e.Id, Id: e.Id,
Name: e.Name, Name: e.Name,
} }
} }
func ToAreaBaseDTO(e entity.Area) AreaBaseDTO { func ToAreaRelationDTO(e entity.Area) AreaRelationDTO {
return AreaBaseDTO{ return AreaRelationDTO{
Id: e.Id, Id: e.Id,
Name: e.Name, Name: e.Name,
} }
@@ -9,7 +9,7 @@ import (
// === DTO Structs === // === DTO Structs ===
type TransferBaseDTO struct { type TransferRelationDTO struct {
Id uint64 `json:"id"` Id uint64 `json:"id"`
TransferReason string `json:"transfer_reason"` TransferReason string `json:"transfer_reason"`
TransferDate string `json:"transfer_date"` TransferDate string `json:"transfer_date"`
@@ -51,12 +51,12 @@ type WarehouseDetailDTO struct {
} }
type TransferListDTO struct { type TransferListDTO struct {
TransferBaseDTO TransferRelationDTO
CreatedUser *userDTO.UserBaseDTO `json:"created_user,omitempty"` CreatedUser *userDTO.UserRelationDTO `json:"created_user,omitempty"`
CreatedAt time.Time `json:"created_at"` CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"` UpdatedAt time.Time `json:"updated_at"`
Details []TransferDetailItemDTO `json:"details"` Details []TransferDetailItemDTO `json:"details"`
Deliveries []TransferDeliveryDTO `json:"deliveries"` Deliveries []TransferDeliveryDTO `json:"deliveries"`
} }
type TransferDetailDTO struct { type TransferDetailDTO struct {
@@ -93,7 +93,7 @@ type TransferDeliveryItemDTO struct {
// === Mapper Functions === // === Mapper Functions ===
func ToTransferBaseDTO(e entity.StockTransfer) TransferBaseDTO { func ToTransferRelationDTO(e entity.StockTransfer) TransferRelationDTO {
var sourceWarehouse *WarehouseDetailDTO var sourceWarehouse *WarehouseDetailDTO
if e.FromWarehouse != nil && e.FromWarehouse.Id != 0 { if e.FromWarehouse != nil && e.FromWarehouse.Id != 0 {
@@ -103,7 +103,7 @@ func ToTransferBaseDTO(e entity.StockTransfer) TransferBaseDTO {
if e.ToWarehouse != nil && e.ToWarehouse.Id != 0 { if e.ToWarehouse != nil && e.ToWarehouse.Id != 0 {
destinationWarehouse = toWarehouseDetailDTO(e.ToWarehouse) destinationWarehouse = toWarehouseDetailDTO(e.ToWarehouse)
} }
return TransferBaseDTO{ return TransferRelationDTO{
Id: e.Id, Id: e.Id,
TransferReason: e.Reason, TransferReason: e.Reason,
TransferDate: e.CreatedAt.Format("2006-01-02"), TransferDate: e.CreatedAt.Format("2006-01-02"),
@@ -145,9 +145,9 @@ func toWarehouseDetailDTO(w *entity.Warehouse) *WarehouseDetailDTO {
} }
func ToTransferListDTO(e entity.StockTransfer) TransferListDTO { func ToTransferListDTO(e entity.StockTransfer) TransferListDTO {
var createdUser *userDTO.UserBaseDTO var createdUser *userDTO.UserRelationDTO
if e.CreatedUser != nil { if e.CreatedUser != nil {
mapped := userDTO.ToUserBaseDTO(*e.CreatedUser) mapped := userDTO.ToUserRelationDTO(*e.CreatedUser)
createdUser = &mapped createdUser = &mapped
} }
// Map details // Map details
@@ -190,12 +190,12 @@ func ToTransferListDTO(e entity.StockTransfer) TransferListDTO {
}) })
} }
return TransferListDTO{ return TransferListDTO{
TransferBaseDTO: ToTransferBaseDTO(e), TransferRelationDTO: ToTransferRelationDTO(e),
CreatedUser: createdUser, CreatedUser: createdUser,
CreatedAt: e.CreatedAt, CreatedAt: e.CreatedAt,
UpdatedAt: e.UpdatedAt, UpdatedAt: e.UpdatedAt,
Details: details, Details: details,
Deliveries: deliveries, Deliveries: deliveries,
} }
} }
@@ -12,7 +12,7 @@ import (
userDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/users/dto" userDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/users/dto"
) )
type MarketingBaseDTO struct { type MarketingRelationDTO struct {
Id uint `json:"id"` Id uint `json:"id"`
SoNumber string `json:"so_number"` SoNumber string `json:"so_number"`
SoDate time.Time `json:"so_date"` SoDate time.Time `json:"so_date"`
@@ -20,28 +20,28 @@ type MarketingBaseDTO struct {
} }
type MarketingListDTO struct { type MarketingListDTO struct {
MarketingBaseDTO MarketingRelationDTO
Customer *customerDTO.CustomerBaseDTO `json:"customer,omitempty"` Customer *customerDTO.CustomerRelationDTO `json:"customer,omitempty"`
SalesPerson *userDTO.UserBaseDTO `json:"sales_person,omitempty"` SalesPerson *userDTO.UserRelationDTO `json:"sales_person,omitempty"`
SoDocs string `json:"so_docs,omitempty"` SoDocs string `json:"so_docs,omitempty"`
SalesOrder []MarketingProductDTO `json:"sales_order,omitempty"` SalesOrder []MarketingProductDTO `json:"sales_order,omitempty"`
CreatedUser *userDTO.UserBaseDTO `json:"created_user"` CreatedUser *userDTO.UserRelationDTO `json:"created_user"`
CreatedAt time.Time `json:"created_at"` CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"` UpdatedAt time.Time `json:"updated_at"`
LatestApproval *approvalDTO.ApprovalBaseDTO `json:"latest_approval,omitempty"` LatestApproval *approvalDTO.ApprovalRelationDTO `json:"latest_approval,omitempty"`
} }
type MarketingDetailDTO struct { type MarketingDetailDTO struct {
MarketingBaseDTO MarketingRelationDTO
Customer *customerDTO.CustomerBaseDTO `json:"customer,omitempty"` Customer *customerDTO.CustomerRelationDTO `json:"customer,omitempty"`
SalesPerson *userDTO.UserBaseDTO `json:"sales_person,omitempty"` SalesPerson *userDTO.UserRelationDTO `json:"sales_person,omitempty"`
SoDocs string `json:"so_docs,omitempty"` SoDocs string `json:"so_docs,omitempty"`
SalesOrder []MarketingProductDTO `json:"sales_order,omitempty"` SalesOrder []MarketingProductDTO `json:"sales_order,omitempty"`
DeliveryOrder []DeliveryGroupDTO `json:"delivery_order,omitempty"` DeliveryOrder []DeliveryGroupDTO `json:"delivery_order,omitempty"`
CreatedUser *userDTO.UserBaseDTO `json:"created_user"` CreatedUser *userDTO.UserRelationDTO `json:"created_user"`
CreatedAt time.Time `json:"created_at"` CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"` UpdatedAt time.Time `json:"updated_at"`
LatestApproval *approvalDTO.ApprovalBaseDTO `json:"latest_approval,omitempty"` LatestApproval *approvalDTO.ApprovalRelationDTO `json:"latest_approval,omitempty"`
} }
type MarketingDeliveryProductDTO struct { type MarketingDeliveryProductDTO struct {
Id uint `json:"id"` Id uint `json:"id"`
@@ -67,10 +67,10 @@ type DeliveryItemDTO struct {
} }
type DeliveryGroupDTO struct { type DeliveryGroupDTO struct {
DoNumber string `json:"do_number"` DoNumber string `json:"do_number"`
DeliveryDate *time.Time `json:"delivery_date"` DeliveryDate *time.Time `json:"delivery_date"`
Warehouse *productwarehouseDTO.WarehouseBaseDTO `json:"warehouse,omitempty"` Warehouse *productwarehouseDTO.WarehouseRelationDTO `json:"warehouse,omitempty"`
Deliveries []DeliveryItemDTO `json:"deliveries"` Deliveries []DeliveryItemDTO `json:"deliveries"`
} }
type MarketingProductDTO struct { type MarketingProductDTO struct {
@@ -86,8 +86,8 @@ type MarketingProductDTO struct {
VehicleNumber string `json:"vehicle_number,omitempty"` VehicleNumber string `json:"vehicle_number,omitempty"`
} }
func ToMarketingBaseDTO(marketing *entity.Marketing) MarketingBaseDTO { func ToMarketingRelationDTO(marketing *entity.Marketing) MarketingRelationDTO {
return MarketingBaseDTO{ return MarketingRelationDTO{
Id: marketing.Id, Id: marketing.Id,
SoNumber: marketing.SoNumber, SoNumber: marketing.SoNumber,
SoDate: marketing.SoDate, SoDate: marketing.SoDate,
@@ -131,25 +131,25 @@ func ToMarketingDeliveryProductDTO(e entity.MarketingDeliveryProduct) MarketingD
} }
func ToMarketingListDTO(marketing *entity.Marketing, deliveryProducts []entity.MarketingDeliveryProduct) MarketingListDTO { func ToMarketingListDTO(marketing *entity.Marketing, deliveryProducts []entity.MarketingDeliveryProduct) MarketingListDTO {
var createdUser *userDTO.UserBaseDTO var createdUser *userDTO.UserRelationDTO
if marketing.CreatedUser.Id != 0 { if marketing.CreatedUser.Id != 0 {
mapped := userDTO.ToUserBaseDTO(marketing.CreatedUser) mapped := userDTO.ToUserRelationDTO(marketing.CreatedUser)
createdUser = &mapped createdUser = &mapped
} }
var customer *customerDTO.CustomerBaseDTO var customer *customerDTO.CustomerRelationDTO
if marketing.Customer.Id != 0 { if marketing.Customer.Id != 0 {
mapped := customerDTO.ToCustomerBaseDTO(marketing.Customer) mapped := customerDTO.ToCustomerRelationDTO(marketing.Customer)
customer = &mapped customer = &mapped
} }
var salesPerson *userDTO.UserBaseDTO var salesPerson *userDTO.UserRelationDTO
if marketing.SalesPerson.Id != 0 { if marketing.SalesPerson.Id != 0 {
mapped := userDTO.ToUserBaseDTO(marketing.SalesPerson) mapped := userDTO.ToUserRelationDTO(marketing.SalesPerson)
salesPerson = &mapped salesPerson = &mapped
} }
var latestApproval *approvalDTO.ApprovalBaseDTO var latestApproval *approvalDTO.ApprovalRelationDTO
if marketing.LatestApproval != nil { if marketing.LatestApproval != nil {
mapped := approvalDTO.ToApprovalDTO(*marketing.LatestApproval) mapped := approvalDTO.ToApprovalDTO(*marketing.LatestApproval)
latestApproval = &mapped latestApproval = &mapped
@@ -164,34 +164,34 @@ func ToMarketingListDTO(marketing *entity.Marketing, deliveryProducts []entity.M
} }
return MarketingListDTO{ return MarketingListDTO{
MarketingBaseDTO: ToMarketingBaseDTO(marketing), MarketingRelationDTO: ToMarketingRelationDTO(marketing),
Customer: customer, Customer: customer,
SalesPerson: salesPerson, SalesPerson: salesPerson,
SoDocs: marketing.SoDocs, SoDocs: marketing.SoDocs,
SalesOrder: salesOrderProducts, SalesOrder: salesOrderProducts,
CreatedUser: createdUser, CreatedUser: createdUser,
CreatedAt: marketing.CreatedAt, CreatedAt: marketing.CreatedAt,
UpdatedAt: marketing.UpdatedAt, UpdatedAt: marketing.UpdatedAt,
LatestApproval: latestApproval, LatestApproval: latestApproval,
} }
} }
func ToMarketingDetailDTO(marketing *entity.Marketing, deliveryProducts []entity.MarketingDeliveryProduct) MarketingDetailDTO { func ToMarketingDetailDTO(marketing *entity.Marketing, deliveryProducts []entity.MarketingDeliveryProduct) MarketingDetailDTO {
var createdUser *userDTO.UserBaseDTO var createdUser *userDTO.UserRelationDTO
if marketing.CreatedUser.Id != 0 { if marketing.CreatedUser.Id != 0 {
mapped := userDTO.ToUserBaseDTO(marketing.CreatedUser) mapped := userDTO.ToUserRelationDTO(marketing.CreatedUser)
createdUser = &mapped createdUser = &mapped
} }
var customer *customerDTO.CustomerBaseDTO var customer *customerDTO.CustomerRelationDTO
if marketing.Customer.Id != 0 { if marketing.Customer.Id != 0 {
mapped := customerDTO.ToCustomerBaseDTO(marketing.Customer) mapped := customerDTO.ToCustomerRelationDTO(marketing.Customer)
customer = &mapped customer = &mapped
} }
var salesPerson *userDTO.UserBaseDTO var salesPerson *userDTO.UserRelationDTO
if marketing.SalesPerson.Id != 0 { if marketing.SalesPerson.Id != 0 {
mapped := userDTO.ToUserBaseDTO(marketing.SalesPerson) mapped := userDTO.ToUserRelationDTO(marketing.SalesPerson)
salesPerson = &mapped salesPerson = &mapped
} }
@@ -214,23 +214,23 @@ func ToMarketingDetailDTO(marketing *entity.Marketing, deliveryProducts []entity
deliveryGroups := groupDeliveryProducts(deliveryProductsDTOs, marketing.SoNumber) deliveryGroups := groupDeliveryProducts(deliveryProductsDTOs, marketing.SoNumber)
var latestApproval *approvalDTO.ApprovalBaseDTO var latestApproval *approvalDTO.ApprovalRelationDTO
if marketing.LatestApproval != nil { if marketing.LatestApproval != nil {
mapped := approvalDTO.ToApprovalDTO(*marketing.LatestApproval) mapped := approvalDTO.ToApprovalDTO(*marketing.LatestApproval)
latestApproval = &mapped latestApproval = &mapped
} }
return MarketingDetailDTO{ return MarketingDetailDTO{
MarketingBaseDTO: ToMarketingBaseDTO(marketing), MarketingRelationDTO: ToMarketingRelationDTO(marketing),
SoDocs: marketing.SoDocs, SoDocs: marketing.SoDocs,
Customer: customer, Customer: customer,
SalesPerson: salesPerson, SalesPerson: salesPerson,
SalesOrder: salesOrderProducts, SalesOrder: salesOrderProducts,
DeliveryOrder: deliveryGroups, DeliveryOrder: deliveryGroups,
CreatedUser: createdUser, CreatedUser: createdUser,
CreatedAt: marketing.CreatedAt, CreatedAt: marketing.CreatedAt,
UpdatedAt: marketing.UpdatedAt, UpdatedAt: marketing.UpdatedAt,
LatestApproval: latestApproval, LatestApproval: latestApproval,
} }
} }
@@ -285,7 +285,7 @@ func groupDeliveryProducts(products []MarketingDeliveryProductDTO, soNumber stri
if !exists { if !exists {
group = &DeliveryGroupDTO{ group = &DeliveryGroupDTO{
DeliveryDate: product.DeliveryDate, DeliveryDate: product.DeliveryDate,
Warehouse: &productwarehouseDTO.WarehouseBaseDTO{ Warehouse: &productwarehouseDTO.WarehouseRelationDTO{
Id: warehouseId, Id: warehouseId,
Name: warehouseName, Name: warehouseName,
}, },
+13 -13
View File
@@ -9,16 +9,16 @@ import (
// === DTO Structs === // === DTO Structs ===
type AreaBaseDTO struct { type AreaRelationDTO struct {
Id uint `json:"id"` Id uint `json:"id"`
Name string `json:"name"` Name string `json:"name"`
} }
type AreaListDTO struct { type AreaListDTO struct {
AreaBaseDTO AreaRelationDTO
CreatedUser *userDTO.UserBaseDTO `json:"created_user"` CreatedUser *userDTO.UserRelationDTO `json:"created_user"`
CreatedAt time.Time `json:"created_at"` CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"` UpdatedAt time.Time `json:"updated_at"`
} }
type AreaDetailDTO struct { type AreaDetailDTO struct {
@@ -27,25 +27,25 @@ type AreaDetailDTO struct {
// === Mapper Functions === // === Mapper Functions ===
func ToAreaBaseDTO(e entity.Area) AreaBaseDTO { func ToAreaRelationDTO(e entity.Area) AreaRelationDTO {
return AreaBaseDTO{ return AreaRelationDTO{
Id: e.Id, Id: e.Id,
Name: e.Name, Name: e.Name,
} }
} }
func ToAreaListDTO(e entity.Area) AreaListDTO { func ToAreaListDTO(e entity.Area) AreaListDTO {
var createdUser *userDTO.UserBaseDTO var createdUser *userDTO.UserRelationDTO
if e.CreatedUser.Id != 0 { if e.CreatedUser.Id != 0 {
mapped := userDTO.ToUserBaseDTO(e.CreatedUser) mapped := userDTO.ToUserRelationDTO(e.CreatedUser)
createdUser = &mapped createdUser = &mapped
} }
return AreaListDTO{ return AreaListDTO{
AreaBaseDTO: ToAreaBaseDTO(e), AreaRelationDTO: ToAreaRelationDTO(e),
CreatedUser: createdUser, CreatedUser: createdUser,
CreatedAt: e.CreatedAt, CreatedAt: e.CreatedAt,
UpdatedAt: e.UpdatedAt, UpdatedAt: e.UpdatedAt,
} }
} }
+13 -13
View File
@@ -9,7 +9,7 @@ import (
// === DTO Structs === // === DTO Structs ===
type BankBaseDTO struct { type BankRelationDTO struct {
Id uint `json:"id"` Id uint `json:"id"`
Name string `json:"name"` Name string `json:"name"`
Alias string `json:"alias"` Alias string `json:"alias"`
@@ -18,10 +18,10 @@ type BankBaseDTO struct {
} }
type BankListDTO struct { type BankListDTO struct {
BankBaseDTO BankRelationDTO
CreatedUser *userDTO.UserBaseDTO `json:"created_user"` CreatedUser *userDTO.UserRelationDTO `json:"created_user"`
CreatedAt time.Time `json:"created_at"` CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"` UpdatedAt time.Time `json:"updated_at"`
} }
type BankDetailDTO struct { type BankDetailDTO struct {
@@ -30,8 +30,8 @@ type BankDetailDTO struct {
// === Mapper Functions === // === Mapper Functions ===
func ToBankBaseDTO(e entity.Bank) BankBaseDTO { func ToBankRelationDTO(e entity.Bank) BankRelationDTO {
return BankBaseDTO{ return BankRelationDTO{
Id: e.Id, Id: e.Id,
Name: e.Name, Name: e.Name,
Alias: e.Alias, Alias: e.Alias,
@@ -41,17 +41,17 @@ func ToBankBaseDTO(e entity.Bank) BankBaseDTO {
} }
func ToBankListDTO(e entity.Bank) BankListDTO { func ToBankListDTO(e entity.Bank) BankListDTO {
var createdUser *userDTO.UserBaseDTO var createdUser *userDTO.UserRelationDTO
if e.CreatedUser.Id != 0 { if e.CreatedUser.Id != 0 {
mapped := userDTO.ToUserBaseDTO(e.CreatedUser) mapped := userDTO.ToUserRelationDTO(e.CreatedUser)
createdUser = &mapped createdUser = &mapped
} }
return BankListDTO{ return BankListDTO{
BankBaseDTO: ToBankBaseDTO(e), BankRelationDTO: ToBankRelationDTO(e),
CreatedAt: e.CreatedAt, CreatedAt: e.CreatedAt,
UpdatedAt: e.UpdatedAt, UpdatedAt: e.UpdatedAt,
CreatedUser: createdUser, CreatedUser: createdUser,
} }
} }
@@ -9,7 +9,7 @@ import (
// === DTO Structs === // === DTO Structs ===
type CustomerBaseDTO struct { type CustomerRelationDTO struct {
Id uint `json:"id"` Id uint `json:"id"`
Name string `json:"name"` Name string `json:"name"`
PicId uint `json:"pic_id"` PicId uint `json:"pic_id"`
@@ -20,14 +20,14 @@ type CustomerBaseDTO struct {
AccountNumber string `json:"account_number"` AccountNumber string `json:"account_number"`
Balance float64 `json:"balance"` Balance float64 `json:"balance"`
Pic *userDTO.UserBaseDTO `json:"pic,omitempty"` Pic *userDTO.UserRelationDTO `json:"pic,omitempty"`
} }
type CustomerListDTO struct { type CustomerListDTO struct {
CustomerBaseDTO CustomerRelationDTO
CreatedUser *userDTO.UserBaseDTO `json:"created_user"` CreatedUser *userDTO.UserRelationDTO `json:"created_user"`
CreatedAt time.Time `json:"created_at"` CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"` UpdatedAt time.Time `json:"updated_at"`
} }
type CustomerDetailDTO struct { type CustomerDetailDTO struct {
@@ -36,14 +36,14 @@ type CustomerDetailDTO struct {
// === Mapper Functions === // === Mapper Functions ===
func ToCustomerBaseDTO(e entity.Customer) CustomerBaseDTO { func ToCustomerRelationDTO(e entity.Customer) CustomerRelationDTO {
var pic *userDTO.UserBaseDTO var pic *userDTO.UserRelationDTO
if e.Pic.Id != 0 { if e.Pic.Id != 0 {
mapped := userDTO.ToUserBaseDTO(e.Pic) mapped := userDTO.ToUserRelationDTO(e.Pic)
pic = &mapped pic = &mapped
} }
return CustomerBaseDTO{ return CustomerRelationDTO{
Id: e.Id, Id: e.Id,
Name: e.Name, Name: e.Name,
PicId: e.PicId, PicId: e.PicId,
@@ -57,17 +57,17 @@ func ToCustomerBaseDTO(e entity.Customer) CustomerBaseDTO {
} }
func ToCustomerListDTO(e entity.Customer) CustomerListDTO { func ToCustomerListDTO(e entity.Customer) CustomerListDTO {
var createdUser *userDTO.UserBaseDTO var createdUser *userDTO.UserRelationDTO
if e.CreatedUser.Id != 0 { if e.CreatedUser.Id != 0 {
mapped := userDTO.ToUserBaseDTO(e.CreatedUser) mapped := userDTO.ToUserRelationDTO(e.CreatedUser)
createdUser = &mapped createdUser = &mapped
} }
return CustomerListDTO{ return CustomerListDTO{
CustomerBaseDTO: ToCustomerBaseDTO(e), CustomerRelationDTO: ToCustomerRelationDTO(e),
CreatedAt: e.CreatedAt, CreatedAt: e.CreatedAt,
UpdatedAt: e.UpdatedAt, UpdatedAt: e.UpdatedAt,
CreatedUser: createdUser, CreatedUser: createdUser,
} }
} }
+13 -13
View File
@@ -9,7 +9,7 @@ import (
// === DTO Structs === // === DTO Structs ===
type FcrBaseDTO struct { type FcrRelationDTO struct {
Id uint `json:"id"` Id uint `json:"id"`
Name string `json:"name"` Name string `json:"name"`
} }
@@ -22,10 +22,10 @@ type FcrStandardDTO struct {
} }
type FcrListDTO struct { type FcrListDTO struct {
FcrBaseDTO FcrRelationDTO
CreatedUser *userDTO.UserBaseDTO `json:"created_user"` CreatedUser *userDTO.UserRelationDTO `json:"created_user"`
CreatedAt time.Time `json:"created_at"` CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"` UpdatedAt time.Time `json:"updated_at"`
} }
type FcrDetailDTO struct { type FcrDetailDTO struct {
@@ -35,25 +35,25 @@ type FcrDetailDTO struct {
// === Mapper Functions === // === Mapper Functions ===
func ToFcrBaseDTO(e entity.Fcr) FcrBaseDTO { func ToFcrRelationDTO(e entity.Fcr) FcrRelationDTO {
return FcrBaseDTO{ return FcrRelationDTO{
Id: e.Id, Id: e.Id,
Name: e.Name, Name: e.Name,
} }
} }
func ToFcrListDTO(e entity.Fcr) FcrListDTO { func ToFcrListDTO(e entity.Fcr) FcrListDTO {
var createdUser *userDTO.UserBaseDTO var createdUser *userDTO.UserRelationDTO
if e.CreatedUser.Id != 0 { if e.CreatedUser.Id != 0 {
mapped := userDTO.ToUserBaseDTO(e.CreatedUser) mapped := userDTO.ToUserRelationDTO(e.CreatedUser)
createdUser = &mapped createdUser = &mapped
} }
return FcrListDTO{ return FcrListDTO{
FcrBaseDTO: ToFcrBaseDTO(e), FcrRelationDTO: ToFcrRelationDTO(e),
CreatedAt: e.CreatedAt, CreatedAt: e.CreatedAt,
UpdatedAt: e.UpdatedAt, UpdatedAt: e.UpdatedAt,
CreatedUser: createdUser, CreatedUser: createdUser,
} }
} }
+13 -13
View File
@@ -9,16 +9,16 @@ import (
// === DTO Structs === // === DTO Structs ===
type FlockBaseDTO struct { type FlockRelationDTO struct {
Id uint `json:"id"` Id uint `json:"id"`
Name string `json:"name"` Name string `json:"name"`
} }
type FlockListDTO struct { type FlockListDTO struct {
FlockBaseDTO FlockRelationDTO
CreatedUser *userDTO.UserBaseDTO `json:"created_user"` CreatedUser *userDTO.UserRelationDTO `json:"created_user"`
CreatedAt time.Time `json:"created_at"` CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"` UpdatedAt time.Time `json:"updated_at"`
} }
type FlockDetailDTO struct { type FlockDetailDTO struct {
@@ -27,25 +27,25 @@ type FlockDetailDTO struct {
// === Mapper Functions === // === Mapper Functions ===
func ToFlockBaseDTO(e entity.Flock) FlockBaseDTO { func ToFlockRelationDTO(e entity.Flock) FlockRelationDTO {
return FlockBaseDTO{ return FlockRelationDTO{
Id: e.Id, Id: e.Id,
Name: e.Name, Name: e.Name,
} }
} }
func ToFlockListDTO(e entity.Flock) FlockListDTO { func ToFlockListDTO(e entity.Flock) FlockListDTO {
var createdUser *userDTO.UserBaseDTO var createdUser *userDTO.UserRelationDTO
if e.CreatedUser.Id != 0 { if e.CreatedUser.Id != 0 {
mapped := userDTO.ToUserBaseDTO(e.CreatedUser) mapped := userDTO.ToUserRelationDTO(e.CreatedUser)
createdUser = &mapped createdUser = &mapped
} }
return FlockListDTO{ return FlockListDTO{
FlockBaseDTO: ToFlockBaseDTO(e), FlockRelationDTO: ToFlockRelationDTO(e),
CreatedAt: e.CreatedAt, CreatedAt: e.CreatedAt,
UpdatedAt: e.UpdatedAt, UpdatedAt: e.UpdatedAt,
CreatedUser: createdUser, CreatedUser: createdUser,
} }
} }
@@ -10,25 +10,25 @@ import (
// === DTO Structs === // === DTO Structs ===
type KandangBaseDTO struct { type KandangRelationDTO struct {
Id uint `json:"id"` Id uint `json:"id"`
Name string `json:"name"` Name string `json:"name"`
Status string `json:"status"` Status string `json:"status"`
Capacity float64 `json:"capacity"` Capacity float64 `json:"capacity"`
Location locationDTO.LocationBaseDTO `json:"location,omitempty"` Location locationDTO.LocationRelationDTO `json:"location,omitempty"`
Pic userDTO.UserBaseDTO `json:"pic,omitempty"` Pic userDTO.UserRelationDTO `json:"pic,omitempty"`
} }
type KandangListDTO struct { type KandangListDTO struct {
Id uint `json:"id"` Id uint `json:"id"`
Name string `json:"name"` Name string `json:"name"`
Status string `json:"status"` Status string `json:"status"`
Capacity float64 `json:"capacity"` Capacity float64 `json:"capacity"`
Location locationDTO.LocationBaseDTO `json:"location"` Location locationDTO.LocationRelationDTO `json:"location"`
Pic userDTO.UserBaseDTO `json:"pic"` Pic userDTO.UserRelationDTO `json:"pic"`
CreatedUser userDTO.UserBaseDTO `json:"created_user"` CreatedUser userDTO.UserRelationDTO `json:"created_user"`
CreatedAt time.Time `json:"created_at"` CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"` UpdatedAt time.Time `json:"updated_at"`
} }
type KandangDetailDTO struct { type KandangDetailDTO struct {
@@ -37,20 +37,20 @@ type KandangDetailDTO struct {
// === Mapper Functions === // === Mapper Functions ===
func ToKandangBaseDTO(e entity.Kandang) KandangBaseDTO { func ToKandangRelationDTO(e entity.Kandang) KandangRelationDTO {
var location locationDTO.LocationBaseDTO var location locationDTO.LocationRelationDTO
if e.Location.Id != 0 { if e.Location.Id != 0 {
mapped := locationDTO.ToLocationBaseDTO(e.Location) mapped := locationDTO.ToLocationRelationDTO(e.Location)
location = mapped location = mapped
} }
var pic userDTO.UserBaseDTO var pic userDTO.UserRelationDTO
if e.Pic.Id != 0 { if e.Pic.Id != 0 {
mapped := userDTO.ToUserBaseDTO(e.Pic) mapped := userDTO.ToUserRelationDTO(e.Pic)
pic = mapped pic = mapped
} }
return KandangBaseDTO{ return KandangRelationDTO{
Id: e.Id, Id: e.Id,
Name: e.Name, Name: e.Name,
Status: e.Status, Status: e.Status,
@@ -61,21 +61,21 @@ func ToKandangBaseDTO(e entity.Kandang) KandangBaseDTO {
} }
func ToKandangListDTO(e entity.Kandang) KandangListDTO { func ToKandangListDTO(e entity.Kandang) KandangListDTO {
var location locationDTO.LocationBaseDTO var location locationDTO.LocationRelationDTO
if e.Location.Id != 0 { if e.Location.Id != 0 {
mapped := locationDTO.ToLocationBaseDTO(e.Location) mapped := locationDTO.ToLocationRelationDTO(e.Location)
location = mapped location = mapped
} }
var pic userDTO.UserBaseDTO var pic userDTO.UserRelationDTO
if e.Pic.Id != 0 { if e.Pic.Id != 0 {
mapped := userDTO.ToUserBaseDTO(e.Pic) mapped := userDTO.ToUserRelationDTO(e.Pic)
pic = mapped pic = mapped
} }
var createdUser userDTO.UserBaseDTO var createdUser userDTO.UserRelationDTO
if e.CreatedUser.Id != 0 { if e.CreatedUser.Id != 0 {
mapped := userDTO.ToUserBaseDTO(e.CreatedUser) mapped := userDTO.ToUserRelationDTO(e.CreatedUser)
createdUser = mapped createdUser = mapped
} }
@@ -10,21 +10,21 @@ import (
// === DTO Structs === // === DTO Structs ===
type LocationBaseDTO struct { type LocationRelationDTO struct {
Id uint `json:"id"` Id uint `json:"id"`
Name string `json:"name"` Name string `json:"name"`
Address string `json:"address"` Address string `json:"address"`
Area *areaDTO.AreaBaseDTO `json:"area,omitempty"` Area *areaDTO.AreaRelationDTO `json:"area,omitempty"`
} }
type LocationListDTO struct { type LocationListDTO struct {
Id uint `json:"id"` Id uint `json:"id"`
Name string `json:"name"` Name string `json:"name"`
Address string `json:"address"` Address string `json:"address"`
Area *areaDTO.AreaBaseDTO `json:"area"` Area *areaDTO.AreaRelationDTO `json:"area"`
CreatedUser *userDTO.UserBaseDTO `json:"created_user"` CreatedUser *userDTO.UserRelationDTO `json:"created_user"`
CreatedAt time.Time `json:"created_at"` CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"` UpdatedAt time.Time `json:"updated_at"`
} }
type LocationDetailDTO struct { type LocationDetailDTO struct {
@@ -33,14 +33,14 @@ type LocationDetailDTO struct {
// === Mapper Functions === // === Mapper Functions ===
func ToLocationBaseDTO(e entity.Location) LocationBaseDTO { func ToLocationRelationDTO(e entity.Location) LocationRelationDTO {
var area *areaDTO.AreaBaseDTO var area *areaDTO.AreaRelationDTO
if e.Area.Id != 0 { if e.Area.Id != 0 {
mapped := areaDTO.ToAreaBaseDTO(e.Area) mapped := areaDTO.ToAreaRelationDTO(e.Area)
area = &mapped area = &mapped
} }
return LocationBaseDTO{ return LocationRelationDTO{
Id: e.Id, Id: e.Id,
Name: e.Name, Name: e.Name,
Address: e.Address, Address: e.Address,
@@ -49,15 +49,15 @@ func ToLocationBaseDTO(e entity.Location) LocationBaseDTO {
} }
func ToLocationListDTO(e entity.Location) LocationListDTO { func ToLocationListDTO(e entity.Location) LocationListDTO {
var createdUser *userDTO.UserBaseDTO var createdUser *userDTO.UserRelationDTO
if e.CreatedUser.Id != 0 { if e.CreatedUser.Id != 0 {
mapped := userDTO.ToUserBaseDTO(e.CreatedUser) mapped := userDTO.ToUserRelationDTO(e.CreatedUser)
createdUser = &mapped createdUser = &mapped
} }
var area *areaDTO.AreaBaseDTO var area *areaDTO.AreaRelationDTO
if e.Area.Id != 0 { if e.Area.Id != 0 {
mapped := areaDTO.ToAreaBaseDTO(e.Area) mapped := areaDTO.ToAreaRelationDTO(e.Area)
area = &mapped area = &mapped
} }
@@ -4,41 +4,39 @@ import (
"time" "time"
entity "gitlab.com/mbugroup/lti-api.git/internal/entities" entity "gitlab.com/mbugroup/lti-api.git/internal/entities"
supplierDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/suppliers/dto"
uomDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/uoms/dto" uomDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/uoms/dto"
userDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/users/dto" userDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/users/dto"
) )
// === DTO Structs === // === DTO Structs ===
type NonstockBaseDTO struct { type NonstockRelationDTO struct {
Id uint `json:"id"` Id uint `json:"id"`
Name string `json:"name"` Name string `json:"name"`
Uom *uomDTO.UomBaseDTO `json:"uom,omitempty"` Uom *uomDTO.UomRelationDTO `json:"uom,omitempty"`
Flags []string `json:"flags"` Flags []string `json:"flags"`
} }
type NonstockListDTO struct { type NonstockListDTO struct {
Id uint `json:"id"` Id uint `json:"id"`
Name string `json:"name"` Name string `json:"name"`
Uom *uomDTO.UomBaseDTO `json:"uom"` Flags []string `json:"flags"`
Suppliers []supplierDTO.SupplierBaseDTO `json:"suppliers"` Uom *uomDTO.UomRelationDTO `json:"uom"`
CreatedUser *userDTO.UserBaseDTO `json:"created_user"` CreatedUser *userDTO.UserRelationDTO `json:"created_user"`
CreatedAt time.Time `json:"created_at"` CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"` UpdatedAt time.Time `json:"updated_at"`
} }
type NonstockDetailDTO struct { type NonstockDetailDTO struct {
NonstockListDTO NonstockListDTO
Flags []string `json:"flags"`
} }
// === Mapper Functions === // === Mapper Functions ===
func ToNonstockBaseDTO(e entity.Nonstock) NonstockBaseDTO { func ToNonstockRelationDTO(e entity.Nonstock) NonstockRelationDTO {
var uomRef *uomDTO.UomBaseDTO var uomRef *uomDTO.UomRelationDTO
if e.Uom.Id != 0 { if e.Uom.Id != 0 {
mapped := uomDTO.ToUomBaseDTO(e.Uom) mapped := uomDTO.ToUomRelationDTO(e.Uom)
uomRef = &mapped uomRef = &mapped
} }
@@ -47,7 +45,7 @@ func ToNonstockBaseDTO(e entity.Nonstock) NonstockBaseDTO {
flags[i] = f.Name flags[i] = f.Name
} }
return NonstockBaseDTO{ return NonstockRelationDTO{
Id: e.Id, Id: e.Id,
Name: e.Name, Name: e.Name,
Uom: uomRef, Uom: uomRef,
@@ -56,23 +54,18 @@ func ToNonstockBaseDTO(e entity.Nonstock) NonstockBaseDTO {
} }
func ToNonstockListDTO(e entity.Nonstock) NonstockListDTO { func ToNonstockListDTO(e entity.Nonstock) NonstockListDTO {
var createdUser *userDTO.UserBaseDTO var createdUser *userDTO.UserRelationDTO
if e.CreatedUser.Id != 0 { if e.CreatedUser.Id != 0 {
mapped := userDTO.ToUserBaseDTO(e.CreatedUser) mapped := userDTO.ToUserRelationDTO(e.CreatedUser)
createdUser = &mapped createdUser = &mapped
} }
var uomRef *uomDTO.UomBaseDTO var uomRef *uomDTO.UomRelationDTO
if e.Uom.Id != 0 { if e.Uom.Id != 0 {
mapped := uomDTO.ToUomBaseDTO(e.Uom) mapped := uomDTO.ToUomRelationDTO(e.Uom)
uomRef = &mapped uomRef = &mapped
} }
suppliers := make([]supplierDTO.SupplierBaseDTO, len(e.Suppliers))
for i, s := range e.Suppliers {
suppliers[i] = supplierDTO.ToSupplierBaseDTO(s)
}
flags := make([]string, len(e.Flags)) flags := make([]string, len(e.Flags))
for i, f := range e.Flags { for i, f := range e.Flags {
flags[i] = f.Name flags[i] = f.Name
@@ -81,11 +74,11 @@ func ToNonstockListDTO(e entity.Nonstock) NonstockListDTO {
return NonstockListDTO{ return NonstockListDTO{
Id: e.Id, Id: e.Id,
Name: e.Name, Name: e.Name,
Flags: flags,
Uom: uomRef, Uom: uomRef,
CreatedAt: e.CreatedAt, CreatedAt: e.CreatedAt,
UpdatedAt: e.UpdatedAt, UpdatedAt: e.UpdatedAt,
CreatedUser: createdUser, CreatedUser: createdUser,
Suppliers: suppliers,
} }
} }
@@ -98,13 +91,7 @@ func ToNonstockListDTOs(e []entity.Nonstock) []NonstockListDTO {
} }
func ToNonstockDetailDTO(e entity.Nonstock) NonstockDetailDTO { func ToNonstockDetailDTO(e entity.Nonstock) NonstockDetailDTO {
flags := make([]string, len(e.Flags))
for i, f := range e.Flags {
flags[i] = f.Name
}
return NonstockDetailDTO{ return NonstockDetailDTO{
NonstockListDTO: ToNonstockListDTO(e), NonstockListDTO: ToNonstockListDTO(e),
Flags: flags,
} }
} }
@@ -57,7 +57,7 @@ func (r *NonstockRepositoryImpl) SyncSuppliersDiff(ctx context.Context, tx *gorm
existingMap := make(map[uint]struct{}, len(existing)) existingMap := make(map[uint]struct{}, len(existing))
for _, rel := range existing { for _, rel := range existing {
existingMap[rel.SupplierID] = struct{}{} existingMap[rel.SupplierId] = struct{}{}
} }
incomingMap := make(map[uint]struct{}, len(supplierIDs)) incomingMap := make(map[uint]struct{}, len(supplierIDs))
@@ -66,16 +66,16 @@ func (r *NonstockRepositoryImpl) SyncSuppliersDiff(ctx context.Context, tx *gorm
if _, exists := existingMap[id]; exists { if _, exists := existingMap[id]; exists {
continue continue
} }
record := entity.NonstockSupplier{NonstockID: nonstockID, SupplierID: id} record := entity.NonstockSupplier{NonstockId: nonstockID, SupplierId: id}
if err := db.WithContext(ctx).Create(&record).Error; err != nil { if err := db.WithContext(ctx).Create(&record).Error; err != nil {
return err return err
} }
} }
for _, rel := range existing { for _, rel := range existing {
if _, keep := incomingMap[rel.SupplierID]; !keep { if _, keep := incomingMap[rel.SupplierId]; !keep {
if err := db.WithContext(ctx). if err := db.WithContext(ctx).
Where("nonstock_id = ? AND supplier_id = ?", nonstockID, rel.SupplierID). Where("nonstock_id = ? AND supplier_id = ?", nonstockID, rel.SupplierId).
Delete(&entity.NonstockSupplier{}). Delete(&entity.NonstockSupplier{}).
Error; err != nil { Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) { if errors.Is(err, gorm.ErrRecordNotFound) {
@@ -44,7 +44,8 @@ func (s nonstockService) withRelations(db *gorm.DB) *gorm.DB {
Preload("CreatedUser"). Preload("CreatedUser").
Preload("Uom"). Preload("Uom").
Preload("Flags"). Preload("Flags").
Preload("Suppliers", func(db *gorm.DB) *gorm.DB { Preload("NonstockSuppliers").
Preload("NonstockSuppliers.Supplier", func(db *gorm.DB) *gorm.DB {
return db.Order("suppliers.name ASC") return db.Order("suppliers.name ASC")
}) })
} }
@@ -9,17 +9,17 @@ import (
// === DTO Structs === // === DTO Structs ===
type ProductCategoryBaseDTO struct { type ProductCategoryRelationDTO struct {
Id uint `json:"id"` Id uint `json:"id"`
Name string `json:"name"` Name string `json:"name"`
Code string `json:"code"` Code string `json:"code"`
} }
type ProductCategoryListDTO struct { type ProductCategoryListDTO struct {
ProductCategoryBaseDTO ProductCategoryRelationDTO
CreatedUser *userDTO.UserBaseDTO `json:"created_user"` CreatedUser *userDTO.UserRelationDTO `json:"created_user"`
CreatedAt time.Time `json:"created_at"` CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"` UpdatedAt time.Time `json:"updated_at"`
} }
type ProductCategoryDetailDTO struct { type ProductCategoryDetailDTO struct {
@@ -28,8 +28,8 @@ type ProductCategoryDetailDTO struct {
// === Mapper Functions === // === Mapper Functions ===
func ToProductCategoryBaseDTO(e entity.ProductCategory) ProductCategoryBaseDTO { func ToProductCategoryRelationDTO(e entity.ProductCategory) ProductCategoryRelationDTO {
return ProductCategoryBaseDTO{ return ProductCategoryRelationDTO{
Id: e.Id, Id: e.Id,
Name: e.Name, Name: e.Name,
Code: e.Code, Code: e.Code,
@@ -37,17 +37,17 @@ func ToProductCategoryBaseDTO(e entity.ProductCategory) ProductCategoryBaseDTO {
} }
func ToProductCategoryListDTO(e entity.ProductCategory) ProductCategoryListDTO { func ToProductCategoryListDTO(e entity.ProductCategory) ProductCategoryListDTO {
var createdUser *userDTO.UserBaseDTO var createdUser *userDTO.UserRelationDTO
if e.CreatedUser.Id != 0 { if e.CreatedUser.Id != 0 {
mapped := userDTO.ToUserBaseDTO(e.CreatedUser) mapped := userDTO.ToUserRelationDTO(e.CreatedUser)
createdUser = &mapped createdUser = &mapped
} }
return ProductCategoryListDTO{ return ProductCategoryListDTO{
ProductCategoryBaseDTO: ToProductCategoryBaseDTO(e), ProductCategoryRelationDTO: ToProductCategoryRelationDTO(e),
CreatedAt: e.CreatedAt, CreatedAt: e.CreatedAt,
UpdatedAt: e.UpdatedAt, UpdatedAt: e.UpdatedAt,
CreatedUser: createdUser, CreatedUser: createdUser,
} }
} }
@@ -5,55 +5,57 @@ import (
entity "gitlab.com/mbugroup/lti-api.git/internal/entities" entity "gitlab.com/mbugroup/lti-api.git/internal/entities"
productCategoryDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/product-categories/dto" productCategoryDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/product-categories/dto"
supplierDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/suppliers/dto"
uomDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/uoms/dto" uomDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/uoms/dto"
userDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/users/dto" userDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/users/dto"
) )
// === DTO Structs === // === DTO Structs ===
type ProductBaseDTO struct { type ProductRelationDTO struct {
Id uint `json:"id"` Id uint `json:"id"`
Name string `json:"name"` Name string `json:"name"`
Uom *uomDTO.UomBaseDTO `json:"uom,omitempty"` ProductPrice float64 `gorm:"type:numeric(15,3);not null"`
Flags []string `json:"flags"` SellingPrice *float64 `gorm:"type:numeric(15,3)"`
Uom *uomDTO.UomRelationDTO `json:"uom,omitempty"`
Flags []string `json:"flags"`
} }
type ProductListDTO struct { type ProductListDTO struct {
ProductBaseDTO Id uint `json:"id"`
Brand string `json:"brand"` Name string `json:"name"`
Sku *string `json:"sku,omitempty"` Brand string `json:"brand"`
ProductPrice float64 `json:"product_price"` Sku *string `json:"sku,omitempty"`
SellingPrice *float64 `json:"selling_price,omitempty"` ProductPrice float64 `json:"product_price"`
Tax *float64 `json:"tax,omitempty"` SellingPrice *float64 `json:"selling_price,omitempty"`
ExpiryPeriod *int `json:"expiry_period,omitempty"` Tax *float64 `json:"tax,omitempty"`
ProductCategory *productCategoryDTO.ProductCategoryBaseDTO `json:"product_category,omitempty"` ExpiryPeriod *int `json:"expiry_period,omitempty"`
Suppliers []supplierDTO.SupplierBaseDTO `json:"suppliers"` Flags []string `json:"flags"`
CreatedUser *userDTO.UserBaseDTO `json:"created_user"` Uom *uomDTO.UomRelationDTO `json:"uom,omitempty"`
CreatedAt time.Time `json:"created_at"` ProductCategory *productCategoryDTO.ProductCategoryRelationDTO `json:"product_category,omitempty"`
UpdatedAt time.Time `json:"updated_at"` CreatedUser *userDTO.UserRelationDTO `json:"created_user"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
} }
type ProductDetailDTO struct { type ProductDetailDTO struct {
ProductListDTO ProductListDTO
Flags []string `json:"flags"`
} }
// === Mapper Functions === // === Mapper Functions ===
func ToProductBaseDTO(e entity.Product) ProductBaseDTO { func ToProductRelationDTO(e entity.Product) ProductRelationDTO {
flags := make([]string, len(e.Flags)) flags := make([]string, len(e.Flags))
for i, f := range e.Flags { for i, f := range e.Flags {
flags[i] = f.Name flags[i] = f.Name
} }
var uomRef *uomDTO.UomBaseDTO var uomRef *uomDTO.UomRelationDTO
if e.Uom.Id != 0 { if e.Uom.Id != 0 {
mapped := uomDTO.ToUomBaseDTO(e.Uom) mapped := uomDTO.ToUomRelationDTO(e.Uom)
uomRef = &mapped uomRef = &mapped
} }
return ProductBaseDTO{ return ProductRelationDTO{
Id: e.Id, Id: e.Id,
Name: e.Name, Name: e.Name,
Flags: flags, Flags: flags,
@@ -62,36 +64,44 @@ func ToProductBaseDTO(e entity.Product) ProductBaseDTO {
} }
func ToProductListDTO(e entity.Product) ProductListDTO { func ToProductListDTO(e entity.Product) ProductListDTO {
var createdUser *userDTO.UserBaseDTO var createdUser *userDTO.UserRelationDTO
if e.CreatedUser.Id != 0 { if e.CreatedUser.Id != 0 {
mapped := userDTO.ToUserBaseDTO(e.CreatedUser) mapped := userDTO.ToUserRelationDTO(e.CreatedUser)
createdUser = &mapped createdUser = &mapped
} }
var categoryRef *productCategoryDTO.ProductCategoryBaseDTO var categoryRef *productCategoryDTO.ProductCategoryRelationDTO
if e.ProductCategory.Id != 0 { if e.ProductCategory.Id != 0 {
mapped := productCategoryDTO.ToProductCategoryBaseDTO(e.ProductCategory) mapped := productCategoryDTO.ToProductCategoryRelationDTO(e.ProductCategory)
categoryRef = &mapped categoryRef = &mapped
} }
suppliers := make([]supplierDTO.SupplierBaseDTO, len(e.Suppliers)) flags := make([]string, len(e.Flags))
for i, s := range e.Suppliers { for i, f := range e.Flags {
suppliers[i] = supplierDTO.ToSupplierBaseDTO(s) flags[i] = f.Name
}
var uomRef *uomDTO.UomRelationDTO
if e.Uom.Id != 0 {
mapped := uomDTO.ToUomRelationDTO(e.Uom)
uomRef = &mapped
} }
return ProductListDTO{ return ProductListDTO{
Id: e.Id,
Name: e.Name,
Flags: flags,
Uom: uomRef,
Brand: e.Brand, Brand: e.Brand,
Sku: e.Sku, Sku: e.Sku,
ProductPrice: e.ProductPrice, ProductPrice: e.ProductPrice,
SellingPrice: e.SellingPrice, SellingPrice: e.SellingPrice,
Tax: e.Tax, Tax: e.Tax,
ExpiryPeriod: e.ExpiryPeriod, ExpiryPeriod: e.ExpiryPeriod,
ProductBaseDTO: ToProductBaseDTO(e),
CreatedAt: e.CreatedAt, CreatedAt: e.CreatedAt,
UpdatedAt: e.UpdatedAt, UpdatedAt: e.UpdatedAt,
CreatedUser: createdUser, CreatedUser: createdUser,
ProductCategory: categoryRef, ProductCategory: categoryRef,
Suppliers: suppliers,
} }
} }
@@ -104,13 +114,7 @@ func ToProductListDTOs(e []entity.Product) []ProductListDTO {
} }
func ToProductDetailDTO(e entity.Product) ProductDetailDTO { func ToProductDetailDTO(e entity.Product) ProductDetailDTO {
flags := make([]string, len(e.Flags))
for i, f := range e.Flags {
flags[i] = f.Name
}
return ProductDetailDTO{ return ProductDetailDTO{
ProductListDTO: ToProductListDTO(e), ProductListDTO: ToProductListDTO(e),
Flags: flags,
} }
} }
@@ -102,13 +102,13 @@ func (r *ProductRepositoryImpl) IsLinkedToSupplier(ctx context.Context, productI
return count > 0, nil return count > 0, nil
} }
func (r *ProductRepositoryImpl) SyncSuppliersDiff(ctx context.Context, tx *gorm.DB, productID uint, supplierIDs []uint) error { func (r *ProductRepositoryImpl) SyncSuppliersDiff(ctx context.Context, tx *gorm.DB, productID uint, supplierIds []uint) error {
db := tx db := tx
if db == nil { if db == nil {
db = r.DB() db = r.DB()
} }
if supplierIDs == nil { if supplierIds == nil {
return db.WithContext(ctx). return db.WithContext(ctx).
Where("product_id = ?", productID). Where("product_id = ?", productID).
Delete(&entity.ProductSupplier{}). Delete(&entity.ProductSupplier{}).
@@ -125,25 +125,25 @@ func (r *ProductRepositoryImpl) SyncSuppliersDiff(ctx context.Context, tx *gorm.
existingMap := make(map[uint]struct{}, len(existing)) existingMap := make(map[uint]struct{}, len(existing))
for _, rel := range existing { for _, rel := range existing {
existingMap[rel.SupplierID] = struct{}{} existingMap[rel.SupplierId] = struct{}{}
} }
incomingMap := make(map[uint]struct{}, len(supplierIDs)) incomingMap := make(map[uint]struct{}, len(supplierIds))
for _, id := range supplierIDs { for _, id := range supplierIds {
incomingMap[id] = struct{}{} incomingMap[id] = struct{}{}
if _, exists := existingMap[id]; exists { if _, exists := existingMap[id]; exists {
continue continue
} }
record := entity.ProductSupplier{ProductID: productID, SupplierID: id} record := entity.ProductSupplier{ProductId: productID, SupplierId: id}
if err := db.WithContext(ctx).Create(&record).Error; err != nil { if err := db.WithContext(ctx).Create(&record).Error; err != nil {
return err return err
} }
} }
for _, rel := range existing { for _, rel := range existing {
if _, keep := incomingMap[rel.SupplierID]; !keep { if _, keep := incomingMap[rel.SupplierId]; !keep {
if err := db.WithContext(ctx). if err := db.WithContext(ctx).
Where("product_id = ? AND supplier_id = ?", productID, rel.SupplierID). Where("product_id = ? AND supplier_id = ?", productID, rel.SupplierId).
Delete(&entity.ProductSupplier{}). Delete(&entity.ProductSupplier{}).
Error; err != nil { Error; err != nil {
return err return err
@@ -55,7 +55,8 @@ func (s productService) withRelations(db *gorm.DB) *gorm.DB {
Preload("Uom"). Preload("Uom").
Preload("ProductCategory"). Preload("ProductCategory").
Preload("Flags"). Preload("Flags").
Preload("Suppliers", func(db *gorm.DB) *gorm.DB { Preload("ProductSuppliers").
Preload("ProductSuppliers.Supplier", func(db *gorm.DB) *gorm.DB {
return db.Order("suppliers.name ASC") return db.Order("suppliers.name ASC")
}) })
} }
@@ -24,9 +24,10 @@ func NewSupplierController(supplierService service.SupplierService) *SupplierCon
func (u *SupplierController) GetAll(c *fiber.Ctx) error { func (u *SupplierController) GetAll(c *fiber.Ctx) error {
query := &validation.Query{ query := &validation.Query{
Page: c.QueryInt("page", 1), Page: c.QueryInt("page", 1),
Limit: c.QueryInt("limit", 10), Limit: c.QueryInt("limit", 10),
Search: c.Query("search", ""), Search: c.Query("search", ""),
Category: c.Query("category", ""),
} }
if query.Page < 1 || query.Limit < 1 { if query.Page < 1 || query.Limit < 1 {
@@ -71,7 +72,7 @@ func (u *SupplierController) GetOne(c *fiber.Ctx) error {
Code: fiber.StatusOK, Code: fiber.StatusOK,
Status: "success", Status: "success",
Message: "Get supplier successfully", Message: "Get supplier successfully",
Data: dto.ToSupplierListDTO(*result), Data: dto.ToSupplierDetailDTO(*result),
}) })
} }
@@ -9,7 +9,7 @@ import (
// === DTO Structs === // === DTO Structs ===
type SupplierBaseDTO struct { type SupplierRelationDTO struct {
Id uint `json:"id"` Id uint `json:"id"`
Name string `json:"name"` Name string `json:"name"`
Alias string `json:"alias"` Alias string `json:"alias"`
@@ -17,30 +17,32 @@ type SupplierBaseDTO struct {
} }
type SupplierListDTO struct { type SupplierListDTO struct {
SupplierBaseDTO SupplierRelationDTO
Pic string `json:"pic"` Pic string `json:"pic"`
Type string `json:"type"` Type string `json:"type"`
Hatchery *string `json:"hatchery,omitempty"` Hatchery *string `json:"hatchery,omitempty"`
Phone string `json:"phone"` Phone string `json:"phone"`
Email string `json:"email"` Email string `json:"email"`
Address string `json:"address"` Address string `json:"address"`
Npwp *string `json:"npwp,omitempty"` Npwp *string `json:"npwp,omitempty"`
AccountNumber *string `json:"account_number,omitempty"` AccountNumber *string `json:"account_number,omitempty"`
Balance float64 `json:"balance"` Balance float64 `json:"balance"`
DueDate int `json:"due_date"` DueDate int `json:"due_date"`
CreatedUser *userDTO.UserBaseDTO `json:"created_user"` CreatedUser *userDTO.UserRelationDTO `json:"created_user"`
CreatedAt time.Time `json:"created_at"` CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"` UpdatedAt time.Time `json:"updated_at"`
} }
type SupplierDetailDTO struct { type SupplierDetailDTO struct {
SupplierListDTO SupplierListDTO
Products []SupplierProductDTO `json:"products"`
Nonstocks []SupplierNonstockDTO `json:"nonstocks"`
} }
// === Mapper Functions === // === Mapper Functions ===
func ToSupplierBaseDTO(e entity.Supplier) SupplierBaseDTO { func ToSupplierRelationDTO(e entity.Supplier) SupplierRelationDTO {
return SupplierBaseDTO{ return SupplierRelationDTO{
Id: e.Id, Id: e.Id,
Name: e.Name, Name: e.Name,
Alias: e.Alias, Alias: e.Alias,
@@ -49,27 +51,27 @@ func ToSupplierBaseDTO(e entity.Supplier) SupplierBaseDTO {
} }
func ToSupplierListDTO(e entity.Supplier) SupplierListDTO { func ToSupplierListDTO(e entity.Supplier) SupplierListDTO {
var createdUser *userDTO.UserBaseDTO var createdUser *userDTO.UserRelationDTO
if e.CreatedUser.Id != 0 { if e.CreatedUser.Id != 0 {
mapped := userDTO.ToUserBaseDTO(e.CreatedUser) mapped := userDTO.ToUserRelationDTO(e.CreatedUser)
createdUser = &mapped createdUser = &mapped
} }
return SupplierListDTO{ return SupplierListDTO{
Pic: e.Pic, Pic: e.Pic,
Type: e.Type, Type: e.Type,
Hatchery: e.Hatchery, Hatchery: e.Hatchery,
Phone: e.Phone, Phone: e.Phone,
Email: e.Email, Email: e.Email,
Address: e.Address, Address: e.Address,
Npwp: e.Npwp, Npwp: e.Npwp,
AccountNumber: e.AccountNumber, AccountNumber: e.AccountNumber,
Balance: e.Balance, Balance: e.Balance,
DueDate: e.DueDate, DueDate: e.DueDate,
SupplierBaseDTO: ToSupplierBaseDTO(e), SupplierRelationDTO: ToSupplierRelationDTO(e),
CreatedAt: e.CreatedAt, CreatedAt: e.CreatedAt,
UpdatedAt: e.UpdatedAt, UpdatedAt: e.UpdatedAt,
CreatedUser: createdUser, CreatedUser: createdUser,
} }
} }
@@ -84,5 +86,7 @@ func ToSupplierListDTOs(e []entity.Supplier) []SupplierListDTO {
func ToSupplierDetailDTO(e entity.Supplier) SupplierDetailDTO { func ToSupplierDetailDTO(e entity.Supplier) SupplierDetailDTO {
return SupplierDetailDTO{ return SupplierDetailDTO{
SupplierListDTO: ToSupplierListDTO(e), SupplierListDTO: ToSupplierListDTO(e),
Products: toSupplierProductDTOs(e.ProductSuppliers),
Nonstocks: toSupplierNonstockDTOs(e.NonstockSuppliers),
} }
} }
@@ -0,0 +1,50 @@
package dto
import (
entity "gitlab.com/mbugroup/lti-api.git/internal/entities"
uomDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/uoms/dto"
)
// === DTO Structs ===
type SupplierNonstockDTO struct {
Id uint `json:"id"`
Name string `json:"name"`
Uom *uomDTO.UomRelationDTO `json:"uom,omitempty"`
Flags []string `json:"flags"`
}
// === Mapper Functions ===
func toSupplierNonstockDTOs(relations []entity.NonstockSupplier) []SupplierNonstockDTO {
if len(relations) == 0 {
return nil
}
result := make([]SupplierNonstockDTO, 0, len(relations))
for _, relation := range relations {
Nonstock := relation.Nonstock
if Nonstock.Id == 0 {
continue
}
flags := make([]string, len(Nonstock.Flags))
for i, f := range Nonstock.Flags {
flags[i] = f.Name
}
var uomRef *uomDTO.UomRelationDTO
if Nonstock.Uom.Id != 0 {
mapped := uomDTO.ToUomRelationDTO(Nonstock.Uom)
uomRef = &mapped
}
result = append(result, SupplierNonstockDTO{
Id: Nonstock.Id,
Name: Nonstock.Name,
Uom: uomRef,
Flags: flags,
})
}
return result
}
@@ -0,0 +1,54 @@
package dto
import (
entity "gitlab.com/mbugroup/lti-api.git/internal/entities"
uomDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/uoms/dto"
)
// === DTO Structs ===
type SupplierProductDTO struct {
Id uint `json:"id"`
Name string `json:"name"`
ProductPrice float64 `gorm:"type:numeric(15,3);not null"`
SellingPrice *float64 `gorm:"type:numeric(15,3)"`
Uom *uomDTO.UomRelationDTO `json:"uom,omitempty"`
Flags []string `json:"flags"`
}
// === Mapper Functions ===
func toSupplierProductDTOs(relations []entity.ProductSupplier) []SupplierProductDTO {
if len(relations) == 0 {
return nil
}
result := make([]SupplierProductDTO, 0, len(relations))
for _, relation := range relations {
product := relation.Product
if product.Id == 0 {
continue
}
flags := make([]string, len(product.Flags))
for i, f := range product.Flags {
flags[i] = f.Name
}
var uomRef *uomDTO.UomRelationDTO
if product.Uom.Id != 0 {
mapped := uomDTO.ToUomRelationDTO(product.Uom)
uomRef = &mapped
}
result = append(result, SupplierProductDTO{
Id: product.Id,
Name: product.Name,
ProductPrice: product.ProductPrice,
SellingPrice: product.SellingPrice,
Uom: uomRef,
Flags: flags,
})
}
return result
}
+2 -2
View File
@@ -1,7 +1,7 @@
package suppliers package suppliers
import ( import (
m "gitlab.com/mbugroup/lti-api.git/internal/middleware" // m "gitlab.com/mbugroup/lti-api.git/internal/middleware"
controller "gitlab.com/mbugroup/lti-api.git/internal/modules/master/suppliers/controllers" controller "gitlab.com/mbugroup/lti-api.git/internal/modules/master/suppliers/controllers"
supplier "gitlab.com/mbugroup/lti-api.git/internal/modules/master/suppliers/services" supplier "gitlab.com/mbugroup/lti-api.git/internal/modules/master/suppliers/services"
user "gitlab.com/mbugroup/lti-api.git/internal/modules/users/services" user "gitlab.com/mbugroup/lti-api.git/internal/modules/users/services"
@@ -13,7 +13,7 @@ func SupplierRoutes(v1 fiber.Router, u user.UserService, s supplier.SupplierServ
ctrl := controller.NewSupplierController(s) ctrl := controller.NewSupplierController(s)
route := v1.Group("/suppliers") route := v1.Group("/suppliers")
route.Use(m.Auth(u)) // route.Use(m.Auth(u))
route.Get("/", ctrl.GetAll) route.Get("/", ctrl.GetAll)
route.Post("/", ctrl.CreateOne) route.Post("/", ctrl.CreateOne)
@@ -39,7 +39,12 @@ func NewSupplierService(repo repository.SupplierRepository, validate *validator.
} }
func (s supplierService) withRelations(db *gorm.DB) *gorm.DB { func (s supplierService) withRelations(db *gorm.DB) *gorm.DB {
return db.Preload("CreatedUser") return db.
Preload("CreatedUser").
Preload("ProductSuppliers.Product.Uom").
Preload("ProductSuppliers.Product.Flags").
Preload("NonstockSuppliers.Nonstock.Uom").
Preload("NonstockSuppliers.Nonstock.Flags")
} }
func (s supplierService) GetAll(c *fiber.Ctx, params *validation.Query) ([]entity.Supplier, int64, error) { func (s supplierService) GetAll(c *fiber.Ctx, params *validation.Query) ([]entity.Supplier, int64, error) {
@@ -47,6 +52,14 @@ func (s supplierService) GetAll(c *fiber.Ctx, params *validation.Query) ([]entit
return nil, 0, err return nil, 0, err
} }
if params.Category != "" {
category := strings.ToUpper(params.Category)
if category != "BOP" && category != "SAPRONAK" {
return nil, 0, fiber.NewError(fiber.StatusBadRequest, "Invalid supplier category")
}
params.Category = category
}
offset := (params.Page - 1) * params.Limit offset := (params.Page - 1) * params.Limit
suppliers, total, err := s.Repository.GetAll(c.Context(), offset, params.Limit, func(db *gorm.DB) *gorm.DB { suppliers, total, err := s.Repository.GetAll(c.Context(), offset, params.Limit, func(db *gorm.DB) *gorm.DB {
@@ -54,6 +67,11 @@ func (s supplierService) GetAll(c *fiber.Ctx, params *validation.Query) ([]entit
if params.Search != "" { if params.Search != "" {
return db.Where("name LIKE ?", "%"+params.Search+"%") return db.Where("name LIKE ?", "%"+params.Search+"%")
} }
if params.Category != "" {
db = db.Where("category LIKE ?", "%"+params.Category+"%")
}
return db.Order("created_at DESC").Order("updated_at DESC") return db.Order("created_at DESC").Order("updated_at DESC")
}) })
@@ -31,7 +31,8 @@ type Update struct {
} }
type Query struct { type Query struct {
Page int `query:"page" validate:"omitempty,number,min=1"` Page int `query:"page" validate:"omitempty,number,min=1"`
Limit int `query:"limit" validate:"omitempty,number,min=1,max=100"` Limit int `query:"limit" validate:"omitempty,number,min=1,max=100"`
Search string `query:"search" validate:"omitempty,max=50"` Search string `query:"search" validate:"omitempty,max=50"`
Category string `query:"category" validate:"omitempty,max=50"`
} }
+10 -10
View File
@@ -9,17 +9,17 @@ import (
// === DTO Structs === // === DTO Structs ===
type UomBaseDTO struct { type UomRelationDTO struct {
Id uint `json:"id"` Id uint `json:"id"`
Name string `json:"name"` Name string `json:"name"`
} }
type UomListDTO struct { type UomListDTO struct {
Id uint `json:"id"` Id uint `json:"id"`
Name string `json:"name"` Name string `json:"name"`
CreatedUser *userDTO.UserBaseDTO `json:"created_user"` CreatedUser *userDTO.UserRelationDTO `json:"created_user"`
CreatedAt time.Time `json:"created_at"` CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"` UpdatedAt time.Time `json:"updated_at"`
} }
type UomDetailDTO struct { type UomDetailDTO struct {
@@ -28,17 +28,17 @@ type UomDetailDTO struct {
// === Mapper Functions === // === Mapper Functions ===
func ToUomBaseDTO(e entity.Uom) UomBaseDTO { func ToUomRelationDTO(e entity.Uom) UomRelationDTO {
return UomBaseDTO{ return UomRelationDTO{
Id: e.Id, Id: e.Id,
Name: e.Name, Name: e.Name,
} }
} }
func ToUomListDTO(e entity.Uom) UomListDTO { func ToUomListDTO(e entity.Uom) UomListDTO {
var createdUser *userDTO.UserBaseDTO var createdUser *userDTO.UserRelationDTO
if e.CreatedUser.Id != 0 { if e.CreatedUser.Id != 0 {
mapped := userDTO.ToUserBaseDTO(e.CreatedUser) mapped := userDTO.ToUserRelationDTO(e.CreatedUser)
createdUser = &mapped createdUser = &mapped
} }
@@ -12,25 +12,25 @@ import (
// === DTO Structs === // === DTO Structs ===
type WarehouseBaseDTO struct { type WarehouseRelationDTO struct {
Id uint `json:"id"` Id uint `json:"id"`
Name string `json:"name"` Name string `json:"name"`
Type string `json:"type"` Type string `json:"type"`
Area *areaDTO.AreaBaseDTO `json:"area,omitempty"` Area *areaDTO.AreaRelationDTO `json:"area,omitempty"`
Location *locationDTO.LocationBaseDTO `json:"location,omitempty"` Location *locationDTO.LocationRelationDTO `json:"location,omitempty"`
Kandang *kandangDTO.KandangBaseDTO `json:"kandang,omitempty"` Kandang *kandangDTO.KandangRelationDTO `json:"kandang,omitempty"`
} }
type WarehouseListDTO struct { type WarehouseListDTO struct {
Id uint `json:"id"` Id uint `json:"id"`
Name string `json:"name"` Name string `json:"name"`
Type string `json:"type"` Type string `json:"type"`
Area *areaDTO.AreaBaseDTO `json:"area"` Area *areaDTO.AreaRelationDTO `json:"area"`
Location *locationDTO.LocationBaseDTO `json:"location"` Location *locationDTO.LocationRelationDTO `json:"location"`
Kandang *kandangDTO.KandangBaseDTO `json:"kandang"` Kandang *kandangDTO.KandangRelationDTO `json:"kandang"`
CreatedUser *userDTO.UserBaseDTO `json:"created_user"` CreatedUser *userDTO.UserRelationDTO `json:"created_user"`
CreatedAt time.Time `json:"created_at"` CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"` UpdatedAt time.Time `json:"updated_at"`
} }
type WarehouseDetailDTO struct { type WarehouseDetailDTO struct {
@@ -39,26 +39,26 @@ type WarehouseDetailDTO struct {
// === Mapper Functions === // === Mapper Functions ===
func ToWarehouseBaseDTO(e entity.Warehouse) WarehouseBaseDTO { func ToWarehouseRelationDTO(e entity.Warehouse) WarehouseRelationDTO {
var area *areaDTO.AreaBaseDTO var area *areaDTO.AreaRelationDTO
if e.Area.Id != 0 { if e.Area.Id != 0 {
mapped := areaDTO.ToAreaBaseDTO(e.Area) mapped := areaDTO.ToAreaRelationDTO(e.Area)
area = &mapped area = &mapped
} }
var location *locationDTO.LocationBaseDTO var location *locationDTO.LocationRelationDTO
if e.Location != nil && e.Location.Id != 0 { if e.Location != nil && e.Location.Id != 0 {
mapped := locationDTO.ToLocationBaseDTO(*e.Location) mapped := locationDTO.ToLocationRelationDTO(*e.Location)
location = &mapped location = &mapped
} }
var kandang *kandangDTO.KandangBaseDTO var kandang *kandangDTO.KandangRelationDTO
if e.Kandang != nil && e.Kandang.Id != 0 { if e.Kandang != nil && e.Kandang.Id != 0 {
mapped := kandangDTO.ToKandangBaseDTO(*e.Kandang) mapped := kandangDTO.ToKandangRelationDTO(*e.Kandang)
kandang = &mapped kandang = &mapped
} }
return WarehouseBaseDTO{ return WarehouseRelationDTO{
Id: e.Id, Id: e.Id,
Name: e.Name, Name: e.Name,
Type: e.Type, Type: e.Type,
@@ -69,27 +69,27 @@ func ToWarehouseBaseDTO(e entity.Warehouse) WarehouseBaseDTO {
} }
func ToWarehouseListDTO(e entity.Warehouse) WarehouseListDTO { func ToWarehouseListDTO(e entity.Warehouse) WarehouseListDTO {
var createdUser *userDTO.UserBaseDTO var createdUser *userDTO.UserRelationDTO
if e.CreatedUser.Id != 0 { if e.CreatedUser.Id != 0 {
mapped := userDTO.ToUserBaseDTO(e.CreatedUser) mapped := userDTO.ToUserRelationDTO(e.CreatedUser)
createdUser = &mapped createdUser = &mapped
} }
var area *areaDTO.AreaBaseDTO var area *areaDTO.AreaRelationDTO
if e.Area.Id != 0 { if e.Area.Id != 0 {
mapped := areaDTO.ToAreaBaseDTO(e.Area) mapped := areaDTO.ToAreaRelationDTO(e.Area)
area = &mapped area = &mapped
} }
var location *locationDTO.LocationBaseDTO var location *locationDTO.LocationRelationDTO
if e.Location != nil && e.Location.Id != 0 { if e.Location != nil && e.Location.Id != 0 {
mapped := locationDTO.ToLocationBaseDTO(*e.Location) mapped := locationDTO.ToLocationRelationDTO(*e.Location)
location = &mapped location = &mapped
} }
var kandang *kandangDTO.KandangBaseDTO var kandang *kandangDTO.KandangRelationDTO
if e.Kandang != nil && e.Kandang.Id != 0 { if e.Kandang != nil && e.Kandang.Id != 0 {
mapped := kandangDTO.ToKandangBaseDTO(*e.Kandang) mapped := kandangDTO.ToKandangRelationDTO(*e.Kandang)
kandang = &mapped kandang = &mapped
} }
@@ -4,26 +4,26 @@ import (
"time" "time"
entity "gitlab.com/mbugroup/lti-api.git/internal/entities" entity "gitlab.com/mbugroup/lti-api.git/internal/entities"
areaBaseDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/areas/dto" areaRelationDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/areas/dto"
fcrBaseDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/fcrs/dto" fcrRelationDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/fcrs/dto"
flockBaseDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/flocks/dto" flockRelationDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/flocks/dto"
kandangBaseDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/kandangs/dto" kandangRelationDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/kandangs/dto"
locationBaseDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/locations/dto" locationRelationDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/locations/dto"
productDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/products/dto" productDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/products/dto"
warehouseDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/warehouses/dto" warehouseDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/warehouses/dto"
pfutils "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project_flocks/utils" pfutils "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project_flocks/utils"
userBaseDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/users/dto" userRelationDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/users/dto"
) )
// === DTO Structs (ordered) === // === DTO Structs (ordered) ===
type ProductWarehouseDTO struct { type ProductWarehouseDTO struct {
Id uint `json:"id"` Id uint `json:"id"`
Product *productDTO.ProductBaseDTO `json:"product,omitempty"` Product *productDTO.ProductRelationDTO `json:"product,omitempty"`
Warehouse *warehouseDTO.WarehouseBaseDTO `json:"warehouse,omitempty"` Warehouse *warehouseDTO.WarehouseRelationDTO `json:"warehouse,omitempty"`
} }
type ChickinBaseDTO struct { type ChickinRelationDTO struct {
Id uint `json:"id"` Id uint `json:"id"`
ProjectFlockKandangId uint `json:"project_flock_kandang_id"` ProjectFlockKandangId uint `json:"project_flock_kandang_id"`
ChickInDate time.Time `json:"chick_in_date"` ChickInDate time.Time `json:"chick_in_date"`
@@ -35,19 +35,19 @@ type ChickinBaseDTO struct {
} }
type ProjectFlockDTO struct { type ProjectFlockDTO struct {
Id uint `json:"id"` Id uint `json:"id"`
Period int `json:"period"` Period int `json:"period"`
Category string `json:"category"` Category string `json:"category"`
Flock *flockBaseDTO.FlockBaseDTO `json:"flock"` Flock *flockRelationDTO.FlockRelationDTO `json:"flock"`
Area *areaBaseDTO.AreaBaseDTO `json:"area"` Area *areaRelationDTO.AreaRelationDTO `json:"area"`
Fcr *fcrBaseDTO.FcrBaseDTO `json:"fcr"` Fcr *fcrRelationDTO.FcrRelationDTO `json:"fcr"`
Location *locationBaseDTO.LocationBaseDTO `json:"location"` Location *locationRelationDTO.LocationRelationDTO `json:"location"`
} }
type ProjectFlockKandangDTO struct { type ProjectFlockKandangDTO struct {
Id uint `json:"id"` Id uint `json:"id"`
ProjectFlock *ProjectFlockDTO `json:"project_flock"` ProjectFlock *ProjectFlockDTO `json:"project_flock"`
Kandang *kandangBaseDTO.KandangBaseDTO `json:"kandang"` Kandang *kandangRelationDTO.KandangRelationDTO `json:"kandang"`
} }
// gunakan base DTO dari package users // gunakan base DTO dari package users
@@ -64,71 +64,71 @@ type ChickinSimpleDTO struct {
} }
type ChickinListDTO struct { type ChickinListDTO struct {
ChickinBaseDTO ChickinRelationDTO
CreatedUser *userBaseDTO.UserBaseDTO `json:"created_user"` CreatedUser *userRelationDTO.UserRelationDTO `json:"created_user"`
CreatedAt time.Time `json:"created_at"` CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"` UpdatedAt time.Time `json:"updated_at"`
} }
type ChickinDetailDTO struct { type ChickinDetailDTO struct {
Id uint `json:"id"` Id uint `json:"id"`
ProjectFlockKandangId uint `json:"project_flock_kandang_id"` ProjectFlockKandangId uint `json:"project_flock_kandang_id"`
ChickInDate time.Time `json:"chick_in_date"` ChickInDate time.Time `json:"chick_in_date"`
ProductWarehouseId uint `json:"product_warehouse_id"` ProductWarehouseId uint `json:"product_warehouse_id"`
UsageQty float64 `json:"usage_qty"` UsageQty float64 `json:"usage_qty"`
PendingUsageQty float64 `json:"pending_usage_qty"` PendingUsageQty float64 `json:"pending_usage_qty"`
Notes string `json:"notes"` Notes string `json:"notes"`
CreatedBy uint `json:"created_by"` CreatedBy uint `json:"created_by"`
CreatedUser *userBaseDTO.UserBaseDTO `json:"created_user"` CreatedUser *userRelationDTO.UserRelationDTO `json:"created_user"`
CreatedAt time.Time `json:"created_at"` CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"` UpdatedAt time.Time `json:"updated_at"`
} }
// === Mapper Functions (ordered) === // === Mapper Functions (ordered) ===
func ToFlockDTO(e entity.Flock) flockBaseDTO.FlockBaseDTO { func ToFlockDTO(e entity.Flock) flockRelationDTO.FlockRelationDTO {
return flockBaseDTO.ToFlockBaseDTO(e) return flockRelationDTO.ToFlockRelationDTO(e)
} }
func ToKandangDTO(e entity.Kandang) kandangBaseDTO.KandangBaseDTO { func ToKandangDTO(e entity.Kandang) kandangRelationDTO.KandangRelationDTO {
return kandangBaseDTO.ToKandangBaseDTO(e) return kandangRelationDTO.ToKandangRelationDTO(e)
} }
func ToAreaDTO(e entity.Area) areaBaseDTO.AreaBaseDTO { func ToAreaDTO(e entity.Area) areaRelationDTO.AreaRelationDTO {
return areaBaseDTO.ToAreaBaseDTO(e) return areaRelationDTO.ToAreaRelationDTO(e)
} }
func ToFcrDTO(e entity.Fcr) fcrBaseDTO.FcrBaseDTO { func ToFcrDTO(e entity.Fcr) fcrRelationDTO.FcrRelationDTO {
return fcrBaseDTO.ToFcrBaseDTO(e) return fcrRelationDTO.ToFcrRelationDTO(e)
} }
func ToLocationDTO(e entity.Location) locationBaseDTO.LocationBaseDTO { func ToLocationDTO(e entity.Location) locationRelationDTO.LocationRelationDTO {
return locationBaseDTO.ToLocationBaseDTO(e) return locationRelationDTO.ToLocationRelationDTO(e)
} }
func ToUserBaseDTO(e entity.User) userBaseDTO.UserBaseDTO { func ToUserRelationDTO(e entity.User) userRelationDTO.UserRelationDTO {
return userBaseDTO.ToUserBaseDTO(e) return userRelationDTO.ToUserRelationDTO(e)
} }
func ToProjectFlockDTO(pfk entity.ProjectFlockKandang) ProjectFlockDTO { func ToProjectFlockDTO(pfk entity.ProjectFlockKandang) ProjectFlockDTO {
e := pfk.ProjectFlock e := pfk.ProjectFlock
var flock *flockBaseDTO.FlockBaseDTO var flock *flockRelationDTO.FlockRelationDTO
if base := pfutils.DeriveBaseName(e.FlockName); base != "" { if base := pfutils.DeriveBaseName(e.FlockName); base != "" {
summary := flockBaseDTO.FlockBaseDTO{Id: 0, Name: base} summary := flockRelationDTO.FlockRelationDTO{Id: 0, Name: base}
flock = &summary flock = &summary
} }
var area *areaBaseDTO.AreaBaseDTO var area *areaRelationDTO.AreaRelationDTO
if e.Area.Id != 0 { if e.Area.Id != 0 {
mapped := areaBaseDTO.ToAreaBaseDTO(e.Area) mapped := areaRelationDTO.ToAreaRelationDTO(e.Area)
area = &mapped area = &mapped
} }
var fcr *fcrBaseDTO.FcrBaseDTO var fcr *fcrRelationDTO.FcrRelationDTO
if e.Fcr.Id != 0 { if e.Fcr.Id != 0 {
mapped := fcrBaseDTO.ToFcrBaseDTO(e.Fcr) mapped := fcrRelationDTO.ToFcrRelationDTO(e.Fcr)
fcr = &mapped fcr = &mapped
} }
var location *locationBaseDTO.LocationBaseDTO var location *locationRelationDTO.LocationRelationDTO
if e.Location.Id != 0 { if e.Location.Id != 0 {
mapped := locationBaseDTO.ToLocationBaseDTO(e.Location) mapped := locationRelationDTO.ToLocationRelationDTO(e.Location)
location = &mapped location = &mapped
} }
return ProjectFlockDTO{ return ProjectFlockDTO{
@@ -148,9 +148,9 @@ func ToProjectFlockKandangDTO(e entity.ProjectFlockKandang) ProjectFlockKandangD
mapped := ToProjectFlockDTO(e) mapped := ToProjectFlockDTO(e)
pf = &mapped pf = &mapped
} }
var kandang *kandangBaseDTO.KandangBaseDTO var kandang *kandangRelationDTO.KandangRelationDTO
if e.Kandang.Id != 0 { if e.Kandang.Id != 0 {
mapped := kandangBaseDTO.ToKandangBaseDTO(e.Kandang) mapped := kandangRelationDTO.ToKandangRelationDTO(e.Kandang)
kandang = &mapped kandang = &mapped
} }
return ProjectFlockKandangDTO{ return ProjectFlockKandangDTO{
@@ -160,7 +160,7 @@ func ToProjectFlockKandangDTO(e entity.ProjectFlockKandang) ProjectFlockKandangD
} }
} }
func ToChickinBaseDTO(e entity.ProjectChickin) ChickinBaseDTO { func ToChickinRelationDTO(e entity.ProjectChickin) ChickinRelationDTO {
var projectFlockKandangId uint var projectFlockKandangId uint
// Check if ProjectFlockKandang relation is loaded // Check if ProjectFlockKandang relation is loaded
if e.ProjectFlockKandang != nil && e.ProjectFlockKandang.Id != 0 { if e.ProjectFlockKandang != nil && e.ProjectFlockKandang.Id != 0 {
@@ -175,7 +175,7 @@ func ToChickinBaseDTO(e entity.ProjectChickin) ChickinBaseDTO {
productWarehouse = toProductWarehouseDTO(e.ProductWarehouse) productWarehouse = toProductWarehouseDTO(e.ProductWarehouse)
} }
return ChickinBaseDTO{ return ChickinRelationDTO{
Id: e.Id, Id: e.Id,
ProjectFlockKandangId: projectFlockKandangId, ProjectFlockKandangId: projectFlockKandangId,
ChickInDate: e.ChickInDate, ChickInDate: e.ChickInDate,
@@ -201,16 +201,16 @@ func ToChickinSimpleDTO(e entity.ProjectChickin) ChickinSimpleDTO {
} }
func ToChickinListDTO(e entity.ProjectChickin) ChickinListDTO { func ToChickinListDTO(e entity.ProjectChickin) ChickinListDTO {
var createdUser *userBaseDTO.UserBaseDTO var createdUser *userRelationDTO.UserRelationDTO
if e.CreatedUser != nil && e.CreatedUser.Id != 0 { if e.CreatedUser != nil && e.CreatedUser.Id != 0 {
mapped := userBaseDTO.ToUserBaseDTO(*e.CreatedUser) mapped := userRelationDTO.ToUserRelationDTO(*e.CreatedUser)
createdUser = &mapped createdUser = &mapped
} }
return ChickinListDTO{ return ChickinListDTO{
ChickinBaseDTO: ToChickinBaseDTO(e), ChickinRelationDTO: ToChickinRelationDTO(e),
CreatedUser: createdUser, CreatedUser: createdUser,
CreatedAt: e.CreatedAt, CreatedAt: e.CreatedAt,
UpdatedAt: e.UpdatedAt, UpdatedAt: e.UpdatedAt,
} }
} }
@@ -231,9 +231,9 @@ func ToChickinSimpleDTOs(e []entity.ProjectChickin) []ChickinSimpleDTO {
} }
func ToChickinDetailDTO(e entity.ProjectChickin) ChickinDetailDTO { func ToChickinDetailDTO(e entity.ProjectChickin) ChickinDetailDTO {
var createdUser *userBaseDTO.UserBaseDTO var createdUser *userRelationDTO.UserRelationDTO
if e.CreatedUser != nil && e.CreatedUser.Id != 0 { if e.CreatedUser != nil && e.CreatedUser.Id != 0 {
mapped := userBaseDTO.ToUserBaseDTO(*e.CreatedUser) mapped := userRelationDTO.ToUserRelationDTO(*e.CreatedUser)
createdUser = &mapped createdUser = &mapped
} }
@@ -268,8 +268,8 @@ func ToProductWarehouseDTO(pw *entity.ProductWarehouse) *ProductWarehouseDTO {
return nil return nil
} }
product := productDTO.ToProductBaseDTO(pw.Product) product := productDTO.ToProductRelationDTO(pw.Product)
warehouse := warehouseDTO.ToWarehouseBaseDTO(pw.Warehouse) warehouse := warehouseDTO.ToWarehouseRelationDTO(pw.Warehouse)
return &ProductWarehouseDTO{ return &ProductWarehouseDTO{
Id: pw.Id, Id: pw.Id,
@@ -48,7 +48,7 @@ func (u *ProjectFlockKandangController) GetAll(c *fiber.Ctx) error {
data := make([]dto.ProjectFlockKandangListDTO, 0) data := make([]dto.ProjectFlockKandangListDTO, 0)
for _, result := range results { for _, result := range results {
var flock *flockDTO.FlockBaseDTO var flock *flockDTO.FlockRelationDTO
if flockMap != nil { if flockMap != nil {
flock = flockMap[result.ProjectFlock.Id] flock = flockMap[result.ProjectFlock.Id]
} }
@@ -18,24 +18,24 @@ import (
// === DTO Structs (ordered) === // === DTO Structs (ordered) ===
type ProjectFlockKandangBaseDTO struct { type ProjectFlockKandangRelationDTO struct {
Id uint `json:"id"` Id uint `json:"id"`
KandangId uint `json:"kandang_id"` KandangId uint `json:"kandang_id"`
ProjectFlockId uint `json:"project_flock_id"` ProjectFlockId uint `json:"project_flock_id"`
} }
type ProjectFlockDTO struct { type ProjectFlockDTO struct {
Id uint `json:"id"` Id uint `json:"id"`
Name string `json:"flock_name,omitempty"` Name string `json:"flock_name,omitempty"`
Period int `json:"period"` Period int `json:"period"`
Flock *flockDTO.FlockBaseDTO `json:"flock,omitempty"` Flock *flockDTO.FlockRelationDTO `json:"flock,omitempty"`
Area *areaDTO.AreaBaseDTO `json:"area,omitempty"` Area *areaDTO.AreaRelationDTO `json:"area,omitempty"`
Category string `json:"category"` Category string `json:"category"`
Fcr *fcrDTO.FcrBaseDTO `json:"fcr,omitempty"` Fcr *fcrDTO.FcrRelationDTO `json:"fcr,omitempty"`
Location *locationDTO.LocationBaseDTO `json:"location,omitempty"` Location *locationDTO.LocationRelationDTO `json:"location,omitempty"`
CreatedUser *userDTO.UserBaseDTO `json:"created_user,omitempty"` CreatedUser *userDTO.UserRelationDTO `json:"created_user,omitempty"`
CreatedAt time.Time `json:"created_at"` CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"` UpdatedAt time.Time `json:"updated_at"`
} }
type KandangDTO struct { type KandangDTO struct {
@@ -45,9 +45,9 @@ type KandangDTO struct {
} }
type ProductWarehouseDTO struct { type ProductWarehouseDTO struct {
Id uint `json:"id"` Id uint `json:"id"`
Product *productDTO.ProductBaseDTO `json:"product,omitempty"` Product *productDTO.ProductRelationDTO `json:"product,omitempty"`
Warehouse *warehouseDTO.WarehouseBaseDTO `json:"warehouse,omitempty"` Warehouse *warehouseDTO.WarehouseRelationDTO `json:"warehouse,omitempty"`
} }
type AvailableQtyDTO struct { type AvailableQtyDTO struct {
@@ -56,24 +56,24 @@ type AvailableQtyDTO struct {
} }
type ProjectFlockKandangListDTO struct { type ProjectFlockKandangListDTO struct {
ProjectFlockKandangBaseDTO ProjectFlockKandangRelationDTO
ProjectFlock *ProjectFlockDTO `json:"project_flock,omitempty"` ProjectFlock *ProjectFlockDTO `json:"project_flock,omitempty"`
Kandang *KandangDTO `json:"kandang,omitempty"` Kandang *KandangDTO `json:"kandang,omitempty"`
CreatedUser *userDTO.UserBaseDTO `json:"created_user,omitempty"` CreatedUser *userDTO.UserRelationDTO `json:"created_user,omitempty"`
CreatedAt time.Time `json:"created_at"` CreatedAt time.Time `json:"created_at"`
Approval *approvalDTO.ApprovalBaseDTO `json:"approval,omitempty"` Approval *approvalDTO.ApprovalRelationDTO `json:"approval,omitempty"`
} }
type ProjectFlockKandangDetailDTO struct { type ProjectFlockKandangDetailDTO struct {
ProjectFlockKandangListDTO ProjectFlockKandangListDTO
Chickins []chickinDTO.ChickinBaseDTO `json:"chickins,omitempty"` Chickins []chickinDTO.ChickinRelationDTO `json:"chickins,omitempty"`
AvailableQtys []AvailableQtyDTO `json:"available_qtys,omitempty"` AvailableQtys []AvailableQtyDTO `json:"available_qtys,omitempty"`
} }
// === Mapper Functions (ordered) === // === Mapper Functions (ordered) ===
func ToProjectFlockKandangBaseDTO(e entity.ProjectFlockKandang) ProjectFlockKandangBaseDTO { func ToProjectFlockKandangRelationDTO(e entity.ProjectFlockKandang) ProjectFlockKandangRelationDTO {
return ProjectFlockKandangBaseDTO{ return ProjectFlockKandangRelationDTO{
Id: e.Id, Id: e.Id,
KandangId: e.KandangId, KandangId: e.KandangId,
ProjectFlockId: e.ProjectFlockId, ProjectFlockId: e.ProjectFlockId,
@@ -104,20 +104,20 @@ func ToProjectFlockKandangDetailDTOWithAvailableQty(e entity.ProjectFlockKandang
return ToProjectFlockKandangDetailDTOWithAvailableQtyAndFlock(e, availableQtyMap, productWarehouses, nil) return ToProjectFlockKandangDetailDTOWithAvailableQtyAndFlock(e, availableQtyMap, productWarehouses, nil)
} }
func ToProjectFlockKandangDetailDTOWithAvailableQtyAndFlock(e entity.ProjectFlockKandang, availableQtyMap map[uint]float64, productWarehouses []entity.ProductWarehouse, flock *flockDTO.FlockBaseDTO) ProjectFlockKandangDetailDTO { func ToProjectFlockKandangDetailDTOWithAvailableQtyAndFlock(e entity.ProjectFlockKandang, availableQtyMap map[uint]float64, productWarehouses []entity.ProductWarehouse, flock *flockDTO.FlockRelationDTO) ProjectFlockKandangDetailDTO {
var projectFlockSummary *projectFlockDTO.ProjectFlockListDTO var projectFlockSummary *projectFlockDTO.ProjectFlockListDTO
if e.ProjectFlock.Id != 0 { if e.ProjectFlock.Id != 0 {
mapped := projectFlockDTO.ToProjectFlockListDTO(e.ProjectFlock, flock) mapped := projectFlockDTO.ToProjectFlockListDTO(e.ProjectFlock)
projectFlockSummary = &mapped projectFlockSummary = &mapped
} }
listDTO := ProjectFlockKandangListDTO{ listDTO := ProjectFlockKandangListDTO{
ProjectFlockKandangBaseDTO: ToProjectFlockKandangBaseDTO(e), ProjectFlockKandangRelationDTO: ToProjectFlockKandangRelationDTO(e),
ProjectFlock: toProjectFlockDTO(projectFlockSummary), ProjectFlock: toProjectFlockDTO(projectFlockSummary),
Kandang: toKandangDTO(e.Kandang), Kandang: toKandangDTO(e.Kandang),
CreatedAt: e.CreatedAt, CreatedAt: e.CreatedAt,
CreatedUser: toCreatedUserDTO(e.ProjectFlock), CreatedUser: toCreatedUserDTO(e.ProjectFlock),
Approval: toApprovalDTO(e), Approval: toApprovalDTO(e),
} }
return ProjectFlockKandangDetailDTO{ return ProjectFlockKandangDetailDTO{
@@ -139,18 +139,18 @@ func toKandangDTO(kandang entity.Kandang) *KandangDTO {
} }
} }
func toFlockDTO(flock *entity.Flock) *flockDTO.FlockBaseDTO { // func toFlockDTO(flock *entity.Flock) *flockDTO.FlockRelationDTO {
if flock == nil || flock.Id == 0 { // if flock == nil || flock.Id == 0 {
return nil // return nil
} // }
return &flockDTO.FlockBaseDTO{ // return &flockDTO.FlockRelationDTO{
Id: flock.Id, // Id: flock.Id,
Name: flock.Name, // Name: flock.Name,
} // }
} // }
func toApprovalDTO(e entity.ProjectFlockKandang) *approvalDTO.ApprovalBaseDTO { func toApprovalDTO(e entity.ProjectFlockKandang) *approvalDTO.ApprovalRelationDTO {
if e.LatestApproval != nil { if e.LatestApproval != nil {
mapped := approvalDTO.ToApprovalDTO(*e.LatestApproval) mapped := approvalDTO.ToApprovalDTO(*e.LatestApproval)
return &mapped return &mapped
@@ -162,7 +162,7 @@ func ToProjectFlockKandangListDTO(e entity.ProjectFlockKandang) ProjectFlockKand
return ToProjectFlockKandangListDTOWithFlock(e, nil) return ToProjectFlockKandangListDTOWithFlock(e, nil)
} }
func ToProjectFlockKandangListDTOWithFlock(e entity.ProjectFlockKandang, flock *flockDTO.FlockBaseDTO) ProjectFlockKandangListDTO { func ToProjectFlockKandangListDTOWithFlock(e entity.ProjectFlockKandang, flock *flockDTO.FlockRelationDTO) ProjectFlockKandangListDTO {
var projectFlockSummary *projectFlockDTO.ProjectFlockListDTO var projectFlockSummary *projectFlockDTO.ProjectFlockListDTO
if e.ProjectFlock.Id != 0 { if e.ProjectFlock.Id != 0 {
mapped := projectFlockDTO.ToProjectFlockListDTOWithFlock(e.ProjectFlock, flock) mapped := projectFlockDTO.ToProjectFlockListDTOWithFlock(e.ProjectFlock, flock)
@@ -170,12 +170,12 @@ func ToProjectFlockKandangListDTOWithFlock(e entity.ProjectFlockKandang, flock *
} }
return ProjectFlockKandangListDTO{ return ProjectFlockKandangListDTO{
ProjectFlockKandangBaseDTO: ToProjectFlockKandangBaseDTO(e), ProjectFlockKandangRelationDTO: ToProjectFlockKandangRelationDTO(e),
ProjectFlock: toProjectFlockDTO(projectFlockSummary), ProjectFlock: toProjectFlockDTO(projectFlockSummary),
Kandang: toKandangDTO(e.Kandang), Kandang: toKandangDTO(e.Kandang),
CreatedAt: e.CreatedAt, CreatedAt: e.CreatedAt,
CreatedUser: toCreatedUserDTO(e.ProjectFlock), CreatedUser: toCreatedUserDTO(e.ProjectFlock),
Approval: toApprovalDTO(e), Approval: toApprovalDTO(e),
} }
} }
@@ -187,12 +187,12 @@ func ToProjectFlockKandangListDTOs(e []entity.ProjectFlockKandang) []ProjectFloc
return result return result
} }
func toCreatedUserDTO(pf entity.ProjectFlock) *userDTO.UserBaseDTO { func toCreatedUserDTO(pf entity.ProjectFlock) *userDTO.UserRelationDTO {
if pf.CreatedUser.Id != 0 { if pf.CreatedUser.Id != 0 {
mapped := userDTO.ToUserBaseDTO(pf.CreatedUser) mapped := userDTO.ToUserRelationDTO(pf.CreatedUser)
return &mapped return &mapped
} else if pf.CreatedBy != 0 { } else if pf.CreatedBy != 0 {
return &userDTO.UserBaseDTO{ return &userDTO.UserRelationDTO{
Id: pf.CreatedBy, Id: pf.CreatedBy,
IdUser: int64(pf.CreatedBy), IdUser: int64(pf.CreatedBy),
} }
@@ -200,14 +200,14 @@ func toCreatedUserDTO(pf entity.ProjectFlock) *userDTO.UserBaseDTO {
return nil return nil
} }
func toChickinDTOs(chickins []entity.ProjectChickin) []chickinDTO.ChickinBaseDTO { func toChickinDTOs(chickins []entity.ProjectChickin) []chickinDTO.ChickinRelationDTO {
if len(chickins) == 0 { if len(chickins) == 0 {
return nil return nil
} }
result := make([]chickinDTO.ChickinBaseDTO, len(chickins)) result := make([]chickinDTO.ChickinRelationDTO, len(chickins))
for i, ch := range chickins { for i, ch := range chickins {
result[i] = chickinDTO.ToChickinBaseDTO(ch) result[i] = chickinDTO.ToChickinRelationDTO(ch)
} }
return result return result
} }
@@ -21,8 +21,8 @@ import (
) )
type ProjectFlockKandangService interface { type ProjectFlockKandangService interface {
GetAll(ctx *fiber.Ctx, params *validation.Query) ([]entity.ProjectFlockKandang, int64, map[uint]*flockDTO.FlockBaseDTO, error) GetAll(ctx *fiber.Ctx, params *validation.Query) ([]entity.ProjectFlockKandang, int64, map[uint]*flockDTO.FlockRelationDTO, error)
GetOne(ctx *fiber.Ctx, id uint) (*entity.ProjectFlockKandang, map[uint]float64, []entity.ProductWarehouse, *flockDTO.FlockBaseDTO, error) GetOne(ctx *fiber.Ctx, id uint) (*entity.ProjectFlockKandang, map[uint]float64, []entity.ProductWarehouse, *flockDTO.FlockRelationDTO, error)
} }
// Note: map[uint]float64 adalah mapping dari ProductWarehouse ID ke calculated available quantity // Note: map[uint]float64 adalah mapping dari ProductWarehouse ID ke calculated available quantity
@@ -51,7 +51,7 @@ func NewProjectFlockKandangService(repo repository.ProjectFlockKandangRepository
} }
} }
func (s projectFlockKandangService) GetAll(c *fiber.Ctx, params *validation.Query) ([]entity.ProjectFlockKandang, int64, map[uint]*flockDTO.FlockBaseDTO, error) { func (s projectFlockKandangService) GetAll(c *fiber.Ctx, params *validation.Query) ([]entity.ProjectFlockKandang, int64, map[uint]*flockDTO.FlockRelationDTO, error) {
if err := s.Validate.Struct(params); err != nil { if err := s.Validate.Struct(params); err != nil {
return nil, 0, nil, err return nil, 0, nil, err
} }
@@ -85,7 +85,7 @@ func (s projectFlockKandangService) GetAll(c *fiber.Ctx, params *validation.Quer
} }
} }
flockMap := make(map[uint]*flockDTO.FlockBaseDTO) flockMap := make(map[uint]*flockDTO.FlockRelationDTO)
for i := range projectFlockKandangs { for i := range projectFlockKandangs {
if projectFlockKandangs[i].ProjectFlock.Id != 0 { if projectFlockKandangs[i].ProjectFlock.Id != 0 {
baseName := pfutils.DeriveBaseName(projectFlockKandangs[i].ProjectFlock.FlockName) baseName := pfutils.DeriveBaseName(projectFlockKandangs[i].ProjectFlock.FlockName)
@@ -95,7 +95,7 @@ func (s projectFlockKandangService) GetAll(c *fiber.Ctx, params *validation.Quer
s.Log.Warnf("Failed to fetch flock %q: %+v", baseName, err) s.Log.Warnf("Failed to fetch flock %q: %+v", baseName, err)
} else if flock != nil { } else if flock != nil {
flockMap[projectFlockKandangs[i].ProjectFlock.Id] = &flockDTO.FlockBaseDTO{ flockMap[projectFlockKandangs[i].ProjectFlock.Id] = &flockDTO.FlockRelationDTO{
Id: flock.Id, Id: flock.Id,
Name: flock.Name, Name: flock.Name,
} }
@@ -107,7 +107,7 @@ func (s projectFlockKandangService) GetAll(c *fiber.Ctx, params *validation.Quer
return projectFlockKandangs, total, flockMap, nil return projectFlockKandangs, total, flockMap, nil
} }
func (s projectFlockKandangService) GetOne(c *fiber.Ctx, id uint) (*entity.ProjectFlockKandang, map[uint]float64, []entity.ProductWarehouse, *flockDTO.FlockBaseDTO, error) { func (s projectFlockKandangService) GetOne(c *fiber.Ctx, id uint) (*entity.ProjectFlockKandang, map[uint]float64, []entity.ProductWarehouse, *flockDTO.FlockRelationDTO, error) {
projectFlockKandang, err := s.Repository.GetByID(c.Context(), id) projectFlockKandang, err := s.Repository.GetByID(c.Context(), id)
if errors.Is(err, gorm.ErrRecordNotFound) { if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, nil, nil, nil, fiber.NewError(fiber.StatusNotFound, "ProjectFlockKandang not found") return nil, nil, nil, nil, fiber.NewError(fiber.StatusNotFound, "ProjectFlockKandang not found")
@@ -147,7 +147,7 @@ func (s projectFlockKandangService) GetOne(c *fiber.Ctx, id uint) (*entity.Proje
productWarehouses = []entity.ProductWarehouse{} productWarehouses = []entity.ProductWarehouse{}
} }
} }
var flockResult *flockDTO.FlockBaseDTO var flockResult *flockDTO.FlockRelationDTO
if projectFlockKandang.ProjectFlock.Id != 0 { if projectFlockKandang.ProjectFlock.Id != 0 {
baseName := pfutils.DeriveBaseName(projectFlockKandang.ProjectFlock.FlockName) baseName := pfutils.DeriveBaseName(projectFlockKandang.ProjectFlock.FlockName)
if baseName != "" { if baseName != "" {
@@ -155,7 +155,7 @@ func (s projectFlockKandangService) GetOne(c *fiber.Ctx, id uint) (*entity.Proje
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
s.Log.Warnf("Failed to fetch flock %q: %+v", baseName, err) s.Log.Warnf("Failed to fetch flock %q: %+v", baseName, err)
} else if flock != nil { } else if flock != nil {
flockResult = &flockDTO.FlockBaseDTO{ flockResult = &flockDTO.FlockRelationDTO{
Id: flock.Id, Id: flock.Id,
Name: flock.Name, Name: flock.Name,
} }
@@ -7,7 +7,6 @@ import (
"strconv" "strconv"
"strings" "strings"
flockDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/flocks/dto"
"gitlab.com/mbugroup/lti-api.git/internal/modules/production/project_flocks/dto" "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project_flocks/dto"
service "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project_flocks/services" service "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project_flocks/services"
validation "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project_flocks/validations" validation "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project_flocks/validations"
@@ -85,7 +84,7 @@ func (u *ProjectflockController) GetAll(c *fiber.Ctx) error {
query.KandangIds = ids query.KandangIds = ids
} }
result, totalResults, flockMap, err := u.ProjectflockService.GetAll(c, query) result, totalResults, _, err := u.ProjectflockService.GetAll(c, query)
if err != nil { if err != nil {
return err return err
} }
@@ -124,7 +123,7 @@ func (u *ProjectflockController) GetOne(c *fiber.Ctx) error {
return fiber.NewError(fiber.StatusBadRequest, "Invalid Id") return fiber.NewError(fiber.StatusBadRequest, "Invalid Id")
} }
result, flock, err := u.ProjectflockService.GetOne(c, uint(id)) result, _, err := u.ProjectflockService.GetOne(c, uint(id))
if err != nil { if err != nil {
return err return err
} }
@@ -162,7 +161,7 @@ func (u *ProjectflockController) CreateOne(c *fiber.Ctx) error {
Code: fiber.StatusCreated, Code: fiber.StatusCreated,
Status: "success", Status: "success",
Message: "Create projectflock successfully", Message: "Create projectflock successfully",
Data: dto.ToProjectFlockListDTO(*result, nil), Data: dto.ToProjectFlockListDTO(*result),
}) })
} }
@@ -189,7 +188,7 @@ func (u *ProjectflockController) UpdateOne(c *fiber.Ctx) error {
Code: fiber.StatusOK, Code: fiber.StatusOK,
Status: "success", Status: "success",
Message: "Update projectflock successfully", Message: "Update projectflock successfully",
Data: dto.ToProjectFlockListDTO(*result, nil), Data: dto.ToProjectFlockListDTO(*result),
}) })
} }
@@ -17,28 +17,28 @@ import (
approvalutils "gitlab.com/mbugroup/lti-api.git/internal/utils/approvals" approvalutils "gitlab.com/mbugroup/lti-api.git/internal/utils/approvals"
) )
type ProjectFlockBaseDTO struct { type ProjectFlockRelationDTO struct {
Id uint `json:"id"` Id uint `json:"id"`
Period int `json:"period"` Period int `json:"period"`
FlockName string `json:"flock_name"` FlockName string `json:"flock_name"`
} }
type ProjectFlockListDTO struct { type ProjectFlockListDTO struct {
ProjectFlockBaseDTO ProjectFlockRelationDTO
Flock *flockDTO.FlockBaseDTO `json:"flock,omitempty"` Flock *flockDTO.FlockRelationDTO `json:"flock,omitempty"`
Area *areaDTO.AreaBaseDTO `json:"area,omitempty"` Area *areaDTO.AreaRelationDTO `json:"area,omitempty"`
Category string `json:"category"` Category string `json:"category"`
Fcr *fcrDTO.FcrBaseDTO `json:"fcr,omitempty"` Fcr *fcrDTO.FcrRelationDTO `json:"fcr,omitempty"`
Location *locationDTO.LocationBaseDTO `json:"location,omitempty"` Location *locationDTO.LocationRelationDTO `json:"location,omitempty"`
Kandangs []KandangWithProjectFlockIdDTO `json:"kandangs,omitempty"` Kandangs []KandangWithProjectFlockIdDTO `json:"kandangs,omitempty"`
CreatedUser *userDTO.UserBaseDTO `json:"created_user"` CreatedUser *userDTO.UserRelationDTO `json:"created_user"`
CreatedAt time.Time `json:"created_at"` CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"` UpdatedAt time.Time `json:"updated_at"`
Approval approvalDTO.ApprovalBaseDTO `json:"approval"` Approval approvalDTO.ApprovalRelationDTO `json:"approval"`
} }
type KandangWithProjectFlockIdDTO struct { type KandangWithProjectFlockIdDTO struct {
kandangDTO.KandangBaseDTO kandangDTO.KandangRelationDTO
ProjectFlockKandangId uint `json:"project_flock_kandang_id"` ProjectFlockKandangId uint `json:"project_flock_kandang_id"`
} }
@@ -47,8 +47,8 @@ type ProjectFlockDetailDTO struct {
} }
type FlockPeriodDTO struct { type FlockPeriodDTO struct {
Flock flockDTO.FlockBaseDTO `json:"flock"` Flock flockDTO.FlockRelationDTO `json:"flock"`
NextPeriod int `json:"next_period"` NextPeriod int `json:"next_period"`
} }
type KandangPeriodSummaryDTO struct { type KandangPeriodSummaryDTO struct {
@@ -58,9 +58,9 @@ type KandangPeriodSummaryDTO struct {
} }
func ToProjectFlockListDTOWithPeriod(e entity.ProjectFlock, period int) ProjectFlockListDTO { func ToProjectFlockListDTOWithPeriod(e entity.ProjectFlock, period int) ProjectFlockListDTO {
var createdUser *userDTO.UserBaseDTO var createdUser *userDTO.UserRelationDTO
if e.CreatedUser.Id != 0 { if e.CreatedUser.Id != 0 {
mapped := userDTO.ToUserBaseDTO(e.CreatedUser) mapped := userDTO.ToUserRelationDTO(e.CreatedUser)
createdUser = &mapped createdUser = &mapped
} }
@@ -77,34 +77,34 @@ func ToProjectFlockListDTOWithPeriod(e entity.ProjectFlock, period int) ProjectF
} }
} }
kandangSummaries[i] = KandangWithProjectFlockIdDTO{ kandangSummaries[i] = KandangWithProjectFlockIdDTO{
KandangBaseDTO: kandangDTO.ToKandangBaseDTO(kandang), KandangRelationDTO: kandangDTO.ToKandangRelationDTO(kandang),
ProjectFlockKandangId: pfkId, ProjectFlockKandangId: pfkId,
} }
} }
} }
var areaSummary *areaDTO.AreaBaseDTO var areaSummary *areaDTO.AreaRelationDTO
if e.Area.Id != 0 { if e.Area.Id != 0 {
mapped := areaDTO.ToAreaBaseDTO(e.Area) mapped := areaDTO.ToAreaRelationDTO(e.Area)
areaSummary = &mapped areaSummary = &mapped
} }
var fcrSummary *fcrDTO.FcrBaseDTO var fcrSummary *fcrDTO.FcrRelationDTO
if e.Fcr.Id != 0 { if e.Fcr.Id != 0 {
mapped := fcrDTO.ToFcrBaseDTO(e.Fcr) mapped := fcrDTO.ToFcrRelationDTO(e.Fcr)
fcrSummary = &mapped fcrSummary = &mapped
} }
var locationSummary *locationDTO.LocationBaseDTO var locationSummary *locationDTO.LocationRelationDTO
if e.Location.Id != 0 { if e.Location.Id != 0 {
mapped := locationDTO.ToLocationBaseDTO(e.Location) mapped := locationDTO.ToLocationRelationDTO(e.Location)
locationSummary = &mapped locationSummary = &mapped
} }
var flockSummary *flockDTO.FlockBaseDTO // var flockSummary *flockDTO.FlockRelationDTO
if flock != nil && flock.Id != 0 { // if flock != nil && flock.Id != 0 {
flockSummary = flock // flockSummary = flock
} // }
latestApproval := defaultProjectFlockLatestApproval(e) latestApproval := defaultProjectFlockLatestApproval(e)
if e.LatestApproval != nil { if e.LatestApproval != nil {
@@ -113,7 +113,7 @@ func ToProjectFlockListDTOWithPeriod(e entity.ProjectFlock, period int) ProjectF
} }
return ProjectFlockListDTO{ return ProjectFlockListDTO{
ProjectFlockBaseDTO: createProjectFlockBaseDTO(e, period), ProjectFlockRelationDTO: createProjectFlockRelationDTO(e, period),
// Flock: flockSummary, // Flock: flockSummary,
Area: areaSummary, Area: areaSummary,
Kandangs: kandangSummaries, Kandangs: kandangSummaries,
@@ -127,8 +127,8 @@ func ToProjectFlockListDTOWithPeriod(e entity.ProjectFlock, period int) ProjectF
} }
} }
func ToProjectFlockListDTOWithFlock(e entity.ProjectFlock, flock *flockDTO.FlockBaseDTO) ProjectFlockListDTO { func ToProjectFlockListDTOWithFlock(e entity.ProjectFlock, flock *flockDTO.FlockRelationDTO) ProjectFlockListDTO {
return ToProjectFlockListDTO(e, flock) return ToProjectFlockListDTO(e)
} }
func ToProjectFlockListDTOs(items []entity.ProjectFlock) []ProjectFlockListDTO { func ToProjectFlockListDTOs(items []entity.ProjectFlock) []ProjectFlockListDTO {
@@ -160,10 +160,10 @@ func ToProjectFlockListDTOsWithPeriods(items []entity.ProjectFlock, periods map[
func ToProjectFlockListDTOsWithFlocks(items []entity.ProjectFlock, flocks map[uint]*entity.Flock) []ProjectFlockListDTO { func ToProjectFlockListDTOsWithFlocks(items []entity.ProjectFlock, flocks map[uint]*entity.Flock) []ProjectFlockListDTO {
result := make([]ProjectFlockListDTO, len(items)) result := make([]ProjectFlockListDTO, len(items))
for i, item := range items { for i, item := range items {
var flock *flockDTO.FlockBaseDTO var flock *flockDTO.FlockRelationDTO
if flocks != nil { if flocks != nil {
if f := flocks[item.Id]; f != nil { if f := flocks[item.Id]; f != nil {
flock = &flockDTO.FlockBaseDTO{ flock = &flockDTO.FlockRelationDTO{
Id: f.Id, Id: f.Id,
Name: f.Name, Name: f.Name,
} }
@@ -174,14 +174,14 @@ func ToProjectFlockListDTOsWithFlocks(items []entity.ProjectFlock, flocks map[ui
return result return result
} }
func ToProjectFlockDetailDTO(e entity.ProjectFlock, flock *flockDTO.FlockBaseDTO) ProjectFlockDetailDTO { func ToProjectFlockDetailDTO(e entity.ProjectFlock, flock *flockDTO.FlockRelationDTO) ProjectFlockDetailDTO {
return ProjectFlockDetailDTO{ return ProjectFlockDetailDTO{
ProjectFlockListDTO: ToProjectFlockListDTOWithPeriod(e, 0), ProjectFlockListDTO: ToProjectFlockListDTOWithPeriod(e, 0),
} }
} }
func defaultProjectFlockLatestApproval(e entity.ProjectFlock) approvalDTO.ApprovalBaseDTO { func defaultProjectFlockLatestApproval(e entity.ProjectFlock) approvalDTO.ApprovalRelationDTO {
result := approvalDTO.ApprovalBaseDTO{} result := approvalDTO.ApprovalRelationDTO{}
step := utils.ProjectFlockStepPengajuan step := utils.ProjectFlockStepPengajuan
if step > 0 { if step > 0 {
@@ -194,9 +194,9 @@ func defaultProjectFlockLatestApproval(e entity.ProjectFlock) approvalDTO.Approv
} }
if e.CreatedUser.Id != 0 { if e.CreatedUser.Id != 0 {
result.ActionBy = userDTO.ToUserBaseDTO(e.CreatedUser) result.ActionBy = userDTO.ToUserRelationDTO(e.CreatedUser)
} else if e.CreatedBy != 0 { } else if e.CreatedBy != 0 {
result.ActionBy = userDTO.UserBaseDTO{ result.ActionBy = userDTO.UserRelationDTO{
Id: e.CreatedBy, Id: e.CreatedBy,
IdUser: int64(e.CreatedBy), IdUser: int64(e.CreatedBy),
} }
@@ -205,16 +205,16 @@ func defaultProjectFlockLatestApproval(e entity.ProjectFlock) approvalDTO.Approv
return result return result
} }
func createProjectFlockBaseDTO(e entity.ProjectFlock, period int) ProjectFlockBaseDTO { func createProjectFlockRelationDTO(e entity.ProjectFlock, period int) ProjectFlockRelationDTO {
return ProjectFlockBaseDTO{ return ProjectFlockRelationDTO{
Id: e.Id, Id: e.Id,
Period: period, Period: period,
FlockName: e.FlockName, FlockName: e.FlockName,
} }
} }
func ToFlockSummaryDTO(e entity.Flock) flockDTO.FlockBaseDTO { func ToFlockSummaryDTO(e entity.Flock) flockDTO.FlockRelationDTO {
return flockDTO.FlockBaseDTO{ return flockDTO.FlockRelationDTO{
Id: e.Id, Id: e.Id,
Name: e.Name, Name: e.Name,
} }
@@ -12,35 +12,35 @@ import (
) )
type KandangWithPivotDTO struct { type KandangWithPivotDTO struct {
kandangDTO.KandangBaseDTO kandangDTO.KandangRelationDTO
AvailableQuantity float64 `json:"available_quantity"` AvailableQuantity float64 `json:"available_quantity"`
} }
type ProjectFlockWithPivotDTO struct { type ProjectFlockWithPivotDTO struct {
ProjectFlockBaseDTO ProjectFlockRelationDTO
Flock *flockDTO.FlockBaseDTO `json:"flock,omitempty"` Flock *flockDTO.FlockRelationDTO `json:"flock,omitempty"`
Area *areaDTO.AreaBaseDTO `json:"area,omitempty"` Area *areaDTO.AreaRelationDTO `json:"area,omitempty"`
Category string `json:"category"` Category string `json:"category"`
Fcr *fcrDTO.FcrBaseDTO `json:"fcr,omitempty"` Fcr *fcrDTO.FcrRelationDTO `json:"fcr,omitempty"`
Location *locationDTO.LocationBaseDTO `json:"location,omitempty"` Location *locationDTO.LocationRelationDTO `json:"location,omitempty"`
Kandangs []KandangWithPivotDTO `json:"kandangs,omitempty"` Kandangs []KandangWithPivotDTO `json:"kandangs,omitempty"`
CreatedUser *userDTO.UserBaseDTO `json:"created_user,omitempty"` CreatedUser *userDTO.UserRelationDTO `json:"created_user,omitempty"`
} }
type ProjectFlockKandangDTO struct { type ProjectFlockKandangDTO struct {
Id uint `json:"id"` Id uint `json:"id"`
ProjectFlockKandangId uint `json:"project_flock_kandang_id"` ProjectFlockKandangId uint `json:"project_flock_kandang_id"`
ProjectFlockId uint `json:"project_flock_id"` ProjectFlockId uint `json:"project_flock_id"`
KandangId uint `json:"kandang_id"` KandangId uint `json:"kandang_id"`
Kandang *kandangDTO.KandangBaseDTO `json:"kandang,omitempty"` Kandang *kandangDTO.KandangRelationDTO `json:"kandang,omitempty"`
ProjectFlock *ProjectFlockWithPivotDTO `json:"project_flock,omitempty"` ProjectFlock *ProjectFlockWithPivotDTO `json:"project_flock,omitempty"`
AvailableQuantity float64 `json:"available_quantity"` AvailableQuantity float64 `json:"available_quantity"`
} }
func ToProjectFlockKandangDTO(e entity.ProjectFlockKandang) ProjectFlockKandangDTO { func ToProjectFlockKandangDTO(e entity.ProjectFlockKandang) ProjectFlockKandangDTO {
var kandang *kandangDTO.KandangBaseDTO var kandang *kandangDTO.KandangRelationDTO
if e.Kandang.Id != 0 { if e.Kandang.Id != 0 {
mapped := kandangDTO.ToKandangBaseDTO(e.Kandang) mapped := kandangDTO.ToKandangRelationDTO(e.Kandang)
kandang = &mapped kandang = &mapped
} }
@@ -48,7 +48,7 @@ func ToProjectFlockKandangDTO(e entity.ProjectFlockKandang) ProjectFlockKandangD
if e.ProjectFlock.Id != 0 { if e.ProjectFlock.Id != 0 {
pfLocal := ProjectFlockWithPivotDTO{ pfLocal := ProjectFlockWithPivotDTO{
ProjectFlockBaseDTO: ProjectFlockBaseDTO{ ProjectFlockRelationDTO: ProjectFlockRelationDTO{
Id: e.ProjectFlock.Id, Id: e.ProjectFlock.Id,
Period: e.Period, Period: e.Period,
FlockName: e.ProjectFlock.FlockName, FlockName: e.ProjectFlock.FlockName,
@@ -57,31 +57,31 @@ func ToProjectFlockKandangDTO(e entity.ProjectFlockKandang) ProjectFlockKandangD
} }
if base := pfutils.DeriveBaseName(e.ProjectFlock.FlockName); base != "" { if base := pfutils.DeriveBaseName(e.ProjectFlock.FlockName); base != "" {
summary := flockDTO.FlockBaseDTO{Id: 0, Name: base} summary := flockDTO.FlockRelationDTO{Id: 0, Name: base}
pfLocal.Flock = &summary pfLocal.Flock = &summary
} }
if e.ProjectFlock.Area.Id != 0 { if e.ProjectFlock.Area.Id != 0 {
mapped := areaDTO.ToAreaBaseDTO(e.ProjectFlock.Area) mapped := areaDTO.ToAreaRelationDTO(e.ProjectFlock.Area)
pfLocal.Area = &mapped pfLocal.Area = &mapped
} }
if e.ProjectFlock.Fcr.Id != 0 { if e.ProjectFlock.Fcr.Id != 0 {
mapped := fcrDTO.ToFcrBaseDTO(e.ProjectFlock.Fcr) mapped := fcrDTO.ToFcrRelationDTO(e.ProjectFlock.Fcr)
pfLocal.Fcr = &mapped pfLocal.Fcr = &mapped
} }
if e.ProjectFlock.Location.Id != 0 { if e.ProjectFlock.Location.Id != 0 {
mapped := locationDTO.ToLocationBaseDTO(e.ProjectFlock.Location) mapped := locationDTO.ToLocationRelationDTO(e.ProjectFlock.Location)
pfLocal.Location = &mapped pfLocal.Location = &mapped
} }
if e.ProjectFlock.CreatedUser.Id != 0 { if e.ProjectFlock.CreatedUser.Id != 0 {
mapped := userDTO.ToUserBaseDTO(e.ProjectFlock.CreatedUser) mapped := userDTO.ToUserRelationDTO(e.ProjectFlock.CreatedUser)
pfLocal.CreatedUser = &mapped pfLocal.CreatedUser = &mapped
} }
for _, k := range e.ProjectFlock.Kandangs { for _, k := range e.ProjectFlock.Kandangs {
kb := kandangDTO.ToKandangBaseDTO(k) kb := kandangDTO.ToKandangRelationDTO(k)
pfLocal.Kandangs = append(pfLocal.Kandangs, KandangWithPivotDTO{ pfLocal.Kandangs = append(pfLocal.Kandangs, KandangWithPivotDTO{
KandangBaseDTO: kb, KandangRelationDTO: kb,
AvailableQuantity: 0, AvailableQuantity: 0,
}) })
} }
@@ -29,8 +29,8 @@ import (
) )
type ProjectflockService interface { type ProjectflockService interface {
GetAll(ctx *fiber.Ctx, params *validation.Query) ([]entity.ProjectFlock, int64, map[uint]*flockDTO.FlockBaseDTO, error) GetAll(ctx *fiber.Ctx, params *validation.Query) ([]entity.ProjectFlock, int64, map[uint]*flockDTO.FlockRelationDTO, error)
GetOne(ctx *fiber.Ctx, id uint) (*entity.ProjectFlock, *flockDTO.FlockBaseDTO, error) GetOne(ctx *fiber.Ctx, id uint) (*entity.ProjectFlock, *flockDTO.FlockRelationDTO, error)
CreateOne(ctx *fiber.Ctx, req *validation.Create) (*entity.ProjectFlock, error) CreateOne(ctx *fiber.Ctx, req *validation.Create) (*entity.ProjectFlock, error)
UpdateOne(ctx *fiber.Ctx, req *validation.Update, id uint) (*entity.ProjectFlock, error) UpdateOne(ctx *fiber.Ctx, req *validation.Update, id uint) (*entity.ProjectFlock, error)
GetAvailableDocQuantity(ctx *fiber.Ctx, kandangID uint) (float64, error) GetAvailableDocQuantity(ctx *fiber.Ctx, kandangID uint) (float64, error)
@@ -96,7 +96,7 @@ func (s projectflockService) withRelations(db *gorm.DB) *gorm.DB {
Preload("KandangHistory.Kandang") Preload("KandangHistory.Kandang")
} }
func (s projectflockService) GetAll(c *fiber.Ctx, params *validation.Query) ([]entity.ProjectFlock, int64, map[uint]*flockDTO.FlockBaseDTO, error) { func (s projectflockService) GetAll(c *fiber.Ctx, params *validation.Query) ([]entity.ProjectFlock, int64, map[uint]*flockDTO.FlockRelationDTO, error) {
if err := s.Validate.Struct(params); err != nil { if err := s.Validate.Struct(params); err != nil {
return nil, 0, nil, err return nil, 0, nil, err
} }
@@ -137,7 +137,7 @@ func (s projectflockService) GetAll(c *fiber.Ctx, params *validation.Query) ([]e
} }
} }
flockMap := make(map[uint]*flockDTO.FlockBaseDTO) flockMap := make(map[uint]*flockDTO.FlockRelationDTO)
for i := range projectflocks { for i := range projectflocks {
if projectflocks[i].FlockName != "" { if projectflocks[i].FlockName != "" {
baseName := pfutils.DeriveBaseName(projectflocks[i].FlockName) baseName := pfutils.DeriveBaseName(projectflocks[i].FlockName)
@@ -146,7 +146,7 @@ func (s projectflockService) GetAll(c *fiber.Ctx, params *validation.Query) ([]e
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
s.Log.Warnf("Failed to fetch flock %q: %+v", baseName, err) s.Log.Warnf("Failed to fetch flock %q: %+v", baseName, err)
} else if flock != nil { } else if flock != nil {
flockMap[projectflocks[i].Id] = &flockDTO.FlockBaseDTO{ flockMap[projectflocks[i].Id] = &flockDTO.FlockRelationDTO{
Id: flock.Id, Id: flock.Id,
Name: flock.Name, Name: flock.Name,
} }
@@ -187,7 +187,7 @@ func (s projectflockService) getOneEntityOnly(c *fiber.Ctx, id uint) (*entity.Pr
return projectflock, nil return projectflock, nil
} }
func (s projectflockService) GetOne(c *fiber.Ctx, id uint) (*entity.ProjectFlock, *flockDTO.FlockBaseDTO, error) { func (s projectflockService) GetOne(c *fiber.Ctx, id uint) (*entity.ProjectFlock, *flockDTO.FlockRelationDTO, error) {
projectflock, err := s.Repository.GetByID(c.Context(), id, s.Repository.WithDefaultRelations()) projectflock, err := s.Repository.GetByID(c.Context(), id, s.Repository.WithDefaultRelations())
if errors.Is(err, gorm.ErrRecordNotFound) { if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, nil, fiber.NewError(fiber.StatusNotFound, "Projectflock not found") return nil, nil, fiber.NewError(fiber.StatusNotFound, "Projectflock not found")
@@ -214,7 +214,7 @@ func (s projectflockService) GetOne(c *fiber.Ctx, id uint) (*entity.ProjectFlock
} }
// Fetch Flock master data for this ProjectFlock // Fetch Flock master data for this ProjectFlock
var flockResult *flockDTO.FlockBaseDTO var flockResult *flockDTO.FlockRelationDTO
if projectflock.FlockName != "" { if projectflock.FlockName != "" {
baseName := pfutils.DeriveBaseName(projectflock.FlockName) baseName := pfutils.DeriveBaseName(projectflock.FlockName)
if baseName != "" { if baseName != "" {
@@ -222,7 +222,7 @@ func (s projectflockService) GetOne(c *fiber.Ctx, id uint) (*entity.ProjectFlock
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
s.Log.Warnf("Failed to fetch flock %q: %+v", baseName, err) s.Log.Warnf("Failed to fetch flock %q: %+v", baseName, err)
} else if flock != nil { } else if flock != nil {
flockResult = &flockDTO.FlockBaseDTO{ flockResult = &flockDTO.FlockRelationDTO{
Id: flock.Id, Id: flock.Id,
Name: flock.Name, Name: flock.Name,
} }
@@ -15,30 +15,30 @@ import (
// === DTO Structs === // === DTO Structs ===
type RecordingBaseDTO struct { type RecordingRelationDTO struct {
Id uint `json:"id"` Id uint `json:"id"`
ProjectFlockKandangId uint `json:"project_flock_kandang_id"` ProjectFlockKandangId uint `json:"project_flock_kandang_id"`
RecordDatetime time.Time `json:"record_datetime"` RecordDatetime time.Time `json:"record_datetime"`
Day int `json:"day"` Day int `json:"day"`
ProjectFlockCategory string `json:"project_flock_category"` ProjectFlockCategory string `json:"project_flock_category"`
TotalDepletionQty float64 `json:"total_depletion_qty"` TotalDepletionQty float64 `json:"total_depletion_qty"`
CumDepletionRate float64 `json:"cum_depletion_rate"` CumDepletionRate float64 `json:"cum_depletion_rate"`
DailyGain float64 `json:"daily_gain"` DailyGain float64 `json:"daily_gain"`
AvgDailyGain float64 `json:"avg_daily_gain"` AvgDailyGain float64 `json:"avg_daily_gain"`
CumIntake int `json:"cum_intake"` CumIntake int `json:"cum_intake"`
FcrValue float64 `json:"fcr_value"` FcrValue float64 `json:"fcr_value"`
TotalChickQty float64 `json:"total_chick_qty"` TotalChickQty float64 `json:"total_chick_qty"`
Approval approvalDTO.ApprovalBaseDTO `json:"approval"` Approval approvalDTO.ApprovalRelationDTO `json:"approval"`
EggGradingStatus *string `json:"egg_grading_status"` EggGradingStatus *string `json:"egg_grading_status"`
EggGradingPendingQty *int `json:"egg_grading_pending_qty"` EggGradingPendingQty *int `json:"egg_grading_pending_qty"`
EggGradingCompletedQty *int `json:"egg_grading_completed_qty"` EggGradingCompletedQty *int `json:"egg_grading_completed_qty"`
} }
type RecordingListDTO struct { type RecordingListDTO struct {
RecordingBaseDTO RecordingRelationDTO
CreatedUser *userDTO.UserBaseDTO `json:"created_user"` CreatedUser *userDTO.UserRelationDTO `json:"created_user"`
CreatedAt time.Time `json:"created_at"` CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"` UpdatedAt time.Time `json:"updated_at"`
} }
type RecordingDetailDTO struct { type RecordingDetailDTO struct {
@@ -91,7 +91,7 @@ type RecordingEggGradingDTO struct {
// === Mapper Functions === // === Mapper Functions ===
func ToRecordingBaseDTO(e entity.Recording) RecordingBaseDTO { func ToRecordingRelationDTO(e entity.Recording) RecordingRelationDTO {
var ( var (
projectFlockCategory string projectFlockCategory string
day int day int
@@ -142,7 +142,7 @@ func ToRecordingBaseDTO(e entity.Recording) RecordingBaseDTO {
gradingStatus, gradingPending, gradingCompleted := computeEggGradingStatus(e) gradingStatus, gradingPending, gradingCompleted := computeEggGradingStatus(e)
return RecordingBaseDTO{ return RecordingRelationDTO{
Id: e.Id, Id: e.Id,
ProjectFlockKandangId: e.ProjectFlockKandangId, ProjectFlockKandangId: e.ProjectFlockKandangId,
RecordDatetime: e.RecordDatetime, RecordDatetime: e.RecordDatetime,
@@ -163,17 +163,17 @@ func ToRecordingBaseDTO(e entity.Recording) RecordingBaseDTO {
} }
func ToRecordingListDTO(e entity.Recording) RecordingListDTO { func ToRecordingListDTO(e entity.Recording) RecordingListDTO {
var createdUser *userDTO.UserBaseDTO var createdUser *userDTO.UserRelationDTO
if e.CreatedUser != nil && e.CreatedUser.Id != 0 { if e.CreatedUser != nil && e.CreatedUser.Id != 0 {
mapped := userDTO.ToUserBaseDTO(*e.CreatedUser) mapped := userDTO.ToUserRelationDTO(*e.CreatedUser)
createdUser = &mapped createdUser = &mapped
} }
return RecordingListDTO{ return RecordingListDTO{
RecordingBaseDTO: ToRecordingBaseDTO(e), RecordingRelationDTO: ToRecordingRelationDTO(e),
CreatedAt: e.CreatedAt, CreatedAt: e.CreatedAt,
UpdatedAt: e.UpdatedAt, UpdatedAt: e.UpdatedAt,
CreatedUser: createdUser, CreatedUser: createdUser,
} }
} }
@@ -344,8 +344,8 @@ func filterGoodEggs(eggs []entity.RecordingEgg) []entity.RecordingEgg {
return result return result
} }
func defaultRecordingLatestApproval(e entity.Recording) approvalDTO.ApprovalBaseDTO { func defaultRecordingLatestApproval(e entity.Recording) approvalDTO.ApprovalRelationDTO {
result := approvalDTO.ApprovalBaseDTO{} result := approvalDTO.ApprovalRelationDTO{}
step := utils.RecordingStepPengajuan step := utils.RecordingStepPengajuan
result.StepNumber = uint16(step) result.StepNumber = uint16(step)
@@ -356,9 +356,9 @@ func defaultRecordingLatestApproval(e entity.Recording) approvalDTO.ApprovalBase
} }
if e.CreatedUser != nil && e.CreatedUser.Id != 0 { if e.CreatedUser != nil && e.CreatedUser.Id != 0 {
result.ActionBy = userDTO.ToUserBaseDTO(*e.CreatedUser) result.ActionBy = userDTO.ToUserRelationDTO(*e.CreatedUser)
} else if e.CreatedBy != 0 { } else if e.CreatedBy != 0 {
result.ActionBy = userDTO.UserBaseDTO{ result.ActionBy = userDTO.UserRelationDTO{
Id: e.CreatedBy, Id: e.CreatedBy,
IdUser: int64(e.CreatedBy), IdUser: int64(e.CreatedBy),
} }
@@ -10,7 +10,7 @@ import (
// === DTO Structs === // === DTO Structs ===
type TransferLayingBaseDTO struct { type TransferLayingRelationDTO struct {
Id uint `json:"id"` Id uint `json:"id"`
TransferNumber string `json:"transfer_number"` TransferNumber string `json:"transfer_number"`
TransferDate time.Time `json:"transfer_date"` TransferDate time.Time `json:"transfer_date"`
@@ -64,22 +64,22 @@ type LayingTransferTargetDTO struct {
} }
type TransferLayingListDTO struct { type TransferLayingListDTO struct {
TransferLayingBaseDTO TransferLayingRelationDTO
FromProjectFlock *ProjectFlockSummaryDTO `json:"from_project_flock,omitempty"` FromProjectFlock *ProjectFlockSummaryDTO `json:"from_project_flock,omitempty"`
ToProjectFlock *ProjectFlockSummaryDTO `json:"to_project_flock,omitempty"` ToProjectFlock *ProjectFlockSummaryDTO `json:"to_project_flock,omitempty"`
PendingUsageQty *float64 `json:"pending_usage_qty"` PendingUsageQty *float64 `json:"pending_usage_qty"`
UsageQty *float64 `json:"usage_qty"` UsageQty *float64 `json:"usage_qty"`
CreatedBy uint `json:"created_by"` CreatedBy uint `json:"created_by"`
CreatedUser *userDTO.UserBaseDTO `json:"created_user,omitempty"` CreatedUser *userDTO.UserRelationDTO `json:"created_user,omitempty"`
CreatedAt time.Time `json:"created_at"` CreatedAt time.Time `json:"created_at"`
Approval *approvalDTO.ApprovalBaseDTO `json:"approval,omitempty"` Approval *approvalDTO.ApprovalRelationDTO `json:"approval,omitempty"`
} }
type TransferLayingDetailDTO struct { type TransferLayingDetailDTO struct {
TransferLayingListDTO TransferLayingListDTO
Sources []LayingTransferSourceDTO `json:"sources,omitempty"` Sources []LayingTransferSourceDTO `json:"sources,omitempty"`
Targets []LayingTransferTargetDTO `json:"targets,omitempty"` Targets []LayingTransferTargetDTO `json:"targets,omitempty"`
Approval *approvalDTO.ApprovalBaseDTO `json:"approval,omitempty"` Approval *approvalDTO.ApprovalRelationDTO `json:"approval,omitempty"`
} }
// === Available Quantity DTOs === // === Available Quantity DTOs ===
@@ -203,8 +203,8 @@ func ToLayingTransferTargetDTOs(targets []entity.LayingTransferTarget) []LayingT
return result return result
} }
func ToTransferLayingBaseDTO(e entity.LayingTransfer) TransferLayingBaseDTO { func ToTransferLayingRelationDTO(e entity.LayingTransfer) TransferLayingRelationDTO {
return TransferLayingBaseDTO{ return TransferLayingRelationDTO{
Id: e.Id, Id: e.Id,
TransferNumber: e.TransferNumber, TransferNumber: e.TransferNumber,
TransferDate: e.TransferDate, TransferDate: e.TransferDate,
@@ -213,26 +213,26 @@ func ToTransferLayingBaseDTO(e entity.LayingTransfer) TransferLayingBaseDTO {
} }
func ToTransferLayingListDTO(e entity.LayingTransfer) TransferLayingListDTO { func ToTransferLayingListDTO(e entity.LayingTransfer) TransferLayingListDTO {
var createdUser *userDTO.UserBaseDTO var createdUser *userDTO.UserRelationDTO
if e.CreatedUser != nil && e.CreatedUser.Id != 0 { if e.CreatedUser != nil && e.CreatedUser.Id != 0 {
mapped := userDTO.ToUserBaseDTO(*e.CreatedUser) mapped := userDTO.ToUserRelationDTO(*e.CreatedUser)
createdUser = &mapped createdUser = &mapped
} }
return TransferLayingListDTO{ return TransferLayingListDTO{
TransferLayingBaseDTO: ToTransferLayingBaseDTO(e), TransferLayingRelationDTO: ToTransferLayingRelationDTO(e),
FromProjectFlock: ToProjectFlockSummaryDTO(e.FromProjectFlock), FromProjectFlock: ToProjectFlockSummaryDTO(e.FromProjectFlock),
ToProjectFlock: ToProjectFlockSummaryDTO(e.ToProjectFlock), ToProjectFlock: ToProjectFlockSummaryDTO(e.ToProjectFlock),
PendingUsageQty: e.PendingUsageQty, PendingUsageQty: e.PendingUsageQty,
UsageQty: e.UsageQty, UsageQty: e.UsageQty,
CreatedBy: e.CreatedBy, CreatedBy: e.CreatedBy,
CreatedUser: createdUser, CreatedUser: createdUser,
CreatedAt: e.CreatedAt, CreatedAt: e.CreatedAt,
} }
} }
func ToTransferLayingDetailDTO(e entity.LayingTransfer, approvals []entity.Approval) TransferLayingDetailDTO { func ToTransferLayingDetailDTO(e entity.LayingTransfer, approvals []entity.Approval) TransferLayingDetailDTO {
var latestApproval *approvalDTO.ApprovalBaseDTO var latestApproval *approvalDTO.ApprovalRelationDTO
if e.LatestApproval != nil { if e.LatestApproval != nil {
mapped := approvalDTO.ToApprovalDTO(*e.LatestApproval) mapped := approvalDTO.ToApprovalDTO(*e.LatestApproval)
@@ -252,7 +252,7 @@ func ToTransferLayingDetailDTO(e entity.LayingTransfer, approvals []entity.Appro
} }
func ToTransferLayingDetailDTOWithSingleApproval(e entity.LayingTransfer, approval *entity.Approval) TransferLayingDetailDTO { func ToTransferLayingDetailDTOWithSingleApproval(e entity.LayingTransfer, approval *entity.Approval) TransferLayingDetailDTO {
var mappedApproval *approvalDTO.ApprovalBaseDTO var mappedApproval *approvalDTO.ApprovalRelationDTO
// Prefer LatestApproval from entity // Prefer LatestApproval from entity
if e.LatestApproval != nil && e.LatestApproval.Id != 0 { if e.LatestApproval != nil && e.LatestApproval.Id != 0 {
+47 -47
View File
@@ -13,52 +13,52 @@ import (
) )
type PurchaseListItemDTO struct { type PurchaseListItemDTO struct {
Id uint64 `json:"id"` Id uint64 `json:"id"`
PrNumber string `json:"pr_number"` PrNumber string `json:"pr_number"`
PoNumber *string `json:"po_number"` PoNumber *string `json:"po_number"`
Supplier *supplierDTO.SupplierBaseDTO `json:"supplier"` Supplier *supplierDTO.SupplierRelationDTO `json:"supplier"`
CreditTerm *int `json:"credit_term"` CreditTerm *int `json:"credit_term"`
DueDate *time.Time `json:"due_date"` DueDate *time.Time `json:"due_date"`
PoDate *time.Time `json:"po_date"` PoDate *time.Time `json:"po_date"`
GrandTotal float64 `json:"grand_total"` GrandTotal float64 `json:"grand_total"`
Notes *string `json:"notes"` Notes *string `json:"notes"`
CreatedAt time.Time `json:"created_at"` CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"` UpdatedAt time.Time `json:"updated_at"`
Approval *approvalDTO.ApprovalBaseDTO `json:"approval"` Approval *approvalDTO.ApprovalRelationDTO `json:"approval"`
} }
type PurchaseDetailDTO struct { type PurchaseDetailDTO struct {
Id uint64 `json:"id"` Id uint64 `json:"id"`
PrNumber string `json:"pr_number"` PrNumber string `json:"pr_number"`
PoNumber *string `json:"po_number"` PoNumber *string `json:"po_number"`
Supplier *supplierDTO.SupplierBaseDTO `json:"supplier"` Supplier *supplierDTO.SupplierRelationDTO `json:"supplier"`
CreditTerm *int `json:"credit_term"` CreditTerm *int `json:"credit_term"`
DueDate *time.Time `json:"due_date"` DueDate *time.Time `json:"due_date"`
PoDate *time.Time `json:"po_date"` PoDate *time.Time `json:"po_date"`
GrandTotal float64 `json:"grand_total"` GrandTotal float64 `json:"grand_total"`
Notes *string `json:"notes"` Notes *string `json:"notes"`
Items []PurchaseItemDTO `json:"items"` Items []PurchaseItemDTO `json:"items"`
CreatedAt time.Time `json:"created_at"` CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"` UpdatedAt time.Time `json:"updated_at"`
Approval *approvalDTO.ApprovalBaseDTO `json:"approval"` Approval *approvalDTO.ApprovalRelationDTO `json:"approval"`
} }
type PurchaseItemDTO struct { type PurchaseItemDTO struct {
Id uint64 `json:"id"` Id uint64 `json:"id"`
ProductID uint64 `json:"product_id"` ProductID uint64 `json:"product_id"`
Product *productDTO.ProductBaseDTO `json:"product"` Product *productDTO.ProductRelationDTO `json:"product"`
WarehouseID uint64 `json:"warehouse_id"` WarehouseID uint64 `json:"warehouse_id"`
Warehouse *warehouseDTO.WarehouseBaseDTO `json:"warehouse"` Warehouse *warehouseDTO.WarehouseRelationDTO `json:"warehouse"`
ProductWarehouseID *uint64 `json:"product_warehouse_id"` ProductWarehouseID *uint64 `json:"product_warehouse_id"`
SubQty float64 `json:"sub_qty"` SubQty float64 `json:"sub_qty"`
TotalQty float64 `json:"total_qty"` TotalQty float64 `json:"total_qty"`
TotalUsed float64 `json:"total_used"` TotalUsed float64 `json:"total_used"`
Price float64 `json:"price"` Price float64 `json:"price"`
TotalPrice float64 `json:"total_price"` TotalPrice float64 `json:"total_price"`
ReceivedDate *time.Time `json:"received_date"` ReceivedDate *time.Time `json:"received_date"`
TravelNumber *string `json:"travel_number"` TravelNumber *string `json:"travel_number"`
TravelDocumentPath *string `json:"travel_document_path"` TravelDocumentPath *string `json:"travel_document_path"`
VehicleNumber *string `json:"vehicle_number"` VehicleNumber *string `json:"vehicle_number"`
} }
func ToPurchaseItemDTO(item entity.PurchaseItem) PurchaseItemDTO { func ToPurchaseItemDTO(item entity.PurchaseItem) PurchaseItemDTO {
@@ -78,17 +78,17 @@ func ToPurchaseItemDTO(item entity.PurchaseItem) PurchaseItemDTO {
VehicleNumber: item.VehicleNumber, VehicleNumber: item.VehicleNumber,
} }
if item.Product != nil && item.Product.Id != 0 { if item.Product != nil && item.Product.Id != 0 {
summary := productDTO.ToProductBaseDTO(*item.Product) summary := productDTO.ToProductRelationDTO(*item.Product)
dto.Product = &summary dto.Product = &summary
} }
if item.Warehouse != nil && item.Warehouse.Id != 0 { if item.Warehouse != nil && item.Warehouse.Id != 0 {
summary := warehouseDTO.ToWarehouseBaseDTO(*item.Warehouse) summary := warehouseDTO.ToWarehouseRelationDTO(*item.Warehouse)
if item.Warehouse.Area.Id != 0 { if item.Warehouse.Area.Id != 0 {
areaSummary := areaDTO.ToAreaBaseDTO(item.Warehouse.Area) areaSummary := areaDTO.ToAreaRelationDTO(item.Warehouse.Area)
summary.Area = &areaSummary summary.Area = &areaSummary
} }
if item.Warehouse.Location != nil && item.Warehouse.Location.Id != 0 { if item.Warehouse.Location != nil && item.Warehouse.Location.Id != 0 {
locationSummary := locationDTO.ToLocationBaseDTO(*item.Warehouse.Location) locationSummary := locationDTO.ToLocationRelationDTO(*item.Warehouse.Location)
summary.Location = &locationSummary summary.Location = &locationSummary
} }
dto.Warehouse = &summary dto.Warehouse = &summary
@@ -145,11 +145,11 @@ func ToPurchaseListDTO(p entity.Purchase) PurchaseListItemDTO {
return dto return dto
} }
func mapSupplier(s entity.Supplier) *supplierDTO.SupplierBaseDTO { func mapSupplier(s entity.Supplier) *supplierDTO.SupplierRelationDTO {
if s.Id == 0 { if s.Id == 0 {
return nil return nil
} }
summary := supplierDTO.ToSupplierBaseDTO(s) summary := supplierDTO.ToSupplierRelationDTO(s)
return &summary return &summary
} }
@@ -164,7 +164,7 @@ func ToPurchaseListDTOs(items []entity.Purchase) []PurchaseListItemDTO {
return result return result
} }
func toPurchaseApprovalDTO(p entity.Purchase) *approvalDTO.ApprovalBaseDTO { func toPurchaseApprovalDTO(p entity.Purchase) *approvalDTO.ApprovalRelationDTO {
if p.LatestApproval == nil || p.LatestApproval.Id == 0 { if p.LatestApproval == nil || p.LatestApproval.Id == 0 {
return nil return nil
} }
+7 -7
View File
@@ -8,7 +8,7 @@ import (
// === DTO Structs === // === DTO Structs ===
type UserBaseDTO struct { type UserRelationDTO struct {
Id uint `json:"id"` Id uint `json:"id"`
IdUser int64 `json:"id_user"` IdUser int64 `json:"id_user"`
Email string `json:"email"` Email string `json:"email"`
@@ -16,7 +16,7 @@ type UserBaseDTO struct {
} }
type UserListDTO struct { type UserListDTO struct {
UserBaseDTO UserRelationDTO
CreatedAt time.Time `json:"created_at"` CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"` UpdatedAt time.Time `json:"updated_at"`
} }
@@ -27,8 +27,8 @@ type UserDetailDTO struct {
// === Mapper Functions === // === Mapper Functions ===
func ToUserBaseDTO(m entity.User) UserBaseDTO { func ToUserRelationDTO(m entity.User) UserRelationDTO {
return UserBaseDTO{ return UserRelationDTO{
Id: m.Id, Id: m.Id,
IdUser: m.IdUser, IdUser: m.IdUser,
Email: m.Email, Email: m.Email,
@@ -38,9 +38,9 @@ func ToUserBaseDTO(m entity.User) UserBaseDTO {
func ToUserListDTO(m entity.User) UserListDTO { func ToUserListDTO(m entity.User) UserListDTO {
return UserListDTO{ return UserListDTO{
UserBaseDTO: ToUserBaseDTO(m), UserRelationDTO: ToUserRelationDTO(m),
CreatedAt: m.CreatedAt, CreatedAt: m.CreatedAt,
UpdatedAt: m.UpdatedAt, UpdatedAt: m.UpdatedAt,
} }
} }
-27
View File
@@ -1,27 +0,0 @@
package test
import (
"net/http"
"testing"
"github.com/gofiber/fiber/v2"
)
func TestAreaIntegration(t *testing.T) {
app, db := setupIntegrationApp(t)
t.Run("create area trims name", func(t *testing.T) {
areaID := createArea(t, app, " Area Trim ")
if got := fetchAreaName(t, db, areaID); got != "Area Trim" {
t.Fatalf("expected trimmed name, got %q", got)
}
})
t.Run("duplicate area returns conflict", func(t *testing.T) {
createArea(t, app, "Duplicate Area")
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/areas", map[string]any{"name": "Duplicate Area"})
if resp.StatusCode != fiber.StatusConflict {
t.Fatalf("expected 409 conflict, got %d: %s", resp.StatusCode, string(body))
}
})
}
-127
View File
@@ -1,127 +0,0 @@
package test
import (
"encoding/json"
"errors"
"fmt"
"net/http"
"testing"
"github.com/gofiber/fiber/v2"
"gorm.io/gorm"
"gitlab.com/mbugroup/lti-api.git/internal/entities"
)
func TestBankIntegration(t *testing.T) {
app, db := setupIntegrationApp(t)
const bankAlias = "BNI"
const bankName = "Bank Negara Indonesia"
const bankOwner = "John Doe"
const bankAccountNumber = "1234567890"
var bankID uint
t.Run("creating bank succeeds", func(t *testing.T) {
bankID = createBank(t, app, bankName, bankAlias, bankAccountNumber, bankOwner)
bank := fetchBank(t, db, bankID)
if bank.Alias != bankAlias {
t.Fatalf("expected alias %q, got %q", bankAlias, bank.Alias)
}
if bank.AccountNumber != bankAccountNumber {
t.Fatalf("expected account number %q, got %q", bankAccountNumber, bank.AccountNumber)
}
})
t.Run("creating bank with duplicate name fails", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/banks", map[string]any{
"name": bankName,
"alias": "NEWALIAS",
"owner": "Owner Name",
"account_number": "1122334455",
})
if resp.StatusCode != fiber.StatusConflict {
t.Fatalf("expected 409 when creating duplicate bank name, got %d: %s", resp.StatusCode, string(body))
}
})
t.Run("getting existing bank succeeds", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodGet, fmt.Sprintf("/api/master-data/banks/%d", bankID), nil)
if resp.StatusCode != fiber.StatusOK {
t.Fatalf("expected 200 when fetching bank, got %d: %s", resp.StatusCode, string(body))
}
var payload struct {
Data struct {
Id uint `json:"id"`
Name string `json:"name"`
Alias string `json:"alias"`
AccountNumber string `json:"account_number"`
} `json:"data"`
}
if err := json.Unmarshal(body, &payload); err != nil {
t.Fatalf("failed to parse response: %v", err)
}
if payload.Data.Id != bankID {
t.Fatalf("expected id %d, got %d", bankID, payload.Data.Id)
}
if payload.Data.Alias != bankAlias {
t.Fatalf("expected alias %q, got %q", bankAlias, payload.Data.Alias)
}
if payload.Data.AccountNumber != bankAccountNumber {
t.Fatalf("expected account number %q, got %q", bankAccountNumber, payload.Data.AccountNumber)
}
})
const updatedName = "BNI Updated"
t.Run("updating bank name succeeds", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodPatch, fmt.Sprintf("/api/master-data/banks/%d", bankID), map[string]any{
"name": updatedName,
})
if resp.StatusCode != fiber.StatusOK {
t.Fatalf("expected 200 when updating bank, got %d: %s", resp.StatusCode, string(body))
}
var payload struct {
Data struct {
Name string `json:"name"`
} `json:"data"`
}
if err := json.Unmarshal(body, &payload); err != nil {
t.Fatalf("failed to parse response: %v", err)
}
if payload.Data.Name != updatedName {
t.Fatalf("expected updated name %q, got %q", updatedName, payload.Data.Name)
}
bank := fetchBank(t, db, bankID)
if bank.Name != updatedName {
t.Fatalf("expected persisted name %q, got %q", updatedName, bank.Name)
}
})
t.Run("updating non existent bank returns 404", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodPatch, "/api/master-data/banks/9999", map[string]any{
"name": "Does Not Matter",
})
if resp.StatusCode != fiber.StatusNotFound {
t.Fatalf("expected 404 when updating missing bank, got %d: %s", resp.StatusCode, string(body))
}
})
t.Run("deleting bank succeeds", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodDelete, fmt.Sprintf("/api/master-data/banks/%d", bankID), nil)
if resp.StatusCode != fiber.StatusOK {
t.Fatalf("expected 200 when deleting bank, got %d: %s", resp.StatusCode, string(body))
}
var bank entities.Bank
if err := db.First(&bank, bankID).Error; !errors.Is(err, gorm.ErrRecordNotFound) {
t.Fatalf("expected bank to be deleted, got error %v", err)
}
})
t.Run("deleting non existent bank returns 404", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodDelete, fmt.Sprintf("/api/master-data/banks/%d", bankID), nil)
if resp.StatusCode != fiber.StatusNotFound {
t.Fatalf("expected 404 when deleting missing bank, got %d: %s", resp.StatusCode, string(body))
}
})
}
@@ -1,189 +0,0 @@
package test
import (
"encoding/json"
"errors"
"fmt"
"net/http"
"testing"
"github.com/gofiber/fiber/v2"
"gorm.io/gorm"
"gitlab.com/mbugroup/lti-api.git/internal/entities"
"gitlab.com/mbugroup/lti-api.git/internal/utils"
)
func TestCustomerIntegration(t *testing.T) {
app, db := setupIntegrationApp(t)
t.Run("creating customer without existing pic fails", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/customers", map[string]any{
"name": "Invalid Customer",
"pic_id": 9999,
"type": utils.CustomerSupplierTypeBisnis,
"address": "Somewhere",
"phone": "0800000000",
"email": "Invalid@example.com",
"account_number": "ACC-INVALID",
})
if resp.StatusCode != fiber.StatusNotFound {
t.Fatalf("expected 404 when pic is missing, got %d: %s", resp.StatusCode, string(body))
}
})
t.Run("creating customer with Invalid type fails", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/customers", map[string]any{
"name": "Invalid Type",
"pic_id": 1,
"type": "UNKNOWN",
"address": "Somewhere",
"phone": "081234567891",
"email": "Invalid-type@example.com",
"account_number": "ACC-INVALID-TYPE",
})
if resp.StatusCode != fiber.StatusBadRequest {
t.Fatalf("expected 400 when type is Invalid, got %d: %s", resp.StatusCode, string(body))
}
})
const customerName = "Customer Alpha"
var customerID uint
t.Run("creating customer succeeds", func(t *testing.T) {
customerID = createCustomer(t, app, customerName, 1)
customer := fetchCustomer(t, db, customerID)
if customer.Name != customerName {
t.Fatalf("expected name %q, got %q", customerName, customer.Name)
}
if customer.PicId != 1 {
t.Fatalf("expected pic id 1, got %d", customer.PicId)
}
if customer.Type != string(utils.CustomerSupplierTypeBisnis) {
t.Fatalf("expected type %q, got %q", utils.CustomerSupplierTypeBisnis, customer.Type)
}
})
t.Run("creating customer with duplicate name fails", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/customers", map[string]any{
"name": customerName,
"pic_id": 1,
"type": utils.CustomerSupplierTypeBisnis,
"address": "Duplicate address",
"phone": "0811111111",
"email": "duplicate@example.com",
"account_number": "ACC-DUP",
})
if resp.StatusCode != fiber.StatusConflict {
t.Fatalf("expected 409 when creating duplicate customer, got %d: %s", resp.StatusCode, string(body))
}
})
t.Run("getting existing customer succeeds", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodGet, fmt.Sprintf("/api/master-data/customers/%d", customerID), nil)
if resp.StatusCode != fiber.StatusOK {
t.Fatalf("expected 200 when fetching customer, got %d: %s", resp.StatusCode, string(body))
}
var payload struct {
Data struct {
Id uint `json:"id"`
Name string `json:"name"`
} `json:"data"`
}
if err := json.Unmarshal(body, &payload); err != nil {
t.Fatalf("failed to parse customer response: %v", err)
}
if payload.Data.Id != customerID {
t.Fatalf("expected id %d, got %d", customerID, payload.Data.Id)
}
if payload.Data.Name != customerName {
t.Fatalf("expected name %q, got %q", customerName, payload.Data.Name)
}
})
const updatedName = "Customer Gamma"
t.Run("updating customer name succeeds", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodPatch, fmt.Sprintf("/api/master-data/customers/%d", customerID), map[string]any{
"name": updatedName,
})
if resp.StatusCode != fiber.StatusOK {
t.Fatalf("expected 200 when updating customer, got %d: %s", resp.StatusCode, string(body))
}
var payload struct {
Data struct {
Name string `json:"name"`
} `json:"data"`
}
if err := json.Unmarshal(body, &payload); err != nil {
t.Fatalf("failed to parse update response: %v", err)
}
if payload.Data.Name != updatedName {
t.Fatalf("expected updated name %q, got %q", updatedName, payload.Data.Name)
}
customer := fetchCustomer(t, db, customerID)
if customer.Name != updatedName {
t.Fatalf("expected persisted name %q, got %q", updatedName, customer.Name)
}
})
t.Run("updating customer type succeeds", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodPatch, fmt.Sprintf("/api/master-data/customers/%d", customerID), map[string]any{
"type": utils.CustomerSupplierTypeIndividual,
})
if resp.StatusCode != fiber.StatusOK {
t.Fatalf("expected 200 when updating customer type, got %d: %s", resp.StatusCode, string(body))
}
customer := fetchCustomer(t, db, customerID)
if customer.Type != string(utils.CustomerSupplierTypeIndividual) {
t.Fatalf("expected persisted type %q, got %q", utils.CustomerSupplierTypeIndividual, customer.Type)
}
})
t.Run("updating customer with Invalid type fails", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodPatch, fmt.Sprintf("/api/master-data/customers/%d", customerID), map[string]any{
"type": "random-type",
})
if resp.StatusCode != fiber.StatusBadRequest {
t.Fatalf("expected 400 when updating with Invalid type, got %d: %s", resp.StatusCode, string(body))
}
customer := fetchCustomer(t, db, customerID)
if customer.Type != string(utils.CustomerSupplierTypeIndividual) {
t.Fatalf("expected type to remain %q after Invalid update, got %q", utils.CustomerSupplierTypeIndividual, customer.Type)
}
})
t.Run("updating non existent customer returns 404", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodPatch, "/api/master-data/customers/9999", map[string]any{
"name": "Does Not Matter",
})
if resp.StatusCode != fiber.StatusNotFound {
t.Fatalf("expected 404 when updating missing customer, got %d: %s", resp.StatusCode, string(body))
}
})
t.Run("deleting customer succeeds", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodDelete, fmt.Sprintf("/api/master-data/customers/%d", customerID), nil)
if resp.StatusCode != fiber.StatusOK {
t.Fatalf("expected 200 when deleting customer, got %d: %s", resp.StatusCode, string(body))
}
var customer entities.Customer
if err := db.First(&customer, customerID).Error; !errors.Is(err, gorm.ErrRecordNotFound) {
t.Fatalf("expected customer to be deleted, got error %v", err)
}
})
t.Run("deleting non existent customer returns 404", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodDelete, fmt.Sprintf("/api/master-data/customers/%d", customerID), nil)
if resp.StatusCode != fiber.StatusNotFound {
t.Fatalf("expected 404 when deleting missing customer, got %d: %s", resp.StatusCode, string(body))
}
})
t.Run("getting deleted customer returns 404", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodGet, fmt.Sprintf("/api/master-data/customers/%d", customerID), nil)
if resp.StatusCode != fiber.StatusNotFound {
t.Fatalf("expected 404 when fetching deleted customer, got %d: %s", resp.StatusCode, string(body))
}
})
}
-218
View File
@@ -1,218 +0,0 @@
package test
import (
"encoding/json"
"errors"
"fmt"
"net/http"
"testing"
"github.com/gofiber/fiber/v2"
"gorm.io/gorm"
"gitlab.com/mbugroup/lti-api.git/internal/entities"
)
func TestFcrIntegration(t *testing.T) {
app, db := setupIntegrationApp(t)
t.Run("creating fcr without standards fails", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/fcrs", map[string]any{
"name": "FCR Alpha",
})
if resp.StatusCode != fiber.StatusBadRequest {
t.Fatalf("expected 400 when standards missing, got %d: %s", resp.StatusCode, string(body))
}
})
initialStandards := []map[string]any{
{
"weight": 7.2,
"fcr_number": 400.0,
"mortality": 12.0,
},
{
"weight": 7.4,
"fcr_number": 410.0,
"mortality": 11.5,
},
}
var fcrID uint
t.Run("creating fcr succeeds", func(t *testing.T) {
fcrID = createFcr(t, app, "FCR Layer", initialStandards)
fcr := fetchFcr(t, db, fcrID)
if fcr.Name != "FCR Layer" {
t.Fatalf("expected name FCR Layer, got %q", fcr.Name)
}
if len(fcr.Standards) != len(initialStandards) {
t.Fatalf("expected %d standards, got %d", len(initialStandards), len(fcr.Standards))
}
if fcr.CreatedBy != 1 {
t.Fatalf("expected created_by 1, got %d", fcr.CreatedBy)
}
})
t.Run("creating duplicate fcr name fails", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/fcrs", map[string]any{
"name": "FCR Layer",
"fcr_standards": initialStandards,
})
if resp.StatusCode != fiber.StatusConflict {
t.Fatalf("expected 409 when creating duplicate, got %d: %s", resp.StatusCode, string(body))
}
})
t.Run("getting fcr detail succeeds", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodGet, fmt.Sprintf("/api/master-data/fcrs/%d", fcrID), nil)
if resp.StatusCode != fiber.StatusOK {
t.Fatalf("expected 200 when fetching fcr, got %d: %s", resp.StatusCode, string(body))
}
var payload struct {
Data struct {
Id uint `json:"id"`
Name string `json:"name"`
FcrStandards []map[string]any `json:"fcr_standards"`
} `json:"data"`
}
if err := json.Unmarshal(body, &payload); err != nil {
t.Fatalf("failed to parse fcr detail: %v", err)
}
if payload.Data.Id != fcrID {
t.Fatalf("expected id %d, got %d", fcrID, payload.Data.Id)
}
if len(payload.Data.FcrStandards) != len(initialStandards) {
t.Fatalf("expected %d standards in response, got %d", len(initialStandards), len(payload.Data.FcrStandards))
}
})
updatedStandards := []map[string]any{
{
"weight": 7.2,
"fcr_number": 395.0,
"mortality": 10.0,
},
{
"weight": 7.5,
"fcr_number": 420.0,
"mortality": 13.0,
},
}
t.Run("updating fcr name and standards succeeds", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodPatch, fmt.Sprintf("/api/master-data/fcrs/%d", fcrID), map[string]any{
"name": "FCR Layer Updated",
"fcr_standards": updatedStandards,
})
if resp.StatusCode != fiber.StatusOK {
t.Fatalf("expected 200 when updating fcr, got %d: %s", resp.StatusCode, string(body))
}
var payload struct {
Data struct {
Name string `json:"name"`
FcrStandards []map[string]any `json:"fcr_standards"`
} `json:"data"`
}
if err := json.Unmarshal(body, &payload); err != nil {
t.Fatalf("failed to parse update response: %v", err)
}
if payload.Data.Name != "FCR Layer Updated" {
t.Fatalf("expected updated name, got %q", payload.Data.Name)
}
if len(payload.Data.FcrStandards) != len(updatedStandards) {
t.Fatalf("expected %d standards after update, got %d", len(updatedStandards), len(payload.Data.FcrStandards))
}
fcr := fetchFcr(t, db, fcrID)
if fcr.Name != "FCR Layer Updated" {
t.Fatalf("expected persisted name FCR Layer Updated, got %q", fcr.Name)
}
if len(fcr.Standards) != len(updatedStandards) {
t.Fatalf("expected %d persisted standards, got %d", len(updatedStandards), len(fcr.Standards))
}
if fcr.Standards[0].FcrNumber != 395.0 {
t.Fatalf("expected first standard fcr_number 395, got %f", fcr.Standards[0].FcrNumber)
}
})
var otherFcrID uint
t.Run("creating another fcr for duplicate update", func(t *testing.T) {
otherFcrID = createFcr(t, app, "FCR Grower", []map[string]any{
{
"weight": 8.0,
"fcr_number": 430.0,
"mortality": 9.0,
},
})
if otherFcrID == 0 {
t.Fatal("expected other fcr id to be non zero")
}
})
t.Run("updating fcr with duplicate name fails", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodPatch, fmt.Sprintf("/api/master-data/fcrs/%d", fcrID), map[string]any{
"name": "FCR Grower",
})
if resp.StatusCode != fiber.StatusConflict {
t.Fatalf("expected 409 when renaming to existing fcr, got %d: %s", resp.StatusCode, string(body))
}
fcr := fetchFcr(t, db, fcrID)
if fcr.Name != "FCR Layer Updated" {
t.Fatalf("expected name unchanged after failed update, got %q", fcr.Name)
}
})
t.Run("updating fcr with invalid standards fails", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodPatch, fmt.Sprintf("/api/master-data/fcrs/%d", fcrID), map[string]any{
"fcr_standards": []map[string]any{
{
"weight": -1,
"fcr_number": 300,
"mortality": 5,
},
},
})
if resp.StatusCode != fiber.StatusBadRequest {
t.Fatalf("expected 400 when updating with invalid standard, got %d: %s", resp.StatusCode, string(body))
}
})
t.Run("deleting fcr succeeds", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodDelete, fmt.Sprintf("/api/master-data/fcrs/%d", fcrID), nil)
if resp.StatusCode != fiber.StatusOK {
t.Fatalf("expected 200 when deleting fcr, got %d: %s", resp.StatusCode, string(body))
}
var fcr entities.Fcr
if err := db.First(&fcr, fcrID).Error; !errors.Is(err, gorm.ErrRecordNotFound) {
t.Fatalf("expected fcr to be deleted, got error %v", err)
}
var standardsCount int64
if err := db.Model(&entities.FcrStandard{}).Where("fcr_id = ?", fcrID).Count(&standardsCount).Error; err != nil {
t.Fatalf("failed counting standards: %v", err)
}
if standardsCount != 0 {
t.Fatalf("expected standards removed, found %d", standardsCount)
}
})
t.Run("deleting fcr again returns 404", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodDelete, fmt.Sprintf("/api/master-data/fcrs/%d", fcrID), nil)
if resp.StatusCode != fiber.StatusNotFound {
t.Fatalf("expected 404 when deleting missing fcr, got %d: %s", resp.StatusCode, string(body))
}
})
t.Run("getting deleted fcr returns 404", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodGet, fmt.Sprintf("/api/master-data/fcrs/%d", fcrID), nil)
if resp.StatusCode != fiber.StatusNotFound {
t.Fatalf("expected 404 when fetching deleted fcr, got %d: %s", resp.StatusCode, string(body))
}
})
t.Run("cleanup other fcr", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodDelete, fmt.Sprintf("/api/master-data/fcrs/%d", otherFcrID), nil)
if resp.StatusCode != fiber.StatusOK {
t.Fatalf("expected 200 when deleting other fcr, got %d: %s", resp.StatusCode, string(body))
}
})
}
@@ -1,96 +0,0 @@
package test
import (
"encoding/json"
"fmt"
"net/http"
"testing"
"github.com/gofiber/fiber/v2"
"gitlab.com/mbugroup/lti-api.git/internal/entities"
"gitlab.com/mbugroup/lti-api.git/internal/utils"
)
func TestKandangIntegration(t *testing.T) {
app, db := setupIntegrationApp(t)
areaID := createArea(t, app, "Area Kandang")
locationID := createLocation(t, app, "Location For Kandang", "Address", areaID)
t.Run("create kandang success", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/kandangs", map[string]any{
"name": "Kandang OK",
"location_id": locationID,
"pic_id": 1,
})
if resp.StatusCode != fiber.StatusCreated {
t.Fatalf("expected 201, got %d: %s", resp.StatusCode, string(body))
}
var createResp struct {
Data struct {
Status string `json:"status"`
} `json:"data"`
}
if err := json.Unmarshal(body, &createResp); err != nil {
t.Fatalf("failed to parse create response: %v", err)
}
if createResp.Data.Status == "" {
t.Fatalf("expected default status to be returned, got empty")
}
})
t.Run("create kandang with unknown location fails", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/kandangs", map[string]any{
"name": "Kandang Fail",
"status": "ACTIVE",
"location_id": 999,
"pic_id": 1,
})
if resp.StatusCode != fiber.StatusNotFound {
t.Fatalf("expected 404, got %d: %s", resp.StatusCode, string(body))
}
})
t.Run("cannot assign project floc with existing active kandang", func(t *testing.T) {
fcrID := createFcr(t, app, "FCR For Floc", []map[string]any{
{"weight": 1.0, "fcr_number": 1.5, "mortality": 2.0},
})
flocID := createFlock(t, app, "Floc Test")
projectFloc := entities.ProjectFlock{
FlockName: fmt.Sprintf("Project Flock %d", flocID),
AreaId: areaID,
Category: string(utils.ProjectFlockCategoryGrowing),
FcrId: fcrID,
LocationId: locationID,
Period: 1,
CreatedBy: 1,
}
if err := db.Create(&projectFloc).Error; err != nil {
t.Fatalf("failed to seed project floc: %v", err)
}
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/kandangs", map[string]any{
"name": "Kandang Active 1",
"status": "ACTIVE",
"location_id": locationID,
"pic_id": 1,
"project_flock_id": projectFloc.Id,
})
if resp.StatusCode != fiber.StatusCreated {
t.Fatalf("expected 201 when creating first kandang, got %d: %s", resp.StatusCode, string(body))
}
resp, body = doJSONRequest(t, app, http.MethodPost, "/api/master-data/kandangs", map[string]any{
"name": "Kandang Active 2",
"status": "ACTIVE",
"location_id": locationID,
"pic_id": 1,
"project_flock_id": projectFloc.Id,
})
if resp.StatusCode != fiber.StatusConflict {
t.Fatalf("expected 409 when creating second active kandang, got %d: %s", resp.StatusCode, string(body))
}
})
}
@@ -1,35 +0,0 @@
package test
import (
"net/http"
"testing"
"github.com/gofiber/fiber/v2"
)
func TestLocationIntegration(t *testing.T) {
app, _ := setupIntegrationApp(t)
t.Run("creating location without existing area fails", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/locations", map[string]any{
"name": "Loc A",
"address": "Address",
"area_id": 999, // non-existent
})
if resp.StatusCode != fiber.StatusNotFound {
t.Fatalf("expected 404, got %d: %s", resp.StatusCode, string(body))
}
})
t.Run("creating location succeeds", func(t *testing.T) {
areaID := createArea(t, app, "Area For Location")
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/locations", map[string]any{
"name": "Location OK",
"address": "Addr",
"area_id": areaID,
})
if resp.StatusCode != fiber.StatusCreated {
t.Fatalf("expected 201, got %d: %s", resp.StatusCode, string(body))
}
})
}
-401
View File
@@ -1,401 +0,0 @@
package test
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"net/http/httptest"
"path/filepath"
"strings"
"testing"
"time"
"github.com/glebarez/sqlite"
"github.com/gofiber/fiber/v2"
"gorm.io/gorm"
"gorm.io/gorm/logger"
"gitlab.com/mbugroup/lti-api.git/internal/entities"
"gitlab.com/mbugroup/lti-api.git/internal/route"
"gitlab.com/mbugroup/lti-api.git/internal/utils"
)
func setupIntegrationApp(t *testing.T) (*fiber.App, *gorm.DB) {
t.Helper()
dir := t.TempDir()
dsn := filepath.Join(dir, "integration.db")
db, err := gorm.Open(sqlite.Open(dsn), &gorm.Config{Logger: logger.Default.LogMode(logger.Silent)})
if err != nil {
t.Fatalf("failed to open sqlite database: %v", err)
}
if err := db.Exec("PRAGMA foreign_keys = ON").Error; err != nil {
t.Fatalf("failed to enable foreign keys: %v", err)
}
if err := db.AutoMigrate(
&entities.User{},
&entities.Area{},
&entities.Location{},
&entities.Flock{},
&entities.ProjectFlock{},
&entities.ProjectFlockKandang{},
&entities.Kandang{},
&entities.Warehouse{},
&entities.Uom{},
&entities.Customer{},
&entities.Supplier{},
&entities.Flag{},
&entities.ProductCategory{},
&entities.Nonstock{},
&entities.NonstockSupplier{},
&entities.Product{},
&entities.ProductSupplier{},
&entities.Fcr{},
&entities.FcrStandard{},
&entities.Bank{},
); err != nil {
t.Fatalf("auto migrate failed: %v", err)
}
seedUser := entities.User{
Id: 1,
IdUser: 1001,
Email: "tester@example.com",
Name: "Tester",
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
}
if err := db.Create(&seedUser).Error; err != nil {
t.Fatalf("failed to seed user: %v", err)
}
app := fiber.New(fiber.Config{ErrorHandler: utils.ErrorHandler})
route.Routes(app, db)
return app, db
}
func doJSONRequest(t *testing.T, app *fiber.App, method, path string, payload any) (*http.Response, []byte) {
t.Helper()
var body io.Reader
if payload != nil {
buf := &bytes.Buffer{}
if err := json.NewEncoder(buf).Encode(payload); err != nil {
t.Fatalf("failed to encode payload: %v", err)
}
body = buf
}
req := httptest.NewRequest(method, path, body)
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Accept", "application/json")
resp, err := app.Test(req, -1)
if err != nil {
t.Fatalf("request failed: %v", err)
}
defer resp.Body.Close()
data, err := io.ReadAll(resp.Body)
if err != nil {
t.Fatalf("failed to read response body: %v", err)
}
return resp, data
}
func parseID(t *testing.T, body []byte) uint {
t.Helper()
var resp struct {
Data struct {
Id uint `json:"id"`
} `json:"data"`
}
if err := json.Unmarshal(body, &resp); err != nil {
t.Fatalf("failed to parse response: %v", err)
}
return resp.Data.Id
}
func createArea(t *testing.T, app *fiber.App, name string) uint {
t.Helper()
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/areas", map[string]any{"name": name})
if resp.StatusCode != fiber.StatusCreated {
t.Fatalf("expected 201 when creating area, got %d: %s", resp.StatusCode, string(body))
}
return parseID(t, body)
}
func createLocation(t *testing.T, app *fiber.App, name, address string, areaID uint) uint {
t.Helper()
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/locations", map[string]any{
"name": name,
"address": address,
"area_id": areaID,
})
if resp.StatusCode != fiber.StatusCreated {
t.Fatalf("expected 201 when creating location, got %d: %s", resp.StatusCode, string(body))
}
return parseID(t, body)
}
func createUom(t *testing.T, app *fiber.App, name string) uint {
t.Helper()
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/uoms", map[string]any{"name": name})
if resp.StatusCode != fiber.StatusCreated {
t.Fatalf("expected 201 when creating uom, got %d: %s", resp.StatusCode, string(body))
}
return parseID(t, body)
}
func createKandang(t *testing.T, app *fiber.App, name string, locationID, picID uint) uint {
t.Helper()
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/kandangs", map[string]any{
"name": name,
"status": "ACTIVE",
"location_id": locationID,
"pic_id": picID,
})
if resp.StatusCode != fiber.StatusCreated {
t.Fatalf("expected 201 when creating kandang, got %d: %s", resp.StatusCode, string(body))
}
return parseID(t, body)
}
func createCustomer(t *testing.T, app *fiber.App, name string, picID uint) uint {
t.Helper()
identifier := strings.ToLower(strings.ReplaceAll(name, " ", "_"))
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/customers", map[string]any{
"name": name,
"pic_id": picID,
"type": utils.CustomerSupplierTypeBisnis,
"address": "Customer address",
"phone": "081234567890",
"email": fmt.Sprintf("%s@example.com", identifier),
"account_number": fmt.Sprintf("ACC-%s", identifier),
})
if resp.StatusCode != fiber.StatusCreated {
t.Fatalf("expected 201 when creating customer, got %d: %s", resp.StatusCode, string(body))
}
return parseID(t, body)
}
func fetchCustomer(t *testing.T, db *gorm.DB, id uint) entities.Customer {
t.Helper()
var customer entities.Customer
if err := db.Preload("Pic").Preload("CreatedUser").First(&customer, id).Error; err != nil {
t.Fatalf("failed to fetch customer: %v", err)
}
return customer
}
func fetchKandang(t *testing.T, db *gorm.DB, id uint) entities.Kandang {
t.Helper()
var kandang entities.Kandang
if err := db.Preload("ProjectFlock").First(&kandang, id).Error; err != nil {
t.Fatalf("failed to fetch kandang: %v", err)
}
return kandang
}
func createSupplier(t *testing.T, app *fiber.App, name, alias, category string) uint {
t.Helper()
identifier := strings.ToLower(strings.ReplaceAll(name, " ", "_"))
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/suppliers", map[string]any{
"name": name,
"alias": alias,
"pic": "John Doe",
"type": utils.CustomerSupplierTypeBisnis,
"category": category,
"hatchery": "Hatchery A",
"phone": "081234567890",
"email": fmt.Sprintf("%s@supplier.com", identifier),
"address": "Supplier address",
"npwp": "NPWP-123",
"account_number": "ACC-SUPPLIER",
"due_date": 30,
})
if resp.StatusCode != fiber.StatusCreated {
t.Fatalf("expected 201 when creating supplier, got %d: %s", resp.StatusCode, string(body))
}
return parseID(t, body)
}
func createProductCategory(t *testing.T, app *fiber.App, name, code string) uint {
t.Helper()
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/product-categories", map[string]any{
"name": name,
"code": code,
})
if resp.StatusCode != fiber.StatusCreated {
t.Fatalf("expected 201 when creating product category, got %d: %s", resp.StatusCode, string(body))
}
return parseID(t, body)
}
func fetchProductCategory(t *testing.T, db *gorm.DB, id uint) entities.ProductCategory {
t.Helper()
var pc entities.ProductCategory
if err := db.Preload("CreatedUser").First(&pc, id).Error; err != nil {
t.Fatalf("failed to fetch product category: %v", err)
}
return pc
}
func createProduct(t *testing.T, app *fiber.App, name, brand string, sku *string, uomID, categoryID uint, productPrice float64, supplierIDs []uint, flags []string) uint {
t.Helper()
payload := map[string]any{
"name": name,
"brand": brand,
"uom_id": uomID,
"product_category_id": categoryID,
"product_price": productPrice,
"supplier_ids": supplierIDs,
}
if sku != nil {
payload["sku"] = *sku
}
if len(flags) > 0 {
payload["flags"] = flags
}
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/products", payload)
if resp.StatusCode != fiber.StatusCreated {
t.Fatalf("expected 201 when creating product, got %d: %s", resp.StatusCode, string(body))
}
return parseID(t, body)
}
func fetchProduct(t *testing.T, db *gorm.DB, id uint) entities.Product {
t.Helper()
var product entities.Product
if err := db.Preload("CreatedUser").
Preload("Uom").
Preload("ProductCategory").
Preload("Suppliers", func(tx *gorm.DB) *gorm.DB { return tx.Order("suppliers.name ASC") }).
Preload("Flags", func(tx *gorm.DB) *gorm.DB { return tx.Order("flags.name ASC") }).
First(&product, id).Error; err != nil {
t.Fatalf("failed to fetch product: %v", err)
}
return product
}
func fetchSupplier(t *testing.T, db *gorm.DB, id uint) entities.Supplier {
t.Helper()
var supplier entities.Supplier
if err := db.Preload("CreatedUser").First(&supplier, id).Error; err != nil {
t.Fatalf("failed to fetch supplier: %v", err)
}
return supplier
}
func createFcr(t *testing.T, app *fiber.App, name string, standards []map[string]any) uint {
t.Helper()
payload := map[string]any{
"name": name,
"fcr_standards": standards,
}
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/fcrs", payload)
if resp.StatusCode != fiber.StatusCreated {
t.Fatalf("expected 201 when creating fcr, got %d: %s", resp.StatusCode, string(body))
}
return parseID(t, body)
}
func createFlock(t *testing.T, app *fiber.App, name string) uint {
t.Helper()
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/flocks", map[string]any{
"name": name,
})
if resp.StatusCode != fiber.StatusCreated {
t.Fatalf("expected 201 when creating flock, got %d: %s", resp.StatusCode, string(body))
}
return parseID(t, body)
}
func fetchFcr(t *testing.T, db *gorm.DB, id uint) entities.Fcr {
t.Helper()
var fcr entities.Fcr
if err := db.Preload("CreatedUser").
Preload("Standards", func(tx *gorm.DB) *gorm.DB {
return tx.Order("weight ASC")
}).
First(&fcr, id).Error; err != nil {
t.Fatalf("failed to fetch fcr: %v", err)
}
return fcr
}
func createNonstock(t *testing.T, app *fiber.App, name string, uomID uint, supplierIDs []uint, flags []string) uint {
t.Helper()
payload := map[string]any{
"name": name,
"uom_id": uomID,
"supplier_ids": supplierIDs,
}
if len(flags) > 0 {
payload["flags"] = flags
}
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/nonstocks", payload)
if resp.StatusCode != fiber.StatusCreated {
t.Fatalf("expected 201 when creating nonstock, got %d: %s", resp.StatusCode, string(body))
}
return parseID(t, body)
}
func fetchNonstock(t *testing.T, db *gorm.DB, id uint) entities.Nonstock {
t.Helper()
var nonstock entities.Nonstock
if err := db.Preload("CreatedUser").
Preload("Uom").
Preload("Suppliers", func(tx *gorm.DB) *gorm.DB { return tx.Order("suppliers.name ASC") }).
Preload("Flags", func(tx *gorm.DB) *gorm.DB { return tx.Order("flags.name ASC") }).
First(&nonstock, id).Error; err != nil {
t.Fatalf("failed to fetch nonstock: %v", err)
}
return nonstock
}
func fetchAreaName(t *testing.T, db *gorm.DB, id uint) string {
t.Helper()
var area entities.Area
if err := db.First(&area, id).Error; err != nil {
t.Fatalf("failed to fetch area: %v", err)
}
return area.Name
}
func fetchWarehouse(t *testing.T, db *gorm.DB, id uint) entities.Warehouse {
t.Helper()
var wh entities.Warehouse
if err := db.First(&wh, id).Error; err != nil {
t.Fatalf("failed to fetch warehouse: %v", err)
}
return wh
}
func createBank(t *testing.T, app *fiber.App, name, alias, accountNumber string, owner any) uint {
t.Helper()
payload := map[string]any{
"name": name,
"alias": alias,
"account_number": accountNumber,
"owner": owner,
}
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/banks", payload)
if resp.StatusCode != fiber.StatusCreated {
t.Fatalf("expected 201 when creating bank, got %d: %s", resp.StatusCode, string(body))
}
return parseID(t, body)
}
func fetchBank(t *testing.T, db *gorm.DB, id uint) entities.Bank {
t.Helper()
var bank entities.Bank
if err := db.Preload("CreatedUser").First(&bank, id).Error; err != nil {
t.Fatalf("failed to fetch bank: %v", err)
}
return bank
}
@@ -1,309 +0,0 @@
package test
import (
"encoding/json"
"errors"
"fmt"
"net/http"
"strings"
"testing"
"github.com/gofiber/fiber/v2"
"gorm.io/gorm"
"gitlab.com/mbugroup/lti-api.git/internal/entities"
"gitlab.com/mbugroup/lti-api.git/internal/utils"
)
func TestNonstockIntegration(t *testing.T) {
app, db := setupIntegrationApp(t)
uomID := createUom(t, app, "Unit Piece")
altUomID := createUom(t, app, "Unit Box")
supplierID1 := createSupplier(t, app, "Nonstock Supplier One", "ns1", string(utils.SupplierCategoryBOP))
supplierID2 := createSupplier(t, app, "Nonstock Supplier Two", "ns2", string(utils.SupplierCategoryBOP))
supplierID3 := createSupplier(t, app, "Nonstock Supplier Three", "ns3", string(utils.SupplierCategoryBOP))
sapronakSupplierID := createSupplier(t, app, "SAPRONAK Supplier", "sap1", string(utils.SupplierCategorySapronak))
nonstockFlags := []string{string(utils.FlagEkspedisi)}
t.Run("create nonstock without suppliers succeeds with empty relations", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/nonstocks", map[string]any{
"name": "Supplierless Nonstock",
"uom_id": uomID,
})
if resp.StatusCode != fiber.StatusCreated {
t.Fatalf("expected 201 when suppliers omitted, got %d: %s", resp.StatusCode, string(body))
}
id := parseID(t, body)
ns := fetchNonstock(t, db, id)
if len(ns.Suppliers) != 0 {
t.Fatalf("expected no suppliers persisted, found %d", len(ns.Suppliers))
}
if len(ns.Flags) != 0 {
t.Fatalf("expected no flags persisted, found %d", len(ns.Flags))
}
resp, _ = doJSONRequest(t, app, http.MethodDelete, fmt.Sprintf("/api/master-data/nonstocks/%d", id), nil)
if resp.StatusCode != fiber.StatusOK {
t.Fatalf("expected cleanup delete to succeed, got %d", resp.StatusCode)
}
})
t.Run("create nonstock with unknown supplier fails", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/nonstocks", map[string]any{
"name": "Unknown Supplier Nonstock",
"uom_id": uomID,
"supplier_ids": []uint{99999},
})
if resp.StatusCode != fiber.StatusNotFound {
t.Fatalf("expected 404 when supplier missing, got %d: %s", resp.StatusCode, string(body))
}
})
t.Run("create nonstock with sapronak supplier fails", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/nonstocks", map[string]any{
"name": "Invalid Category Nonstock",
"uom_id": uomID,
"supplier_ids": []uint{sapronakSupplierID},
})
if resp.StatusCode != fiber.StatusBadRequest {
t.Fatalf("expected 400 when supplier category is not BOP, got %d: %s", resp.StatusCode, string(body))
}
})
t.Run("create nonstock with invalid flags fails", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/nonstocks", map[string]any{
"name": "Invalid Flag Nonstock",
"uom_id": uomID,
"supplier_ids": []uint{supplierID1},
"flags": []string{"UNKNOWN"},
})
if resp.StatusCode != fiber.StatusBadRequest {
t.Fatalf("expected 400 when flags invalid, got %d: %s", resp.StatusCode, string(body))
}
})
var nonstockID uint
t.Run("create nonstock succeeds", func(t *testing.T) {
nonstockID = createNonstock(t, app, "Layer Feed", uomID, []uint{supplierID1, supplierID2, supplierID1}, nonstockFlags)
if nonstockID == 0 {
t.Fatal("expected nonstock id to be non zero")
}
ns := fetchNonstock(t, db, nonstockID)
if ns.Name != "Layer Feed" {
t.Fatalf("expected name Layer Feed, got %q", ns.Name)
}
if ns.UomId != uomID {
t.Fatalf("expected uom_id %d, got %d", uomID, ns.UomId)
}
if ns.CreatedBy != 1 {
t.Fatalf("expected created_by 1, got %d", ns.CreatedBy)
}
if len(ns.Suppliers) != 2 {
t.Fatalf("expected 2 unique suppliers, got %d", len(ns.Suppliers))
}
if len(ns.Flags) != len(nonstockFlags) {
t.Fatalf("expected %d flags, got %d", len(nonstockFlags), len(ns.Flags))
}
expectedFlags := make(map[string]struct{}, len(nonstockFlags))
for _, flag := range nonstockFlags {
expectedFlags[strings.ToUpper(flag)] = struct{}{}
}
for _, flag := range ns.Flags {
upper := strings.ToUpper(flag.Name)
if _, ok := expectedFlags[upper]; !ok {
t.Fatalf("unexpected flag stored: %s", upper)
}
delete(expectedFlags, upper)
}
if len(expectedFlags) != 0 {
t.Fatalf("missing flags after create: %v", expectedFlags)
}
})
t.Run("get nonstock detail includes suppliers", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodGet, fmt.Sprintf("/api/master-data/nonstocks/%d", nonstockID), nil)
if resp.StatusCode != fiber.StatusOK {
t.Fatalf("expected 200 when fetching nonstock, got %d: %s", resp.StatusCode, string(body))
}
var payload struct {
Data struct {
Id uint `json:"id"`
Name string `json:"name"`
UomID uint `json:"uom_id"`
Suppliers []map[string]any `json:"suppliers"`
Flags []string `json:"flags"`
} `json:"data"`
}
if err := json.Unmarshal(body, &payload); err != nil {
t.Fatalf("failed to parse nonstock detail: %v", err)
}
if payload.Data.Id != nonstockID {
t.Fatalf("expected id %d, got %d", nonstockID, payload.Data.Id)
}
if payload.Data.UomID != uomID {
t.Fatalf("expected response uom_id %d, got %d", uomID, payload.Data.UomID)
}
if len(payload.Data.Suppliers) != 2 {
t.Fatalf("expected 2 suppliers in response, got %d", len(payload.Data.Suppliers))
}
if len(payload.Data.Flags) != len(nonstockFlags) {
t.Fatalf("expected %d flags in response, got %d", len(nonstockFlags), len(payload.Data.Flags))
}
expected := make(map[string]struct{}, len(nonstockFlags))
for _, flag := range nonstockFlags {
expected[strings.ToUpper(flag)] = struct{}{}
}
for _, flag := range payload.Data.Flags {
flag = strings.ToUpper(flag)
if _, ok := expected[flag]; !ok {
t.Fatalf("unexpected flag %s returned", flag)
}
delete(expected, flag)
}
if len(expected) != 0 {
t.Fatalf("missing flags in response: %v", expected)
}
})
t.Run("update nonstock with invalid uom fails", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodPatch, fmt.Sprintf("/api/master-data/nonstocks/%d", nonstockID), map[string]any{
"uom_id": 99999,
})
if resp.StatusCode != fiber.StatusNotFound {
t.Fatalf("expected 404 when updating with invalid uom, got %d: %s", resp.StatusCode, string(body))
}
})
t.Run("update nonstock with invalid supplier fails", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodPatch, fmt.Sprintf("/api/master-data/nonstocks/%d", nonstockID), map[string]any{
"supplier_ids": []uint{supplierID1, 99999},
})
if resp.StatusCode != fiber.StatusNotFound {
t.Fatalf("expected 404 when updating with invalid supplier, got %d: %s", resp.StatusCode, string(body))
}
})
t.Run("update nonstock with sapronak supplier fails", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodPatch, fmt.Sprintf("/api/master-data/nonstocks/%d", nonstockID), map[string]any{
"supplier_ids": []uint{sapronakSupplierID},
})
if resp.StatusCode != fiber.StatusBadRequest {
t.Fatalf("expected 400 when updating with non-BOP supplier, got %d: %s", resp.StatusCode, string(body))
}
})
t.Run("update nonstock with invalid flags fails", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodPatch, fmt.Sprintf("/api/master-data/nonstocks/%d", nonstockID), map[string]any{
"flags": []string{"BAD"},
})
if resp.StatusCode != fiber.StatusBadRequest {
t.Fatalf("expected 400 when updating flags invalid, got %d: %s", resp.StatusCode, string(body))
}
})
t.Run("update nonstock name uom and suppliers succeeds", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodPatch, fmt.Sprintf("/api/master-data/nonstocks/%d", nonstockID), map[string]any{
"name": "Layer Feed Premium",
"uom_id": altUomID,
"supplier_ids": []uint{supplierID3},
"flags": nonstockFlags,
})
if resp.StatusCode != fiber.StatusOK {
t.Fatalf("expected 200 when updating nonstock, got %d: %s", resp.StatusCode, string(body))
}
ns := fetchNonstock(t, db, nonstockID)
if ns.Name != "Layer Feed Premium" {
t.Fatalf("expected name Layer Feed Premium, got %q", ns.Name)
}
if ns.UomId != altUomID {
t.Fatalf("expected uom_id %d, got %d", altUomID, ns.UomId)
}
if len(ns.Suppliers) != 1 || ns.Suppliers[0].Id != supplierID3 {
t.Fatalf("expected suppliers to contain only %d", supplierID3)
}
if len(ns.Flags) != len(nonstockFlags) {
t.Fatalf("expected flags retained, got %d", len(ns.Flags))
}
})
t.Run("clear suppliers succeeds", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodPatch, fmt.Sprintf("/api/master-data/nonstocks/%d", nonstockID), map[string]any{
"supplier_ids": []uint{},
})
if resp.StatusCode != fiber.StatusOK {
t.Fatalf("expected 200 when clearing suppliers, got %d: %s", resp.StatusCode, string(body))
}
ns := fetchNonstock(t, db, nonstockID)
if len(ns.Suppliers) != 0 {
t.Fatalf("expected suppliers to be cleared, got %d entries", len(ns.Suppliers))
}
if len(ns.Flags) != len(nonstockFlags) {
t.Fatalf("expected flags unaffected, got %d", len(ns.Flags))
}
})
t.Run("clear nonstock flags succeeds", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodPatch, fmt.Sprintf("/api/master-data/nonstocks/%d", nonstockID), map[string]any{
"flags": []string{},
})
if resp.StatusCode != fiber.StatusOK {
t.Fatalf("expected 200 when clearing nonstock flags, got %d: %s", resp.StatusCode, string(body))
}
ns := fetchNonstock(t, db, nonstockID)
if len(ns.Flags) != 0 {
t.Fatalf("expected flags cleared, got %d", len(ns.Flags))
}
})
t.Run("delete nonstock succeeds", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodDelete, fmt.Sprintf("/api/master-data/nonstocks/%d", nonstockID), nil)
if resp.StatusCode != fiber.StatusOK {
t.Fatalf("expected 200 when deleting nonstock, got %d: %s", resp.StatusCode, string(body))
}
var ns entities.Nonstock
if err := db.First(&ns, nonstockID).Error; !errors.Is(err, gorm.ErrRecordNotFound) {
t.Fatalf("expected nonstock to be deleted, got error %v", err)
}
var links int64
if err := db.Model(&entities.NonstockSupplier{}).Where("nonstock_id = ?", nonstockID).Count(&links).Error; err != nil {
t.Fatalf("failed counting nonstock suppliers: %v", err)
}
if links != 0 {
t.Fatalf("expected link table cleared, found %d rows", links)
}
var flagCount int64
if err := db.Model(&entities.Flag{}).
Where("flagable_id = ? AND flagable_type = ?", nonstockID, entities.FlagableTypeNonstock).
Count(&flagCount).Error; err != nil {
t.Fatalf("failed counting nonstock flags: %v", err)
}
if flagCount != 0 {
t.Fatalf("expected flags removed, found %d", flagCount)
}
})
t.Run("deleting nonstock twice returns 404", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodDelete, fmt.Sprintf("/api/master-data/nonstocks/%d", nonstockID), nil)
if resp.StatusCode != fiber.StatusNotFound {
t.Fatalf("expected 404 when deleting missing nonstock, got %d: %s", resp.StatusCode, string(body))
}
})
t.Run("fetching deleted nonstock returns 404", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodGet, fmt.Sprintf("/api/master-data/nonstocks/%d", nonstockID), nil)
if resp.StatusCode != fiber.StatusNotFound {
t.Fatalf("expected 404 when fetching deleted nonstock, got %d: %s", resp.StatusCode, string(body))
}
})
t.Run("cleanup additional supplier references", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodDelete, fmt.Sprintf("/api/master-data/suppliers/%d", supplierID3), nil)
if resp.StatusCode != fiber.StatusOK {
t.Fatalf("expected 200 when deleting supplier, got %d: %s", resp.StatusCode, string(body))
}
doJSONRequest(t, app, http.MethodDelete, fmt.Sprintf("/api/master-data/suppliers/%d", sapronakSupplierID), nil)
})
}
@@ -1,150 +0,0 @@
package test
import (
"encoding/json"
"errors"
"fmt"
"net/http"
"testing"
"github.com/gofiber/fiber/v2"
"gorm.io/gorm"
"gitlab.com/mbugroup/lti-api.git/internal/entities"
)
func TestProductCategoryIntegration(t *testing.T) {
app, db := setupIntegrationApp(t)
t.Run("create product category missing code fails", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/product-categories", map[string]any{
"name": "Layer Feed",
})
if resp.StatusCode != fiber.StatusBadRequest {
t.Fatalf("expected 400 when code missing, got %d: %s", resp.StatusCode, string(body))
}
})
var categoryID uint
t.Run("create product category succeeds", func(t *testing.T) {
categoryID = createProductCategory(t, app, "Layer Feed", "LFD")
pc := fetchProductCategory(t, db, categoryID)
if pc.Name != "Layer Feed" {
t.Fatalf("expected name Layer Feed, got %q", pc.Name)
}
if pc.Code != "LFD" {
t.Fatalf("expected code LFD, got %q", pc.Code)
}
if pc.CreatedBy != 1 {
t.Fatalf("expected created_by 1, got %d", pc.CreatedBy)
}
})
t.Run("creating duplicate name fails", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/product-categories", map[string]any{
"name": "Layer Feed",
"code": "LF2",
})
if resp.StatusCode != fiber.StatusConflict {
t.Fatalf("expected 409 when creating duplicate name, got %d: %s", resp.StatusCode, string(body))
}
})
t.Run("creating duplicate code fails", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/product-categories", map[string]any{
"name": "Layer Feed Premium",
"code": "LFD",
})
if resp.StatusCode != fiber.StatusConflict {
t.Fatalf("expected 409 when creating duplicate code, got %d: %s", resp.StatusCode, string(body))
}
})
t.Run("get product category detail", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodGet, fmt.Sprintf("/api/master-data/product-categories/%d", categoryID), nil)
if resp.StatusCode != fiber.StatusOK {
t.Fatalf("expected 200 when fetching product category, got %d: %s", resp.StatusCode, string(body))
}
var payload struct {
Data struct {
Id uint `json:"id"`
Name string `json:"name"`
Code string `json:"code"`
} `json:"data"`
}
if err := json.Unmarshal(body, &payload); err != nil {
t.Fatalf("failed to parse response: %v", err)
}
if payload.Data.Id != categoryID {
t.Fatalf("expected id %d, got %d", categoryID, payload.Data.Id)
}
if payload.Data.Code != "LFD" {
t.Fatalf("expected code LFD, got %q", payload.Data.Code)
}
})
t.Run("update product category with duplicate name fails", func(t *testing.T) {
otherID := createProductCategory(t, app, "Layer Feed Alt", "LFA")
resp, body := doJSONRequest(t, app, http.MethodPatch, fmt.Sprintf("/api/master-data/product-categories/%d", otherID), map[string]any{
"name": "Layer Feed",
})
if resp.StatusCode != fiber.StatusConflict {
t.Fatalf("expected 409 when updating with duplicate name, got %d: %s", resp.StatusCode, string(body))
}
})
t.Run("update product category succeeds", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodPatch, fmt.Sprintf("/api/master-data/product-categories/%d", categoryID), map[string]any{
"name": "Layer Feed Updated",
"code": "LFU",
})
if resp.StatusCode != fiber.StatusOK {
t.Fatalf("expected 200 when updating product category, got %d: %s", resp.StatusCode, string(body))
}
var payload struct {
Data struct {
Name string `json:"name"`
Code string `json:"code"`
} `json:"data"`
}
if err := json.Unmarshal(body, &payload); err != nil {
t.Fatalf("failed to parse update response: %v", err)
}
if payload.Data.Name != "Layer Feed Updated" {
t.Fatalf("expected updated name, got %q", payload.Data.Name)
}
if payload.Data.Code != "LFU" {
t.Fatalf("expected code LFU, got %q", payload.Data.Code)
}
pc := fetchProductCategory(t, db, categoryID)
if pc.Code != "LFU" {
t.Fatalf("expected persisted code LFU, got %q", pc.Code)
}
})
t.Run("delete product category", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodDelete, fmt.Sprintf("/api/master-data/product-categories/%d", categoryID), nil)
if resp.StatusCode != fiber.StatusOK {
t.Fatalf("expected 200 when deleting product category, got %d: %s", resp.StatusCode, string(body))
}
var pc entities.ProductCategory
if err := db.First(&pc, categoryID).Error; !errors.Is(err, gorm.ErrRecordNotFound) {
t.Fatalf("expected product category deleted, got error %v", err)
}
})
t.Run("delete non existing product category returns 404", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodDelete, fmt.Sprintf("/api/master-data/product-categories/%d", categoryID), nil)
if resp.StatusCode != fiber.StatusNotFound {
t.Fatalf("expected 404 when deleting missing product category, got %d: %s", resp.StatusCode, string(body))
}
})
t.Run("get deleted product category returns 404", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodGet, fmt.Sprintf("/api/master-data/product-categories/%d", categoryID), nil)
if resp.StatusCode != fiber.StatusNotFound {
t.Fatalf("expected 404 when fetching deleted product category, got %d: %s", resp.StatusCode, string(body))
}
})
}
@@ -1,410 +0,0 @@
package test
import (
"encoding/json"
"errors"
"fmt"
"net/http"
"strings"
"testing"
"github.com/gofiber/fiber/v2"
"gorm.io/gorm"
"gitlab.com/mbugroup/lti-api.git/internal/entities"
"gitlab.com/mbugroup/lti-api.git/internal/utils"
)
func TestProductIntegration(t *testing.T) {
app, db := setupIntegrationApp(t)
uomID := createUom(t, app, "Kilogram")
categoryID := createProductCategory(t, app, "Feed", "FED")
sapSupplier1 := createSupplier(t, app, "Feed Supplier One", "fs1", string(utils.SupplierCategorySapronak))
sapSupplier2 := createSupplier(t, app, "Feed Supplier Two", "fs2", string(utils.SupplierCategorySapronak))
bopSupplier := createSupplier(t, app, "BOP Supplier", "bop1", string(utils.SupplierCategoryBOP))
productFlags := []string{string(utils.FlagDOC), string(utils.FlagPakan)}
updatedProductFlags := []string{string(utils.FlagFinisher), string(utils.FlagObat)}
t.Run("create product without suppliers succeeds with empty relations", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/products", map[string]any{
"name": "Supplierless Product",
"brand": "Brand A",
"uom_id": uomID,
"product_category_id": categoryID,
"product_price": 12000,
})
if resp.StatusCode != fiber.StatusCreated {
t.Fatalf("expected 201 when suppliers omitted, got %d: %s", resp.StatusCode, string(body))
}
id := parseID(t, body)
product := fetchProduct(t, db, id)
if len(product.Suppliers) != 0 {
t.Fatalf("expected no suppliers persisted, found %d", len(product.Suppliers))
}
if len(product.Flags) != 0 {
t.Fatalf("expected no flags persisted, found %d", len(product.Flags))
}
resp, _ = doJSONRequest(t, app, http.MethodDelete, fmt.Sprintf("/api/master-data/products/%d", id), nil)
if resp.StatusCode != fiber.StatusOK {
t.Fatalf("expected cleanup delete to succeed, got %d", resp.StatusCode)
}
})
t.Run("create product with invalid uom fails", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/products", map[string]any{
"name": "Layer Feed Invalid UOM",
"brand": "Brand A",
"uom_id": 9999,
"product_category_id": categoryID,
"product_price": 12000,
"supplier_ids": []uint{sapSupplier1},
})
if resp.StatusCode != fiber.StatusNotFound {
t.Fatalf("expected 404 when uom missing, got %d: %s", resp.StatusCode, string(body))
}
})
t.Run("create product with invalid category fails", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/products", map[string]any{
"name": "Layer Feed Invalid Category",
"brand": "Brand A",
"uom_id": uomID,
"product_category_id": 9999,
"product_price": 12000,
"supplier_ids": []uint{sapSupplier1},
})
if resp.StatusCode != fiber.StatusNotFound {
t.Fatalf("expected 404 when category missing, got %d: %s", resp.StatusCode, string(body))
}
})
t.Run("create product with invalid supplier fails", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/products", map[string]any{
"name": "Layer Feed Missing Supplier",
"brand": "Brand A",
"uom_id": uomID,
"product_category_id": categoryID,
"product_price": 12000,
"supplier_ids": []uint{99999},
})
if resp.StatusCode != fiber.StatusNotFound {
t.Fatalf("expected 404 when supplier missing, got %d: %s", resp.StatusCode, string(body))
}
})
t.Run("create product with BOP supplier fails", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/products", map[string]any{
"name": "Layer Feed Wrong Supplier",
"brand": "Brand A",
"uom_id": uomID,
"product_category_id": categoryID,
"product_price": 12000,
"supplier_ids": []uint{bopSupplier},
})
if resp.StatusCode != fiber.StatusBadRequest {
t.Fatalf("expected 400 when supplier category invalid, got %d: %s", resp.StatusCode, string(body))
}
})
t.Run("create product with invalid flags fails", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/products", map[string]any{
"name": "Layer Feed Invalid Flags",
"brand": "Brand A",
"uom_id": uomID,
"product_category_id": categoryID,
"product_price": 12000,
"supplier_ids": []uint{sapSupplier1},
"flags": []string{"INVALID"},
})
if resp.StatusCode != fiber.StatusBadRequest {
t.Fatalf("expected 400 when flags invalid, got %d: %s", resp.StatusCode, string(body))
}
})
var productID uint
t.Run("create product succeeds", func(t *testing.T) {
sku := "lfd-001"
productID = createProduct(t, app, "Layer Feed", "Brand A", &sku, uomID, categoryID, 15000, []uint{sapSupplier1, sapSupplier2}, productFlags)
product := fetchProduct(t, db, productID)
if product.Name != "Layer Feed" {
t.Fatalf("expected name Layer Feed, got %q", product.Name)
}
if product.Brand != "Brand A" {
t.Fatalf("expected brand Brand A, got %q", product.Brand)
}
if product.Sku == nil || *product.Sku != strings.ToUpper(sku) {
t.Fatalf("expected sku %q, got %+v", strings.ToUpper(sku), product.Sku)
}
if product.UomId != uomID {
t.Fatalf("expected uom_id %d, got %d", uomID, product.UomId)
}
if product.ProductCategoryId != categoryID {
t.Fatalf("expected product_category_id %d, got %d", categoryID, product.ProductCategoryId)
}
if product.CreatedBy != 1 {
t.Fatalf("expected created_by 1, got %d", product.CreatedBy)
}
if len(product.Suppliers) != 2 {
t.Fatalf("expected 2 suppliers, got %d", len(product.Suppliers))
}
if len(product.Flags) != len(productFlags) {
t.Fatalf("expected %d flags, got %d", len(productFlags), len(product.Flags))
}
expectedFlags := make(map[string]struct{}, len(productFlags))
for _, flag := range productFlags {
expectedFlags[strings.ToUpper(flag)] = struct{}{}
}
for _, flag := range product.Flags {
if _, ok := expectedFlags[strings.ToUpper(flag.Name)]; !ok {
t.Fatalf("unexpected flag %s present", flag.Name)
}
delete(expectedFlags, strings.ToUpper(flag.Name))
}
if len(expectedFlags) != 0 {
t.Fatalf("missing expected flags: %v", expectedFlags)
}
})
t.Run("creating duplicate name fails", func(t *testing.T) {
sku := "lfd-002"
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/products", map[string]any{
"name": "Layer Feed",
"brand": "Brand B",
"sku": sku,
"uom_id": uomID,
"product_category_id": categoryID,
"product_price": 16000,
"supplier_ids": []uint{sapSupplier1},
})
if resp.StatusCode != fiber.StatusConflict {
t.Fatalf("expected 409 when creating duplicate name, got %d: %s", resp.StatusCode, string(body))
}
})
t.Run("creating duplicate sku fails", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/products", map[string]any{
"name": "Layer Feed Premium",
"brand": "Brand B",
"sku": "LFD-001",
"uom_id": uomID,
"product_category_id": categoryID,
"product_price": 17000,
"supplier_ids": []uint{sapSupplier1},
})
if resp.StatusCode != fiber.StatusConflict {
t.Fatalf("expected 409 when creating duplicate sku, got %d: %s", resp.StatusCode, string(body))
}
})
t.Run("get product detail returns nested data", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodGet, fmt.Sprintf("/api/master-data/products/%d", productID), nil)
if resp.StatusCode != fiber.StatusOK {
t.Fatalf("expected 200 when fetching product, got %d: %s", resp.StatusCode, string(body))
}
var payload struct {
Data struct {
Id uint `json:"id"`
Name string `json:"name"`
Brand string `json:"brand"`
Uom *struct {
Id uint `json:"id"`
} `json:"uom"`
Suppliers []map[string]any `json:"suppliers"`
Flags []string `json:"flags"`
} `json:"data"`
}
if err := json.Unmarshal(body, &payload); err != nil {
t.Fatalf("failed to parse product detail: %v", err)
}
if payload.Data.Id != productID {
t.Fatalf("expected id %d, got %d", productID, payload.Data.Id)
}
if payload.Data.Uom == nil || payload.Data.Uom.Id != uomID {
t.Fatalf("expected uom id %d, got %+v", uomID, payload.Data.Uom)
}
if len(payload.Data.Suppliers) != 2 {
t.Fatalf("expected 2 suppliers in response, got %d", len(payload.Data.Suppliers))
}
if len(payload.Data.Flags) != len(productFlags) {
t.Fatalf("expected %d flags in response, got %d", len(productFlags), len(payload.Data.Flags))
}
expected := make(map[string]struct{}, len(productFlags))
for _, flag := range productFlags {
expected[strings.ToUpper(flag)] = struct{}{}
}
for _, flag := range payload.Data.Flags {
flag = strings.ToUpper(flag)
if _, ok := expected[flag]; !ok {
t.Fatalf("unexpected flag %s returned", flag)
}
delete(expected, flag)
}
if len(expected) != 0 {
t.Fatalf("missing expected flags in response: %v", expected)
}
})
t.Run("update product with invalid supplier category fails", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodPatch, fmt.Sprintf("/api/master-data/products/%d", productID), map[string]any{
"supplier_ids": []uint{bopSupplier},
})
if resp.StatusCode != fiber.StatusBadRequest {
t.Fatalf("expected 400 when updating with non SAPRONAK supplier, got %d: %s", resp.StatusCode, string(body))
}
})
t.Run("update product with invalid flags fails", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodPatch, fmt.Sprintf("/api/master-data/products/%d", productID), map[string]any{
"flags": []string{"UNKNOWN"},
})
if resp.StatusCode != fiber.StatusBadRequest {
t.Fatalf("expected 400 when updating with invalid flags, got %d: %s", resp.StatusCode, string(body))
}
})
t.Run("update product succeeds", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodPatch, fmt.Sprintf("/api/master-data/products/%d", productID), map[string]any{
"name": "Layer Feed Updated",
"brand": "Brand C",
"sku": "lfd-100",
"product_price": 18000,
"selling_price": 19000,
"tax": 1000,
"expiry_period": 30,
"supplier_ids": []uint{sapSupplier1},
"flags": updatedProductFlags,
})
if resp.StatusCode != fiber.StatusOK {
t.Fatalf("expected 200 when updating product, got %d: %s", resp.StatusCode, string(body))
}
var payload struct {
Data struct {
Name string `json:"name"`
Brand string `json:"brand"`
Sku *string `json:"sku"`
ProductPrice float64 `json:"product_price"`
SupplierIds []map[string]any `json:"suppliers"`
Flags []string `json:"flags"`
} `json:"data"`
}
if err := json.Unmarshal(body, &payload); err != nil {
t.Fatalf("failed to parse update response: %v", err)
}
if payload.Data.Name != "Layer Feed Updated" {
t.Fatalf("expected updated name, got %q", payload.Data.Name)
}
if len(payload.Data.Flags) != len(updatedProductFlags) {
t.Fatalf("expected %d flags in response, got %d", len(updatedProductFlags), len(payload.Data.Flags))
}
respFlags := make(map[string]struct{}, len(payload.Data.Flags))
for _, flag := range payload.Data.Flags {
respFlags[strings.ToUpper(flag)] = struct{}{}
}
for _, flag := range updatedProductFlags {
if _, ok := respFlags[strings.ToUpper(flag)]; !ok {
t.Fatalf("missing flag %s in response", flag)
}
}
product := fetchProduct(t, db, productID)
if product.Brand != "Brand C" {
t.Fatalf("expected persisted brand Brand C, got %q", product.Brand)
}
if product.Sku == nil || *product.Sku != "LFD-100" {
t.Fatalf("expected persisted sku LFD-100, got %+v", product.Sku)
}
if len(product.Suppliers) != 1 || product.Suppliers[0].Id != sapSupplier1 {
t.Fatalf("expected supplier to be %d", sapSupplier1)
}
if len(product.Flags) != len(updatedProductFlags) {
t.Fatalf("expected %d flags after update, got %d", len(updatedProductFlags), len(product.Flags))
}
expectedFlags := make(map[string]struct{}, len(updatedProductFlags))
for _, flag := range updatedProductFlags {
expectedFlags[strings.ToUpper(flag)] = struct{}{}
}
for _, flag := range product.Flags {
upper := strings.ToUpper(flag.Name)
if _, ok := expectedFlags[upper]; !ok {
t.Fatalf("unexpected flag after update: %s", upper)
}
delete(expectedFlags, upper)
}
if len(expectedFlags) != 0 {
t.Fatalf("missing flags after update: %v", expectedFlags)
}
})
t.Run("clear suppliers succeeds", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodPatch, fmt.Sprintf("/api/master-data/products/%d", productID), map[string]any{
"supplier_ids": []uint{},
})
if resp.StatusCode != fiber.StatusOK {
t.Fatalf("expected 200 when clearing suppliers, got %d: %s", resp.StatusCode, string(body))
}
product := fetchProduct(t, db, productID)
if len(product.Suppliers) != 0 {
t.Fatalf("expected no suppliers after clearing, got %d", len(product.Suppliers))
}
if len(product.Flags) != len(updatedProductFlags) {
t.Fatalf("expected flags untouched after clearing suppliers, got %d", len(product.Flags))
}
})
t.Run("clear flags succeeds", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodPatch, fmt.Sprintf("/api/master-data/products/%d", productID), map[string]any{
"flags": []string{},
})
if resp.StatusCode != fiber.StatusOK {
t.Fatalf("expected 200 when clearing flags, got %d: %s", resp.StatusCode, string(body))
}
product := fetchProduct(t, db, productID)
if len(product.Flags) != 0 {
t.Fatalf("expected all flags cleared, got %d", len(product.Flags))
}
})
t.Run("delete product succeeds", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodDelete, fmt.Sprintf("/api/master-data/products/%d", productID), nil)
if resp.StatusCode != fiber.StatusOK {
t.Fatalf("expected 200 when deleting product, got %d: %s", resp.StatusCode, string(body))
}
var product entities.Product
if err := db.First(&product, productID).Error; !errors.Is(err, gorm.ErrRecordNotFound) {
t.Fatalf("expected product deleted, got error %v", err)
}
var links int64
if err := db.Model(&entities.ProductSupplier{}).Where("product_id = ?", productID).Count(&links).Error; err != nil {
t.Fatalf("failed counting product suppliers: %v", err)
}
if links != 0 {
t.Fatalf("expected pivot cleared, found %d rows", links)
}
var flagCount int64
if err := db.Model(&entities.Flag{}).
Where("flagable_id = ? AND flagable_type = ?", productID, entities.FlagableTypeProduct).
Count(&flagCount).Error; err != nil {
t.Fatalf("failed counting product flags: %v", err)
}
if flagCount != 0 {
t.Fatalf("expected flags removed, found %d", flagCount)
}
})
t.Run("delete missing product returns 404", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodDelete, fmt.Sprintf("/api/master-data/products/%d", productID), nil)
if resp.StatusCode != fiber.StatusNotFound {
t.Fatalf("expected 404 when deleting missing product, got %d: %s", resp.StatusCode, string(body))
}
})
t.Run("get deleted product returns 404", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodGet, fmt.Sprintf("/api/master-data/products/%d", productID), nil)
if resp.StatusCode != fiber.StatusNotFound {
t.Fatalf("expected 404 when fetching deleted product, got %d: %s", resp.StatusCode, string(body))
}
})
}
@@ -1,417 +0,0 @@
package test
// import (
// "encoding/json"
// "fmt"
// "net/http"
// "net/url"
// "testing"
// "github.com/gofiber/fiber/v2"
// "gitlab.com/mbugroup/lti-api.git/internal/entities"
// "gitlab.com/mbugroup/lti-api.git/internal/utils"
// )
// func TestProjectFlockSummary(t *testing.T) {
// app, db := setupIntegrationApp(t)
// areaID := createArea(t, app, "Area Project")
// locationID := createLocation(t, app, "Location Project", "Address", areaID)
// flockID := createFlock(t, app, "Flock Summary")
// fcrID := createFcr(t, app, "FCR Summary", []map[string]any{
// {"weight": 1.0, "fcr_number": 1.5, "mortality": 2.0},
// })
// kandangID := createKandang(t, app, "Kandang Summary", locationID, 1)
// createPayload := map[string]any{
// "flock_id": flockID,
// "area_id": areaID,
// "category": "growing",
// "fcr_id": fcrID,
// "location_id": locationID,
// "kandang_ids": []uint{kandangID},
// }
// resp, body := doJSONRequest(t, app, http.MethodPost, "/api/production/project_flocks", createPayload)
// if resp.StatusCode != fiber.StatusCreated {
// t.Fatalf("expected 201 when creating project flock, got %d: %s", resp.StatusCode, string(body))
// }
// var createResp struct {
// Data struct {
// Id uint `json:"id"`
// Period int `json:"period"`
// Category string `json:"category"`
// Flock struct {
// Id uint `json:"id"`
// Name string `json:"name"`
// } `json:"flock"`
// Area struct {
// Id uint `json:"id"`
// Name string `json:"name"`
// } `json:"area"`
// Fcr struct {
// Id uint `json:"id"`
// Name string `json:"name"`
// } `json:"fcr"`
// Location struct {
// Id uint `json:"id"`
// Name string `json:"name"`
// Address string `json:"address"`
// } `json:"location"`
// Kandangs []struct {
// Id uint `json:"id"`
// Name string `json:"name"`
// Status string `json:"status"`
// } `json:"kandangs"`
// CreatedUser struct {
// Id uint `json:"id"`
// IdUser uint `json:"id_user"`
// Email string `json:"email"`
// Name string `json:"name"`
// } `json:"created_user"`
// } `json:"data"`
// }
// if err := json.Unmarshal(body, &createResp); err != nil {
// t.Fatalf("failed to parse create response: %v", err)
// }
// if createResp.Data.Flock.Id != flockID || createResp.Data.Flock.Name == "" {
// t.Fatalf("expected flock detail to be present, got %+v", createResp.Data.Flock)
// }
// if createResp.Data.Area.Id != areaID || createResp.Data.Area.Name == "" {
// t.Fatalf("expected area detail to be present, got %+v", createResp.Data.Area)
// }
// if createResp.Data.Category != string(utils.ProjectFlockCategoryGrowing) {
// t.Fatalf("expected category to be %s, got %s", utils.ProjectFlockCategoryGrowing, createResp.Data.Category)
// }
// if createResp.Data.Location.Id != locationID || createResp.Data.Location.Name == "" {
// t.Fatalf("expected location detail to be present, got %+v", createResp.Data.Location)
// }
// if len(createResp.Data.Kandangs) != 1 || createResp.Data.Kandangs[0].Id != kandangID {
// t.Fatalf("expected kandang detail to be present, got %+v", createResp.Data.Kandangs)
// }
// if createResp.Data.Kandangs[0].Status != string(utils.KandangStatusPengajuan) {
// t.Fatalf("expected kandang status to be PENGAJUAN, got %s", createResp.Data.Kandangs[0].Status)
// }
// if createResp.Data.Period != 1 {
// t.Fatalf("expected period 1 to be assigned automatically, got %d", createResp.Data.Period)
// }
// createdKandang := fetchKandang(t, db, kandangID)
// if createdKandang.Status != string(utils.KandangStatusPengajuan) {
// t.Fatalf("expected kandang status in DB to be PENGAJUAN, got %s", createdKandang.Status)
// }
// var pivotRecords []entities.ProjectFlockKandang
// if err := db.Where("project_flock_id = ?", createResp.Data.Id).Find(&pivotRecords).Error; err != nil {
// t.Fatalf("failed to fetch pivot records: %v", err)
// }
// if len(pivotRecords) != 1 {
// t.Fatalf("expected 1 pivot record, got %d", len(pivotRecords))
// }
// firstPivotRecord := pivotRecords[0]
// if firstPivotRecord.KandangId != kandangID {
// t.Fatalf("expected pivot kandang id %d, got %d", kandangID, firstPivotRecord.KandangId)
// }
// secondKandangID := createKandang(t, app, "Kandang Summary 2", locationID, 1)
// secondPayload := map[string]any{
// "flock_id": flockID,
// "area_id": areaID,
// "category": "laying",
// "fcr_id": fcrID,
// "location_id": locationID,
// "kandang_ids": []uint{secondKandangID},
// }
// resp, body = doJSONRequest(t, app, http.MethodPost, "/api/production/project_flocks", secondPayload)
// if resp.StatusCode != fiber.StatusCreated {
// t.Fatalf("expected 201 when creating second project flock, got %d: %s", resp.StatusCode, string(body))
// }
// var createRespSecond struct {
// Data struct {
// Id uint `json:"id"`
// Period int `json:"period"`
// Category string `json:"category"`
// } `json:"data"`
// }
// if err := json.Unmarshal(body, &createRespSecond); err != nil {
// t.Fatalf("failed to parse second create response: %v", err)
// }
// if createRespSecond.Data.Period != 2 {
// t.Fatalf("expected second period to be 2, got %d", createRespSecond.Data.Period)
// }
// if createRespSecond.Data.Category != string(utils.ProjectFlockCategoryLaying) {
// t.Fatalf("expected category to be %s, got %s", utils.ProjectFlockCategoryLaying, createRespSecond.Data.Category)
// }
// pivotRecords = nil
// if err := db.Where("project_flock_id = ?", createRespSecond.Data.Id).Find(&pivotRecords).Error; err != nil {
// t.Fatalf("failed to fetch second pivot records: %v", err)
// }
// if len(pivotRecords) != 1 {
// t.Fatalf("expected 1 pivot record for second project, got %d", len(pivotRecords))
// }
// secondPivotRecord := pivotRecords[0]
// if secondPivotRecord.KandangId != secondKandangID {
// t.Fatalf("expected second pivot kandang id %d, got %d", secondKandangID, secondPivotRecord.KandangId)
// }
// secondKandang := fetchKandang(t, db, secondKandangID)
// if secondKandang.Status != string(utils.KandangStatusPengajuan) {
// t.Fatalf("expected second kandang status in DB to be PENGAJUAN, got %s", secondKandang.Status)
// }
// resp, body = doJSONRequest(t, app, http.MethodGet, "/api/production/project_flocks/flocks/"+uintToString(flockID)+"/periods", nil)
// if resp.StatusCode != fiber.StatusOK {
// t.Fatalf("expected 200 when fetching summary, got %d: %s", resp.StatusCode, string(body))
// }
// var summary struct {
// Data struct {
// NextPeriod int `json:"next_period"`
// } `json:"data"`
// }
// if err := json.Unmarshal(body, &summary); err != nil {
// t.Fatalf("failed to parse summary response: %v", err)
// }
// if summary.Data.NextPeriod != 3 {
// t.Fatalf("expected next_period 3, got %d", summary.Data.NextPeriod)
// }
// resp, body = doJSONRequest(t, app, http.MethodDelete, "/api/production/project_flocks/"+uintToString(createResp.Data.Id), nil)
// if resp.StatusCode != fiber.StatusOK {
// t.Fatalf("expected 200 when deleting first project flock, got %d: %s", resp.StatusCode, string(body))
// }
// firstKandang := fetchKandang(t, db, kandangID)
// if firstKandang.ProjectFlockId != nil {
// t.Fatalf("expected project_flock_id to be nil after delete, got %v", *firstKandang.ProjectFlockId)
// }
// if firstKandang.Status != string(utils.KandangStatusNonActive) {
// t.Fatalf("expected kandang status to revert to NON_ACTIVE, got %s", firstKandang.Status)
// }
// var remainingFirst int64
// if err := db.Model(&entities.ProjectFlockKandang{}).
// Where("project_flock_id = ? AND kandang_id = ?", createResp.Data.Id, kandangID).
// Count(&remainingFirst).Error; err != nil {
// t.Fatalf("failed to count first pivot records after delete: %v", err)
// }
// if remainingFirst != 0 {
// t.Fatalf("expected no pivot records remaining after delete, found %d", remainingFirst)
// }
// resp, body = doJSONRequest(t, app, http.MethodDelete, "/api/production/project_flocks/"+uintToString(createRespSecond.Data.Id), nil)
// if resp.StatusCode != fiber.StatusOK {
// t.Fatalf("expected 200 when deleting second project flock, got %d: %s", resp.StatusCode, string(body))
// }
// secondKandang = fetchKandang(t, db, secondKandangID)
// if secondKandang.ProjectFlockId != nil {
// t.Fatalf("expected second project_flock_id to be nil after delete, got %v", *secondKandang.ProjectFlockId)
// }
// if secondKandang.Status != string(utils.KandangStatusNonActive) {
// t.Fatalf("expected second kandang status to revert to NON_ACTIVE, got %s", secondKandang.Status)
// }
// var remainingSecond int64
// if err := db.Model(&entities.ProjectFlockKandang{}).
// Where("project_flock_id = ? AND kandang_id = ?", createRespSecond.Data.Id, secondKandangID).
// Count(&remainingSecond).Error; err != nil {
// t.Fatalf("failed to count second pivot records after delete: %v", err)
// }
// if remainingSecond != 0 {
// t.Fatalf("expected no second pivot records remaining after delete, found %d", remainingSecond)
// }
// resp, body = doJSONRequest(t, app, http.MethodGet, "/api/production/project_flocks/flocks/"+uintToString(flockID)+"/periods", nil)
// if resp.StatusCode != fiber.StatusOK {
// t.Fatalf("expected 200 when fetching summary after delete, got %d: %s", resp.StatusCode, string(body))
// }
// if err := json.Unmarshal(body, &summary); err != nil {
// t.Fatalf("failed to parse summary response after delete: %v", err)
// }
// if summary.Data.NextPeriod != 1 {
// t.Fatalf("expected next_period 1 after soft deletes, got %d", summary.Data.NextPeriod)
// }
// }
// func uintToString(v uint) string {
// return fmt.Sprintf("%d", v)
// }
// func TestProjectFlockSearchByRelatedFields(t *testing.T) {
// app, _ := setupIntegrationApp(t)
// areaID := createArea(t, app, "Area Search Target")
// locationID := createLocation(t, app, "Location Search Target", "Location Address Target", areaID)
// flockID := createFlock(t, app, "Flock Search Target")
// fcrID := createFcr(t, app, "FCR Search Target", []map[string]any{
// {"weight": 1.0, "fcr_number": 1.5, "mortality": 2.0},
// })
// kandangID := createKandang(t, app, "Kandang Search Target", locationID, 1)
// createPayload := map[string]any{
// "flock_id": flockID,
// "area_id": areaID,
// "category": "growing",
// "fcr_id": fcrID,
// "location_id": locationID,
// "kandang_ids": []uint{kandangID},
// }
// resp, body := doJSONRequest(t, app, http.MethodPost, "/api/production/project_flocks", createPayload)
// if resp.StatusCode != fiber.StatusCreated {
// t.Fatalf("expected 201 when creating project flock, got %d: %s", resp.StatusCode, string(body))
// }
// var createResp struct {
// Data struct {
// Id uint `json:"id"`
// } `json:"data"`
// }
// if err := json.Unmarshal(body, &createResp); err != nil {
// t.Fatalf("failed to parse create response: %v", err)
// }
// searchTerms := []string{
// "Flock Search Target",
// "Area Search Target",
// string(utils.ProjectFlockCategoryGrowing),
// "growing",
// "FCR Search Target",
// "Kandang Search Target",
// "Location Search Target",
// "Location Address Target",
// "Tester",
// "1",
// }
// for _, term := range searchTerms {
// path := "/api/production/project_flocks?search=" + url.QueryEscape(term)
// resp, body := doJSONRequest(t, app, http.MethodGet, path, nil)
// if resp.StatusCode != fiber.StatusOK {
// t.Fatalf("expected 200 when searching for %q, got %d: %s", term, resp.StatusCode, string(body))
// }
// var listResp struct {
// Data []struct {
// Id uint `json:"id"`
// } `json:"data"`
// Meta struct {
// TotalResults int64 `json:"total_results"`
// } `json:"meta"`
// }
// if err := json.Unmarshal(body, &listResp); err != nil {
// t.Fatalf("failed to parse list response for %q: %v", term, err)
// }
// if listResp.Meta.TotalResults == 0 {
// t.Fatalf("expected at least one result when searching for %q", term)
// }
// if len(listResp.Data) == 0 {
// t.Fatalf("expected data when searching for %q", term)
// }
// if listResp.Data[0].Id != createResp.Data.Id {
// t.Fatalf("expected project flock id %d for search term %q, got %d", createResp.Data.Id, term, listResp.Data[0].Id)
// }
// }
// }
// func TestProjectFlockSorting(t *testing.T) {
// app, _ := setupIntegrationApp(t)
// areaA := createArea(t, app, "Area Alpha")
// areaB := createArea(t, app, "Area Beta")
// locationA := createLocation(t, app, "Location Alpha", "Address Alpha", areaA)
// locationB := createLocation(t, app, "Location Beta", "Address Beta", areaB)
// flockOne := createFlock(t, app, "Flock Sort One")
// flockTwo := createFlock(t, app, "Flock Sort Two")
// fcrID := createFcr(t, app, "FCR Sort", []map[string]any{
// {"weight": 1.0, "fcr_number": 1.5, "mortality": 2.0},
// })
// kandangOne := createKandang(t, app, "Kandang Sort One", locationA, 1)
// kandangTwo := createKandang(t, app, "Kandang Sort Two", locationB, 1)
// kandangThree := createKandang(t, app, "Kandang Sort Three", locationB, 1)
// projectOnePayload := map[string]any{
// "flock_id": flockOne,
// "area_id": areaA,
// "category": "growing",
// "fcr_id": fcrID,
// "location_id": locationA,
// "kandang_ids": []uint{kandangOne},
// }
// resp, body := doJSONRequest(t, app, http.MethodPost, "/api/production/project_flocks", projectOnePayload)
// if resp.StatusCode != fiber.StatusCreated {
// t.Fatalf("expected 201 for project one, got %d: %s", resp.StatusCode, string(body))
// }
// projectOneID := parseProjectFlockID(t, body)
// projectTwoPayload := map[string]any{
// "flock_id": flockTwo,
// "area_id": areaB,
// "category": "laying",
// "fcr_id": fcrID,
// "location_id": locationB,
// "kandang_ids": []uint{kandangTwo, kandangThree},
// }
// resp, body = doJSONRequest(t, app, http.MethodPost, "/api/production/project_flocks", projectTwoPayload)
// if resp.StatusCode != fiber.StatusCreated {
// t.Fatalf("expected 201 for project two, got %d: %s", resp.StatusCode, string(body))
// }
// projectTwoID := parseProjectFlockID(t, body)
// updatePeriodPayload := map[string]any{"period": 5}
// resp, body = doJSONRequest(t, app, http.MethodPatch, "/api/production/project_flocks/"+uintToString(projectTwoID), updatePeriodPayload)
// if resp.StatusCode != fiber.StatusOK {
// t.Fatalf("expected 200 when updating period, got %d: %s", resp.StatusCode, string(body))
// }
// assertOrder := func(t *testing.T, app *fiber.App, query string, expectedFirst uint) {
// t.Helper()
// resp, body := doJSONRequest(t, app, http.MethodGet, "/api/production/project_flocks?"+query, nil)
// if resp.StatusCode != fiber.StatusOK {
// t.Fatalf("expected 200 for query %q, got %d: %s", query, resp.StatusCode, string(body))
// }
// var listResp struct {
// Data []struct {
// Id uint `json:"id"`
// } `json:"data"`
// }
// if err := json.Unmarshal(body, &listResp); err != nil {
// t.Fatalf("failed to parse list response for %q: %v", query, err)
// }
// if len(listResp.Data) == 0 {
// t.Fatalf("expected data for query %q", query)
// }
// if listResp.Data[0].Id != expectedFirst {
// t.Fatalf("expected first id %d for query %q, got %d", expectedFirst, query, listResp.Data[0].Id)
// }
// }
// assertOrder(t, app, "sort_by=area&sort_order=asc", projectOneID)
// assertOrder(t, app, "sort_by=location&sort_order=desc", projectTwoID)
// assertOrder(t, app, "sort_by=period&sort_order=desc", projectTwoID)
// assertOrder(t, app, "sort_by=kandangs&sort_order=desc", projectTwoID)
// assertOrder(t, app, "sort_by=kandangs&sort_order=asc", projectOneID)
// }
// func parseProjectFlockID(t *testing.T, body []byte) uint {
// t.Helper()
// var resp struct {
// Data struct {
// Id uint `json:"id"`
// } `json:"data"`
// }
// if err := json.Unmarshal(body, &resp); err != nil {
// t.Fatalf("failed to parse project flock response: %v", err)
// }
// return resp.Data.Id
// }
@@ -1,238 +0,0 @@
package test
import (
"encoding/json"
"errors"
"fmt"
"net/http"
"strings"
"testing"
"github.com/gofiber/fiber/v2"
"gorm.io/gorm"
"gitlab.com/mbugroup/lti-api.git/internal/entities"
"gitlab.com/mbugroup/lti-api.git/internal/utils"
)
func TestSupplierIntegration(t *testing.T) {
app, db := setupIntegrationApp(t)
t.Run("creating supplier with invalid type fails", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/suppliers", map[string]any{
"name": "Invalid Supplier",
"alias": "inv01",
"pic": "Jane Doe",
"type": "random-type",
"category": utils.SupplierCategoryBOP,
"hatchery": "Hatchery X",
"phone": "081234567891",
"email": "invalid@supplier.com",
"address": "Somewhere",
"npwp": "NPWP-INVALID",
"account_number": "ACC-INVALID",
"due_date": 30,
})
if resp.StatusCode != fiber.StatusBadRequest {
t.Fatalf("expected 400 when type is invalid, got %d: %s", resp.StatusCode, string(body))
}
})
t.Run("creating supplier with invalid category fails", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/suppliers", map[string]any{
"name": "Invalid Category Supplier",
"alias": "cat01",
"pic": "Jane Doe",
"type": utils.CustomerSupplierTypeBisnis,
"category": "invalid",
"phone": "081234567892",
"email": "invalid-category@supplier.com",
"address": "Somewhere",
"due_date": 30,
})
if resp.StatusCode != fiber.StatusBadRequest {
t.Fatalf("expected 400 when category is invalid, got %d: %s", resp.StatusCode, string(body))
}
})
const supplierName = "Supplier Alpha"
const alias = "al001"
var supplierID uint
t.Run("creating supplier succeeds", func(t *testing.T) {
supplierID = createSupplier(t, app, supplierName, alias, string(utils.SupplierCategoryBOP))
supplier := fetchSupplier(t, db, supplierID)
if supplier.Name != supplierName {
t.Fatalf("expected name %q, got %q", supplierName, supplier.Name)
}
if supplier.Alias != strings.ToUpper(alias) {
t.Fatalf("expected alias %q, got %q", strings.ToUpper(alias), supplier.Alias)
}
if supplier.Type != string(utils.CustomerSupplierTypeBisnis) {
t.Fatalf("expected type %q, got %q", utils.CustomerSupplierTypeBisnis, supplier.Type)
}
if supplier.Category != string(utils.SupplierCategoryBOP) {
t.Fatalf("expected category %q, got %q", utils.SupplierCategoryBOP, supplier.Category)
}
if supplier.DueDate != 30 {
t.Fatalf("expected due date 30, got %d", supplier.DueDate)
}
if supplier.CreatedUser.Id != 1 {
t.Fatalf("expected created user id 1, got %d", supplier.CreatedUser.Id)
}
})
t.Run("creating supplier with duplicate name fails", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/suppliers", map[string]any{
"name": supplierName,
"alias": "dup01",
"pic": "Jane Doe",
"type": utils.CustomerSupplierTypeBisnis,
"category": utils.SupplierCategoryBOP,
"phone": "0811111111",
"email": "duplicate@supplier.com",
"address": "Duplicate address",
"due_date": 15,
})
if resp.StatusCode != fiber.StatusConflict {
t.Fatalf("expected 409 when creating duplicate supplier, got %d: %s", resp.StatusCode, string(body))
}
})
t.Run("getting existing supplier succeeds", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodGet, fmt.Sprintf("/api/master-data/suppliers/%d", supplierID), nil)
if resp.StatusCode != fiber.StatusOK {
t.Fatalf("expected 200 when fetching supplier, got %d: %s", resp.StatusCode, string(body))
}
var payload struct {
Data struct {
Id uint `json:"id"`
Name string `json:"name"`
Alias string `json:"alias"`
Type string `json:"type"`
Category string `json:"category"`
CreatedUser *struct {
Id uint `json:"id"`
} `json:"created_user"`
} `json:"data"`
}
if err := json.Unmarshal(body, &payload); err != nil {
t.Fatalf("failed to parse supplier response: %v", err)
}
if payload.Data.Id != supplierID {
t.Fatalf("expected id %d, got %d", supplierID, payload.Data.Id)
}
if payload.Data.Name != supplierName {
t.Fatalf("expected name %q, got %q", supplierName, payload.Data.Name)
}
if payload.Data.Alias != strings.ToUpper(alias) {
t.Fatalf("expected alias %q, got %q", strings.ToUpper(alias), payload.Data.Alias)
}
if payload.Data.Type != string(utils.CustomerSupplierTypeBisnis) {
t.Fatalf("expected type %q, got %q", utils.CustomerSupplierTypeBisnis, payload.Data.Type)
}
if payload.Data.Category != string(utils.SupplierCategoryBOP) {
t.Fatalf("expected category %q, got %q", utils.SupplierCategoryBOP, payload.Data.Category)
}
if payload.Data.CreatedUser == nil || payload.Data.CreatedUser.Id != 1 {
t.Fatalf("expected created_user id 1, got %+v", payload.Data.CreatedUser)
}
})
const updatedAlias = "beta1"
t.Run("updating supplier fields succeeds", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodPatch, fmt.Sprintf("/api/master-data/suppliers/%d", supplierID), map[string]any{
"alias": updatedAlias,
"type": utils.CustomerSupplierTypeIndividual,
"category": utils.SupplierCategorySapronak,
"due_date": 45,
})
if resp.StatusCode != fiber.StatusOK {
t.Fatalf("expected 200 when updating supplier, got %d: %s", resp.StatusCode, string(body))
}
var payload struct {
Data struct {
Alias string `json:"alias"`
Type string `json:"type"`
Category string `json:"category"`
} `json:"data"`
}
if err := json.Unmarshal(body, &payload); err != nil {
t.Fatalf("failed to parse update response: %v", err)
}
if payload.Data.Alias != strings.ToUpper(updatedAlias) {
t.Fatalf("expected alias %q, got %q", strings.ToUpper(updatedAlias), payload.Data.Alias)
}
if payload.Data.Type != string(utils.CustomerSupplierTypeIndividual) {
t.Fatalf("expected type %q, got %q", utils.CustomerSupplierTypeIndividual, payload.Data.Type)
}
if payload.Data.Category != string(utils.SupplierCategorySapronak) {
t.Fatalf("expected category %q, got %q", utils.SupplierCategorySapronak, payload.Data.Category)
}
supplier := fetchSupplier(t, db, supplierID)
if supplier.Alias != strings.ToUpper(updatedAlias) {
t.Fatalf("expected persisted alias %q, got %q", strings.ToUpper(updatedAlias), supplier.Alias)
}
if supplier.Type != string(utils.CustomerSupplierTypeIndividual) {
t.Fatalf("expected persisted type %q, got %q", utils.CustomerSupplierTypeIndividual, supplier.Type)
}
if supplier.Category != string(utils.SupplierCategorySapronak) {
t.Fatalf("expected persisted category %q, got %q", utils.SupplierCategorySapronak, supplier.Category)
}
if supplier.DueDate != 45 {
t.Fatalf("expected due date 45, got %d", supplier.DueDate)
}
})
t.Run("updating supplier with invalid type fails", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodPatch, fmt.Sprintf("/api/master-data/suppliers/%d", supplierID), map[string]any{
"type": "invalid-type",
})
if resp.StatusCode != fiber.StatusBadRequest {
t.Fatalf("expected 400 when updating with invalid type, got %d: %s", resp.StatusCode, string(body))
}
supplier := fetchSupplier(t, db, supplierID)
if supplier.Type != string(utils.CustomerSupplierTypeIndividual) {
t.Fatalf("expected type to remain %q after invalid update, got %q", utils.CustomerSupplierTypeIndividual, supplier.Type)
}
})
t.Run("updating supplier with invalid category fails", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodPatch, fmt.Sprintf("/api/master-data/suppliers/%d", supplierID), map[string]any{
"category": "invalid",
})
if resp.StatusCode != fiber.StatusBadRequest {
t.Fatalf("expected 400 when updating with invalid category, got %d: %s", resp.StatusCode, string(body))
}
supplier := fetchSupplier(t, db, supplierID)
if supplier.Category != string(utils.SupplierCategorySapronak) {
t.Fatalf("expected category to remain %q after invalid update, got %q", utils.SupplierCategorySapronak, supplier.Category)
}
})
t.Run("deleting supplier succeeds", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodDelete, fmt.Sprintf("/api/master-data/suppliers/%d", supplierID), nil)
if resp.StatusCode != fiber.StatusOK {
t.Fatalf("expected 200 when deleting supplier, got %d: %s", resp.StatusCode, string(body))
}
var supplier entities.Supplier
if err := db.First(&supplier, supplierID).Error; !errors.Is(err, gorm.ErrRecordNotFound) {
t.Fatalf("expected supplier to be deleted, got error %v", err)
}
})
t.Run("deleting non existent supplier returns 404", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodDelete, fmt.Sprintf("/api/master-data/suppliers/%d", supplierID), nil)
if resp.StatusCode != fiber.StatusNotFound {
t.Fatalf("expected 404 when deleting missing supplier, got %d: %s", resp.StatusCode, string(body))
}
})
t.Run("getting deleted supplier returns 404", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodGet, fmt.Sprintf("/api/master-data/suppliers/%d", supplierID), nil)
if resp.StatusCode != fiber.StatusNotFound {
t.Fatalf("expected 404 when fetching deleted supplier, got %d: %s", resp.StatusCode, string(body))
}
})
}
@@ -1,96 +0,0 @@
package test
import (
"net/http"
"testing"
"github.com/gofiber/fiber/v2"
)
func TestWarehouseIntegration(t *testing.T) {
app, db := setupIntegrationApp(t)
areaID := createArea(t, app, "Warehouse Area")
locationID := createLocation(t, app, "Location WH", "Addr", areaID)
kandangID := createKandang(t, app, "Kandang WH", locationID, 1)
t.Run("type AREA only needs area_id", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/warehouses", map[string]any{
"name": "WH Area",
"type": "AREA",
"area_id": areaID,
})
if resp.StatusCode != fiber.StatusCreated {
t.Fatalf("expected 201, got %d: %s", resp.StatusCode, string(body))
}
})
t.Run("type AREA rejects location_id", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/warehouses", map[string]any{
"name": "WH Area Invalid",
"type": "AREA",
"area_id": areaID,
"location_id": locationID,
})
if resp.StatusCode != fiber.StatusBadRequest {
t.Fatalf("expected 400, got %d: %s", resp.StatusCode, string(body))
}
})
t.Run("type LOKASI requires location_id", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/warehouses", map[string]any{
"name": "WH Lokasi Fail",
"type": "LOKASI",
"area_id": areaID,
})
if resp.StatusCode != fiber.StatusBadRequest {
t.Fatalf("expected 400, got %d: %s", resp.StatusCode, string(body))
}
})
t.Run("type LOKASI success", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/warehouses", map[string]any{
"name": "WH Lokasi",
"type": "LOKASI",
"area_id": areaID,
"location_id": locationID,
})
if resp.StatusCode != fiber.StatusCreated {
t.Fatalf("expected 201, got %d: %s", resp.StatusCode, string(body))
}
whID := parseID(t, body)
wh := fetchWarehouse(t, db, whID)
if wh.LocationId == nil || *wh.LocationId != locationID {
t.Fatalf("expected location_id %d, got %v", locationID, wh.LocationId)
}
})
t.Run("type KANDANG requires all ids", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/warehouses", map[string]any{
"name": "WH Kandang Fail",
"type": "KANDANG",
"area_id": areaID,
"location_id": locationID,
})
if resp.StatusCode != fiber.StatusBadRequest {
t.Fatalf("expected 400, got %d: %s", resp.StatusCode, string(body))
}
})
t.Run("type KANDANG success", func(t *testing.T) {
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/warehouses", map[string]any{
"name": "WH Kandang",
"type": "KANDANG",
"area_id": areaID,
"location_id": locationID,
"kandang_id": kandangID,
})
if resp.StatusCode != fiber.StatusCreated {
t.Fatalf("expected 201, got %d: %s", resp.StatusCode, string(body))
}
whID := parseID(t, body)
wh := fetchWarehouse(t, db, whID)
if wh.KandangId == nil || *wh.KandangId != kandangID {
t.Fatalf("expected kandang_id %d, got %v", kandangID, wh.KandangId)
}
})
}
+6 -6
View File
@@ -9,7 +9,7 @@ import (
// === DTO Structs === // === DTO Structs ===
type {{Pascal .Entity}}BaseDTO struct { type {{Pascal .Entity}}RelationDTO struct {
Id uint `json:"id"` Id uint `json:"id"`
Name string `json:"name"` Name string `json:"name"`
} }
@@ -17,7 +17,7 @@ type {{Pascal .Entity}}BaseDTO struct {
type {{Pascal .Entity}}ListDTO struct { type {{Pascal .Entity}}ListDTO struct {
Id uint `json:"id"` Id uint `json:"id"`
Name string `json:"name"` Name string `json:"name"`
CreatedUser *userDTO.UserBaseDTO `json:"created_user"` CreatedUser *userDTO.UserRelationDTO `json:"created_user"`
CreatedAt time.Time `json:"created_at"` CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"` UpdatedAt time.Time `json:"updated_at"`
} }
@@ -28,17 +28,17 @@ type {{Pascal .Entity}}DetailDTO struct {
// === Mapper Functions === // === Mapper Functions ===
func To{{Pascal .Entity}}BaseDTO(e entity.{{Pascal .Entity}}) {{Pascal .Entity}}BaseDTO { func To{{Pascal .Entity}}RelationDTO(e entity.{{Pascal .Entity}}) {{Pascal .Entity}}RelationDTO {
return {{Pascal .Entity}}BaseDTO{ return {{Pascal .Entity}}RelationDTO{
Id: e.Id, Id: e.Id,
Name: e.Name, Name: e.Name,
} }
} }
func To{{Pascal .Entity}}ListDTO(e entity.{{Pascal .Entity}}) {{Pascal .Entity}}ListDTO { func To{{Pascal .Entity}}ListDTO(e entity.{{Pascal .Entity}}) {{Pascal .Entity}}ListDTO {
var createdUser *userDTO.UserBaseDTO var createdUser *userDTO.UserRelationDTO
if e.CreatedUser.Id != 0 { if e.CreatedUser.Id != 0 {
mapped := userDTO.ToUserBaseDTO(e.CreatedUser) mapped := userDTO.ToUserRelationDTO(e.CreatedUser)
createdUser = &mapped createdUser = &mapped
} }