From fd0943dfafc85e388c029cb0b19d9233e9adab48 Mon Sep 17 00:00:00 2001 From: aguhh18 Date: Mon, 10 Nov 2025 14:49:46 +0700 Subject: [PATCH] feat[BE-222]: create migration create template for SO API and kandang id param on product warehouse --- .../product_warehouse.controller.go | 1 + .../inventory/product-warehouses/module.go | 5 +- .../product_warehouse.repository.go | 5 ++ .../services/product_warehouse.service.go | 32 +++++++--- .../product_warehouse.validation.go | 1 + .../controllers/sales-orders.controller.go | 12 ++-- .../modules/marketing/sales-orders/module.go | 10 ++- .../repositories/marketings.repository.go | 21 +++++++ .../services/sales-orders.service.go | 63 +++++++++++++++---- .../validations/sales-orders.validation.go | 18 +++++- .../repositories/customer.repository.go | 5 ++ .../repositories/kandang.repository.go | 5 ++ 12 files changed, 147 insertions(+), 31 deletions(-) create mode 100644 internal/modules/marketing/sales-orders/repositories/marketings.repository.go diff --git a/internal/modules/inventory/product-warehouses/controllers/product_warehouse.controller.go b/internal/modules/inventory/product-warehouses/controllers/product_warehouse.controller.go index 26f23278..671d964b 100644 --- a/internal/modules/inventory/product-warehouses/controllers/product_warehouse.controller.go +++ b/internal/modules/inventory/product-warehouses/controllers/product_warehouse.controller.go @@ -29,6 +29,7 @@ func (u *ProductWarehouseController) GetAll(c *fiber.Ctx) error { ProductId: uint(c.QueryInt("product_id", 0)), WarehouseId: uint(c.QueryInt("warehouse_id", 0)), Flags: c.Query("flags", ""), + KandangId: uint(c.QueryInt("kandang_id", 0)), } if query.Page < 1 || query.Limit < 1 { diff --git a/internal/modules/inventory/product-warehouses/module.go b/internal/modules/inventory/product-warehouses/module.go index dfb72e8f..0dd8047e 100644 --- a/internal/modules/inventory/product-warehouses/module.go +++ b/internal/modules/inventory/product-warehouses/module.go @@ -7,6 +7,7 @@ import ( rProductWarehouse "gitlab.com/mbugroup/lti-api.git/internal/modules/inventory/product-warehouses/repositories" sProductWarehouse "gitlab.com/mbugroup/lti-api.git/internal/modules/inventory/product-warehouses/services" + rKandang "gitlab.com/mbugroup/lti-api.git/internal/modules/master/kandangs/repositories" rUser "gitlab.com/mbugroup/lti-api.git/internal/modules/users/repositories" sUser "gitlab.com/mbugroup/lti-api.git/internal/modules/users/services" @@ -17,10 +18,10 @@ type ProductWarehouseModule struct{} func (ProductWarehouseModule) RegisterRoutes(router fiber.Router, db *gorm.DB, validate *validator.Validate) { productWarehouseRepo := rProductWarehouse.NewProductWarehouseRepository(db) userRepo := rUser.NewUserRepository(db) + kandangRepo := rKandang.NewKandangRepository(db) - productWarehouseService := sProductWarehouse.NewProductWarehouseService(productWarehouseRepo, validate) + productWarehouseService := sProductWarehouse.NewProductWarehouseService(productWarehouseRepo, validate, kandangRepo) userService := sUser.NewUserService(userRepo, validate) ProductWarehouseRoutes(router, userService, productWarehouseService) } - diff --git a/internal/modules/inventory/product-warehouses/repositories/product_warehouse.repository.go b/internal/modules/inventory/product-warehouses/repositories/product_warehouse.repository.go index 151a3697..80c551eb 100644 --- a/internal/modules/inventory/product-warehouses/repositories/product_warehouse.repository.go +++ b/internal/modules/inventory/product-warehouses/repositories/product_warehouse.repository.go @@ -24,6 +24,7 @@ type ProductWarehouseRepository interface { ApplyFlagsFilter(db *gorm.DB, flags []string) *gorm.DB AdjustQuantities(ctx context.Context, deltas map[uint]float64, modifier func(*gorm.DB) *gorm.DB) error GetDetailByID(ctx context.Context, id uint) (*entity.ProductWarehouse, error) + IdExists(ctx context.Context, id uint) (bool, error) } type ProductWarehouseRepositoryImpl struct { @@ -47,6 +48,10 @@ func (r *ProductWarehouseRepositoryImpl) ExistsByID(ctx context.Context, id uint return repository.Exists[entity.ProductWarehouse](ctx, r.DB(), id) } +func (r *ProductWarehouseRepositoryImpl) IdExists(ctx context.Context, id uint) (bool, error) { + return repository.Exists[entity.ProductWarehouse](ctx, r.DB(), id) +} + func (r *ProductWarehouseRepositoryImpl) ProductWarehouseExists(ctx context.Context, productId, warehouseId uint, excludeID *uint) (bool, error) { var count int64 query := r.DB().WithContext(ctx).Model(&entity.ProductWarehouse{}). diff --git a/internal/modules/inventory/product-warehouses/services/product_warehouse.service.go b/internal/modules/inventory/product-warehouses/services/product_warehouse.service.go index cc925970..cc7d5b85 100644 --- a/internal/modules/inventory/product-warehouses/services/product_warehouse.service.go +++ b/internal/modules/inventory/product-warehouses/services/product_warehouse.service.go @@ -6,6 +6,7 @@ import ( entity "gitlab.com/mbugroup/lti-api.git/internal/entities" repository "gitlab.com/mbugroup/lti-api.git/internal/modules/inventory/product-warehouses/repositories" validation "gitlab.com/mbugroup/lti-api.git/internal/modules/inventory/product-warehouses/validations" + kandangrepo "gitlab.com/mbugroup/lti-api.git/internal/modules/master/kandangs/repositories" "gitlab.com/mbugroup/lti-api.git/internal/utils" "github.com/go-playground/validator/v10" @@ -20,16 +21,18 @@ type ProductWarehouseService interface { } type productWarehouseService struct { - Log *logrus.Logger - Validate *validator.Validate - Repository repository.ProductWarehouseRepository + Log *logrus.Logger + Validate *validator.Validate + Repository repository.ProductWarehouseRepository + KandangRepo kandangrepo.KandangRepository } -func NewProductWarehouseService(repo repository.ProductWarehouseRepository, validate *validator.Validate) ProductWarehouseService { +func NewProductWarehouseService(repo repository.ProductWarehouseRepository, validate *validator.Validate, kandangRepo kandangrepo.KandangRepository) ProductWarehouseService { return &productWarehouseService{ - Log: utils.Log, - Validate: validate, - Repository: repo, + Log: utils.Log, + Validate: validate, + Repository: repo, + KandangRepo: kandangRepo, } } @@ -69,6 +72,16 @@ func (s productWarehouseService) GetAll(c *fiber.Ctx, params *validation.Query) } } + if params.KandangId > 0 { + isKandangExist, err := s.KandangRepo.IdExists(c.Context(), params.KandangId) + if err != nil { + return nil, 0, err + } + if !isKandangExist { + return nil, 0, fiber.NewError(fiber.StatusNotFound, "Kandang not found") + } + } + offset := (params.Page - 1) * params.Limit cleanFlags := utils.ParseFlags(params.Flags) @@ -80,6 +93,11 @@ func (s productWarehouseService) GetAll(c *fiber.Ctx, params *validation.Query) db = db.Where("product_id = ?", params.ProductId) } + if params.KandangId != 0 { + db = db.Joins("JOIN warehouses ON product_warehouses.warehouse_id = warehouses.id"). + Where("warehouses.kandang_id = ?", params.KandangId) + } + if params.WarehouseId != 0 { db = db.Where("warehouse_id = ?", params.WarehouseId) } diff --git a/internal/modules/inventory/product-warehouses/validations/product_warehouse.validation.go b/internal/modules/inventory/product-warehouses/validations/product_warehouse.validation.go index 3a3acb28..322d0a00 100644 --- a/internal/modules/inventory/product-warehouses/validations/product_warehouse.validation.go +++ b/internal/modules/inventory/product-warehouses/validations/product_warehouse.validation.go @@ -18,4 +18,5 @@ type Query struct { ProductId uint `query:"product_id" validate:"omitempty,number,min=1"` WarehouseId uint `query:"warehouse_id" validate:"omitempty,number,min=1"` Flags string `query:"flags" validate:"omitempty"` + KandangId uint `query:"kandang_id" validate:"omitempty,number,min=1"` } diff --git a/internal/modules/marketing/sales-orders/controllers/sales-orders.controller.go b/internal/modules/marketing/sales-orders/controllers/sales-orders.controller.go index 837a8ee0..be578e15 100644 --- a/internal/modules/marketing/sales-orders/controllers/sales-orders.controller.go +++ b/internal/modules/marketing/sales-orders/controllers/sales-orders.controller.go @@ -29,7 +29,7 @@ func (u *SalesOrdersController) GetAll(c *fiber.Ctx) error { Search: c.Query("search", ""), } - if query.Page < 1 || query.Limit < 1 { + if query.Page < 1 || query.Limit < 1 { return fiber.NewError(fiber.StatusBadRequest, "page and limit must be greater than 0") } @@ -82,17 +82,17 @@ func (u *SalesOrdersController) CreateOne(c *fiber.Ctx) error { return fiber.NewError(fiber.StatusBadRequest, "Invalid request body") } - // result, err := u.SalesOrdersService.CreateOne(c, req) - // if err != nil { - // return err - // } + result, err := u.SalesOrdersService.CreateOne(c, req) + if err != nil { + return err + } return c.Status(fiber.StatusCreated). JSON(response.Success{ Code: fiber.StatusCreated, Status: "success", Message: "Create salesOrders successfully", - Data: req, + Data: result, }) } diff --git a/internal/modules/marketing/sales-orders/module.go b/internal/modules/marketing/sales-orders/module.go index 12310354..21926f93 100644 --- a/internal/modules/marketing/sales-orders/module.go +++ b/internal/modules/marketing/sales-orders/module.go @@ -5,8 +5,11 @@ import ( "github.com/gofiber/fiber/v2" "gorm.io/gorm" + rProductWarehouse "gitlab.com/mbugroup/lti-api.git/internal/modules/inventory/product-warehouses/repositories" rSalesOrders "gitlab.com/mbugroup/lti-api.git/internal/modules/marketing/sales-orders/repositories" sSalesOrders "gitlab.com/mbugroup/lti-api.git/internal/modules/marketing/sales-orders/services" + rCustomer "gitlab.com/mbugroup/lti-api.git/internal/modules/master/customers/repositories" + rKandang "gitlab.com/mbugroup/lti-api.git/internal/modules/master/kandangs/repositories" rUser "gitlab.com/mbugroup/lti-api.git/internal/modules/users/repositories" sUser "gitlab.com/mbugroup/lti-api.git/internal/modules/users/services" @@ -17,10 +20,13 @@ type SalesOrdersModule struct{} func (SalesOrdersModule) RegisterRoutes(router fiber.Router, db *gorm.DB, validate *validator.Validate) { salesOrdersRepo := rSalesOrders.NewSalesOrdersRepository(db) userRepo := rUser.NewUserRepository(db) + customerRepo := rCustomer.NewCustomerRepository(db) + kandangRepo := rKandang.NewKandangRepository(db) + productWarehouseRepo := rProductWarehouse.NewProductWarehouseRepository(db) + marketingRepo := rSalesOrders.NewMarketingRepository(db) - salesOrdersService := sSalesOrders.NewSalesOrdersService(salesOrdersRepo, validate) + salesOrdersService := sSalesOrders.NewSalesOrdersService(salesOrdersRepo, customerRepo, kandangRepo, productWarehouseRepo, marketingRepo, validate) userService := sUser.NewUserService(userRepo, validate) SalesOrdersRoutes(router, userService, salesOrdersService) } - diff --git a/internal/modules/marketing/sales-orders/repositories/marketings.repository.go b/internal/modules/marketing/sales-orders/repositories/marketings.repository.go new file mode 100644 index 00000000..bb4896cb --- /dev/null +++ b/internal/modules/marketing/sales-orders/repositories/marketings.repository.go @@ -0,0 +1,21 @@ +package repository + +import ( + "gitlab.com/mbugroup/lti-api.git/internal/common/repository" + entity "gitlab.com/mbugroup/lti-api.git/internal/entities" + "gorm.io/gorm" +) + +type MarketingRepository interface { + repository.BaseRepository[entity.Marketing] +} + +type MarketingRepositoryImpl struct { + *repository.BaseRepositoryImpl[entity.Marketing] +} + +func NewMarketingRepository(db *gorm.DB) MarketingRepository { + return &MarketingRepositoryImpl{ + BaseRepositoryImpl: repository.NewBaseRepository[entity.Marketing](db), + } +} diff --git a/internal/modules/marketing/sales-orders/services/sales-orders.service.go b/internal/modules/marketing/sales-orders/services/sales-orders.service.go index 33c93f6d..847305c1 100644 --- a/internal/modules/marketing/sales-orders/services/sales-orders.service.go +++ b/internal/modules/marketing/sales-orders/services/sales-orders.service.go @@ -3,9 +3,13 @@ package service import ( "errors" + commonSvc "gitlab.com/mbugroup/lti-api.git/internal/common/service" entity "gitlab.com/mbugroup/lti-api.git/internal/entities" + productWarehouseRepo "gitlab.com/mbugroup/lti-api.git/internal/modules/inventory/product-warehouses/repositories" repository "gitlab.com/mbugroup/lti-api.git/internal/modules/marketing/sales-orders/repositories" validation "gitlab.com/mbugroup/lti-api.git/internal/modules/marketing/sales-orders/validations" + customerRepo "gitlab.com/mbugroup/lti-api.git/internal/modules/master/customers/repositories" + kandangRepo "gitlab.com/mbugroup/lti-api.git/internal/modules/master/kandangs/repositories" "gitlab.com/mbugroup/lti-api.git/internal/utils" "github.com/go-playground/validator/v10" @@ -23,16 +27,24 @@ type SalesOrdersService interface { } type salesOrdersService struct { - Log *logrus.Logger - Validate *validator.Validate - Repository repository.SalesOrdersRepository + Log *logrus.Logger + Validate *validator.Validate + Repository repository.SalesOrdersRepository + CustomerRepo customerRepo.CustomerRepository + KandangRepo kandangRepo.KandangRepository + ProductWarehouseRepo productWarehouseRepo.ProductWarehouseRepository + MarketingRepo repository.MarketingRepository } -func NewSalesOrdersService(repo repository.SalesOrdersRepository, validate *validator.Validate) SalesOrdersService { +func NewSalesOrdersService(repo repository.SalesOrdersRepository, customerRepo customerRepo.CustomerRepository, kandangRepo kandangRepo.KandangRepository, productWarehouseRepo productWarehouseRepo.ProductWarehouseRepository, marketingRepo repository.MarketingRepository, validate *validator.Validate) SalesOrdersService { return &salesOrdersService{ - Log: utils.Log, - Validate: validate, - Repository: repo, + Log: utils.Log, + Validate: validate, + Repository: repo, + CustomerRepo: customerRepo, + KandangRepo: kandangRepo, + ProductWarehouseRepo: productWarehouseRepo, + MarketingRepo: marketingRepo, } } @@ -79,13 +91,40 @@ func (s *salesOrdersService) CreateOne(c *fiber.Ctx, req *validation.Create) (*e return nil, err } - createBody := &entity.SalesOrders{ - Name: req.Name, + if err := commonSvc.EnsureRelations(c.Context(), + commonSvc.RelationCheck{Name: "Customer", ID: &req.CustomerId, Exists: s.CustomerRepo.IdExists}, + ); err != nil { + return nil, err } - if err := s.Repository.CreateOne(c.Context(), createBody, nil); err != nil { - s.Log.Errorf("Failed to create salesOrders: %+v", err) - return nil, err + for _, item := range req.MarketingProducts { + if err := commonSvc.EnsureRelations(c.Context(), + commonSvc.RelationCheck{Name: "Kandang", ID: &item.KandangId, Exists: s.KandangRepo.IdExists}, + commonSvc.RelationCheck{Name: "ProductWarehouse", ID: &item.ProductWarehouseId, Exists: s.ProductWarehouseRepo.IdExists}, + ); err != nil { + return nil, err + } + } + + createBody := &entity.Marketing{ + CustomerId: req.CustomerId, + } + + err := s.MarketingRepo.DB().WithContext(c.Context()).Transaction(func(dbTransaction *gorm.DB) error { + marketingRepoTx := repository.NewMarketingRepository(dbTransaction) + + if err := marketingRepoTx.CreateOne(c.Context(), createBody, nil); err != nil { + s.Log.Errorf("Failed to create marketing: %+v", err) + return err + } + + return nil + }) + if err != nil { + if fiberErr, ok := err.(*fiber.Error); ok { + return nil, fiberErr + } + return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to create salesOrders") } return s.GetOne(c, createBody.Id) diff --git a/internal/modules/marketing/sales-orders/validations/sales-orders.validation.go b/internal/modules/marketing/sales-orders/validations/sales-orders.validation.go index 7d16d3ee..b09129bc 100644 --- a/internal/modules/marketing/sales-orders/validations/sales-orders.validation.go +++ b/internal/modules/marketing/sales-orders/validations/sales-orders.validation.go @@ -1,11 +1,25 @@ package validation type Create struct { - Name string `json:"name" validate:"required_strict,min=3"` + CustomerId uint `json:"customer_id" validate:"required,gt=0"` + Date string `json:"date" validate:"required,datetime=2006-01-02"` + Notes string `json:"notes" validate:"omitempty,max=500"` + MarketingProducts []CreateMarketingProduct `json:"marketing_products" validate:"required,min=1,dive"` +} + +type CreateMarketingProduct struct { + VehicleNumber string `json:"vehicle_number" validate:"required,min=1,max=50"` + KandangId uint `json:"kandang_id" validate:"required,gt=0"` + ProductWarehouseId uint `json:"product_warehouse_id" validate:"required,gt=0"` + UnitPrice float64 `json:"unit_price" validate:"required,gt=0"` + TotalWeight float64 `json:"total_weight" validate:"required,gt=0"` + Qty float64 `json:"qty" validate:"required,gt=0"` + AvgWeight float64 `json:"avg_weight" validate:"required,gt=0"` + TotalPrice float64 `json:"total_price" validate:"required,gt=0"` } type Update struct { - Name *string `json:"name,omitempty" validate:"omitempty"` + Name *string `json:"name,omitempty" validate:"omitempty"` } type Query struct { diff --git a/internal/modules/master/customers/repositories/customer.repository.go b/internal/modules/master/customers/repositories/customer.repository.go index 13a08211..68877548 100644 --- a/internal/modules/master/customers/repositories/customer.repository.go +++ b/internal/modules/master/customers/repositories/customer.repository.go @@ -12,6 +12,7 @@ type CustomerRepository interface { repository.BaseRepository[entity.Customer] PicExists(ctx context.Context, areaId uint) (bool, error) NameExists(ctx context.Context, name string, excludeID *uint) (bool, error) + IdExists(ctx context.Context, id uint) (bool, error) } type CustomerRepositoryImpl struct { @@ -33,3 +34,7 @@ func (r *CustomerRepositoryImpl) PicExists(ctx context.Context, picId uint) (boo func (r *CustomerRepositoryImpl) NameExists(ctx context.Context, name string, excludeID *uint) (bool, error) { return repository.ExistsByName[entity.Customer](ctx, r.db, name, excludeID) } + +func (r *CustomerRepositoryImpl) IdExists(ctx context.Context, id uint) (bool, error) { + return repository.Exists[entity.Customer](ctx, r.db, id) +} diff --git a/internal/modules/master/kandangs/repositories/kandang.repository.go b/internal/modules/master/kandangs/repositories/kandang.repository.go index 8f32a7b2..04b6a914 100644 --- a/internal/modules/master/kandangs/repositories/kandang.repository.go +++ b/internal/modules/master/kandangs/repositories/kandang.repository.go @@ -21,6 +21,7 @@ type KandangRepository interface { UpdateStatusByProjectFlockID(ctx context.Context, projectFlockID uint, status utils.KandangStatus) error UpsertProjectFlockKandang(ctx context.Context, projectFlockID, kandangID uint) error UpdateStatusByIDs(ctx context.Context, kandangIDs []uint, status utils.KandangStatus) error + IdExists(ctx context.Context, id uint) (bool, error) } type KandangRepositoryImpl struct { @@ -59,6 +60,10 @@ func (r *KandangRepositoryImpl) ProjectFlockExists(ctx context.Context, projectF return count > 0, nil } +func (r *KandangRepositoryImpl) IdExists(ctx context.Context, id uint) (bool, error) { + return repository.Exists[entity.Kandang](ctx, r.db, id) +} + func (r *KandangRepositoryImpl) HasActiveKandangForProjectFlock(ctx context.Context, projectFlockID uint, excludeID *uint) (bool, error) { var count int64 q := r.db.WithContext(ctx).