mirror of
https://gitlab.com/mbugroup/lti-api.git
synced 2026-05-20 13:31:56 +00:00
merge: ragil-before-sso from development-before-sso
This commit is contained in:
@@ -2,6 +2,7 @@ package repository
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
@@ -32,3 +33,21 @@ func ExistsByName[T any](ctx context.Context, db *gorm.DB, name string, excludeI
|
|||||||
}
|
}
|
||||||
return count > 0, nil
|
return count > 0, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ExistsByField[T any](ctx context.Context, db *gorm.DB, field string, value any, excludeID *uint) (bool, error) {
|
||||||
|
if field == "" {
|
||||||
|
return false, fmt.Errorf("field is required")
|
||||||
|
}
|
||||||
|
var count int64
|
||||||
|
q := db.WithContext(ctx).
|
||||||
|
Model(new(T)).
|
||||||
|
Where(fmt.Sprintf("%s = ?", field), value).
|
||||||
|
Where("deleted_at IS NULL")
|
||||||
|
if excludeID != nil {
|
||||||
|
q = q.Where("id <> ?", *excludeID)
|
||||||
|
}
|
||||||
|
if err := q.Count(&count).Error; err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return count > 0, nil
|
||||||
|
}
|
||||||
|
|||||||
+5
-2
@@ -28,6 +28,11 @@ func (u *ProductWarehouseController) GetAll(c *fiber.Ctx) error {
|
|||||||
Limit: c.QueryInt("limit", 10),
|
Limit: c.QueryInt("limit", 10),
|
||||||
ProductId: uint(c.QueryInt("product_id", 0)),
|
ProductId: uint(c.QueryInt("product_id", 0)),
|
||||||
WarehouseId: uint(c.QueryInt("warehouse_id", 0)),
|
WarehouseId: uint(c.QueryInt("warehouse_id", 0)),
|
||||||
|
Flags: c.Query("flags", ""),
|
||||||
|
}
|
||||||
|
|
||||||
|
if query.Page < 1 || query.Limit < 1 {
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, "page and limit must be greater than 0")
|
||||||
}
|
}
|
||||||
|
|
||||||
result, totalResults, err := u.ProductWarehouseService.GetAll(c, query)
|
result, totalResults, err := u.ProductWarehouseService.GetAll(c, query)
|
||||||
@@ -71,5 +76,3 @@ func (u *ProductWarehouseController) GetOne(c *fiber.Ctx) error {
|
|||||||
Data: dto.ToProductWarehouseListDTO(*result),
|
Data: dto.ToProductWarehouseListDTO(*result),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+28
-11
@@ -16,6 +16,7 @@ type ProductWarehouseRepository interface {
|
|||||||
ProductWarehouseExistByProductAndWarehouseID(ctx context.Context, productId, warehouseId uint) (bool, error)
|
ProductWarehouseExistByProductAndWarehouseID(ctx context.Context, productId, warehouseId uint) (bool, error)
|
||||||
ExistsByID(ctx context.Context, id uint) (bool, error)
|
ExistsByID(ctx context.Context, id uint) (bool, error)
|
||||||
GetProductWarehouseByProductAndWarehouseID(ctx context.Context, productId, warehouseId uint) (*entity.ProductWarehouse, error)
|
GetProductWarehouseByProductAndWarehouseID(ctx context.Context, productId, warehouseId uint) (*entity.ProductWarehouse, error)
|
||||||
|
GetByCategoryCodeAndWarehouseID(ctx context.Context, categoryCode string, warehouseId uint) ([]entity.ProductWarehouse, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type ProductWarehouseRepositoryImpl struct {
|
type ProductWarehouseRepositoryImpl struct {
|
||||||
@@ -30,6 +31,17 @@ func NewProductWarehouseRepository(db *gorm.DB) ProductWarehouseRepository {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *ProductWarehouseRepositoryImpl) IsProductExist(ctx context.Context, productId uint) (bool, error) {
|
||||||
|
return repository.Exists[entity.Product](ctx, r.db, productId)
|
||||||
|
}
|
||||||
|
func (r *ProductWarehouseRepositoryImpl) IsWarehouseExist(ctx context.Context, warehouseId uint) (bool, error) {
|
||||||
|
return repository.Exists[entity.Warehouse](ctx, r.db, warehouseId)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *ProductWarehouseRepositoryImpl) ExistsByID(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) {
|
func (r *ProductWarehouseRepositoryImpl) ProductWarehouseExists(ctx context.Context, productId, warehouseId uint, excludeID *uint) (bool, error) {
|
||||||
var count int64
|
var count int64
|
||||||
query := r.db.WithContext(ctx).Model(&entity.ProductWarehouse{}).
|
query := r.db.WithContext(ctx).Model(&entity.ProductWarehouse{}).
|
||||||
@@ -43,17 +55,6 @@ func (r *ProductWarehouseRepositoryImpl) ProductWarehouseExists(ctx context.Cont
|
|||||||
return count > 0, nil
|
return count > 0, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *ProductWarehouseRepositoryImpl) IsProductExist(ctx context.Context, productId uint) (bool, error) {
|
|
||||||
return repository.Exists[entity.Product](ctx, r.db, productId)
|
|
||||||
}
|
|
||||||
func (r *ProductWarehouseRepositoryImpl) IsWarehouseExist(ctx context.Context, warehouseId uint) (bool, error) {
|
|
||||||
return repository.Exists[entity.Warehouse](ctx, r.db, warehouseId)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *ProductWarehouseRepositoryImpl) ExistsByID(ctx context.Context, id uint) (bool, error) {
|
|
||||||
return repository.Exists[entity.ProductWarehouse](ctx, r.db, id)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *ProductWarehouseRepositoryImpl) ProductWarehouseExistByProductAndWarehouseID(ctx context.Context, productId, warehouseId uint) (bool, error) {
|
func (r *ProductWarehouseRepositoryImpl) ProductWarehouseExistByProductAndWarehouseID(ctx context.Context, productId, warehouseId uint) (bool, error) {
|
||||||
var count int64
|
var count int64
|
||||||
if err := r.db.WithContext(ctx).
|
if err := r.db.WithContext(ctx).
|
||||||
@@ -72,3 +73,19 @@ func (r *ProductWarehouseRepositoryImpl) GetProductWarehouseByProductAndWarehous
|
|||||||
}
|
}
|
||||||
return &productWarehouse, nil
|
return &productWarehouse, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *ProductWarehouseRepositoryImpl) GetByCategoryCodeAndWarehouseID(ctx context.Context, categoryCode string, warehouseId uint) ([]entity.ProductWarehouse, error) {
|
||||||
|
var productWarehouses []entity.ProductWarehouse
|
||||||
|
err := r.db.WithContext(ctx).
|
||||||
|
Table("product_warehouses").
|
||||||
|
Select("product_warehouses.*").
|
||||||
|
Joins("JOIN products ON products.id = product_warehouses.product_id").
|
||||||
|
Joins("JOIN product_categories ON product_categories.id = products.product_category_id").
|
||||||
|
Where("product_categories.code = ? AND product_warehouses.warehouse_id = ?", categoryCode, warehouseId).
|
||||||
|
Order("product_warehouses.created_at DESC").
|
||||||
|
Find(&productWarehouses).Error
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return productWarehouses, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -49,8 +49,30 @@ func (s productWarehouseService) GetAll(c *fiber.Ctx, params *validation.Query)
|
|||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if params.ProductId > 0 {
|
||||||
|
isProductExist, err := s.Repository.IsProductExist(c.Context(), params.ProductId)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
if !isProductExist {
|
||||||
|
return nil, 0, fiber.NewError(fiber.StatusNotFound, "Product not found")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if params.WarehouseId > 0 {
|
||||||
|
isWarehouseExist, err := s.Repository.IsWarehouseExist(c.Context(), params.WarehouseId)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
if !isWarehouseExist {
|
||||||
|
return nil, 0, fiber.NewError(fiber.StatusNotFound, "Warehouse not found")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
offset := (params.Page - 1) * params.Limit
|
offset := (params.Page - 1) * params.Limit
|
||||||
|
|
||||||
|
cleanFlags := utils.ParseFlags(params.Flags)
|
||||||
|
|
||||||
productWarehouses, total, err := s.Repository.GetAll(c.Context(), offset, params.Limit, func(db *gorm.DB) *gorm.DB {
|
productWarehouses, total, err := s.Repository.GetAll(c.Context(), offset, params.Limit, func(db *gorm.DB) *gorm.DB {
|
||||||
db = s.withRelations(db)
|
db = s.withRelations(db)
|
||||||
|
|
||||||
@@ -62,6 +84,12 @@ func (s productWarehouseService) GetAll(c *fiber.Ctx, params *validation.Query)
|
|||||||
db = db.Where("warehouse_id = ?", params.WarehouseId)
|
db = db.Where("warehouse_id = ?", params.WarehouseId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(cleanFlags) > 0 {
|
||||||
|
db = db.Joins("JOIN products ON products.id = product_warehouses.product_id").
|
||||||
|
Joins("JOIN flags ON flags.flagable_id = products.id AND flags.flagable_type = ?", "products").
|
||||||
|
Where("flags.name IN ?", cleanFlags)
|
||||||
|
}
|
||||||
|
|
||||||
return db.Order("created_at DESC").Order("updated_at DESC")
|
return db.Order("created_at DESC").Order("updated_at DESC")
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
+5
-4
@@ -13,8 +13,9 @@ 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"`
|
||||||
ProductId uint `query:"product_id" validate:"omitempty,number,min=1"`
|
ProductId uint `query:"product_id" validate:"omitempty,number,min=1"`
|
||||||
WarehouseId uint `query:"warehouse_id" validate:"omitempty,number,min=1"`
|
WarehouseId uint `query:"warehouse_id" validate:"omitempty,number,min=1"`
|
||||||
|
Flags string `query:"flags" validate:"omitempty"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,6 +29,10 @@ func (u *AreaController) GetAll(c *fiber.Ctx) error {
|
|||||||
Search: c.Query("search", ""),
|
Search: c.Query("search", ""),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if query.Page < 1 || query.Limit < 1 {
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, "page and limit must be greater than 0")
|
||||||
|
}
|
||||||
|
|
||||||
result, totalResults, err := u.AreaService.GetAll(c, query)
|
result, totalResults, err := u.AreaService.GetAll(c, query)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -29,6 +29,10 @@ func (u *BankController) GetAll(c *fiber.Ctx) error {
|
|||||||
Search: c.Query("search", ""),
|
Search: c.Query("search", ""),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if query.Page < 1 || query.Limit < 1 {
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, "page and limit must be greater than 0")
|
||||||
|
}
|
||||||
|
|
||||||
result, totalResults, err := u.BankService.GetAll(c, query)
|
result, totalResults, err := u.BankService.GetAll(c, query)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import (
|
|||||||
type BankRepository interface {
|
type BankRepository interface {
|
||||||
repository.BaseRepository[entity.Bank]
|
repository.BaseRepository[entity.Bank]
|
||||||
NameExists(ctx context.Context, name string, excludeID *uint) (bool, error)
|
NameExists(ctx context.Context, name string, excludeID *uint) (bool, error)
|
||||||
|
AccountNumberExists(ctx context.Context, accountNumber string, excludeID *uint) (bool, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type BankRepositoryImpl struct {
|
type BankRepositoryImpl struct {
|
||||||
@@ -28,3 +29,7 @@ func NewBankRepository(db *gorm.DB) BankRepository {
|
|||||||
func (r *BankRepositoryImpl) NameExists(ctx context.Context, name string, excludeID *uint) (bool, error) {
|
func (r *BankRepositoryImpl) NameExists(ctx context.Context, name string, excludeID *uint) (bool, error) {
|
||||||
return repository.ExistsByName[entity.Bank](ctx, r.db, name, excludeID)
|
return repository.ExistsByName[entity.Bank](ctx, r.db, name, excludeID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *BankRepositoryImpl) AccountNumberExists(ctx context.Context, accountNumber string, excludeID *uint) (bool, error) {
|
||||||
|
return repository.ExistsByField[entity.Bank](ctx, r.db, "account_number", accountNumber, excludeID)
|
||||||
|
}
|
||||||
|
|||||||
@@ -87,6 +87,13 @@ func (s *bankService) CreateOne(c *fiber.Ctx, req *validation.Create) (*entity.B
|
|||||||
return nil, fiber.NewError(fiber.StatusConflict, fmt.Sprintf("Bank with name %s already exists", req.Name))
|
return nil, fiber.NewError(fiber.StatusConflict, fmt.Sprintf("Bank with name %s already exists", req.Name))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if exists, err := s.Repository.AccountNumberExists(c.Context(), req.AccountNumber, nil); err != nil {
|
||||||
|
s.Log.Errorf("Failed to check bank account number: %+v", err)
|
||||||
|
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to check bank account number")
|
||||||
|
} else if exists {
|
||||||
|
return nil, fiber.NewError(fiber.StatusConflict, fmt.Sprintf("Bank with account number %s already exists", req.AccountNumber))
|
||||||
|
}
|
||||||
|
|
||||||
createBody := &entity.Bank{
|
createBody := &entity.Bank{
|
||||||
Name: req.Name,
|
Name: req.Name,
|
||||||
Alias: req.Alias,
|
Alias: req.Alias,
|
||||||
|
|||||||
@@ -29,6 +29,10 @@ func (u *CustomerController) GetAll(c *fiber.Ctx) error {
|
|||||||
Search: c.Query("search", ""),
|
Search: c.Query("search", ""),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if query.Page < 1 || query.Limit < 1 {
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, "page and limit must be greater than 0")
|
||||||
|
}
|
||||||
|
|
||||||
result, totalResults, err := u.CustomerService.GetAll(c, query)
|
result, totalResults, err := u.CustomerService.GetAll(c, query)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -29,6 +29,10 @@ func (u *FcrController) GetAll(c *fiber.Ctx) error {
|
|||||||
Search: c.Query("search", ""),
|
Search: c.Query("search", ""),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if query.Page < 1 || query.Limit < 1 {
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, "page and limit must be greater than 0")
|
||||||
|
}
|
||||||
|
|
||||||
result, totalResults, err := u.FcrService.GetAll(c, query)
|
result, totalResults, err := u.FcrService.GetAll(c, query)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -29,6 +29,10 @@ func (u *FlockController) GetAll(c *fiber.Ctx) error {
|
|||||||
Search: c.Query("search", ""),
|
Search: c.Query("search", ""),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if query.Page < 1 || query.Limit < 1 {
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, "page and limit must be greater than 0")
|
||||||
|
}
|
||||||
|
|
||||||
result, totalResults, err := u.FlockService.GetAll(c, query)
|
result, totalResults, err := u.FlockService.GetAll(c, query)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -31,6 +31,10 @@ func (u *KandangController) GetAll(c *fiber.Ctx) error {
|
|||||||
PicId: c.QueryInt("pic_id", 0),
|
PicId: c.QueryInt("pic_id", 0),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if query.Page < 1 || query.Limit < 1 {
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, "page and limit must be greater than 0")
|
||||||
|
}
|
||||||
|
|
||||||
result, totalResults, err := u.KandangService.GetAll(c, query)
|
result, totalResults, err := u.KandangService.GetAll(c, query)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -30,6 +30,10 @@ func (u *LocationController) GetAll(c *fiber.Ctx) error {
|
|||||||
AreaId: c.QueryInt("area_id", 0),
|
AreaId: c.QueryInt("area_id", 0),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if query.Page < 1 || query.Limit < 1 {
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, "page and limit must be greater than 0")
|
||||||
|
}
|
||||||
|
|
||||||
result, totalResults, err := u.LocationService.GetAll(c, query)
|
result, totalResults, err := u.LocationService.GetAll(c, query)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -29,6 +29,10 @@ func (u *NonstockController) GetAll(c *fiber.Ctx) error {
|
|||||||
Search: c.Query("search", ""),
|
Search: c.Query("search", ""),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if query.Page < 1 || query.Limit < 1 {
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, "page and limit must be greater than 0")
|
||||||
|
}
|
||||||
|
|
||||||
result, totalResults, err := u.NonstockService.GetAll(c, query)
|
result, totalResults, err := u.NonstockService.GetAll(c, query)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -29,6 +29,10 @@ func (u *ProductCategoryController) GetAll(c *fiber.Ctx) error {
|
|||||||
Search: c.Query("search", ""),
|
Search: c.Query("search", ""),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if query.Page < 1 || query.Limit < 1 {
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, "page and limit must be greater than 0")
|
||||||
|
}
|
||||||
|
|
||||||
result, totalResults, err := u.ProductCategoryService.GetAll(c, query)
|
result, totalResults, err := u.ProductCategoryService.GetAll(c, query)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -30,6 +30,10 @@ func (u *ProductController) GetAll(c *fiber.Ctx) error {
|
|||||||
ProductCategoryID: c.QueryInt("product_category_id", 0),
|
ProductCategoryID: c.QueryInt("product_category_id", 0),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if query.Page < 1 || query.Limit < 1 {
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, "page and limit must be greater than 0")
|
||||||
|
}
|
||||||
|
|
||||||
result, totalResults, err := u.ProductService.GetAll(c, query)
|
result, totalResults, err := u.ProductService.GetAll(c, query)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -29,6 +29,10 @@ func (u *SupplierController) GetAll(c *fiber.Ctx) error {
|
|||||||
Search: c.Query("search", ""),
|
Search: c.Query("search", ""),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if query.Page < 1 || query.Limit < 1 {
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, "page and limit must be greater than 0")
|
||||||
|
}
|
||||||
|
|
||||||
result, totalResults, err := u.SupplierService.GetAll(c, query)
|
result, totalResults, err := u.SupplierService.GetAll(c, query)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import (
|
|||||||
type SupplierRepository interface {
|
type SupplierRepository interface {
|
||||||
repository.BaseRepository[entity.Supplier]
|
repository.BaseRepository[entity.Supplier]
|
||||||
NameExists(ctx context.Context, name string, excludeID *uint) (bool, error)
|
NameExists(ctx context.Context, name string, excludeID *uint) (bool, error)
|
||||||
|
AliasExists(ctx context.Context, alias string, excludeID *uint) (bool, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type SupplierRepositoryImpl struct {
|
type SupplierRepositoryImpl struct {
|
||||||
@@ -29,3 +29,7 @@ func NewSupplierRepository(db *gorm.DB) SupplierRepository {
|
|||||||
func (r *SupplierRepositoryImpl) NameExists(ctx context.Context, name string, excludeID *uint) (bool, error) {
|
func (r *SupplierRepositoryImpl) NameExists(ctx context.Context, name string, excludeID *uint) (bool, error) {
|
||||||
return repository.ExistsByName[entity.Supplier](ctx, r.db, name, excludeID)
|
return repository.ExistsByName[entity.Supplier](ctx, r.db, name, excludeID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *SupplierRepositoryImpl) AliasExists(ctx context.Context, alias string, excludeID *uint) (bool, error) {
|
||||||
|
return repository.ExistsByField[entity.Supplier](ctx, r.db, "alias", alias, excludeID)
|
||||||
|
}
|
||||||
|
|||||||
@@ -88,6 +88,13 @@ func (s *supplierService) CreateOne(c *fiber.Ctx, req *validation.Create) (*enti
|
|||||||
return nil, fiber.NewError(fiber.StatusConflict, fmt.Sprintf("Supplier with name %s already exists", req.Name))
|
return nil, fiber.NewError(fiber.StatusConflict, fmt.Sprintf("Supplier with name %s already exists", req.Name))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if exists, err := s.Repository.AliasExists(c.Context(), strings.TrimSpace(strings.ToUpper(req.Alias)), nil); err != nil {
|
||||||
|
s.Log.Errorf("Failed to check supplier alias: %+v", err)
|
||||||
|
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to check supplier alias")
|
||||||
|
} else if exists {
|
||||||
|
return nil, fiber.NewError(fiber.StatusConflict, fmt.Sprintf("Supplier with alias %s already exists", strings.TrimSpace(strings.ToUpper(req.Alias))))
|
||||||
|
}
|
||||||
|
|
||||||
typ := strings.ToUpper(req.Type)
|
typ := strings.ToUpper(req.Type)
|
||||||
if !utils.IsValidCustomerSupplierType(typ) {
|
if !utils.IsValidCustomerSupplierType(typ) {
|
||||||
return nil, fiber.NewError(fiber.StatusBadRequest, "Invalid supplier type")
|
return nil, fiber.NewError(fiber.StatusBadRequest, "Invalid supplier type")
|
||||||
@@ -143,6 +150,12 @@ func (s supplierService) UpdateOne(c *fiber.Ctx, req *validation.Update, id uint
|
|||||||
}
|
}
|
||||||
|
|
||||||
if req.Alias != nil {
|
if req.Alias != nil {
|
||||||
|
if exists, err := s.Repository.AliasExists(c.Context(), strings.TrimSpace(strings.ToUpper(*req.Alias)), &id); err != nil {
|
||||||
|
s.Log.Errorf("Failed to check supplier alias: %+v", err)
|
||||||
|
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to check supplier alias")
|
||||||
|
} else if exists {
|
||||||
|
return nil, fiber.NewError(fiber.StatusConflict, fmt.Sprintf("Supplier with alias %s already exists", strings.TrimSpace(strings.ToUpper(*req.Alias))))
|
||||||
|
}
|
||||||
updateBody["alias"] = strings.TrimSpace(strings.ToUpper(*req.Alias))
|
updateBody["alias"] = strings.TrimSpace(strings.ToUpper(*req.Alias))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,10 @@ func (u *UomController) GetAll(c *fiber.Ctx) error {
|
|||||||
Search: c.Query("search", ""),
|
Search: c.Query("search", ""),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if query.Page < 1 || query.Limit < 1 {
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, "page and limit must be greater than 0")
|
||||||
|
}
|
||||||
|
|
||||||
result, totalResults, err := u.UomService.GetAll(c, query)
|
result, totalResults, err := u.UomService.GetAll(c, query)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -30,6 +30,10 @@ func (u *WarehouseController) GetAll(c *fiber.Ctx) error {
|
|||||||
AreaId: c.QueryInt("area_id", 0),
|
AreaId: c.QueryInt("area_id", 0),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if query.Page < 1 || query.Limit < 1 {
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, "page and limit must be greater than 0")
|
||||||
|
}
|
||||||
|
|
||||||
result, totalResults, err := u.WarehouseService.GetAll(c, query)
|
result, totalResults, err := u.WarehouseService.GetAll(c, query)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -121,14 +121,8 @@ func (s *chickinService) CreateOne(c *fiber.Ctx, req *validation.Create) (*entit
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var productWarehouses []entity.ProductWarehouse
|
// move complex DB query into repository for cleaner service
|
||||||
err = s.ProductWarehouseRepo.DB().
|
productWarehouses, err := s.ProductWarehouseRepo.GetByCategoryCodeAndWarehouseID(c.Context(), "DOC", warehouse.Id)
|
||||||
WithContext(c.Context()).
|
|
||||||
Joins("JOIN products ON products.id = product_warehouses.product_id").
|
|
||||||
Joins("JOIN product_categories ON product_categories.id = products.product_category_id").
|
|
||||||
Where("product_categories.code = ? AND product_warehouses.warehouse_id = ?", "DOC", warehouse.Id).
|
|
||||||
Order("created_at DESC").
|
|
||||||
Find(&productWarehouses).Error
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.Log.Errorf("Failed to get product warehouses: %+v", err)
|
s.Log.Errorf("Failed to get product warehouses: %+v", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -136,8 +130,6 @@ func (s *chickinService) CreateOne(c *fiber.Ctx, req *validation.Create) (*entit
|
|||||||
if len(productWarehouses) == 0 {
|
if len(productWarehouses) == 0 {
|
||||||
return nil, fiber.NewError(fiber.StatusNotFound, "Product Warehouse not found for the given Project Flock and Warehouse")
|
return nil, fiber.NewError(fiber.StatusNotFound, "Product Warehouse not found for the given Project Flock and Warehouse")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Jumlahkan semua quantity DOC
|
|
||||||
totalQuantity := 0.0
|
totalQuantity := 0.0
|
||||||
for _, pw := range productWarehouses {
|
for _, pw := range productWarehouses {
|
||||||
totalQuantity += pw.Quantity
|
totalQuantity += pw.Quantity
|
||||||
@@ -147,7 +139,6 @@ func (s *chickinService) CreateOne(c *fiber.Ctx, req *validation.Create) (*entit
|
|||||||
return nil, fiber.NewError(fiber.StatusBadRequest, "Insufficient quantity in Product Warehouses")
|
return nil, fiber.NewError(fiber.StatusBadRequest, "Insufficient quantity in Product Warehouses")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Buat satu chickin dengan total quantity
|
|
||||||
chickinDate, err := utils.ParseDateString(req.ChickInDate)
|
chickinDate, err := utils.ParseDateString(req.ChickInDate)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.Log.Errorf("Failed to parse chickin date: %+v", err)
|
s.Log.Errorf("Failed to parse chickin date: %+v", err)
|
||||||
@@ -157,7 +148,7 @@ func (s *chickinService) CreateOne(c *fiber.Ctx, req *validation.Create) (*entit
|
|||||||
ProjectFlockKandangId: projectflockkandang.Id,
|
ProjectFlockKandangId: projectflockkandang.Id,
|
||||||
ChickInDate: chickinDate,
|
ChickInDate: chickinDate,
|
||||||
Quantity: totalQuantity,
|
Quantity: totalQuantity,
|
||||||
Note: "",
|
Note: req.Note,
|
||||||
CreatedBy: 1, //todo: ganti dengan user login
|
CreatedBy: 1, //todo: ganti dengan user login
|
||||||
}
|
}
|
||||||
err = s.Repository.CreateOne(c.Context(), newChickin, nil)
|
err = s.Repository.CreateOne(c.Context(), newChickin, nil)
|
||||||
@@ -176,7 +167,6 @@ func (s *chickinService) CreateOne(c *fiber.Ctx, req *validation.Create) (*entit
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// add ke detail chickin
|
|
||||||
newChickinDetail := &entity.ProjectChickinDetail{
|
newChickinDetail := &entity.ProjectChickinDetail{
|
||||||
ProjectChickinId: newChickin.Id,
|
ProjectChickinId: newChickin.Id,
|
||||||
ProductWarehouseId: pw.Id,
|
ProductWarehouseId: pw.Id,
|
||||||
@@ -232,6 +222,9 @@ func (s chickinService) UpdateOne(c *fiber.Ctx, req *validation.Update, id uint)
|
|||||||
if req.ChickInDate != "" {
|
if req.ChickInDate != "" {
|
||||||
updateBody["chick_in_date"] = req.ChickInDate
|
updateBody["chick_in_date"] = req.ChickInDate
|
||||||
}
|
}
|
||||||
|
if req.Note != "" {
|
||||||
|
updateBody["note"] = req.Note
|
||||||
|
}
|
||||||
if len(updateBody) == 0 {
|
if len(updateBody) == 0 {
|
||||||
return s.GetOne(c, id)
|
return s.GetOne(c, id)
|
||||||
}
|
}
|
||||||
@@ -293,7 +286,6 @@ func (s chickinService) DeleteOne(c *fiber.Ctx, id uint) error {
|
|||||||
return rollback(err)
|
return rollback(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// helper: restore quantities from details; returns (restored bool, error)
|
|
||||||
restoreFromDetails := func() (bool, error) {
|
restoreFromDetails := func() (bool, error) {
|
||||||
var details []entity.ProjectChickinDetail
|
var details []entity.ProjectChickinDetail
|
||||||
if err := tx.WithContext(c.Context()).Where("project_chickin_id = ?", chickin.Id).Find(&details).Error; err != nil {
|
if err := tx.WithContext(c.Context()).Where("project_chickin_id = ?", chickin.Id).Find(&details).Error; err != nil {
|
||||||
|
|||||||
@@ -3,10 +3,12 @@ package validation
|
|||||||
type Create struct {
|
type Create struct {
|
||||||
ProjectFlockKandangId uint `json:"project_flock_kandang_id" validate:"required,number,min=1"`
|
ProjectFlockKandangId uint `json:"project_flock_kandang_id" validate:"required,number,min=1"`
|
||||||
ChickInDate string `json:"chick_in_date" validate:"required,datetime=2006-01-02"`
|
ChickInDate string `json:"chick_in_date" validate:"required,datetime=2006-01-02"`
|
||||||
|
Note string `json:"note" validate:"omitempty`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Update struct {
|
type Update struct {
|
||||||
ChickInDate string `json:"chick_in_date" validate:"required,datetime=2006-01-02"`
|
ChickInDate string `json:"chick_in_date" validate:"required,datetime=2006-01-02"`
|
||||||
|
Note string `json:"note" validate:"omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Query struct {
|
type Query struct {
|
||||||
|
|||||||
@@ -246,17 +246,39 @@ func (u *ProjectflockController) GetFlockPeriodSummary(c *fiber.Ctx) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (u *ProjectflockController) LookupProjectFlockKandang(c *fiber.Ctx) error {
|
func (u *ProjectflockController) LookupProjectFlockKandang(c *fiber.Ctx) error {
|
||||||
projectFlockIdStr := c.Query("project_flock_id", "")
|
projectFlockId := c.QueryInt("project_flock_id", 0)
|
||||||
kandangIdStr := c.Query("kandang_id", "")
|
kandangId := c.QueryInt("kandang_id", 0)
|
||||||
|
|
||||||
result, err := u.ProjectflockService.GetProjectFlockKandangByParams(c, "", projectFlockIdStr, kandangIdStr)
|
if projectFlockId == 0 || kandangId == 0 {
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, "Invalid project_flock_id or kandang_id")
|
||||||
|
}
|
||||||
|
|
||||||
|
result, availableStock, err := u.ProjectflockService.GetProjectFlockKandangByProjectAndKandang(c, uint(projectFlockId), uint(kandangId))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dtoResult := dto.ToProjectFlockKandangDTO(*result)
|
||||||
|
dtoResult.AvailableQuantity = float64(availableStock)
|
||||||
|
|
||||||
|
// populate available quantity for each kandang inside project_flock
|
||||||
|
if dtoResult.ProjectFlock != nil {
|
||||||
|
for i := range dtoResult.ProjectFlock.Kandangs {
|
||||||
|
kand := &dtoResult.ProjectFlock.Kandangs[i]
|
||||||
|
if kand.Id == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if q, qerr := u.ProjectflockService.GetAvailableDocQuantity(c, kand.Id); qerr == nil {
|
||||||
|
kand.AvailableQuantity = q
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// remove inner kandangs from project_flock to avoid duplication
|
||||||
|
dtoResult.ProjectFlock.Kandangs = nil
|
||||||
|
}
|
||||||
|
|
||||||
return c.Status(fiber.StatusOK).
|
return c.Status(fiber.StatusOK).
|
||||||
JSON(response.Success{Code: fiber.StatusOK,
|
JSON(response.Success{Code: fiber.StatusOK,
|
||||||
Status: "success",
|
Status: "success",
|
||||||
Message: "Get projectflock kandang successfully",
|
Message: "Get projectflock kandang successfully",
|
||||||
Data: dto.ToProjectFlockKandangDTO(*result)})
|
Data: dtoResult})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,10 +10,9 @@ import (
|
|||||||
userDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/users/dto"
|
userDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/users/dto"
|
||||||
)
|
)
|
||||||
|
|
||||||
// internal DTO used only for lookup response: project flock with kandangs carrying pivot ids
|
|
||||||
type KandangWithPivotDTO struct {
|
type KandangWithPivotDTO struct {
|
||||||
kandangDTO.KandangBaseDTO
|
kandangDTO.KandangBaseDTO
|
||||||
ProjectFlockKandangId *uint `json:"project_flock_kandang_id,omitempty"`
|
AvailableQuantity float64 `json:"available_quantity"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ProjectFlockWithPivotDTO struct {
|
type ProjectFlockWithPivotDTO struct {
|
||||||
@@ -28,11 +27,13 @@ type ProjectFlockWithPivotDTO struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ProjectFlockKandangDTO struct {
|
type ProjectFlockKandangDTO struct {
|
||||||
Id uint `json:"id"`
|
Id uint `json:"id"`
|
||||||
ProjectFlockId uint `json:"project_flock_id"`
|
ProjectFlockKandangId uint `json:"project_flock_kandang_id"`
|
||||||
KandangId uint `json:"kandang_id"`
|
ProjectFlockId uint `json:"project_flock_id"`
|
||||||
Kandang *kandangDTO.KandangBaseDTO `json:"kandang,omitempty"`
|
KandangId uint `json:"kandang_id"`
|
||||||
ProjectFlock *ProjectFlockWithPivotDTO `json:"project_flock,omitempty"`
|
Kandang *kandangDTO.KandangBaseDTO `json:"kandang,omitempty"`
|
||||||
|
ProjectFlock *ProjectFlockWithPivotDTO `json:"project_flock,omitempty"`
|
||||||
|
AvailableQuantity float64 `json:"available_quantity"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func ToProjectFlockKandangDTO(e entity.ProjectFlockKandang) ProjectFlockKandangDTO {
|
func ToProjectFlockKandangDTO(e entity.ProjectFlockKandang) ProjectFlockKandangDTO {
|
||||||
@@ -44,7 +45,7 @@ func ToProjectFlockKandangDTO(e entity.ProjectFlockKandang) ProjectFlockKandangD
|
|||||||
|
|
||||||
var pf *ProjectFlockWithPivotDTO
|
var pf *ProjectFlockWithPivotDTO
|
||||||
if e.ProjectFlock.Id != 0 {
|
if e.ProjectFlock.Id != 0 {
|
||||||
// build project flock with kandangs that include pivot ids
|
|
||||||
pfLocal := ProjectFlockWithPivotDTO{
|
pfLocal := ProjectFlockWithPivotDTO{
|
||||||
ProjectFlockBaseDTO: ProjectFlockBaseDTO{
|
ProjectFlockBaseDTO: ProjectFlockBaseDTO{
|
||||||
Id: e.ProjectFlock.Id,
|
Id: e.ProjectFlock.Id,
|
||||||
@@ -53,7 +54,6 @@ func ToProjectFlockKandangDTO(e entity.ProjectFlockKandang) ProjectFlockKandangD
|
|||||||
Category: e.ProjectFlock.Category,
|
Category: e.ProjectFlock.Category,
|
||||||
}
|
}
|
||||||
|
|
||||||
// fill related small summaries
|
|
||||||
if e.ProjectFlock.Flock.Id != 0 {
|
if e.ProjectFlock.Flock.Id != 0 {
|
||||||
mapped := ToFlockSummaryDTO(e.ProjectFlock.Flock)
|
mapped := ToFlockSummaryDTO(e.ProjectFlock.Flock)
|
||||||
pfLocal.Flock = &mapped
|
pfLocal.Flock = &mapped
|
||||||
@@ -75,23 +75,16 @@ func ToProjectFlockKandangDTO(e entity.ProjectFlockKandang) ProjectFlockKandangD
|
|||||||
pfLocal.CreatedUser = &mapped
|
pfLocal.CreatedUser = &mapped
|
||||||
}
|
}
|
||||||
|
|
||||||
// build pivot map
|
|
||||||
pivotMap := make(map[uint]uint)
|
pivotMap := make(map[uint]uint)
|
||||||
for _, ph := range e.ProjectFlock.KandangHistory {
|
for _, ph := range e.ProjectFlock.KandangHistory {
|
||||||
pivotMap[ph.KandangId] = ph.Id
|
pivotMap[ph.KandangId] = ph.Id
|
||||||
}
|
}
|
||||||
|
|
||||||
// populate kandangs with pivot ids
|
|
||||||
for _, k := range e.ProjectFlock.Kandangs {
|
for _, k := range e.ProjectFlock.Kandangs {
|
||||||
kb := kandangDTO.ToKandangBaseDTO(k)
|
kb := kandangDTO.ToKandangBaseDTO(k)
|
||||||
var pid *uint
|
|
||||||
if v, ok := pivotMap[k.Id]; ok {
|
|
||||||
vv := v
|
|
||||||
pid = &vv
|
|
||||||
}
|
|
||||||
pfLocal.Kandangs = append(pfLocal.Kandangs, KandangWithPivotDTO{
|
pfLocal.Kandangs = append(pfLocal.Kandangs, KandangWithPivotDTO{
|
||||||
KandangBaseDTO: kb,
|
KandangBaseDTO: kb,
|
||||||
ProjectFlockKandangId: pid,
|
AvailableQuantity: 0,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,10 +92,12 @@ func ToProjectFlockKandangDTO(e entity.ProjectFlockKandang) ProjectFlockKandangD
|
|||||||
}
|
}
|
||||||
|
|
||||||
return ProjectFlockKandangDTO{
|
return ProjectFlockKandangDTO{
|
||||||
Id: e.Id,
|
Id: e.Id,
|
||||||
ProjectFlockId: e.ProjectFlockId,
|
ProjectFlockKandangId: e.Id,
|
||||||
KandangId: e.KandangId,
|
ProjectFlockId: e.ProjectFlockId,
|
||||||
Kandang: kandang,
|
KandangId: e.KandangId,
|
||||||
ProjectFlock: pf,
|
Kandang: kandang,
|
||||||
|
ProjectFlock: pf,
|
||||||
|
AvailableQuantity: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,8 +9,10 @@ import (
|
|||||||
commonSvc "gitlab.com/mbugroup/lti-api.git/internal/common/service"
|
commonSvc "gitlab.com/mbugroup/lti-api.git/internal/common/service"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
|
|
||||||
|
rProductWarehouse "gitlab.com/mbugroup/lti-api.git/internal/modules/inventory/product-warehouses/repositories"
|
||||||
rFlock "gitlab.com/mbugroup/lti-api.git/internal/modules/master/flocks/repositories"
|
rFlock "gitlab.com/mbugroup/lti-api.git/internal/modules/master/flocks/repositories"
|
||||||
rKandang "gitlab.com/mbugroup/lti-api.git/internal/modules/master/kandangs/repositories"
|
rKandang "gitlab.com/mbugroup/lti-api.git/internal/modules/master/kandangs/repositories"
|
||||||
|
rWarehouse "gitlab.com/mbugroup/lti-api.git/internal/modules/master/warehouses/repositories"
|
||||||
rProjectflock "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project_flocks/repositories"
|
rProjectflock "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project_flocks/repositories"
|
||||||
|
|
||||||
sProjectflock "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project_flocks/services"
|
sProjectflock "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project_flocks/services"
|
||||||
@@ -27,6 +29,8 @@ func (ProjectflockModule) RegisterRoutes(router fiber.Router, db *gorm.DB, valid
|
|||||||
kandangRepo := rKandang.NewKandangRepository(db)
|
kandangRepo := rKandang.NewKandangRepository(db)
|
||||||
projectflockRepo := rProjectflock.NewProjectflockRepository(db)
|
projectflockRepo := rProjectflock.NewProjectflockRepository(db)
|
||||||
projectflockKandangRepo := rProjectflock.NewProjectFlockKandangRepository(db)
|
projectflockKandangRepo := rProjectflock.NewProjectFlockKandangRepository(db)
|
||||||
|
warehouseRepo := rWarehouse.NewWarehouseRepository(db)
|
||||||
|
productWarehouseRepo := rProductWarehouse.NewProductWarehouseRepository(db)
|
||||||
userRepo := rUser.NewUserRepository(db)
|
userRepo := rUser.NewUserRepository(db)
|
||||||
|
|
||||||
approvalRepo := commonRepo.NewApprovalRepository(db)
|
approvalRepo := commonRepo.NewApprovalRepository(db)
|
||||||
@@ -35,7 +39,7 @@ func (ProjectflockModule) RegisterRoutes(router fiber.Router, db *gorm.DB, valid
|
|||||||
panic(fmt.Sprintf("failed to register project flock approval workflow: %v", err))
|
panic(fmt.Sprintf("failed to register project flock approval workflow: %v", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
projectflockService := sProjectflock.NewProjectflockService(projectflockRepo, flockRepo, kandangRepo, projectflockKandangRepo, approvalService, validate)
|
projectflockService := sProjectflock.NewProjectflockService(projectflockRepo, flockRepo, kandangRepo, projectflockKandangRepo, warehouseRepo, productWarehouseRepo, approvalService, validate)
|
||||||
userService := sUser.NewUserService(userRepo, validate)
|
userService := sUser.NewUserService(userRepo, validate)
|
||||||
|
|
||||||
ProjectflockRoutes(router, userService, projectflockService)
|
ProjectflockRoutes(router, userService, projectflockService)
|
||||||
|
|||||||
@@ -4,14 +4,15 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
commonRepo "gitlab.com/mbugroup/lti-api.git/internal/common/repository"
|
commonRepo "gitlab.com/mbugroup/lti-api.git/internal/common/repository"
|
||||||
commonSvc "gitlab.com/mbugroup/lti-api.git/internal/common/service"
|
commonSvc "gitlab.com/mbugroup/lti-api.git/internal/common/service"
|
||||||
entity "gitlab.com/mbugroup/lti-api.git/internal/entities"
|
entity "gitlab.com/mbugroup/lti-api.git/internal/entities"
|
||||||
|
productWarehouseRepository "gitlab.com/mbugroup/lti-api.git/internal/modules/inventory/product-warehouses/repositories"
|
||||||
flockRepository "gitlab.com/mbugroup/lti-api.git/internal/modules/master/flocks/repositories"
|
flockRepository "gitlab.com/mbugroup/lti-api.git/internal/modules/master/flocks/repositories"
|
||||||
kandangRepository "gitlab.com/mbugroup/lti-api.git/internal/modules/master/kandangs/repositories"
|
kandangRepository "gitlab.com/mbugroup/lti-api.git/internal/modules/master/kandangs/repositories"
|
||||||
|
warehouseRepository "gitlab.com/mbugroup/lti-api.git/internal/modules/master/warehouses/repositories"
|
||||||
repository "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project_flocks/repositories"
|
repository "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project_flocks/repositories"
|
||||||
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"
|
||||||
utils "gitlab.com/mbugroup/lti-api.git/internal/utils"
|
utils "gitlab.com/mbugroup/lti-api.git/internal/utils"
|
||||||
@@ -29,20 +30,23 @@ type ProjectflockService interface {
|
|||||||
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)
|
||||||
DeleteOne(ctx *fiber.Ctx, id uint) error
|
DeleteOne(ctx *fiber.Ctx, id uint) error
|
||||||
GetProjectFlockKandangByParams(ctx *fiber.Ctx, idStr string, projectFlockIdStr string, kandangIdStr string) (*entity.ProjectFlockKandang, error)
|
GetProjectFlockKandangByProjectAndKandang(ctx *fiber.Ctx, projectFlockID uint, kandangID uint) (*entity.ProjectFlockKandang, error)
|
||||||
|
GetAvailableDocQuantity(ctx *fiber.Ctx, kandangID uint) (float64, error)
|
||||||
GetFlockPeriodSummary(ctx *fiber.Ctx, flockID uint) (*FlockPeriodSummary, error)
|
GetFlockPeriodSummary(ctx *fiber.Ctx, flockID uint) (*FlockPeriodSummary, error)
|
||||||
Approval(ctx *fiber.Ctx, req *validation.Approve) ([]entity.ProjectFlock, error)
|
Approval(ctx *fiber.Ctx, req *validation.Approve) ([]entity.ProjectFlock, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type projectflockService struct {
|
type projectflockService struct {
|
||||||
Log *logrus.Logger
|
Log *logrus.Logger
|
||||||
Validate *validator.Validate
|
Validate *validator.Validate
|
||||||
Repository repository.ProjectflockRepository
|
Repository repository.ProjectflockRepository
|
||||||
FlockRepo flockRepository.FlockRepository
|
FlockRepo flockRepository.FlockRepository
|
||||||
KandangRepo kandangRepository.KandangRepository
|
KandangRepo kandangRepository.KandangRepository
|
||||||
|
WarehouseRepo warehouseRepository.WarehouseRepository
|
||||||
|
ProductWarehouseRepo productWarehouseRepository.ProductWarehouseRepository
|
||||||
PivotRepo repository.ProjectFlockKandangRepository
|
PivotRepo repository.ProjectFlockKandangRepository
|
||||||
ApprovalSvc commonSvc.ApprovalService
|
ApprovalSvc commonSvc.ApprovalService
|
||||||
approvalWorkflow approvalutils.ApprovalWorkflowKey
|
approvalWorkflow approvalutils.ApprovalWorkflowKey
|
||||||
}
|
}
|
||||||
|
|
||||||
type FlockPeriodSummary struct {
|
type FlockPeriodSummary struct {
|
||||||
@@ -55,18 +59,22 @@ func NewProjectflockService(
|
|||||||
flockRepo flockRepository.FlockRepository,
|
flockRepo flockRepository.FlockRepository,
|
||||||
kandangRepo kandangRepository.KandangRepository,
|
kandangRepo kandangRepository.KandangRepository,
|
||||||
pivotRepo repository.ProjectFlockKandangRepository,
|
pivotRepo repository.ProjectFlockKandangRepository,
|
||||||
|
warehouseRepo warehouseRepository.WarehouseRepository,
|
||||||
|
productWarehouseRepo productWarehouseRepository.ProductWarehouseRepository,
|
||||||
approvalSvc commonSvc.ApprovalService,
|
approvalSvc commonSvc.ApprovalService,
|
||||||
validate *validator.Validate,
|
validate *validator.Validate,
|
||||||
) ProjectflockService {
|
) ProjectflockService {
|
||||||
return &projectflockService{
|
return &projectflockService{
|
||||||
Log: utils.Log,
|
Log: utils.Log,
|
||||||
Validate: validate,
|
Validate: validate,
|
||||||
Repository: repo,
|
Repository: repo,
|
||||||
FlockRepo: flockRepo,
|
FlockRepo: flockRepo,
|
||||||
KandangRepo: kandangRepo,
|
KandangRepo: kandangRepo,
|
||||||
|
WarehouseRepo: warehouseRepo,
|
||||||
|
ProductWarehouseRepo: productWarehouseRepo,
|
||||||
PivotRepo: pivotRepo,
|
PivotRepo: pivotRepo,
|
||||||
ApprovalSvc: approvalSvc,
|
ApprovalSvc: approvalSvc,
|
||||||
approvalWorkflow: utils.ApprovalWorkflowProjectFlock,
|
approvalWorkflow: utils.ApprovalWorkflowProjectFlock,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -648,11 +656,6 @@ func (s projectflockService) DeleteOne(c *fiber.Ctx, id uint) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s projectflockService) GetProjectFlockKandang(ctx *fiber.Ctx, id uint) (*entity.ProjectFlockKandang, error) {
|
|
||||||
// keep for backward compatibility; delegate to new consolidated method
|
|
||||||
return s.GetProjectFlockKandangByParams(ctx, fmt.Sprintf("%d", id), "", "")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s projectflockService) GetProjectFlockKandangByProjectAndKandang(ctx *fiber.Ctx, projectFlockID uint, kandangID uint) (*entity.ProjectFlockKandang, error) {
|
func (s projectflockService) GetProjectFlockKandangByProjectAndKandang(ctx *fiber.Ctx, projectFlockID uint, kandangID uint) (*entity.ProjectFlockKandang, error) {
|
||||||
|
|
||||||
pfk, err := s.PivotRepo.GetByProjectFlockAndKandang(ctx.Context(), projectFlockID, kandangID)
|
pfk, err := s.PivotRepo.GetByProjectFlockAndKandang(ctx.Context(), projectFlockID, kandangID)
|
||||||
@@ -665,38 +668,30 @@ func (s projectflockService) GetProjectFlockKandangByProjectAndKandang(ctx *fibe
|
|||||||
return pfk, nil
|
return pfk, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s projectflockService) GetProjectFlockKandangByParams(ctx *fiber.Ctx, idStr string, projectFlockIdStr string, kandangIdStr string) (*entity.ProjectFlockKandang, error) {
|
func (s projectflockService) GetAvailableDocQuantity(ctx *fiber.Ctx, kandangID uint) (float64, error) {
|
||||||
idStr = strings.TrimSpace(idStr)
|
|
||||||
projectFlockIdStr = strings.TrimSpace(projectFlockIdStr)
|
|
||||||
kandangIdStr = strings.TrimSpace(kandangIdStr)
|
|
||||||
|
|
||||||
if idStr != "" {
|
wh, err := s.WarehouseRepo.GetByKandangID(ctx.Context(), kandangID)
|
||||||
id, err := strconv.Atoi(idStr)
|
if err != nil {
|
||||||
if err != nil || id <= 0 {
|
return 0, err
|
||||||
return nil, fiber.NewError(fiber.StatusBadRequest, "Invalid Id")
|
|
||||||
}
|
|
||||||
pfk, err := s.PivotRepo.GetByID(ctx.Context(), uint(id))
|
|
||||||
if err != nil {
|
|
||||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
|
||||||
return nil, fiber.NewError(fiber.StatusNotFound, "ProjectFlockKandang not found")
|
|
||||||
}
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return pfk, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if projectFlockIdStr == "" || kandangIdStr == "" {
|
var productWarehouses []entity.ProductWarehouse
|
||||||
return nil, fiber.NewError(fiber.StatusBadRequest, "Missing lookup parameters")
|
err = s.ProductWarehouseRepo.DB().
|
||||||
|
WithContext(ctx.Context()).
|
||||||
|
Joins("JOIN products ON products.id = product_warehouses.product_id").
|
||||||
|
Joins("JOIN product_categories ON product_categories.id = products.product_category_id").
|
||||||
|
Where("product_categories.code = ? AND product_warehouses.warehouse_id = ?", "DOC", wh.Id).
|
||||||
|
Order("created_at DESC").
|
||||||
|
Find(&productWarehouses).Error
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
}
|
}
|
||||||
pfid, err := strconv.Atoi(projectFlockIdStr)
|
|
||||||
if err != nil || pfid <= 0 {
|
total := 0.0
|
||||||
return nil, fiber.NewError(fiber.StatusBadRequest, "Invalid project_flock_id")
|
for _, pw := range productWarehouses {
|
||||||
|
total += pw.Quantity
|
||||||
}
|
}
|
||||||
kid, err := strconv.Atoi(kandangIdStr)
|
return total, nil
|
||||||
if err != nil || kid <= 0 {
|
|
||||||
return nil, fiber.NewError(fiber.StatusBadRequest, "Invalid kandang_id")
|
|
||||||
}
|
|
||||||
return s.GetProjectFlockKandangByProjectAndKandang(ctx, uint(pfid), uint(kid))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s projectflockService) GetFlockPeriodSummary(c *fiber.Ctx, flockID uint) (*FlockPeriodSummary, error) {
|
func (s projectflockService) GetFlockPeriodSummary(c *fiber.Ctx, flockID uint) (*FlockPeriodSummary, error) {
|
||||||
@@ -853,7 +848,6 @@ func (s projectflockService) detachKandangs(ctx context.Context, dbTransaction *
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func (s projectflockService) pivotRepoWithTx(dbTransaction *gorm.DB) repository.ProjectFlockKandangRepository {
|
func (s projectflockService) pivotRepoWithTx(dbTransaction *gorm.DB) repository.ProjectFlockKandangRepository {
|
||||||
if s.PivotRepo == nil {
|
if s.PivotRepo == nil {
|
||||||
return repository.NewProjectFlockKandangRepository(dbTransaction)
|
return repository.NewProjectFlockKandangRepository(dbTransaction)
|
||||||
@@ -874,3 +868,4 @@ func (s projectflockService) anyKandangLinkedToOtherProject(ctx context.Context,
|
|||||||
}
|
}
|
||||||
return count > 0, nil
|
return count > 0, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
package utils
|
package utils
|
||||||
|
|
||||||
import "strings"
|
import (
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
// NormalizeTrim returns the input string without leading/trailing whitespace.
|
// NormalizeTrim returns the input string without leading/trailing whitespace.
|
||||||
func NormalizeTrim(value string) string {
|
func NormalizeTrim(value string) string {
|
||||||
@@ -11,3 +14,36 @@ func NormalizeTrim(value string) string {
|
|||||||
func NormalizeUpper(value string) string {
|
func NormalizeUpper(value string) string {
|
||||||
return strings.ToUpper(NormalizeTrim(value))
|
return strings.ToUpper(NormalizeTrim(value))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NormalizeFlag trims whitespace, removes surrounding brackets/quotes and returns upper-case flag
|
||||||
|
func NormalizeFlag(value string) string {
|
||||||
|
v := NormalizeTrim(value)
|
||||||
|
v = strings.Trim(v, "[]\"'")
|
||||||
|
return strings.ToUpper(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseFlags parses a raw flags string like "[DOC, PAKAN]" or "DOC,PAKAN"
|
||||||
|
// and returns a deduplicated, sorted slice of normalized flags (upper-case, trimmed).
|
||||||
|
func ParseFlags(raw string) []string {
|
||||||
|
if raw == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
parts := strings.Split(raw, ",")
|
||||||
|
set := make(map[string]struct{}, len(parts))
|
||||||
|
for _, p := range parts {
|
||||||
|
f := NormalizeFlag(p)
|
||||||
|
if f == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
set[f] = struct{}{}
|
||||||
|
}
|
||||||
|
if len(set) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
res := make([]string, 0, len(set))
|
||||||
|
for k := range set {
|
||||||
|
res = append(res, k)
|
||||||
|
}
|
||||||
|
sort.Strings(res)
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|||||||
@@ -29,6 +29,10 @@ func (u *{{Pascal .Entity}}Controller) GetAll(c *fiber.Ctx) error {
|
|||||||
Search: c.Query("search", ""),
|
Search: c.Query("search", ""),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if query.Page < 1 || query.Limit < 1 {
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, "page and limit must be greater than 0")
|
||||||
|
}
|
||||||
|
|
||||||
result, totalResults, err := u.{{Pascal .Entity}}Service.GetAll(c, query)
|
result, totalResults, err := u.{{Pascal .Entity}}Service.GetAll(c, query)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
Reference in New Issue
Block a user