From 14eccfb3366cba7d1d0a70e5cbb7a1fc7bd1c1bc Mon Sep 17 00:00:00 2001 From: Habib Fatkhul Rohman Date: Mon, 24 Nov 2025 14:57:41 +0700 Subject: [PATCH] feat: update status field validation in inventory DTOs and add completed constant --- .../dto/inventory_issue_dto.go | 2 +- .../dto/inventory_movement_dto.go | 2 +- .../dto/inventory_receipt_dto.go | 4 +- .../dto/inventory_request_dto.go | 14 +- modules/product/dto/product_dto.go | 151 ++++++++++++++++- modules/product/service/product_service.go | 152 +----------------- pkg/constants/common.go | 1 + 7 files changed, 163 insertions(+), 163 deletions(-) diff --git a/modules/inventory_issue/dto/inventory_issue_dto.go b/modules/inventory_issue/dto/inventory_issue_dto.go index 051c023..a921c7d 100644 --- a/modules/inventory_issue/dto/inventory_issue_dto.go +++ b/modules/inventory_issue/dto/inventory_issue_dto.go @@ -26,7 +26,7 @@ type InventoryIssueCreateRequest struct { IssuerBy string `json:"issuer_by"` InvRequestID string `json:"inv_request_id"` ClientID string `json:"client_id" binding:"required"` - Status string `json:"status" binding:"required"` + Status string `json:"status"` IssueLines []InventoryIssueLineCreateRequest `json:"issue_lines,omitempty" binding:"dive"` } diff --git a/modules/inventory_movement/dto/inventory_movement_dto.go b/modules/inventory_movement/dto/inventory_movement_dto.go index 46f938b..99138d1 100644 --- a/modules/inventory_movement/dto/inventory_movement_dto.go +++ b/modules/inventory_movement/dto/inventory_movement_dto.go @@ -29,7 +29,7 @@ type InventoryMovementCreateRequest struct { MovementDate string `json:"movement_date"` MovementType string `json:"movement_type"` ClientID string `json:"client_id" binding:"required"` - Status string `json:"status" binding:"required"` + Status string `json:"status"` SourceLocationID string `json:"source_location_id"` DestinationLocationID string `json:"destination_location_id"` MovementLines []InventoryMovementLineCreateRequest `json:"movement_lines,omitempty" binding:"dive"` diff --git a/modules/inventory_receipt/dto/inventory_receipt_dto.go b/modules/inventory_receipt/dto/inventory_receipt_dto.go index 893582c..81b1ae3 100644 --- a/modules/inventory_receipt/dto/inventory_receipt_dto.go +++ b/modules/inventory_receipt/dto/inventory_receipt_dto.go @@ -26,8 +26,8 @@ type InventoryReceiptCreateRequest struct { Source string `json:"source"` QrCodeFile string `json:"qr_code_file"` ClientID string `json:"client_id" binding:"required"` - Status string `json:"status" binding:"required"` - ReceiptLines []InventoryReceiptLineCreateRequest `json:"inventory_lines,omitempty" binding:"dive"` + Status string `json:"status"` + ReceiptLines []InventoryReceiptLineCreateRequest `json:"receipt_lines,omitempty" binding:"dive"` } type InventoryReceiptLineCreateRequest struct { diff --git a/modules/inventory_request/dto/inventory_request_dto.go b/modules/inventory_request/dto/inventory_request_dto.go index 5825de7..537c155 100644 --- a/modules/inventory_request/dto/inventory_request_dto.go +++ b/modules/inventory_request/dto/inventory_request_dto.go @@ -21,14 +21,14 @@ const ( ) type InventoryRequestCreateRequest struct { - ReferenceNumber string `json:"reference_number"` + ReferenceNumber string `json:"reference_number"` // DocumentNumber string `json:"document_number"` - DueDate string `json:"due_date"` - RequestType string `json:"request_type"` - Note string `json:"note"` - ClientID string `json:"client_id" binding:"required"` - Status string `json:"status" binding:"required"` - RequestLines []InventoryRequestLineCreateRequest `json:"request_lines,omitempty" binding:"dive"` + DueDate string `json:"due_date"` + RequestType string `json:"request_type"` + Note string `json:"note"` + ClientID string `json:"client_id" binding:"required"` + Status string `json:"status"` + RequestLines []InventoryRequestLineCreateRequest `json:"request_lines,omitempty" binding:"dive"` } type InventoryRequestLineCreateRequest struct { diff --git a/modules/product/dto/product_dto.go b/modules/product/dto/product_dto.go index bbb4f36..250eb09 100644 --- a/modules/product/dto/product_dto.go +++ b/modules/product/dto/product_dto.go @@ -3,7 +3,11 @@ package dto import ( "errors" + "github.com/Caknoooo/go-gin-clean-starter/database/entities" + "github.com/Caknoooo/go-gin-clean-starter/pkg/constants" pkgdto "github.com/Caknoooo/go-gin-clean-starter/pkg/dto" + "github.com/Caknoooo/go-gin-clean-starter/pkg/utils" + "github.com/google/uuid" ) const ( @@ -33,7 +37,7 @@ var ( type ( ProductCreateRequest struct { - Name string `json:"name" binding:"required"` + Name string `json:"name" binding:"required"` // RefNumber string `json:"ref_number" binding:"required"` SKU string `json:"sku" binding:"required"` Description string `json:"description"` @@ -68,7 +72,7 @@ type ( } ProductUpdateRequest struct { - Name *string `json:"name"` + Name *string `json:"name"` // RefNumber *string `json:"ref_number"` SKU *string `json:"sku"` Description *string `json:"description"` @@ -164,3 +168,146 @@ type ( InvMoveRef string `json:"inv_move_ref,omitempty"` } ) + +func MapProductToResponse(product entities.MProductEntity) ProductResponse { + crossRefs := make([]ProductVendorResponse, 0, len(product.CrossReferences)) + for _, v := range product.CrossReferences { + crossRefs = append(crossRefs, ProductVendorResponse{ + ID: v.Vendor.ID.String(), + Name: v.Vendor.Name, + Address: v.Vendor.Address, + ContactPerson: v.Vendor.ContactPerson, + SearchKey: v.Vendor.SearchKey, + }) + } + + invTransactions := make([]ProductInventoryTransactionResponse, 0, len(product.InventoryTransactions)) + for _, it := range product.InventoryTransactions { + var transactionQuantity float64 + var lot, locater, invReceiptRef, invIssueRef, invMoveRef string + var transactionDate string + valid := false + + // Receipt + if it.InvReceipt.ID != uuid.Nil && it.InvReceipt.Status == constants.COMPLETED { + invReceiptRef = it.InvReceipt.ReferenceNumber + transactionDate = utils.DateTimeToString(it.TransactionDate) + for _, line := range it.InvReceipt.ReceiptLines { + if line.ProductID == it.ProductID { + transactionQuantity = line.Quantity + lot = line.BatchNumber + valid = true + break + } + } + } + + // Issue + if it.InvIssue.ID != uuid.Nil && it.InvIssue.Status == constants.COMPLETED { + invIssueRef = it.InvIssue.DocumentNumber + transactionDate = utils.DateTimeToString(it.TransactionDate) + for _, line := range it.InvIssue.IssueLines { + if line.ProductID == it.ProductID { + transactionQuantity = line.IssuedQuantity + valid = true + break + } + } + } + + // Move + if it.InvMove.ID != uuid.Nil && it.InvMove.Status == constants.COMPLETED { + invMoveRef = it.InvMove.MovementNumber + transactionDate = utils.DateTimeToString(it.TransactionDate) + for _, line := range it.InvMove.MovementLines { + if line.ProductID == it.ProductID { + transactionQuantity = line.MovedQuantity + valid = true + break + } + } + } + + if valid { + invTransactions = append(invTransactions, ProductInventoryTransactionResponse{ + ID: it.ID.String(), + TransactionDate: transactionDate, + TransactionType: it.TransactionType, + TransactionQuantity: transactionQuantity, + Lot: lot, + Locater: locater, + InvReceiptRef: invReceiptRef, + InvIssueRef: invIssueRef, + InvMoveRef: invMoveRef, + }) + } + } + + return ProductResponse{ + ID: product.ID.String(), + Name: product.Name, + RefNumber: product.RefNumber, + SKU: product.SKU, + Description: product.Description, + Status: product.Status, + IsReturnable: product.IsReturnable, + DimLength: product.DimLength, + DimWidth: product.DimWidth, + DimHeight: product.DimHeight, + Weight: product.Weight, + Volume: product.Volume, + MaxStackHeight: product.MaxStackHeight, + Temperature: product.Temperature, + IsHazardous: product.IsHazardous, + MinStock: product.MinStock, + MaxStock: product.MaxStock, + ReplenishType: product.ReplenishType, + CycleCount: product.CycleCount, + LotRules: product.LotRules, + LeadTime: product.LeadTime, + MultiplyRate: product.MultiplyRate, + DivideRate: product.DivideRate, + Client: pkgdto.IdNameResponse{ + ID: product.Client.ID.String(), + Name: product.Client.Name, + }, + Category: pkgdto.IdNameResponse{ + ID: product.Category.ID.String(), + Name: product.Category.Name, + }, + Uom: pkgdto.IdNameResponse{ + ID: product.Uom.ID.String(), + Name: product.Uom.Name, + }, + DimUom: pkgdto.IdNameResponse{ + ID: product.DimUom.ID.String(), + Name: product.DimUom.Name, + }, + WeightUom: pkgdto.IdNameResponse{ + ID: product.WeightUom.ID.String(), + Name: product.WeightUom.Name, + }, + VolumeUom: pkgdto.IdNameResponse{ + ID: product.VolumeUom.ID.String(), + Name: product.VolumeUom.Name, + }, + MinStockUom: pkgdto.IdNameResponse{ + ID: product.MinStockUom.ID.String(), + Name: product.MinStockUom.Name, + }, + MaxStockUom: pkgdto.IdNameResponse{ + ID: product.MaxStockUom.ID.String(), + Name: product.MaxStockUom.Name, + }, + LeadTimeUom: pkgdto.IdNameResponse{ + ID: product.LeadTimeUom.ID.String(), + Name: product.LeadTimeUom.Name, + }, + UomToUom: pkgdto.IdNameResponse{ + ID: product.UomToUom.ID.String(), + Name: product.UomToUom.Name, + }, + CrossReferences: crossRefs, + InvTransactions: invTransactions, + } +} diff --git a/modules/product/service/product_service.go b/modules/product/service/product_service.go index 704fa1a..a41cde4 100644 --- a/modules/product/service/product_service.go +++ b/modules/product/service/product_service.go @@ -7,10 +7,7 @@ import ( "github.com/Caknoooo/go-gin-clean-starter/modules/product/dto" "github.com/Caknoooo/go-gin-clean-starter/modules/product/query" "github.com/Caknoooo/go-gin-clean-starter/modules/product/repository" - pkgdto "github.com/Caknoooo/go-gin-clean-starter/pkg/dto" - "github.com/Caknoooo/go-gin-clean-starter/pkg/utils" "github.com/google/uuid" - "github.com/sirupsen/logrus" "gorm.io/gorm" ) @@ -148,7 +145,7 @@ func (s *productService) GetById(ctx context.Context, productId string) (dto.Pro if err != nil { return dto.ProductResponse{}, err } - return mapProductToResponse(product), nil + return dto.MapProductToResponse(product), nil } func (s *productService) GetAll(ctx context.Context, filter query.ProductFilter) ([]dto.ProductResponse, int64, error) { @@ -158,7 +155,7 @@ func (s *productService) GetAll(ctx context.Context, filter query.ProductFilter) } var responses []dto.ProductResponse for _, p := range products { - responses = append(responses, mapProductToResponse(p)) + responses = append(responses, dto.MapProductToResponse(p)) } if len(responses) == 0 { responses = []dto.ProductResponse{} // <-- pastikan slice kosong, bukan nil @@ -322,148 +319,3 @@ func parseUUID(id string) uuid.UUID { } return u } - -func mapProductToResponse(product entities.MProductEntity) dto.ProductResponse { - crossRefs := make([]dto.ProductVendorResponse, 0, len(product.CrossReferences)) - for _, v := range product.CrossReferences { - crossRefs = append(crossRefs, dto.ProductVendorResponse{ - ID: v.Vendor.ID.String(), - Name: v.Vendor.Name, - Address: v.Vendor.Address, - ContactPerson: v.Vendor.ContactPerson, - SearchKey: v.Vendor.SearchKey, - }) - } - - logrus.Infof("Inventory Transactions Count: %d", len(product.InventoryTransactions)) - invTransactions := make([]dto.ProductInventoryTransactionResponse, 0, len(product.InventoryTransactions)) - for _, it := range product.InventoryTransactions { - var transactionQuantity float64 - var lot, locater, invReceiptRef, invIssueRef, invMoveRef string - var transactionDate string - - // Receipt - if it.InvReceipt.ID != uuid.Nil { - invReceiptRef = it.InvReceipt.ReferenceNumber - transactionDate = utils.DateTimeToString(it.TransactionDate) - // Cari line yang sesuai product - for _, line := range it.InvReceipt.ReceiptLines { - if line.ProductID == it.ProductID { - transactionQuantity = line.Quantity - lot = line.BatchNumber - // Jika ada field lokasi, isi di sini - // locater = line.Locater - break - } - } - } - - // Issue - if it.InvIssue.ID != uuid.Nil { - invIssueRef = it.InvIssue.DocumentNumber - transactionDate = utils.DateTimeToString(it.TransactionDate) - for _, line := range it.InvIssue.IssueLines { - if line.ProductID == it.ProductID { - transactionQuantity = line.IssuedQuantity - // lot = line.BatchNumber - // locater = line.Locater - break - } - } - } - - // Move - if it.InvMove.ID != uuid.Nil { - invMoveRef = it.InvMove.MovementNumber - transactionDate = utils.DateTimeToString(it.TransactionDate) - for _, line := range it.InvMove.MovementLines { - if line.ProductID == it.ProductID { - transactionQuantity = line.MovedQuantity - // lot = line.BatchNumber - // locater = line.Locater - break - } - } - } - - invTransactions = append(invTransactions, dto.ProductInventoryTransactionResponse{ - ID: it.ID.String(), - TransactionDate: transactionDate, - TransactionType: it.TransactionType, - TransactionQuantity: transactionQuantity, - Lot: lot, - Locater: locater, - InvReceiptRef: invReceiptRef, - InvIssueRef: invIssueRef, - InvMoveRef: invMoveRef, - }) - } - - return dto.ProductResponse{ - ID: product.ID.String(), - Name: product.Name, - RefNumber: product.RefNumber, - SKU: product.SKU, - Description: product.Description, - Status: product.Status, - IsReturnable: product.IsReturnable, - DimLength: product.DimLength, - DimWidth: product.DimWidth, - DimHeight: product.DimHeight, - Weight: product.Weight, - Volume: product.Volume, - MaxStackHeight: product.MaxStackHeight, - Temperature: product.Temperature, - IsHazardous: product.IsHazardous, - MinStock: product.MinStock, - MaxStock: product.MaxStock, - ReplenishType: product.ReplenishType, - CycleCount: product.CycleCount, - LotRules: product.LotRules, - LeadTime: product.LeadTime, - MultiplyRate: product.MultiplyRate, - DivideRate: product.DivideRate, - Client: pkgdto.IdNameResponse{ - ID: product.Client.ID.String(), - Name: product.Client.Name, - }, - Category: pkgdto.IdNameResponse{ - ID: product.Category.ID.String(), - Name: product.Category.Name, - }, - Uom: pkgdto.IdNameResponse{ - ID: product.Uom.ID.String(), - Name: product.Uom.Name, - }, - DimUom: pkgdto.IdNameResponse{ - ID: product.DimUom.ID.String(), - Name: product.DimUom.Name, - }, - WeightUom: pkgdto.IdNameResponse{ - ID: product.WeightUom.ID.String(), - Name: product.WeightUom.Name, - }, - VolumeUom: pkgdto.IdNameResponse{ - ID: product.VolumeUom.ID.String(), - Name: product.VolumeUom.Name, - }, - MinStockUom: pkgdto.IdNameResponse{ - ID: product.MinStockUom.ID.String(), - Name: product.MinStockUom.Name, - }, - MaxStockUom: pkgdto.IdNameResponse{ - ID: product.MaxStockUom.ID.String(), - Name: product.MaxStockUom.Name, - }, - LeadTimeUom: pkgdto.IdNameResponse{ - ID: product.LeadTimeUom.ID.String(), - Name: product.LeadTimeUom.Name, - }, - UomToUom: pkgdto.IdNameResponse{ - ID: product.UomToUom.ID.String(), - Name: product.UomToUom.Name, - }, - CrossReferences: crossRefs, - InvTransactions: invTransactions, - } -} diff --git a/pkg/constants/common.go b/pkg/constants/common.go index 4fca7a5..43f8286 100644 --- a/pkg/constants/common.go +++ b/pkg/constants/common.go @@ -14,4 +14,5 @@ const ( JWTService = "JWTService" LOGGER = "logger" SUPERADMIN = "superadmin" + COMPLETED = "completed" )