feat: implement inventory movement management with CRUD operations and routing
This commit is contained in:
parent
59333e5144
commit
5773c34131
|
|
@ -15,6 +15,7 @@ import (
|
|||
"github.com/Caknoooo/go-gin-clean-starter/modules/category"
|
||||
"github.com/Caknoooo/go-gin-clean-starter/modules/client"
|
||||
inventoryissue "github.com/Caknoooo/go-gin-clean-starter/modules/inventory_issue"
|
||||
inventorymovement "github.com/Caknoooo/go-gin-clean-starter/modules/inventory_movement"
|
||||
inventoryreceipt "github.com/Caknoooo/go-gin-clean-starter/modules/inventory_receipt"
|
||||
inventoryrequest "github.com/Caknoooo/go-gin-clean-starter/modules/inventory_request"
|
||||
inventoryreturn "github.com/Caknoooo/go-gin-clean-starter/modules/inventory_return"
|
||||
|
|
@ -171,6 +172,7 @@ func main() {
|
|||
inventoryrequest.RegisterRoutes(server, injector)
|
||||
inventoryissue.RegisterRoutes(server, injector)
|
||||
inventoryreturn.RegisterRoutes(server, injector)
|
||||
inventorymovement.RegisterRoutes(server, injector)
|
||||
|
||||
// register swagger route
|
||||
server.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
|
||||
|
|
|
|||
|
|
@ -20,7 +20,10 @@ type TInventoryMovementEntity struct {
|
|||
SourceLocationID uuid.UUID `gorm:"type:uuid;index;" json:"source_location_id"`
|
||||
DestinationLocationID uuid.UUID `gorm:"type:uuid;index;" json:"destination_location_id"`
|
||||
|
||||
Client M_Client `gorm:"foreignKey:ClientID;references:ID"`
|
||||
MovementLines []TInventoryMovementLineEntity `gorm:"foreignKey:InventoryMovementID;references:ID"`
|
||||
SourceLocation MWarehouseEntity `gorm:"foreignKey:SourceLocationID;references:ID"`
|
||||
DestinationLocation MWarehouseEntity `gorm:"foreignKey:DestinationLocationID;references:ID"`
|
||||
Client M_Client `gorm:"foreignKey:ClientID;references:ID"`
|
||||
|
||||
FullAuditTrail
|
||||
}
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ func MigrateFresh(db *gorm.DB) error {
|
|||
// &entities.MWarehouseEntity{},
|
||||
// &entities.MZonaEntity{},
|
||||
// &entities.MAisleEntity{},
|
||||
&entities.MUserWarehouseEntity{},
|
||||
// &entities.MUserWarehouseEntity{},
|
||||
// &entities.TAssignmentEntity{},
|
||||
// &entities.TAssignmentUserEntity{},
|
||||
// &entities.TInventoryReceiptEntity{},
|
||||
|
|
|
|||
|
|
@ -0,0 +1,174 @@
|
|||
package controller
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/Caknoooo/go-gin-clean-starter/modules/inventory_movement/dto"
|
||||
"github.com/Caknoooo/go-gin-clean-starter/modules/inventory_movement/query"
|
||||
"github.com/Caknoooo/go-gin-clean-starter/modules/inventory_movement/service"
|
||||
"github.com/Caknoooo/go-gin-clean-starter/pkg/utils"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/samber/do"
|
||||
)
|
||||
|
||||
type InventoryMovementController interface {
|
||||
Create(ctx *gin.Context)
|
||||
Update(ctx *gin.Context)
|
||||
Delete(ctx *gin.Context)
|
||||
GetById(ctx *gin.Context)
|
||||
GetAll(ctx *gin.Context)
|
||||
CreateLine(ctx *gin.Context)
|
||||
UpdateLine(ctx *gin.Context)
|
||||
DeleteLine(ctx *gin.Context)
|
||||
}
|
||||
|
||||
type inventoryMovementController struct {
|
||||
movementService service.InventoryMovementService
|
||||
}
|
||||
|
||||
func (c *inventoryMovementController) Create(ctx *gin.Context) {
|
||||
var req dto.InventoryMovementCreateRequest
|
||||
if err := ctx.ShouldBindJSON(&req); err != nil {
|
||||
res := utils.BuildResponseFailed(dto.MESSAGE_FAILED_GET_DATA_FROM_BODY, err.Error(), nil)
|
||||
ctx.JSON(http.StatusBadRequest, res)
|
||||
return
|
||||
}
|
||||
result, err := c.movementService.Create(ctx, req)
|
||||
if err != nil {
|
||||
res := utils.BuildResponseFailed(dto.MESSAGE_FAILED_CREATE_INVENTORY_MOVEMENT, err.Error(), nil)
|
||||
ctx.JSON(http.StatusInternalServerError, res)
|
||||
return
|
||||
}
|
||||
res := utils.BuildResponseSuccess(dto.MESSAGE_SUCCESS_CREATE_INVENTORY_MOVEMENT, result)
|
||||
ctx.JSON(http.StatusOK, res)
|
||||
}
|
||||
|
||||
func (c *inventoryMovementController) Update(ctx *gin.Context) {
|
||||
id := ctx.Param("id")
|
||||
var req dto.InventoryMovementUpdateRequest
|
||||
if err := ctx.ShouldBindJSON(&req); err != nil {
|
||||
res := utils.BuildResponseFailed(dto.MESSAGE_FAILED_GET_DATA_FROM_BODY, err.Error(), nil)
|
||||
ctx.JSON(http.StatusBadRequest, res)
|
||||
return
|
||||
}
|
||||
result, err := c.movementService.Update(ctx, req, id)
|
||||
if err != nil {
|
||||
res := utils.BuildResponseFailed(dto.MESSAGE_FAILED_UPDATE_INVENTORY_MOVEMENT, err.Error(), nil)
|
||||
ctx.JSON(http.StatusInternalServerError, res)
|
||||
return
|
||||
}
|
||||
res := utils.BuildResponseSuccess(dto.MESSAGE_SUCCESS_UPDATE_INVENTORY_MOVEMENT, result)
|
||||
ctx.JSON(http.StatusOK, res)
|
||||
}
|
||||
|
||||
func (c *inventoryMovementController) Delete(ctx *gin.Context) {
|
||||
id := ctx.Param("id")
|
||||
if err := c.movementService.Delete(ctx, id); err != nil {
|
||||
res := utils.BuildResponseFailed(dto.MESSAGE_FAILED_DELETE_INVENTORY_MOVEMENT, err.Error(), nil)
|
||||
ctx.JSON(http.StatusInternalServerError, res)
|
||||
return
|
||||
}
|
||||
res := utils.BuildResponseSuccess(dto.MESSAGE_SUCCESS_DELETE_INVENTORY_MOVEMENT, nil)
|
||||
ctx.JSON(http.StatusOK, res)
|
||||
}
|
||||
|
||||
func (c *inventoryMovementController) GetById(ctx *gin.Context) {
|
||||
id := ctx.Param("id")
|
||||
result, err := c.movementService.GetById(ctx, id)
|
||||
if err != nil {
|
||||
res := utils.BuildResponseFailed(dto.MESSAGE_FAILED_GET_INVENTORY_MOVEMENT, err.Error(), nil)
|
||||
ctx.JSON(http.StatusInternalServerError, res)
|
||||
return
|
||||
}
|
||||
res := utils.BuildResponseSuccess(dto.MESSAGE_SUCCESS_GET_INVENTORY_MOVEMENT, result)
|
||||
ctx.JSON(http.StatusOK, res)
|
||||
}
|
||||
|
||||
func (c *inventoryMovementController) GetAll(ctx *gin.Context) {
|
||||
clientId := ctx.DefaultQuery("client_id", "")
|
||||
var filter query.InventoryMovementFilter
|
||||
filter.ClientID = clientId
|
||||
if err := ctx.ShouldBindQuery(&filter); err != nil {
|
||||
res := utils.BuildResponseFailed(dto.MESSAGE_FAILED_GET_INVENTORY_MOVEMENT, err.Error(), nil)
|
||||
ctx.JSON(http.StatusBadRequest, res)
|
||||
return
|
||||
}
|
||||
getAll := ctx.Query("get_all")
|
||||
if getAll != "" {
|
||||
movements, _, err := c.movementService.GetAll(ctx, filter)
|
||||
if err != nil {
|
||||
res := utils.BuildResponseFailed(dto.MESSAGE_FAILED_GET_INVENTORY_MOVEMENT, err.Error(), nil)
|
||||
ctx.JSON(http.StatusBadRequest, res)
|
||||
return
|
||||
}
|
||||
response := utils.BuildResponseSuccess(dto.MESSAGE_SUCCESS_GET_INVENTORY_MOVEMENT, movements)
|
||||
ctx.JSON(http.StatusOK, response)
|
||||
return
|
||||
}
|
||||
perPage := utils.ParseInt(ctx.DefaultQuery("per_page", "10"))
|
||||
page := utils.ParseInt(ctx.DefaultQuery("page", "1"))
|
||||
filter.PerPage = perPage
|
||||
filter.Page = (page - 1) * perPage
|
||||
movements, total, err := c.movementService.GetAll(ctx, filter)
|
||||
if err != nil {
|
||||
res := utils.BuildResponseFailed(dto.MESSAGE_FAILED_GET_INVENTORY_MOVEMENT, err.Error(), nil)
|
||||
ctx.JSON(http.StatusInternalServerError, res)
|
||||
return
|
||||
}
|
||||
paginationResponse := utils.BuildPaginationResponse(perPage, page, total)
|
||||
res := utils.BuildResponseSuccessWithPagination(http.StatusOK, dto.MESSAGE_SUCCESS_GET_INVENTORY_MOVEMENT, movements, paginationResponse)
|
||||
ctx.JSON(http.StatusOK, res)
|
||||
}
|
||||
|
||||
func (c *inventoryMovementController) CreateLine(ctx *gin.Context) {
|
||||
id := ctx.Param("id")
|
||||
var req dto.InventoryMovementLineCreateRequest
|
||||
if err := ctx.ShouldBindJSON(&req); err != nil {
|
||||
res := utils.BuildResponseFailed(dto.MESSAGE_FAILED_GET_DATA_FROM_BODY, err.Error(), nil)
|
||||
ctx.JSON(http.StatusBadRequest, res)
|
||||
return
|
||||
}
|
||||
created, err := c.movementService.CreateLine(ctx, id, req)
|
||||
if err != nil {
|
||||
res := utils.BuildResponseFailed(dto.MESSAGE_FAILED_CREATE_INVENTORY_MOVEMENT_LINE, err.Error(), nil)
|
||||
ctx.JSON(http.StatusInternalServerError, res)
|
||||
return
|
||||
}
|
||||
res := utils.BuildResponseSuccess(dto.MESSAGE_SUCCESS_CREATE_INVENTORY_MOVEMENT_LINE, created)
|
||||
ctx.JSON(http.StatusOK, res)
|
||||
}
|
||||
|
||||
func (c *inventoryMovementController) UpdateLine(ctx *gin.Context) {
|
||||
id := ctx.Param("id")
|
||||
var req dto.InventoryMovementLineUpdateRequest
|
||||
if err := ctx.ShouldBindJSON(&req); err != nil {
|
||||
res := utils.BuildResponseFailed(dto.MESSAGE_FAILED_GET_DATA_FROM_BODY, err.Error(), nil)
|
||||
ctx.JSON(http.StatusBadRequest, res)
|
||||
return
|
||||
}
|
||||
updated, err := c.movementService.UpdateLine(ctx, id, req)
|
||||
if err != nil {
|
||||
res := utils.BuildResponseFailed(dto.MESSAGE_FAILED_UPDATE_INVENTORY_MOVEMENT_LINE, err.Error(), nil)
|
||||
ctx.JSON(http.StatusInternalServerError, res)
|
||||
return
|
||||
}
|
||||
res := utils.BuildResponseSuccess(dto.MESSAGE_SUCCESS_UPDATE_INVENTORY_MOVEMENT_LINE, updated)
|
||||
ctx.JSON(http.StatusOK, res)
|
||||
}
|
||||
|
||||
func (c *inventoryMovementController) DeleteLine(ctx *gin.Context) {
|
||||
id := ctx.Param("id")
|
||||
if err := c.movementService.DeleteLine(ctx, id); err != nil {
|
||||
res := utils.BuildResponseFailed(dto.MESSAGE_FAILED_DELETE_INVENTORY_MOVEMENT_LINE, err.Error(), nil)
|
||||
ctx.JSON(http.StatusInternalServerError, res)
|
||||
return
|
||||
}
|
||||
res := utils.BuildResponseSuccess(dto.MESSAGE_SUCCESS_DELETE_INVENTORY_MOVEMENT_LINE, nil)
|
||||
ctx.JSON(http.StatusOK, res)
|
||||
}
|
||||
|
||||
func NewInventoryMovementController(i *do.Injector, movementService service.InventoryMovementService) InventoryMovementController {
|
||||
return &inventoryMovementController{
|
||||
movementService: movementService,
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
package dto
|
||||
|
||||
import (
|
||||
"github.com/Caknoooo/go-gin-clean-starter/database/entities"
|
||||
"github.com/Caknoooo/go-gin-clean-starter/pkg/utils"
|
||||
)
|
||||
|
||||
const (
|
||||
MESSAGE_FAILED_CREATE_INVENTORY_MOVEMENT = "failed create inventory movement"
|
||||
MESSAGE_FAILED_CREATE_INVENTORY_MOVEMENT_LINE = "failed create inventory movement line"
|
||||
MESSAGE_SUCCESS_CREATE_INVENTORY_MOVEMENT = "success create inventory movement"
|
||||
MESSAGE_SUCCESS_CREATE_INVENTORY_MOVEMENT_LINE = "success create inventory movement line"
|
||||
MESSAGE_FAILED_GET_INVENTORY_MOVEMENT = "failed get inventory movement"
|
||||
MESSAGE_SUCCESS_GET_INVENTORY_MOVEMENT = "success get inventory movement"
|
||||
MESSAGE_FAILED_UPDATE_INVENTORY_MOVEMENT = "failed update inventory movement"
|
||||
MESSAGE_FAILED_UPDATE_INVENTORY_MOVEMENT_LINE = "failed update inventory movement line"
|
||||
MESSAGE_SUCCESS_UPDATE_INVENTORY_MOVEMENT = "success update inventory movement"
|
||||
MESSAGE_SUCCESS_UPDATE_INVENTORY_MOVEMENT_LINE = "success update inventory movement line"
|
||||
MESSAGE_FAILED_DELETE_INVENTORY_MOVEMENT = "failed delete inventory movement"
|
||||
MESSAGE_FAILED_DELETE_INVENTORY_MOVEMENT_LINE = "failed delete inventory movement line"
|
||||
MESSAGE_SUCCESS_DELETE_INVENTORY_MOVEMENT = "success delete inventory movement"
|
||||
MESSAGE_SUCCESS_DELETE_INVENTORY_MOVEMENT_LINE = "success delete inventory movement line"
|
||||
MESSAGE_FAILED_GET_DATA_FROM_BODY = "failed get data from body"
|
||||
)
|
||||
|
||||
type InventoryMovementCreateRequest struct {
|
||||
// MovementNumber string `json:"movement_number"`
|
||||
MovementDate string `json:"movement_date"`
|
||||
MovementType string `json:"movement_type"`
|
||||
ClientID string `json:"client_id" binding:"required"`
|
||||
Status string `json:"status" binding:"required"`
|
||||
SourceLocationID string `json:"source_location_id"`
|
||||
DestinationLocationID string `json:"destination_location_id"`
|
||||
MovementLines []InventoryMovementLineCreateRequest `json:"movement_lines,omitempty" binding:"dive"`
|
||||
}
|
||||
|
||||
type InventoryMovementLineCreateRequest struct {
|
||||
MovedQuantity float64 `json:"moved_quantity"`
|
||||
ProductID string `json:"product_id"`
|
||||
StorageID string `json:"storage_id"`
|
||||
ClientID string `json:"client_id"`
|
||||
Status string `json:"status"`
|
||||
}
|
||||
|
||||
type InventoryMovementUpdateRequest struct {
|
||||
// MovementNumber string `json:"movement_number"`
|
||||
MovementDate string `json:"movement_date"`
|
||||
MovementType string `json:"movement_type"`
|
||||
Status string `json:"status"`
|
||||
}
|
||||
|
||||
type InventoryMovementLineUpdateRequest struct {
|
||||
MovedQuantity *float64 `json:"moved_quantity"`
|
||||
Status *string `json:"status"`
|
||||
}
|
||||
|
||||
type InventoryMovementResponse struct {
|
||||
ID string `json:"id"`
|
||||
MovementNumber string `json:"movement_number"`
|
||||
MovementDate string `json:"movement_date"`
|
||||
MovementType string `json:"movement_type"`
|
||||
Status string `json:"status"`
|
||||
ClientID string `json:"client_id"`
|
||||
SourceLocationID string `json:"source_location_id"`
|
||||
DestinationLocationID string `json:"destination_location_id"`
|
||||
}
|
||||
|
||||
type InventoryMovementLineResponse struct {
|
||||
ID string `json:"id"`
|
||||
MovedQuantity float64 `json:"moved_quantity"`
|
||||
ProductID string `json:"product_id"`
|
||||
StorageID string `json:"storage_id"`
|
||||
ClientID string `json:"client_id"`
|
||||
Status string `json:"status"`
|
||||
}
|
||||
|
||||
func ToInventoryMovementResponse(e entities.TInventoryMovementEntity) InventoryMovementResponse {
|
||||
return InventoryMovementResponse{
|
||||
ID: e.ID.String(),
|
||||
MovementNumber: e.MovementNumber,
|
||||
MovementDate: utils.DateTimeToString(e.MovementDate),
|
||||
MovementType: e.MovementType,
|
||||
Status: e.Status,
|
||||
ClientID: e.ClientID.String(),
|
||||
SourceLocationID: e.SourceLocationID.String(),
|
||||
DestinationLocationID: e.DestinationLocationID.String(),
|
||||
}
|
||||
}
|
||||
|
||||
func ToInventoryMovementLineResponse(e entities.TInventoryMovementLineEntity) InventoryMovementLineResponse {
|
||||
return InventoryMovementLineResponse{
|
||||
ID: e.ID.String(),
|
||||
MovedQuantity: e.MovedQuantity,
|
||||
ProductID: e.ProductID.String(),
|
||||
StorageID: e.StorageID.String(),
|
||||
ClientID: e.ClientID.String(),
|
||||
Status: e.Status,
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
package query
|
||||
|
||||
import (
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type InventoryMovementFilter struct {
|
||||
ClientID string `form:"client_id"`
|
||||
SourceLocation string `form:"source_location"`
|
||||
DestinationLocation string `form:"destination_location"`
|
||||
PerPage int `form:"per_page"`
|
||||
Page int `form:"page"`
|
||||
}
|
||||
|
||||
func ApplyInventoryMovementFilters(db *gorm.DB, filter InventoryMovementFilter) *gorm.DB {
|
||||
if filter.ClientID != "" {
|
||||
db = db.Where("client_id = ?", filter.ClientID)
|
||||
}
|
||||
if filter.SourceLocation != "" {
|
||||
db = db.Where("source_location_id = ?", filter.SourceLocation)
|
||||
}
|
||||
if filter.DestinationLocation != "" {
|
||||
db = db.Where("destination_location_id = ?", filter.DestinationLocation)
|
||||
}
|
||||
return db
|
||||
}
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
package repository
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/Caknoooo/go-gin-clean-starter/database/entities"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type InventoryMovementLineRepository interface {
|
||||
Create(ctx context.Context, tx *gorm.DB, line entities.TInventoryMovementLineEntity) (entities.TInventoryMovementLineEntity, error)
|
||||
GetById(ctx context.Context, tx *gorm.DB, id string) (entities.TInventoryMovementLineEntity, error)
|
||||
Update(ctx context.Context, tx *gorm.DB, line entities.TInventoryMovementLineEntity) (entities.TInventoryMovementLineEntity, error)
|
||||
Delete(ctx context.Context, tx *gorm.DB, id string) error
|
||||
GetAllByMovementId(ctx context.Context, movementId string) ([]entities.TInventoryMovementLineEntity, error)
|
||||
BulkCreate(ctx context.Context, tx *gorm.DB, lines []entities.TInventoryMovementLineEntity) error
|
||||
DeleteByMovementId(ctx context.Context, tx *gorm.DB, movementId string) error
|
||||
}
|
||||
|
||||
type inventoryMovementLineRepository struct {
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
func NewInventoryMovementLineRepository(db *gorm.DB) InventoryMovementLineRepository {
|
||||
return &inventoryMovementLineRepository{db: db}
|
||||
}
|
||||
|
||||
func (r *inventoryMovementLineRepository) Create(ctx context.Context, tx *gorm.DB, line entities.TInventoryMovementLineEntity) (entities.TInventoryMovementLineEntity, error) {
|
||||
if tx == nil {
|
||||
tx = r.db
|
||||
}
|
||||
if err := tx.WithContext(ctx).Create(&line).Error; err != nil {
|
||||
return line, err
|
||||
}
|
||||
return line, nil
|
||||
}
|
||||
|
||||
func (r *inventoryMovementLineRepository) GetById(ctx context.Context, tx *gorm.DB, id string) (entities.TInventoryMovementLineEntity, error) {
|
||||
if tx == nil {
|
||||
tx = r.db
|
||||
}
|
||||
var line entities.TInventoryMovementLineEntity
|
||||
if err := tx.WithContext(ctx).First(&line, "id = ?", id).Error; err != nil {
|
||||
return line, err
|
||||
}
|
||||
return line, nil
|
||||
}
|
||||
|
||||
func (r *inventoryMovementLineRepository) Update(ctx context.Context, tx *gorm.DB, line entities.TInventoryMovementLineEntity) (entities.TInventoryMovementLineEntity, error) {
|
||||
if tx == nil {
|
||||
tx = r.db
|
||||
}
|
||||
if err := tx.WithContext(ctx).Save(&line).Error; err != nil {
|
||||
return line, err
|
||||
}
|
||||
return line, nil
|
||||
}
|
||||
|
||||
func (r *inventoryMovementLineRepository) Delete(ctx context.Context, tx *gorm.DB, id string) error {
|
||||
if tx == nil {
|
||||
tx = r.db
|
||||
}
|
||||
if err := tx.WithContext(ctx).Delete(&entities.TInventoryMovementLineEntity{}, "id = ?", id).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *inventoryMovementLineRepository) GetAllByMovementId(ctx context.Context, movementId string) ([]entities.TInventoryMovementLineEntity, error) {
|
||||
var lines []entities.TInventoryMovementLineEntity
|
||||
if err := r.db.WithContext(ctx).Where("inv_movement_id = ?", movementId).Preload("Product").Preload("InvMovement").Preload("InvStorage").Preload("Client").Find(&lines).Error; err != nil {
|
||||
return lines, err
|
||||
}
|
||||
return lines, nil
|
||||
}
|
||||
|
||||
func (r *inventoryMovementLineRepository) BulkCreate(ctx context.Context, tx *gorm.DB, lines []entities.TInventoryMovementLineEntity) error {
|
||||
if tx == nil {
|
||||
tx = r.db
|
||||
}
|
||||
return tx.WithContext(ctx).Create(&lines).Error
|
||||
}
|
||||
|
||||
func (r *inventoryMovementLineRepository) DeleteByMovementId(ctx context.Context, tx *gorm.DB, movementId string) error {
|
||||
if tx == nil {
|
||||
tx = r.db
|
||||
}
|
||||
return tx.WithContext(ctx).Where("inv_movement_id = ?", movementId).Delete(&entities.TInventoryMovementLineEntity{}).Error
|
||||
}
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
package repository
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/Caknoooo/go-gin-clean-starter/database/entities"
|
||||
"github.com/Caknoooo/go-gin-clean-starter/modules/inventory_movement/query"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type InventoryMovementRepository interface {
|
||||
Create(ctx context.Context, tx *gorm.DB, movement entities.TInventoryMovementEntity) (entities.TInventoryMovementEntity, error)
|
||||
GetById(ctx context.Context, tx *gorm.DB, id string) (entities.TInventoryMovementEntity, error)
|
||||
GetAll(ctx context.Context, filter query.InventoryMovementFilter) ([]entities.TInventoryMovementEntity, int64, error)
|
||||
Update(ctx context.Context, tx *gorm.DB, movement entities.TInventoryMovementEntity) (entities.TInventoryMovementEntity, error)
|
||||
Delete(ctx context.Context, tx *gorm.DB, id string) error
|
||||
}
|
||||
|
||||
type inventoryMovementRepository struct {
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
func NewInventoryMovementRepository(db *gorm.DB) InventoryMovementRepository {
|
||||
return &inventoryMovementRepository{db: db}
|
||||
}
|
||||
|
||||
func (r *inventoryMovementRepository) Create(ctx context.Context, tx *gorm.DB, movement entities.TInventoryMovementEntity) (entities.TInventoryMovementEntity, error) {
|
||||
if tx == nil {
|
||||
tx = r.db
|
||||
}
|
||||
if err := tx.WithContext(ctx).Create(&movement).Error; err != nil {
|
||||
return movement, err
|
||||
}
|
||||
return movement, nil
|
||||
}
|
||||
|
||||
func (r *inventoryMovementRepository) GetById(ctx context.Context, tx *gorm.DB, id string) (entities.TInventoryMovementEntity, error) {
|
||||
if tx == nil {
|
||||
tx = r.db
|
||||
}
|
||||
var movement entities.TInventoryMovementEntity
|
||||
if err := tx.WithContext(ctx).
|
||||
Preload("Client").
|
||||
First(&movement, "id = ?", id).Error; err != nil {
|
||||
return movement, err
|
||||
}
|
||||
return movement, nil
|
||||
}
|
||||
|
||||
func (r *inventoryMovementRepository) GetAll(ctx context.Context, filter query.InventoryMovementFilter) ([]entities.TInventoryMovementEntity, int64, error) {
|
||||
db := r.db.WithContext(ctx)
|
||||
db = query.ApplyInventoryMovementFilters(db, filter)
|
||||
var movements []entities.TInventoryMovementEntity
|
||||
var total int64
|
||||
if err := db.Find(&movements).Count(&total).Error; err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
return movements, total, nil
|
||||
}
|
||||
|
||||
func (r *inventoryMovementRepository) Update(ctx context.Context, tx *gorm.DB, movement entities.TInventoryMovementEntity) (entities.TInventoryMovementEntity, error) {
|
||||
if tx == nil {
|
||||
tx = r.db
|
||||
}
|
||||
if err := tx.WithContext(ctx).Save(&movement).Error; err != nil {
|
||||
return movement, err
|
||||
}
|
||||
return movement, nil
|
||||
}
|
||||
|
||||
func (r *inventoryMovementRepository) Delete(ctx context.Context, tx *gorm.DB, id string) error {
|
||||
if tx == nil {
|
||||
tx = r.db
|
||||
}
|
||||
if err := tx.WithContext(ctx).Delete(&entities.TInventoryMovementEntity{}, "id = ?", id).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
package inventorymovement
|
||||
|
||||
import (
|
||||
"github.com/Caknoooo/go-gin-clean-starter/middlewares"
|
||||
"github.com/Caknoooo/go-gin-clean-starter/modules/auth/service"
|
||||
"github.com/Caknoooo/go-gin-clean-starter/modules/inventory_movement/controller"
|
||||
"github.com/Caknoooo/go-gin-clean-starter/pkg/constants"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/samber/do"
|
||||
)
|
||||
|
||||
func RegisterRoutes(server *gin.Engine, injector *do.Injector) {
|
||||
movementController := do.MustInvoke[controller.InventoryMovementController](injector)
|
||||
jwtService := do.MustInvokeNamed[service.JWTService](injector, constants.JWTService)
|
||||
|
||||
movementRoutes := server.Group("/api/v1/inventory-movements")
|
||||
{
|
||||
movementRoutes.POST("", middlewares.Authenticate(jwtService), movementController.Create)
|
||||
movementRoutes.GET(":id", middlewares.Authenticate(jwtService), movementController.GetById)
|
||||
movementRoutes.PUT(":id", middlewares.Authenticate(jwtService), movementController.Update)
|
||||
movementRoutes.DELETE(":id", middlewares.Authenticate(jwtService), movementController.Delete)
|
||||
movementRoutes.GET("", middlewares.Authenticate(jwtService), movementController.GetAll)
|
||||
movementRoutes.POST(":id/lines", middlewares.Authenticate(jwtService), movementController.CreateLine)
|
||||
movementRoutes.PUT("lines/:id", middlewares.Authenticate(jwtService), movementController.UpdateLine)
|
||||
movementRoutes.DELETE("lines/:id", middlewares.Authenticate(jwtService), movementController.DeleteLine)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,231 @@
|
|||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/Caknoooo/go-gin-clean-starter/database/entities"
|
||||
dtodomain "github.com/Caknoooo/go-gin-clean-starter/modules/inventory_movement/dto"
|
||||
"github.com/Caknoooo/go-gin-clean-starter/modules/inventory_movement/query"
|
||||
"github.com/Caknoooo/go-gin-clean-starter/modules/inventory_movement/repository"
|
||||
"github.com/Caknoooo/go-gin-clean-starter/pkg/utils"
|
||||
"github.com/google/uuid"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type InventoryMovementService interface {
|
||||
Create(ctx context.Context, req dtodomain.InventoryMovementCreateRequest) (dtodomain.InventoryMovementResponse, error)
|
||||
GetById(ctx context.Context, id string) (dtodomain.InventoryMovementResponse, error)
|
||||
GetAll(ctx context.Context, filter query.InventoryMovementFilter) ([]dtodomain.InventoryMovementResponse, int64, error)
|
||||
Update(ctx context.Context, req dtodomain.InventoryMovementUpdateRequest, id string) (dtodomain.InventoryMovementResponse, error)
|
||||
Delete(ctx context.Context, id string) error
|
||||
CreateLine(ctx context.Context, movementId string, req dtodomain.InventoryMovementLineCreateRequest) (dtodomain.InventoryMovementLineResponse, error)
|
||||
UpdateLine(ctx context.Context, lineId string, req dtodomain.InventoryMovementLineUpdateRequest) (dtodomain.InventoryMovementLineResponse, error)
|
||||
DeleteLine(ctx context.Context, lineId string) error
|
||||
}
|
||||
|
||||
type inventoryMovementService struct {
|
||||
db *gorm.DB
|
||||
movementRepo repository.InventoryMovementRepository
|
||||
movementLineRepo repository.InventoryMovementLineRepository
|
||||
}
|
||||
|
||||
func (s *inventoryMovementService) Create(ctx context.Context, req dtodomain.InventoryMovementCreateRequest) (dtodomain.InventoryMovementResponse, error) {
|
||||
tx := s.db.Begin()
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
tx.Rollback()
|
||||
}
|
||||
}()
|
||||
clientUUID, err := uuid.Parse(req.ClientID)
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
return dtodomain.InventoryMovementResponse{}, err
|
||||
}
|
||||
movNumber, err := entities.GenerateDocumentNumberInvMovement(s.db, req.ClientID)
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
return dtodomain.InventoryMovementResponse{}, err
|
||||
}
|
||||
movement := entities.TInventoryMovementEntity{
|
||||
MovementNumber: movNumber,
|
||||
MovementDate: utils.StringToDateTime(req.MovementDate),
|
||||
MovementType: req.MovementType,
|
||||
ClientID: clientUUID,
|
||||
Status: req.Status,
|
||||
SourceLocationID: uuid.MustParse(req.SourceLocationID),
|
||||
DestinationLocationID: uuid.MustParse(req.DestinationLocationID),
|
||||
}
|
||||
created, err := s.movementRepo.Create(ctx, tx, movement)
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
return dtodomain.InventoryMovementResponse{}, err
|
||||
}
|
||||
// Bulk create lines
|
||||
var lines []entities.TInventoryMovementLineEntity
|
||||
for _, lineReq := range req.MovementLines {
|
||||
productUUID := uuid.Nil
|
||||
if lineReq.ProductID != "" {
|
||||
productUUID, err = uuid.Parse(lineReq.ProductID)
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
return dtodomain.InventoryMovementResponse{}, err
|
||||
}
|
||||
}
|
||||
clientLineUUID, err := uuid.Parse(lineReq.ClientID)
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
return dtodomain.InventoryMovementResponse{}, err
|
||||
}
|
||||
lines = append(lines, entities.TInventoryMovementLineEntity{
|
||||
MovedQuantity: lineReq.MovedQuantity,
|
||||
InvMovementID: created.ID,
|
||||
ProductID: productUUID,
|
||||
StorageID: uuid.MustParse(lineReq.StorageID),
|
||||
ClientID: clientLineUUID,
|
||||
Status: lineReq.Status,
|
||||
})
|
||||
}
|
||||
if len(lines) > 0 {
|
||||
err = s.movementLineRepo.BulkCreate(ctx, tx, lines)
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
return dtodomain.InventoryMovementResponse{}, err
|
||||
}
|
||||
}
|
||||
tx.Commit()
|
||||
result, err := s.movementRepo.GetById(ctx, nil, created.ID.String())
|
||||
if err != nil {
|
||||
return dtodomain.InventoryMovementResponse{}, err
|
||||
}
|
||||
return dtodomain.ToInventoryMovementResponse(result), nil
|
||||
}
|
||||
|
||||
func (s *inventoryMovementService) GetById(ctx context.Context, id string) (dtodomain.InventoryMovementResponse, error) {
|
||||
movement, err := s.movementRepo.GetById(ctx, nil, id)
|
||||
if err != nil {
|
||||
return dtodomain.InventoryMovementResponse{}, err
|
||||
}
|
||||
return dtodomain.ToInventoryMovementResponse(movement), nil
|
||||
}
|
||||
|
||||
func (s *inventoryMovementService) GetAll(ctx context.Context, filter query.InventoryMovementFilter) ([]dtodomain.InventoryMovementResponse, int64, error) {
|
||||
movements, total, err := s.movementRepo.GetAll(ctx, filter)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
var responses []dtodomain.InventoryMovementResponse
|
||||
for _, e := range movements {
|
||||
responses = append(responses, dtodomain.ToInventoryMovementResponse(e))
|
||||
}
|
||||
if responses == nil {
|
||||
responses = make([]dtodomain.InventoryMovementResponse, 0)
|
||||
}
|
||||
return responses, total, nil
|
||||
}
|
||||
|
||||
func (s *inventoryMovementService) Update(ctx context.Context, req dtodomain.InventoryMovementUpdateRequest, id string) (dtodomain.InventoryMovementResponse, error) {
|
||||
tx := s.db.Begin()
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
tx.Rollback()
|
||||
}
|
||||
}()
|
||||
movement, err := s.movementRepo.GetById(ctx, tx, id)
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
return dtodomain.InventoryMovementResponse{}, err
|
||||
}
|
||||
// if req.MovementNumber != "" {
|
||||
// movement.MovementNumber = req.MovementNumber
|
||||
// }
|
||||
movement.MovementDate = utils.StringToDateTime(req.MovementDate)
|
||||
movement.MovementType = req.MovementType
|
||||
movement.Status = req.Status
|
||||
updated, err := s.movementRepo.Update(ctx, tx, movement)
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
return dtodomain.InventoryMovementResponse{}, err
|
||||
}
|
||||
tx.Commit()
|
||||
result, err := s.movementRepo.GetById(ctx, nil, updated.ID.String())
|
||||
if err != nil {
|
||||
return dtodomain.InventoryMovementResponse{}, err
|
||||
}
|
||||
return dtodomain.ToInventoryMovementResponse(result), nil
|
||||
}
|
||||
|
||||
func (s *inventoryMovementService) Delete(ctx context.Context, id string) error {
|
||||
tx := s.db.Begin()
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
tx.Rollback()
|
||||
}
|
||||
}()
|
||||
if err := s.movementRepo.Delete(ctx, tx, id); err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
tx.Commit()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *inventoryMovementService) CreateLine(ctx context.Context, movementId string, req dtodomain.InventoryMovementLineCreateRequest) (dtodomain.InventoryMovementLineResponse, error) {
|
||||
movementUUID, err := uuid.Parse(movementId)
|
||||
if err != nil {
|
||||
return dtodomain.InventoryMovementLineResponse{}, err
|
||||
}
|
||||
productUUID := uuid.Nil
|
||||
if req.ProductID != "" {
|
||||
productUUID, err = uuid.Parse(req.ProductID)
|
||||
if err != nil {
|
||||
return dtodomain.InventoryMovementLineResponse{}, err
|
||||
}
|
||||
}
|
||||
clientLineUUID, err := uuid.Parse(req.ClientID)
|
||||
if err != nil {
|
||||
return dtodomain.InventoryMovementLineResponse{}, err
|
||||
}
|
||||
line := entities.TInventoryMovementLineEntity{
|
||||
MovedQuantity: req.MovedQuantity,
|
||||
InvMovementID: movementUUID,
|
||||
ProductID: productUUID,
|
||||
StorageID: uuid.MustParse(req.StorageID),
|
||||
ClientID: clientLineUUID,
|
||||
Status: req.Status,
|
||||
}
|
||||
created, err := s.movementLineRepo.Create(ctx, nil, line)
|
||||
if err != nil {
|
||||
return dtodomain.InventoryMovementLineResponse{}, err
|
||||
}
|
||||
return dtodomain.ToInventoryMovementLineResponse(created), nil
|
||||
}
|
||||
|
||||
func (s *inventoryMovementService) UpdateLine(ctx context.Context, lineId string, req dtodomain.InventoryMovementLineUpdateRequest) (dtodomain.InventoryMovementLineResponse, error) {
|
||||
line, err := s.movementLineRepo.GetById(ctx, nil, lineId)
|
||||
if err != nil {
|
||||
return dtodomain.InventoryMovementLineResponse{}, err
|
||||
}
|
||||
if req.MovedQuantity != nil {
|
||||
line.MovedQuantity = *req.MovedQuantity
|
||||
}
|
||||
if req.Status != nil {
|
||||
line.Status = *req.Status
|
||||
}
|
||||
updated, err := s.movementLineRepo.Update(ctx, nil, line)
|
||||
if err != nil {
|
||||
return dtodomain.InventoryMovementLineResponse{}, err
|
||||
}
|
||||
return dtodomain.ToInventoryMovementLineResponse(updated), nil
|
||||
}
|
||||
|
||||
func (s *inventoryMovementService) DeleteLine(ctx context.Context, lineId string) error {
|
||||
return s.movementLineRepo.Delete(ctx, nil, lineId)
|
||||
}
|
||||
|
||||
func NewInventoryMovementService(db *gorm.DB, movementRepo repository.InventoryMovementRepository, movementLineRepo repository.InventoryMovementLineRepository) InventoryMovementService {
|
||||
return &inventoryMovementService{
|
||||
db: db,
|
||||
movementRepo: movementRepo,
|
||||
movementLineRepo: movementLineRepo,
|
||||
}
|
||||
}
|
||||
|
|
@ -83,6 +83,11 @@ import (
|
|||
inventoryReturnRepo "github.com/Caknoooo/go-gin-clean-starter/modules/inventory_return/repository"
|
||||
inventoryReturnService "github.com/Caknoooo/go-gin-clean-starter/modules/inventory_return/service"
|
||||
|
||||
inventoryMovementController "github.com/Caknoooo/go-gin-clean-starter/modules/inventory_movement/controller"
|
||||
inventoryMovementLineRepo "github.com/Caknoooo/go-gin-clean-starter/modules/inventory_movement/repository"
|
||||
inventoryMovementRepo "github.com/Caknoooo/go-gin-clean-starter/modules/inventory_movement/repository"
|
||||
inventoryMovementService "github.com/Caknoooo/go-gin-clean-starter/modules/inventory_movement/service"
|
||||
|
||||
"github.com/Caknoooo/go-gin-clean-starter/modules/user/controller"
|
||||
"github.com/Caknoooo/go-gin-clean-starter/modules/user/repository"
|
||||
userService "github.com/Caknoooo/go-gin-clean-starter/modules/user/service"
|
||||
|
|
@ -142,6 +147,8 @@ func RegisterDependencies(injector *do.Injector) {
|
|||
inventoryIssueLineRepository := inventoryIssueLineRepo.NewInventoryIssueLineRepository(db)
|
||||
inventoryReturnRepository := inventoryReturnRepo.NewInventoryReturnRepository(db)
|
||||
inventoryReturnLineRepository := inventoryReturnLineRepo.NewInventoryReturnLineRepository(db)
|
||||
inventoryMovementRepository := inventoryMovementRepo.NewInventoryMovementRepository(db)
|
||||
inventoryMovementLineRepository := inventoryMovementLineRepo.NewInventoryMovementLineRepository(db)
|
||||
|
||||
// Service
|
||||
userServ := userService.NewUserService(userRepository, roleRepository, warehouseRepository, refreshTokenRepository, jwtService, db)
|
||||
|
|
@ -162,6 +169,7 @@ func RegisterDependencies(injector *do.Injector) {
|
|||
inventoryRequestServ := inventoryRequestService.NewInventoryRequestService(db, inventoryRequestRepository, inventoryRequestLineRepository)
|
||||
inventoryIssueServ := inventoryIssueService.NewInventoryIssueService(db, inventoryIssueRepository, inventoryIssueLineRepository)
|
||||
inventoryReturnServ := inventoryReturnService.NewInventoryReturnService(db, inventoryReturnRepository, inventoryReturnLineRepository, inventoryIssueLineRepository, productRepository)
|
||||
inventoryMovementServ := inventoryMovementService.NewInventoryMovementService(db, inventoryMovementRepository, inventoryMovementLineRepository)
|
||||
|
||||
// Controller
|
||||
do.Provide(
|
||||
|
|
@ -264,4 +272,9 @@ func RegisterDependencies(injector *do.Injector) {
|
|||
return inventoryReturnController.NewInventoryReturnController(i, inventoryReturnServ), nil
|
||||
},
|
||||
)
|
||||
do.Provide(
|
||||
injector, func(i *do.Injector) (inventoryMovementController.InventoryMovementController, error) {
|
||||
return inventoryMovementController.NewInventoryMovementController(i, inventoryMovementServ), nil
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue