mirror of
https://gitlab.com/mbugroup/lti-api.git
synced 2026-05-20 13:31:56 +00:00
feat[BE-127]: create available qty API and inisiate sales order and delivery order
This commit is contained in:
@@ -0,0 +1,26 @@
|
|||||||
|
package entities
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Marketing struct {
|
||||||
|
Id uint `gorm:"primaryKey;autoIncrement"`
|
||||||
|
SoNumber string `gorm:"uniqueIndex;not null"`
|
||||||
|
CustomerId uint `gorm:"not null"`
|
||||||
|
SoDocs string `gorm:"type:varchar(20)"`
|
||||||
|
SoDate time.Time `gorm:"type:date;not null"`
|
||||||
|
SalesPersonId uint `gorm:"not null"`
|
||||||
|
Notes string `gorm:"type:text"`
|
||||||
|
CreatedBy uint `gorm:"not null"`
|
||||||
|
CreatedAt time.Time `gorm:"autoCreateTime"`
|
||||||
|
UpdatedAt time.Time `gorm:"autoUpdateTime"`
|
||||||
|
DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
|
||||||
|
|
||||||
|
Customer Customer `gorm:"foreignKey:CustomerId;references:Id"`
|
||||||
|
SalesPerson User `gorm:"foreignKey:SalesPersonId;references:Id"`
|
||||||
|
CreatedUser User `gorm:"foreignKey:CreatedBy;references:Id"`
|
||||||
|
Products []MarketingProduct `gorm:"foreignKey:MarketingId;references:Id"`
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package entities
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MarketingDeliveryProduct struct {
|
||||||
|
Id uint `gorm:"primaryKey;autoIncrement"`
|
||||||
|
MarketingProductId uint `gorm:"uniqueIndex;not null"`
|
||||||
|
Qty float64 `gorm:"type:numeric(15,3);not null"`
|
||||||
|
UnitPrice float64 `gorm:"type:numeric(15,3);not null"`
|
||||||
|
TotalWeight float64 `gorm:"type:numeric(15,3);not null"`
|
||||||
|
AvgWeight float64 `gorm:"type:numeric(15,3);not null"`
|
||||||
|
TotalPrice float64 `gorm:"type:numeric(15,3);not null"`
|
||||||
|
DeliveryDate *time.Time `gorm:"type:timestamptz"`
|
||||||
|
VehicleNumber string `gorm:"type:varchar(50)"`
|
||||||
|
CreatedAt time.Time `gorm:"autoCreateTime"`
|
||||||
|
UpdatedAt time.Time `gorm:"autoUpdateTime"`
|
||||||
|
DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
|
||||||
|
|
||||||
|
MarketingProduct MarketingProduct `gorm:"foreignKey:MarketingProductId;references:Id"`
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package entities
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MarketingProduct struct {
|
||||||
|
Id uint `gorm:"primaryKey;autoIncrement"`
|
||||||
|
MarketingId uint `gorm:"not null"`
|
||||||
|
ProductWarehouseId uint `gorm:"not null"`
|
||||||
|
Qty float64 `gorm:"type:numeric(15,3);not null"`
|
||||||
|
UnitPrice float64 `gorm:"type:numeric(15,3);not null"`
|
||||||
|
AvgWeight float64 `gorm:"type:numeric(15,3);not null"`
|
||||||
|
TotalWeight float64 `gorm:"type:numeric(15,3);not null"`
|
||||||
|
TotalPrice float64 `gorm:"type:numeric(15,3);not null"`
|
||||||
|
CreatedAt time.Time `gorm:"autoCreateTime"`
|
||||||
|
UpdatedAt time.Time `gorm:"autoUpdateTime"`
|
||||||
|
DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
|
||||||
|
|
||||||
|
Marketing Marketing `gorm:"foreignKey:MarketingId;references:Id"`
|
||||||
|
ProductWarehouse ProductWarehouse `gorm:"foreignKey:ProductWarehouseId;references:Id"`
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package entities
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SalesOrders struct {
|
||||||
|
Id uint `gorm:"primaryKey"`
|
||||||
|
Name string `gorm:"not null;uniqueIndex:idx_name,where:deleted_at IS NULL"`
|
||||||
|
CreatedBy uint `gorm:"not null"`
|
||||||
|
CreatedAt time.Time `gorm:"autoCreateTime"`
|
||||||
|
UpdatedAt time.Time `gorm:"autoUpdateTime"`
|
||||||
|
DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
|
||||||
|
|
||||||
|
CreatedUser User `gorm:"foreignKey:CreatedBy;references:Id"`
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package marketing
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/go-playground/validator/v10"
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MarketingModule struct{}
|
||||||
|
|
||||||
|
func (MarketingModule) RegisterRoutes(router fiber.Router, db *gorm.DB, validate *validator.Validate) {
|
||||||
|
RegisterRoutes(router, db, validate)
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package marketing
|
||||||
|
|
||||||
|
import (
|
||||||
|
"gitlab.com/mbugroup/lti-api.git/internal/modules"
|
||||||
|
|
||||||
|
"github.com/go-playground/validator/v10"
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
|
||||||
|
salesOrderss "gitlab.com/mbugroup/lti-api.git/internal/modules/marketing/sales-orders"
|
||||||
|
// MODULE IMPORTS
|
||||||
|
)
|
||||||
|
|
||||||
|
func RegisterRoutes(router fiber.Router, db *gorm.DB, validate *validator.Validate) {
|
||||||
|
group := router.Group("/marketing")
|
||||||
|
|
||||||
|
allModules := []modules.Module{
|
||||||
|
salesOrderss.SalesOrdersModule{},
|
||||||
|
// MODULE REGISTRY
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, m := range allModules {
|
||||||
|
m.RegisterRoutes(group, db, validate)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,144 @@
|
|||||||
|
package controller
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"gitlab.com/mbugroup/lti-api.git/internal/modules/marketing/sales-orders/dto"
|
||||||
|
service "gitlab.com/mbugroup/lti-api.git/internal/modules/marketing/sales-orders/services"
|
||||||
|
validation "gitlab.com/mbugroup/lti-api.git/internal/modules/marketing/sales-orders/validations"
|
||||||
|
"gitlab.com/mbugroup/lti-api.git/internal/response"
|
||||||
|
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SalesOrdersController struct {
|
||||||
|
SalesOrdersService service.SalesOrdersService
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSalesOrdersController(salesOrdersService service.SalesOrdersService) *SalesOrdersController {
|
||||||
|
return &SalesOrdersController{
|
||||||
|
SalesOrdersService: salesOrdersService,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *SalesOrdersController) GetAll(c *fiber.Ctx) error {
|
||||||
|
query := &validation.Query{
|
||||||
|
Page: c.QueryInt("page", 1),
|
||||||
|
Limit: c.QueryInt("limit", 10),
|
||||||
|
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.SalesOrdersService.GetAll(c, query)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.Status(fiber.StatusOK).
|
||||||
|
JSON(response.SuccessWithPaginate[dto.SalesOrdersListDTO]{
|
||||||
|
Code: fiber.StatusOK,
|
||||||
|
Status: "success",
|
||||||
|
Message: "Get all salesOrderss successfully",
|
||||||
|
Meta: response.Meta{
|
||||||
|
Page: query.Page,
|
||||||
|
Limit: query.Limit,
|
||||||
|
TotalPages: int64(math.Ceil(float64(totalResults) / float64(query.Limit))),
|
||||||
|
TotalResults: totalResults,
|
||||||
|
},
|
||||||
|
Data: dto.ToSalesOrdersListDTOs(result),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *SalesOrdersController) GetOne(c *fiber.Ctx) error {
|
||||||
|
param := c.Params("id")
|
||||||
|
|
||||||
|
id, err := strconv.Atoi(param)
|
||||||
|
if err != nil {
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, "Invalid Id")
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := u.SalesOrdersService.GetOne(c, uint(id))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.Status(fiber.StatusOK).
|
||||||
|
JSON(response.Success{
|
||||||
|
Code: fiber.StatusOK,
|
||||||
|
Status: "success",
|
||||||
|
Message: "Get salesOrders successfully",
|
||||||
|
Data: dto.ToSalesOrdersListDTO(*result),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *SalesOrdersController) CreateOne(c *fiber.Ctx) error {
|
||||||
|
req := new(validation.Create)
|
||||||
|
|
||||||
|
if err := c.BodyParser(req); err != nil {
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, "Invalid request body")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *SalesOrdersController) UpdateOne(c *fiber.Ctx) error {
|
||||||
|
req := new(validation.Update)
|
||||||
|
param := c.Params("id")
|
||||||
|
|
||||||
|
id, err := strconv.Atoi(param)
|
||||||
|
if err != nil {
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, "Invalid Id")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.BodyParser(req); err != nil {
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, "Invalid request body")
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := u.SalesOrdersService.UpdateOne(c, req, uint(id))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.Status(fiber.StatusOK).
|
||||||
|
JSON(response.Success{
|
||||||
|
Code: fiber.StatusOK,
|
||||||
|
Status: "success",
|
||||||
|
Message: "Update salesOrders successfully",
|
||||||
|
Data: dto.ToSalesOrdersListDTO(*result),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *SalesOrdersController) DeleteOne(c *fiber.Ctx) error {
|
||||||
|
param := c.Params("id")
|
||||||
|
|
||||||
|
id, err := strconv.Atoi(param)
|
||||||
|
if err != nil {
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, "Invalid Id")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := u.SalesOrdersService.DeleteOne(c, uint(id)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.Status(fiber.StatusOK).
|
||||||
|
JSON(response.Common{
|
||||||
|
Code: fiber.StatusOK,
|
||||||
|
Status: "success",
|
||||||
|
Message: "Delete salesOrders successfully",
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
package dto
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
entity "gitlab.com/mbugroup/lti-api.git/internal/entities"
|
||||||
|
userDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/users/dto"
|
||||||
|
)
|
||||||
|
|
||||||
|
// === DTO Structs ===
|
||||||
|
|
||||||
|
type SalesOrdersBaseDTO struct {
|
||||||
|
Id uint `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type SalesOrdersListDTO struct {
|
||||||
|
SalesOrdersBaseDTO
|
||||||
|
CreatedUser *userDTO.UserBaseDTO `json:"created_user"`
|
||||||
|
CreatedAt time.Time `json:"created_at"`
|
||||||
|
UpdatedAt time.Time `json:"updated_at"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type SalesOrdersDetailDTO struct {
|
||||||
|
SalesOrdersListDTO
|
||||||
|
}
|
||||||
|
|
||||||
|
// === Mapper Functions ===
|
||||||
|
|
||||||
|
func ToSalesOrdersBaseDTO(e entity.SalesOrders) SalesOrdersBaseDTO {
|
||||||
|
return SalesOrdersBaseDTO{
|
||||||
|
Id: e.Id,
|
||||||
|
Name: e.Name,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ToSalesOrdersListDTO(e entity.SalesOrders) SalesOrdersListDTO {
|
||||||
|
var createdUser *userDTO.UserBaseDTO
|
||||||
|
if e.CreatedUser.Id != 0 {
|
||||||
|
mapped := userDTO.ToUserBaseDTO(e.CreatedUser)
|
||||||
|
createdUser = &mapped
|
||||||
|
}
|
||||||
|
|
||||||
|
return SalesOrdersListDTO{
|
||||||
|
SalesOrdersBaseDTO: ToSalesOrdersBaseDTO(e),
|
||||||
|
CreatedAt: e.CreatedAt,
|
||||||
|
UpdatedAt: e.UpdatedAt,
|
||||||
|
CreatedUser: createdUser,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ToSalesOrdersListDTOs(e []entity.SalesOrders) []SalesOrdersListDTO {
|
||||||
|
result := make([]SalesOrdersListDTO, len(e))
|
||||||
|
for i, r := range e {
|
||||||
|
result[i] = ToSalesOrdersListDTO(r)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func ToSalesOrdersDetailDTO(e entity.SalesOrders) SalesOrdersDetailDTO {
|
||||||
|
return SalesOrdersDetailDTO{
|
||||||
|
SalesOrdersListDTO: ToSalesOrdersListDTO(e),
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package sales_orders
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/go-playground/validator/v10"
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
|
||||||
|
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"
|
||||||
|
|
||||||
|
rUser "gitlab.com/mbugroup/lti-api.git/internal/modules/users/repositories"
|
||||||
|
sUser "gitlab.com/mbugroup/lti-api.git/internal/modules/users/services"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SalesOrdersModule struct{}
|
||||||
|
|
||||||
|
func (SalesOrdersModule) RegisterRoutes(router fiber.Router, db *gorm.DB, validate *validator.Validate) {
|
||||||
|
salesOrdersRepo := rSalesOrders.NewSalesOrdersRepository(db)
|
||||||
|
userRepo := rUser.NewUserRepository(db)
|
||||||
|
|
||||||
|
salesOrdersService := sSalesOrders.NewSalesOrdersService(salesOrdersRepo, validate)
|
||||||
|
userService := sUser.NewUserService(userRepo, validate)
|
||||||
|
|
||||||
|
SalesOrdersRoutes(router, userService, salesOrdersService)
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package repository
|
||||||
|
|
||||||
|
import (
|
||||||
|
entity "gitlab.com/mbugroup/lti-api.git/internal/entities"
|
||||||
|
"gitlab.com/mbugroup/lti-api.git/internal/common/repository"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SalesOrdersRepository interface {
|
||||||
|
repository.BaseRepository[entity.SalesOrders]
|
||||||
|
}
|
||||||
|
|
||||||
|
type SalesOrdersRepositoryImpl struct {
|
||||||
|
*repository.BaseRepositoryImpl[entity.SalesOrders]
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSalesOrdersRepository(db *gorm.DB) SalesOrdersRepository {
|
||||||
|
return &SalesOrdersRepositoryImpl{
|
||||||
|
BaseRepositoryImpl: repository.NewBaseRepository[entity.SalesOrders](db),
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package sales_orders
|
||||||
|
|
||||||
|
import (
|
||||||
|
// m "gitlab.com/mbugroup/lti-api.git/internal/middleware"
|
||||||
|
controller "gitlab.com/mbugroup/lti-api.git/internal/modules/marketing/sales-orders/controllers"
|
||||||
|
salesOrders "gitlab.com/mbugroup/lti-api.git/internal/modules/marketing/sales-orders/services"
|
||||||
|
user "gitlab.com/mbugroup/lti-api.git/internal/modules/users/services"
|
||||||
|
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func SalesOrdersRoutes(v1 fiber.Router, u user.UserService, s salesOrders.SalesOrdersService) {
|
||||||
|
ctrl := controller.NewSalesOrdersController(s)
|
||||||
|
|
||||||
|
route := v1.Group("/sales-orders")
|
||||||
|
|
||||||
|
// route.Get("/", m.Auth(u), ctrl.GetAll)
|
||||||
|
// route.Post("/", m.Auth(u), ctrl.CreateOne)
|
||||||
|
// route.Get("/:id", m.Auth(u), ctrl.GetOne)
|
||||||
|
// route.Patch("/:id", m.Auth(u), ctrl.UpdateOne)
|
||||||
|
// route.Delete("/:id", m.Auth(u), ctrl.DeleteOne)
|
||||||
|
|
||||||
|
route.Get("/", ctrl.GetAll)
|
||||||
|
route.Post("/", ctrl.CreateOne)
|
||||||
|
route.Get("/:id", ctrl.GetOne)
|
||||||
|
route.Patch("/:id", ctrl.UpdateOne)
|
||||||
|
route.Delete("/:id", ctrl.DeleteOne)
|
||||||
|
}
|
||||||
@@ -0,0 +1,129 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
entity "gitlab.com/mbugroup/lti-api.git/internal/entities"
|
||||||
|
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"
|
||||||
|
"gitlab.com/mbugroup/lti-api.git/internal/utils"
|
||||||
|
|
||||||
|
"github.com/go-playground/validator/v10"
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SalesOrdersService interface {
|
||||||
|
GetAll(ctx *fiber.Ctx, params *validation.Query) ([]entity.SalesOrders, int64, error)
|
||||||
|
GetOne(ctx *fiber.Ctx, id uint) (*entity.SalesOrders, error)
|
||||||
|
CreateOne(ctx *fiber.Ctx, req *validation.Create) (*entity.SalesOrders, error)
|
||||||
|
UpdateOne(ctx *fiber.Ctx, req *validation.Update, id uint) (*entity.SalesOrders, error)
|
||||||
|
DeleteOne(ctx *fiber.Ctx, id uint) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type salesOrdersService struct {
|
||||||
|
Log *logrus.Logger
|
||||||
|
Validate *validator.Validate
|
||||||
|
Repository repository.SalesOrdersRepository
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSalesOrdersService(repo repository.SalesOrdersRepository, validate *validator.Validate) SalesOrdersService {
|
||||||
|
return &salesOrdersService{
|
||||||
|
Log: utils.Log,
|
||||||
|
Validate: validate,
|
||||||
|
Repository: repo,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s salesOrdersService) withRelations(db *gorm.DB) *gorm.DB {
|
||||||
|
return db.Preload("CreatedUser")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s salesOrdersService) GetAll(c *fiber.Ctx, params *validation.Query) ([]entity.SalesOrders, int64, error) {
|
||||||
|
if err := s.Validate.Struct(params); err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
offset := (params.Page - 1) * params.Limit
|
||||||
|
|
||||||
|
salesOrderss, total, err := s.Repository.GetAll(c.Context(), offset, params.Limit, func(db *gorm.DB) *gorm.DB {
|
||||||
|
db = s.withRelations(db)
|
||||||
|
if params.Search != "" {
|
||||||
|
return db.Where("name LIKE ?", "%"+params.Search+"%")
|
||||||
|
}
|
||||||
|
return db.Order("created_at DESC").Order("updated_at DESC")
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
s.Log.Errorf("Failed to get salesOrderss: %+v", err)
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
return salesOrderss, total, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s salesOrdersService) GetOne(c *fiber.Ctx, id uint) (*entity.SalesOrders, error) {
|
||||||
|
salesOrders, err := s.Repository.GetByID(c.Context(), id, s.withRelations)
|
||||||
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
return nil, fiber.NewError(fiber.StatusNotFound, "SalesOrders not found")
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
s.Log.Errorf("Failed get salesOrders by id: %+v", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return salesOrders, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *salesOrdersService) CreateOne(c *fiber.Ctx, req *validation.Create) (*entity.SalesOrders, error) {
|
||||||
|
if err := s.Validate.Struct(req); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
createBody := &entity.SalesOrders{
|
||||||
|
Name: req.Name,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := s.Repository.CreateOne(c.Context(), createBody, nil); err != nil {
|
||||||
|
s.Log.Errorf("Failed to create salesOrders: %+v", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.GetOne(c, createBody.Id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s salesOrdersService) UpdateOne(c *fiber.Ctx, req *validation.Update, id uint) (*entity.SalesOrders, error) {
|
||||||
|
if err := s.Validate.Struct(req); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
updateBody := make(map[string]any)
|
||||||
|
|
||||||
|
if req.Name != nil {
|
||||||
|
updateBody["name"] = *req.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(updateBody) == 0 {
|
||||||
|
return s.GetOne(c, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := s.Repository.PatchOne(c.Context(), id, updateBody, nil); err != nil {
|
||||||
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
return nil, fiber.NewError(fiber.StatusNotFound, "SalesOrders not found")
|
||||||
|
}
|
||||||
|
s.Log.Errorf("Failed to update salesOrders: %+v", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.GetOne(c, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s salesOrdersService) DeleteOne(c *fiber.Ctx, id uint) error {
|
||||||
|
if err := s.Repository.DeleteOne(c.Context(), id); err != nil {
|
||||||
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
return fiber.NewError(fiber.StatusNotFound, "SalesOrders not found")
|
||||||
|
}
|
||||||
|
s.Log.Errorf("Failed to delete salesOrders: %+v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package validation
|
||||||
|
|
||||||
|
type Create struct {
|
||||||
|
Name string `json:"name" validate:"required_strict,min=3"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Update struct {
|
||||||
|
Name *string `json:"name,omitempty" validate:"omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Query struct {
|
||||||
|
Page int `query:"page" validate:"omitempty,number,min=1,gt=0"`
|
||||||
|
Limit int `query:"limit" validate:"omitempty,number,min=1,max=100,gt=0"`
|
||||||
|
Search string `query:"search" validate:"omitempty,max=50"`
|
||||||
|
}
|
||||||
@@ -71,6 +71,10 @@ func (u *ProjectflockController) GetAll(c *fiber.Ctx) error {
|
|||||||
if period := c.QueryInt("period", 0); period > 0 {
|
if period := c.QueryInt("period", 0); period > 0 {
|
||||||
query.Period = period
|
query.Period = period
|
||||||
}
|
}
|
||||||
|
if category := c.Query("category", ""); category != "" {
|
||||||
|
query.Category = category
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
if kandangRaw := c.Query("kandang_id", c.Query("kandang_ids", "")); kandangRaw != "" {
|
if kandangRaw := c.Query("kandang_id", c.Query("kandang_ids", "")); kandangRaw != "" {
|
||||||
ids, err := parseUintList(kandangRaw)
|
ids, err := parseUintList(kandangRaw)
|
||||||
|
|||||||
+15
@@ -14,6 +14,7 @@ type ProjectFlockPopulationRepository interface {
|
|||||||
ExistsByProjectChickinID(ctx context.Context, projectChickinID uint) (bool, error)
|
ExistsByProjectChickinID(ctx context.Context, projectChickinID uint) (bool, error)
|
||||||
GetByProjectChickinIDAndProductWarehouseID(ctx context.Context, projectChickinID uint, productWarehouseID uint) ([]entity.ProjectFlockPopulation, error)
|
GetByProjectChickinIDAndProductWarehouseID(ctx context.Context, projectChickinID uint, productWarehouseID uint) ([]entity.ProjectFlockPopulation, error)
|
||||||
GetByProjectFlockKandangIDAndProductWarehouseID(ctx context.Context, projectFlockKandangID uint, productWarehouseID uint) ([]entity.ProjectFlockPopulation, error)
|
GetByProjectFlockKandangIDAndProductWarehouseID(ctx context.Context, projectFlockKandangID uint, productWarehouseID uint) ([]entity.ProjectFlockPopulation, error)
|
||||||
|
GetTotalQtyByProjectFlockKandangID(ctx context.Context, projectFlockKandangID uint) (float64, error)
|
||||||
|
|
||||||
// subset of base repository methods used by services
|
// subset of base repository methods used by services
|
||||||
CreateOne(ctx context.Context, entity *entity.ProjectFlockPopulation, modifier func(*gorm.DB) *gorm.DB) error
|
CreateOne(ctx context.Context, entity *entity.ProjectFlockPopulation, modifier func(*gorm.DB) *gorm.DB) error
|
||||||
@@ -91,3 +92,17 @@ func (r *projectFlockPopulationRepositoryImpl) GetByProjectFlockKandangIDAndProd
|
|||||||
}
|
}
|
||||||
return records, nil
|
return records, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *projectFlockPopulationRepositoryImpl) GetTotalQtyByProjectFlockKandangID(ctx context.Context, projectFlockKandangID uint) (float64, error) {
|
||||||
|
var total float64
|
||||||
|
err := r.DB().WithContext(ctx).
|
||||||
|
Table("project_flock_populations").
|
||||||
|
Select("COALESCE(SUM(total_qty), 0) AS total_qty").
|
||||||
|
Joins("JOIN project_chickins ON project_chickins.id = project_flock_populations.project_chickin_id").
|
||||||
|
Where("project_chickins.project_flock_kandang_id = ?", projectFlockKandangID).
|
||||||
|
Scan(&total).Error
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return total, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -127,6 +127,9 @@ func (r *ProjectflockRepositoryImpl) applyQueryFilters(db *gorm.DB, params *vali
|
|||||||
return db
|
return db
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if params.Category != "" {
|
||||||
|
db = db.Where("project_flocks.category = ?", params.Category)
|
||||||
|
}
|
||||||
if params.AreaId > 0 {
|
if params.AreaId > 0 {
|
||||||
db = db.Where("project_flocks.area_id = ?", params.AreaId)
|
db = db.Where("project_flocks.area_id = ?", params.AreaId)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,5 +28,5 @@ func ProjectflockRoutes(v1 fiber.Router, u user.UserService, s projectflock.Proj
|
|||||||
route.Get("/kandangs/lookup", ctrl.LookupProjectFlockKandang)
|
route.Get("/kandangs/lookup", ctrl.LookupProjectFlockKandang)
|
||||||
route.Post("/approvals", ctrl.Approval)
|
route.Post("/approvals", ctrl.Approval)
|
||||||
route.Get("/kandangs/:project-flock_kandang-id/periods", ctrl.GetFlockPeriodSummary)
|
route.Get("/kandangs/:project-flock_kandang-id/periods", ctrl.GetFlockPeriodSummary)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ type Query struct {
|
|||||||
AreaId uint `query:"area_id" validate:"omitempty,number,gt=0"`
|
AreaId uint `query:"area_id" validate:"omitempty,number,gt=0"`
|
||||||
LocationId uint `query:"location_id" validate:"omitempty,number,gt=0"`
|
LocationId uint `query:"location_id" validate:"omitempty,number,gt=0"`
|
||||||
Period int `query:"period" validate:"omitempty,number,gt=0"`
|
Period int `query:"period" validate:"omitempty,number,gt=0"`
|
||||||
|
Category string `query:"category" validate:"omitempty"`
|
||||||
KandangIds []uint `query:"kandang_id" validate:"omitempty,dive,gt=0"`
|
KandangIds []uint `query:"kandang_id" validate:"omitempty,dive,gt=0"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+49
-14
@@ -1,6 +1,7 @@
|
|||||||
package controller
|
package controller
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
@@ -24,16 +25,8 @@ func NewTransferLayingController(transferLayingService service.TransferLayingSer
|
|||||||
|
|
||||||
func (u *TransferLayingController) GetAll(c *fiber.Ctx) error {
|
func (u *TransferLayingController) 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),
|
||||||
SourceProjectFlockId: uint(c.QueryInt("source_project_flock_id", 0)),
|
|
||||||
TargetProjectFlockId: uint(c.QueryInt("target_project_flock_id", 0)),
|
|
||||||
TransferDateFrom: c.Query("transfer_date_from", ""),
|
|
||||||
TransferDateTo: c.Query("transfer_date_to", ""),
|
|
||||||
ApprovalStatus: c.Query("approval_status", ""),
|
|
||||||
TransferNumber: c.Query("transfer_number", ""),
|
|
||||||
Sort: c.Query("sort", "created_at"),
|
|
||||||
Order: c.Query("order", "desc"),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if query.Page < 1 || query.Limit < 1 {
|
if query.Page < 1 || query.Limit < 1 {
|
||||||
@@ -45,8 +38,13 @@ func (u *TransferLayingController) GetAll(c *fiber.Ctx) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data := make([]dto.TransferLayingDetailDTO, len(result))
|
||||||
|
for i, transfer := range result {
|
||||||
|
data[i] = dto.ToTransferLayingDetailDTOWithSingleApproval(transfer, transfer.LatestApproval)
|
||||||
|
}
|
||||||
|
|
||||||
return c.Status(fiber.StatusOK).
|
return c.Status(fiber.StatusOK).
|
||||||
JSON(response.SuccessWithPaginate[dto.TransferLayingListDTO]{
|
JSON(response.SuccessWithPaginate[dto.TransferLayingDetailDTO]{
|
||||||
Code: fiber.StatusOK,
|
Code: fiber.StatusOK,
|
||||||
Status: "success",
|
Status: "success",
|
||||||
Message: "Get all transferLayings successfully",
|
Message: "Get all transferLayings successfully",
|
||||||
@@ -56,7 +54,7 @@ func (u *TransferLayingController) GetAll(c *fiber.Ctx) error {
|
|||||||
TotalPages: int64(math.Ceil(float64(totalResults) / float64(query.Limit))),
|
TotalPages: int64(math.Ceil(float64(totalResults) / float64(query.Limit))),
|
||||||
TotalResults: totalResults,
|
TotalResults: totalResults,
|
||||||
},
|
},
|
||||||
Data: dto.ToTransferLayingListDTOs(result),
|
Data: data,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,7 +111,7 @@ func (u *TransferLayingController) UpdateOne(c *fiber.Ctx) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err := c.BodyParser(req); err != nil {
|
if err := c.BodyParser(req); err != nil {
|
||||||
return fiber.NewError(fiber.StatusBadRequest, "Invalid request body")
|
return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Invalid request body: %s", err.Error()))
|
||||||
}
|
}
|
||||||
|
|
||||||
result, err := u.TransferLayingService.UpdateOne(c, req, uint(id))
|
result, err := u.TransferLayingService.UpdateOne(c, req, uint(id))
|
||||||
@@ -126,7 +124,7 @@ func (u *TransferLayingController) UpdateOne(c *fiber.Ctx) error {
|
|||||||
Code: fiber.StatusOK,
|
Code: fiber.StatusOK,
|
||||||
Status: "success",
|
Status: "success",
|
||||||
Message: "Update transferLaying successfully",
|
Message: "Update transferLaying successfully",
|
||||||
Data: dto.ToTransferLayingListDTO(*result),
|
Data: dto.ToTransferLayingDetailDTOWithSingleApproval(*result, result.LatestApproval),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -180,3 +178,40 @@ func (u *TransferLayingController) Approval(c *fiber.Ctx) error {
|
|||||||
Data: data,
|
Data: data,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func (u *TransferLayingController) GetAvailableQtyPerKandang(c *fiber.Ctx) error {
|
||||||
|
projectFlockID, err := strconv.ParseUint(c.Params("project_flock_id"), 10, 32)
|
||||||
|
if err != nil {
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, "Invalid project_flock_id")
|
||||||
|
}
|
||||||
|
|
||||||
|
pf, kandangQtyMap, err := u.TransferLayingService.GetAvailableQtyPerKandang(c, uint(projectFlockID))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build kandang list response
|
||||||
|
kandangs := make([]dto.KandangAvailableQtyDTO, 0, len(kandangQtyMap))
|
||||||
|
for kandangPFID, qty := range kandangQtyMap {
|
||||||
|
kandangs = append(kandangs, dto.KandangAvailableQtyDTO{
|
||||||
|
ProjectFlockKandangId: kandangPFID,
|
||||||
|
AvailableQty: qty,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
resp := dto.AvailableQtyForTransferDTO{
|
||||||
|
ProjectFlockId: pf.Id,
|
||||||
|
ProjectFlockCode: pf.FlockName,
|
||||||
|
Category: pf.Category,
|
||||||
|
Kandangs: kandangs,
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.Status(fiber.StatusOK).
|
||||||
|
JSON(response.Success{
|
||||||
|
Code: fiber.StatusOK,
|
||||||
|
Status: "success",
|
||||||
|
Message: "Get available quantity successfully",
|
||||||
|
Data: resp,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@@ -77,6 +77,20 @@ type TransferLayingDetailDTO struct {
|
|||||||
Approval *approvalDTO.ApprovalBaseDTO `json:"approval,omitempty"`
|
Approval *approvalDTO.ApprovalBaseDTO `json:"approval,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// === Available Quantity DTOs ===
|
||||||
|
|
||||||
|
type KandangAvailableQtyDTO struct {
|
||||||
|
ProjectFlockKandangId uint `json:"project_flock_kandang_id"`
|
||||||
|
AvailableQty float64 `json:"available_qty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type AvailableQtyForTransferDTO struct {
|
||||||
|
ProjectFlockId uint `json:"project_flock_id"`
|
||||||
|
ProjectFlockCode string `json:"project_flock_code"`
|
||||||
|
Category string `json:"category"`
|
||||||
|
Kandangs []KandangAvailableQtyDTO `json:"kandangs"`
|
||||||
|
}
|
||||||
|
|
||||||
// === Mapper Functions ===
|
// === Mapper Functions ===
|
||||||
|
|
||||||
func ToProjectFlockSummaryDTO(pf *entity.ProjectFlock) *ProjectFlockSummaryDTO {
|
func ToProjectFlockSummaryDTO(pf *entity.ProjectFlock) *ProjectFlockSummaryDTO {
|
||||||
@@ -207,7 +221,6 @@ func ToTransferLayingListDTO(e entity.LayingTransfer) TransferLayingListDTO {
|
|||||||
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.ApprovalBaseDTO
|
||||||
|
|
||||||
// Use LatestApproval from entity if available
|
|
||||||
if e.LatestApproval != nil {
|
if e.LatestApproval != nil {
|
||||||
mapped := approvalDTO.ToApprovalDTO(*e.LatestApproval)
|
mapped := approvalDTO.ToApprovalDTO(*e.LatestApproval)
|
||||||
latestApproval = &mapped
|
latestApproval = &mapped
|
||||||
|
|||||||
@@ -27,4 +27,5 @@ func TransferLayingRoutes(v1 fiber.Router, u user.UserService, s transferLaying.
|
|||||||
route.Patch("/:id", ctrl.UpdateOne)
|
route.Patch("/:id", ctrl.UpdateOne)
|
||||||
route.Delete("/:id", ctrl.DeleteOne)
|
route.Delete("/:id", ctrl.DeleteOne)
|
||||||
route.Post("/approvals", ctrl.Approval)
|
route.Post("/approvals", ctrl.Approval)
|
||||||
|
route.Get("/project-flocks/:project_flock_id/available-qty", ctrl.GetAvailableQtyPerKandang)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ type TransferLayingService interface {
|
|||||||
UpdateOne(ctx *fiber.Ctx, req *validation.Update, id uint) (*entity.LayingTransfer, error)
|
UpdateOne(ctx *fiber.Ctx, req *validation.Update, id uint) (*entity.LayingTransfer, error)
|
||||||
DeleteOne(ctx *fiber.Ctx, id uint) error
|
DeleteOne(ctx *fiber.Ctx, id uint) error
|
||||||
Approval(ctx *fiber.Ctx, req *validation.Approve) ([]entity.LayingTransfer, error)
|
Approval(ctx *fiber.Ctx, req *validation.Approve) ([]entity.LayingTransfer, error)
|
||||||
|
GetAvailableQtyPerKandang(ctx *fiber.Ctx, projectFlockID uint) (*entity.ProjectFlock, map[uint]float64, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type transferLayingService struct {
|
type transferLayingService struct {
|
||||||
@@ -92,32 +93,7 @@ func (s transferLayingService) GetAll(c *fiber.Ctx, params *validation.Query) ([
|
|||||||
|
|
||||||
transferLayings, total, err := s.Repository.GetAll(c.Context(), offset, params.Limit, func(db *gorm.DB) *gorm.DB {
|
transferLayings, total, err := s.Repository.GetAll(c.Context(), offset, params.Limit, func(db *gorm.DB) *gorm.DB {
|
||||||
db = s.withRelations(db)
|
db = s.withRelations(db)
|
||||||
if params.SourceProjectFlockId != 0 {
|
db = db.Order("created_at DESC")
|
||||||
db = db.Where("from_project_flock_id = ?", params.SourceProjectFlockId)
|
|
||||||
}
|
|
||||||
if params.TargetProjectFlockId != 0 {
|
|
||||||
db = db.Where("to_project_flock_id = ?", params.TargetProjectFlockId)
|
|
||||||
}
|
|
||||||
if params.TransferDateFrom != "" {
|
|
||||||
db = db.Where("transfer_date >= ?", params.TransferDateFrom)
|
|
||||||
}
|
|
||||||
if params.TransferDateTo != "" {
|
|
||||||
db = db.Where("transfer_date <= ?", params.TransferDateTo)
|
|
||||||
}
|
|
||||||
if params.TransferNumber != "" {
|
|
||||||
db = db.Where("transfer_number ILIKE ?", "%"+params.TransferNumber+"%")
|
|
||||||
}
|
|
||||||
|
|
||||||
sortField := "created_at"
|
|
||||||
if params.Sort != "" {
|
|
||||||
sortField = params.Sort
|
|
||||||
}
|
|
||||||
sortOrder := "DESC"
|
|
||||||
if params.Order == "asc" {
|
|
||||||
sortOrder = "ASC"
|
|
||||||
}
|
|
||||||
db = db.Order(fmt.Sprintf("%s %s", sortField, sortOrder))
|
|
||||||
|
|
||||||
return db
|
return db
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -126,19 +102,14 @@ func (s transferLayingService) GetAll(c *fiber.Ctx, params *validation.Query) ([
|
|||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if params.ApprovalStatus != "" {
|
approvalRepo := commonRepo.NewApprovalRepository(s.Repository.DB())
|
||||||
var filtered []entity.LayingTransfer
|
for i, transfer := range transferLayings {
|
||||||
approvalRepo := commonRepo.NewApprovalRepository(s.Repository.DB())
|
latestApproval, err := approvalRepo.LatestByTarget(c.Context(), string(utils.ApprovalWorkflowTransferToLaying), transfer.Id, func(db *gorm.DB) *gorm.DB {
|
||||||
|
return db.Preload("ActionUser")
|
||||||
for _, transfer := range transferLayings {
|
})
|
||||||
latestApproval, err := approvalRepo.LatestByTarget(c.Context(), string(utils.ApprovalWorkflowTransferToLaying), transfer.Id, nil)
|
if err == nil && latestApproval != nil {
|
||||||
if err == nil && latestApproval != nil && latestApproval.Action != nil {
|
transferLayings[i].LatestApproval = latestApproval
|
||||||
if string(*latestApproval.Action) == params.ApprovalStatus {
|
|
||||||
filtered = append(filtered, transfer)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
transferLayings = filtered
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return transferLayings, total, nil
|
return transferLayings, total, nil
|
||||||
@@ -155,7 +126,9 @@ func (s transferLayingService) GetOne(c *fiber.Ctx, id uint) (*entity.LayingTran
|
|||||||
}
|
}
|
||||||
|
|
||||||
approvalRepo := commonRepo.NewApprovalRepository(s.Repository.DB())
|
approvalRepo := commonRepo.NewApprovalRepository(s.Repository.DB())
|
||||||
latestApproval, err := approvalRepo.LatestByTarget(c.Context(), string(utils.ApprovalWorkflowTransferToLaying), transferLaying.Id, nil)
|
latestApproval, err := approvalRepo.LatestByTarget(c.Context(), string(utils.ApprovalWorkflowTransferToLaying), transferLaying.Id, func(db *gorm.DB) *gorm.DB {
|
||||||
|
return db.Preload("ActionUser")
|
||||||
|
})
|
||||||
if err == nil && latestApproval != nil {
|
if err == nil && latestApproval != nil {
|
||||||
transferLaying.LatestApproval = latestApproval
|
transferLaying.LatestApproval = latestApproval
|
||||||
}
|
}
|
||||||
@@ -547,7 +520,6 @@ func (s transferLayingService) DeleteOne(c *fiber.Ctx, id uint) error {
|
|||||||
return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Cannot delete transfer laying with status %s", action))
|
return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Cannot delete transfer laying with status %s", action))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = s.Repository.DB().WithContext(c.Context()).Transaction(func(dbTransaction *gorm.DB) error {
|
err = s.Repository.DB().WithContext(c.Context()).Transaction(func(dbTransaction *gorm.DB) error {
|
||||||
|
|
||||||
productWarehouseRepoTx := s.ProductWarehouseRepo.WithTx(dbTransaction)
|
productWarehouseRepoTx := s.ProductWarehouseRepo.WithTx(dbTransaction)
|
||||||
@@ -851,8 +823,6 @@ func (s *transferLayingService) restoreProjectFlockPopulation(ctx context.Contex
|
|||||||
return fiber.NewError(fiber.StatusBadRequest, "No populations found for restoration")
|
return fiber.NewError(fiber.StatusBadRequest, "No populations found for restoration")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Restore in LIFO order (from newest to oldest)
|
|
||||||
// Add all quantity back to the last (newest) population
|
|
||||||
if len(populations) > 0 {
|
if len(populations) > 0 {
|
||||||
lastPop := populations[len(populations)-1]
|
lastPop := populations[len(populations)-1]
|
||||||
newQty := lastPop.TotalQty + quantityToRestore
|
newQty := lastPop.TotalQty + quantityToRestore
|
||||||
@@ -863,3 +833,37 @@ func (s *transferLayingService) restoreProjectFlockPopulation(ctx context.Contex
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s transferLayingService) GetAvailableQtyPerKandang(ctx *fiber.Ctx, projectFlockID uint) (*entity.ProjectFlock, map[uint]float64, error) {
|
||||||
|
|
||||||
|
pf, err := s.ProjectFlockRepo.GetByID(ctx.Context(), projectFlockID, func(db *gorm.DB) *gorm.DB {
|
||||||
|
return db
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
s.Log.Errorf("Failed to get project flock %d: %+v", projectFlockID, err)
|
||||||
|
return nil, nil, fiber.NewError(fiber.StatusNotFound, "Project flock not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
kandangs, _, err := s.ProjectFlockKandangRepo.GetAll(ctx.Context(), 0, 1000, func(db *gorm.DB) *gorm.DB {
|
||||||
|
return db.Where("project_flock_id = ?", projectFlockID).Order("kandang_id ASC")
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
s.Log.Errorf("Failed to get kandangs for project flock %d: %+v", projectFlockID, err)
|
||||||
|
return nil, nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch kandangs")
|
||||||
|
}
|
||||||
|
|
||||||
|
kandangAvailableQty := make(map[uint]float64)
|
||||||
|
for _, kandang := range kandangs {
|
||||||
|
|
||||||
|
totalQty, err := s.ProjectFlockPopulationRepo.GetTotalQtyByProjectFlockKandangID(ctx.Context(), kandang.Id)
|
||||||
|
if err != nil {
|
||||||
|
s.Log.Warnf("Failed to get total qty for kandang %d: %+v", kandang.Id, err)
|
||||||
|
kandangAvailableQty[kandang.Id] = 0
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
kandangAvailableQty[kandang.Id] = totalQty
|
||||||
|
}
|
||||||
|
|
||||||
|
return pf, kandangAvailableQty, nil
|
||||||
|
}
|
||||||
|
|||||||
+2
-10
@@ -29,16 +29,8 @@ type Update struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Query struct {
|
type Query struct {
|
||||||
Page int `query:"page" validate:"omitempty,number,min=1,gt=0"`
|
Page int `query:"page" validate:"omitempty,number,min=1,gt=0"`
|
||||||
Limit int `query:"limit" validate:"omitempty,number,min=1,max=100,gt=0"`
|
Limit int `query:"limit" validate:"omitempty,number,min=1,max=100,gt=0"`
|
||||||
SourceProjectFlockId uint `query:"source_project_flock_id" validate:"omitempty"`
|
|
||||||
TargetProjectFlockId uint `query:"target_project_flock_id" validate:"omitempty"`
|
|
||||||
TransferDateFrom string `query:"transfer_date_from" validate:"omitempty,datetime=2006-01-02"`
|
|
||||||
TransferDateTo string `query:"transfer_date_to" validate:"omitempty,datetime=2006-01-02"`
|
|
||||||
ApprovalStatus string `query:"approval_status" validate:"omitempty,oneof=PENDING APPROVED REJECTED"` // Filter by latest approval status
|
|
||||||
TransferNumber string `query:"transfer_number" validate:"omitempty"` // Search by transfer number
|
|
||||||
Sort string `query:"sort" validate:"omitempty,oneof=created_at transfer_date"` // Sort by field
|
|
||||||
Order string `query:"order" validate:"omitempty,oneof=asc desc"` // Sort order
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type Approve struct {
|
type Approve struct {
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import (
|
|||||||
production "gitlab.com/mbugroup/lti-api.git/internal/modules/production"
|
production "gitlab.com/mbugroup/lti-api.git/internal/modules/production"
|
||||||
purchases "gitlab.com/mbugroup/lti-api.git/internal/modules/purchases"
|
purchases "gitlab.com/mbugroup/lti-api.git/internal/modules/purchases"
|
||||||
users "gitlab.com/mbugroup/lti-api.git/internal/modules/users"
|
users "gitlab.com/mbugroup/lti-api.git/internal/modules/users"
|
||||||
|
marketing "gitlab.com/mbugroup/lti-api.git/internal/modules/marketing"
|
||||||
// MODULE IMPORTS
|
// MODULE IMPORTS
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -32,6 +33,7 @@ func Routes(app *fiber.App, db *gorm.DB) {
|
|||||||
production.ProductionModule{},
|
production.ProductionModule{},
|
||||||
approvals.ApprovalModule{},
|
approvals.ApprovalModule{},
|
||||||
purchases.PurchaseModule{},
|
purchases.PurchaseModule{},
|
||||||
|
marketing.MarketingModule{},
|
||||||
// MODULE REGISTRY
|
// MODULE REGISTRY
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user