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 ( MESSAGE_FAILED_CREATE_PRODUCT = "failed create product" MESSAGE_SUCCESS_CREATE_PRODUCT = "success create product" MESSAGE_FAILED_GET_PRODUCT = "failed get product" MESSAGE_SUCCESS_GET_PRODUCT = "success get product" MESSAGE_FAILED_UPDATE_PRODUCT = "failed update product" MESSAGE_SUCCESS_UPDATE_PRODUCT = "success update product" MESSAGE_FAILED_DELETE_PRODUCT = "failed delete product" MESSAGE_SUCCESS_DELETE_PRODUCT = "success delete product" MESSAGE_FAILED_GET_DATA_FROM_BODY = "failed get data from body" MESSAGE_FAILED_ASSIGN_CROSS_REF = "failed assign cross reference" MESSAGE_SUCCESS_ASSIGN_CROSS_REF = "success assign cross reference" MESSAGE_FAILED_REMOVE_CROSS_REF = "failed remove cross reference" MESSAGE_SUCCESS_REMOVE_CROSS_REF = "success remove cross reference" MESSAGE_FAILED_GET_INV_STORAGES = "failed get inventory storages by product and client" MESSAGE_SUCCESS_GET_INV_STORAGES = "success get inventory storages by product and client" MESSAGE_FAILED_GET_INV_TRANSACTIONS = "failed get inventory transactions by product and client" MESSAGE_SUCCESS_GET_INV_TRANSACTIONS = "success get inventory transactions by product and client" MESSAGE_SUCCESS_GET_CROSS_REFERENCES = "success get cross references by product and client" MESSAGE_FAILED_GET_CROSS_REFERENCES = "failed get cross references by product and client" ) var ( ErrCreateProduct = errors.New("failed to create product") ErrGetProductById = errors.New("failed to get product by id") ErrUpdateProduct = errors.New("failed to update product") ErrDeleteProduct = errors.New("failed to delete product") ErrAssignCrossRef = errors.New("failed to assign cross reference") ErrRemoveCrossRef = errors.New("failed to remove cross reference") ) type ( ProductCreateRequest struct { Name string `json:"name" binding:"required"` // RefNumber string `json:"ref_number" binding:"required"` SKU string `json:"sku" binding:"required"` Description string `json:"description"` Status string `json:"status" binding:"required"` IsReturnable bool `json:"is_returnable"` // DimLength float64 `json:"dim_length"` // DimWidth float64 `json:"dim_width"` // DimHeight float64 `json:"dim_height"` // Weight float64 `json:"weight"` // Volume float64 `json:"volume"` // MaxStackHeight int `json:"max_stack_height"` // Temperature string `json:"temperature"` // IsHazardous bool `json:"is_hazardous"` // MinStock int `json:"min_stock"` // MaxStock int `json:"max_stock"` // ReplenishType string `json:"replenish_type"` // CycleCount string `json:"cycle_count"` // LotRules string `json:"lot_rules"` // LeadTime int `json:"lead_time"` // MultiplyRate string `json:"multiply_rate"` // DivideRate float64 `json:"divide_rate"` ClientID string `json:"client_id" binding:"required"` CategoryID *string `json:"category_id"` UomID *string `json:"uom_id"` // DimUomID string `json:"dim_uom_id"` // WeightUomID string `json:"weight_uom_id"` // VolumeUomID string `json:"volume_uom_id"` // MinStockUomID string `json:"min_stock_uom_id"` // MaxStockUomID string `json:"max_stock_uom_id"` // LeadTimeUomID string `json:"lead_time_uom_id"` // UomToUomID string `json:"uom_to_uom_id"` } ProductUpdateRequest struct { Name *string `json:"name"` // RefNumber *string `json:"ref_number"` SKU *string `json:"sku"` Description *string `json:"description"` Status *string `json:"status"` IsReturnable *bool `json:"is_returnable"` DimLength *float64 `json:"dim_length"` DimWidth *float64 `json:"dim_width"` DimHeight *float64 `json:"dim_height"` Weight *float64 `json:"weight"` Volume *float64 `json:"volume"` MaxStackHeight *int `json:"max_stack_height"` Temperature *string `json:"temperature"` IsHazardous *bool `json:"is_hazardous"` MinStock *int `json:"min_stock"` MaxStock *int `json:"max_stock"` ReplenishType *string `json:"replenish_type"` CycleCount *string `json:"cycle_count"` LotRules *string `json:"lot_rules"` LeadTime *int `json:"lead_time"` MultiplyRate *string `json:"multiply_rate"` DivideRate *float64 `json:"divide_rate"` ClientID *string `json:"client_id"` CategoryID *string `json:"category_id"` UomID *string `json:"uom_id"` DimUomID *string `json:"dim_uom_id"` WeightUomID *string `json:"weight_uom_id"` VolumeUomID *string `json:"volume_uom_id"` MinStockUomID *string `json:"min_stock_uom_id"` MaxStockUomID *string `json:"max_stock_uom_id"` LeadTimeUomID *string `json:"lead_time_uom_id"` UomToUomID *string `json:"uom_to_uom_id"` } ProductResponse struct { ID string `json:"id"` Name string `json:"name"` RefNumber string `json:"ref_number"` SKU string `json:"sku"` Description string `json:"description"` Status string `json:"status"` IsReturnable bool `json:"is_returnable"` DimLength float64 `json:"dim_length"` DimWidth float64 `json:"dim_width"` DimHeight float64 `json:"dim_height"` Weight float64 `json:"weight"` Volume float64 `json:"volume"` MaxStackHeight int `json:"max_stack_height"` Temperature string `json:"temperature"` IsHazardous bool `json:"is_hazardous"` MinStock int `json:"min_stock"` MaxStock int `json:"max_stock"` ReplenishType string `json:"replenish_type"` CycleCount string `json:"cycle_count"` LotRules string `json:"lot_rules"` LeadTime int `json:"lead_time"` MultiplyRate string `json:"multiply_rate"` DivideRate float64 `json:"divide_rate"` Client pkgdto.IdNameResponse `json:"client"` Category pkgdto.IdNameResponse `json:"category"` Uom pkgdto.IdNameResponse `json:"uom"` DimUom pkgdto.IdNameResponse `json:"dim_uom"` WeightUom pkgdto.IdNameResponse `json:"weight_uom"` VolumeUom pkgdto.IdNameResponse `json:"volume_uom"` MinStockUom pkgdto.IdNameResponse `json:"min_stock_uom"` MaxStockUom pkgdto.IdNameResponse `json:"max_stock_uom"` LeadTimeUom pkgdto.IdNameResponse `json:"lead_time_uom"` UomToUom pkgdto.IdNameResponse `json:"uom_to_uom"` // CrossReferences []ProductVendorResponse `json:"cross_references"` // InvTransactions []ProductInventoryTransactionResponse `json:"inv_transactions"` // InvStorages []ProductInventoryStorageResponse `json:"inv_storages"` } CrossReferenceRequest struct { VendorIDs []string `json:"vendor_ids" binding:"required"` } ProductVendorResponse struct { ID string `json:"id"` Name string `json:"name"` SearchKey string `json:"search_key"` Address string `json:"address"` ContactPerson string `json:"contact_person"` } ProductInventoryTransactionResponse struct { ID string `json:"id"` TransactionDate string `json:"transaction_date"` TransactionType string `json:"transaction_type"` TransactionQuantity float64 `json:"transaction_quantity"` Lot string `json:"lot"` Locater string `json:"locater"` InvReceiptRef string `json:"inv_receipt_ref,omitempty"` InvIssueRef string `json:"inv_issue_ref,omitempty"` InvMoveRef string `json:"inv_move_ref,omitempty"` } ProductInventoryStorageResponse struct { ID string `json:"id"` Locater string `json:"locater"` Lot string `json:"lot"` OnHandQuantity float64 `json:"on_hand_quantity"` AvailableQuantity float64 `json:"available_quantity"` AisleID pkgdto.IdNameResponse `json:"aisle_id"` Uom pkgdto.IdNameResponse `json:"uom"` InvReceipt pkgdto.IdNameResponse `json:"inv_receipt"` InvRequest pkgdto.IdNameResponse `json:"inv_request"` } ) func MapProductToResponse(product entities.MProductEntity) ProductResponse { 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, }, } } func MapInventoryTransactionsToResponses(transactions []entities.InventoryTransactionEntity) []ProductInventoryTransactionResponse { responses := make([]ProductInventoryTransactionResponse, 0, len(transactions)) for _, t := range transactions { resp := MapInventoryTransactionToProductInventoryTransactionResponse(t) if resp.ID != "" { // hanya tambahkan jika mapping valid responses = append(responses, resp) } } return responses } func MapInventoryTransactionToProductInventoryTransactionResponse(transaction entities.InventoryTransactionEntity) ProductInventoryTransactionResponse { var transactionQuantity float64 var lot, locater, invReceiptRef, invIssueRef, invMoveRef string var transactionDate string valid := false if transaction.InvReceipt.ID != uuid.Nil && transaction.InvReceipt.Status == constants.COMPLETED { invReceiptRef = transaction.InvReceipt.ReferenceNumber transactionDate = utils.DateTimeToString(transaction.TransactionDate) for _, line := range transaction.InvReceipt.ReceiptLines { if line.ProductID == transaction.ProductID { transactionQuantity = line.Quantity lot = line.BatchNumber valid = true break } } } if transaction.InvIssue.ID != uuid.Nil && transaction.InvIssue.Status == constants.COMPLETED { invIssueRef = transaction.InvIssue.DocumentNumber transactionDate = utils.DateTimeToString(transaction.TransactionDate) for _, line := range transaction.InvIssue.IssueLines { if line.ProductID == transaction.ProductID { transactionQuantity = line.IssuedQuantity valid = true break } } } if transaction.InvMove.ID != uuid.Nil && transaction.InvMove.Status == constants.COMPLETED { invMoveRef = transaction.InvMove.MovementNumber transactionDate = utils.DateTimeToString(transaction.TransactionDate) for _, line := range transaction.InvMove.MovementLines { if line.ProductID == transaction.ProductID { transactionQuantity = line.MovedQuantity valid = true break } } } if !valid { return ProductInventoryTransactionResponse{} } return ProductInventoryTransactionResponse{ ID: transaction.ID.String(), TransactionDate: transactionDate, TransactionType: transaction.TransactionType, TransactionQuantity: transactionQuantity, Lot: lot, Locater: locater, InvReceiptRef: invReceiptRef, InvIssueRef: invIssueRef, InvMoveRef: invMoveRef, } } func MapInventoryStorageToProductInventoryStorageResponse(storage entities.InventoryStorageEntity) ProductInventoryStorageResponse { return ProductInventoryStorageResponse{ ID: storage.ID.String(), // Locater: storage.Locater, // Lot: storage.BatchNumber, OnHandQuantity: storage.OnHandQuantity, AvailableQuantity: storage.AvailableQuantity, AisleID: pkgdto.IdNameResponse{ ID: storage.Aisle.ID.String(), Name: storage.Aisle.Name, }, Uom: pkgdto.IdNameResponse{ ID: storage.Uom.ID.String(), Name: storage.Uom.Name, }, InvReceipt: pkgdto.IdNameResponse{ ID: storage.InvReceipt.ID.String(), Name: storage.InvReceipt.ReferenceNumber, }, InvRequest: pkgdto.IdNameResponse{ ID: storage.InvRequest.ID.String(), Name: storage.InvRequest.ReferenceNumber, }, } } func MapCrossReferenceToProductVendorResponse(crossRef entities.MCrossReferenceEntity) ProductVendorResponse { return ProductVendorResponse{ ID: crossRef.Vendor.ID.String(), Name: crossRef.Vendor.Name, ContactPerson: crossRef.Vendor.ContactPerson, SearchKey: crossRef.Vendor.SearchKey, Address: crossRef.Vendor.Address} }