diff --git a/internal/modules/closings/controllers/closing.controller.go b/internal/modules/closings/controllers/closing.controller.go index ecbded41..7b294d1e 100644 --- a/internal/modules/closings/controllers/closing.controller.go +++ b/internal/modules/closings/controllers/closing.controller.go @@ -40,7 +40,7 @@ func (u *ClosingController) GetAll(c *fiber.Ctx) error { } return c.Status(fiber.StatusOK). - JSON(response.SuccessWithPaginate[dto.ClosingSummaryDTO]{ + JSON(response.SuccessWithPaginate[dto.ClosingListItemDTO]{ Code: fiber.StatusOK, Status: "success", Message: "Retrieved closing projects list successfully", @@ -152,25 +152,17 @@ func (u *ClosingController) GetClosingSapronak(c *fiber.Ctx) error { return err } - resp := struct { - Code int `json:"code"` - Status string `json:"status"` - Message string `json:"message"` - Meta response.Meta `json:"meta"` - Data interface{} `json:"data"` - }{ - Code: fiber.StatusOK, - Status: "success", - Message: "Retrieved closing report (sapronak) successfully", - Meta: response.Meta{ - Page: query.Page, - Limit: query.Limit, - TotalPages: int64(math.Ceil(float64(totalResults) / float64(query.Limit))), - TotalResults: totalResults, - }, - Data: result, - } - return c.Status(fiber.StatusOK). - JSON(resp) + JSON(response.SuccessWithPaginate[dto.ClosingSapronakItemDTO]{ + Code: fiber.StatusOK, + Status: "success", + Message: "Retrieved closing report (sapronak) successfully", + Meta: response.Meta{ + Page: query.Page, + Limit: query.Limit, + TotalPages: int64(math.Ceil(float64(totalResults) / float64(query.Limit))), + TotalResults: totalResults, + }, + Data: result, + }) } diff --git a/internal/modules/closings/dto/closing.dto.go b/internal/modules/closings/dto/closing.dto.go index 22654549..1f1cb492 100644 --- a/internal/modules/closings/dto/closing.dto.go +++ b/internal/modules/closings/dto/closing.dto.go @@ -27,6 +27,21 @@ type ClosingDetailDTO struct { ClosingListDTO } +type ClosingListItemDTO struct { + Id uint `json:"id"` + LocationID uint `json:"location_id"` + LocationName string `json:"location_name"` + ProjectCategory string `json:"project_category"` + Period int `json:"period"` + ClosingDate string `json:"closing_date"` + ShedLabel string `json:"shed_label"` + ShedCount int `json:"shed_count"` + SalesPaidAmount int64 `json:"sales_paid_amount"` + SalesRemainingAmount int64 `json:"sales_remaining_amount"` + SalesPaymentStatus string `json:"sales_payment_status"` + ProjectStatus string `json:"project_status"` +} + type ClosingSummaryDTO struct { FlockID uint `json:"flock_id"` Period int `json:"period"` @@ -68,6 +83,25 @@ func ToClosingSummaryDTO(project entity.ProjectFlock, statusProject, statusClosi } } +func ToClosingListItemDTO(project entity.ProjectFlock, projectStatus string) ClosingListItemDTO { + shedCount := len(project.KandangHistory) + + return ClosingListItemDTO{ + Id: project.Id, + LocationID: project.LocationId, + LocationName: project.Location.Name, + ProjectCategory: project.Category, + Period: maxPeriod(project.KandangHistory), + ClosingDate: "17-Nov-2025", + ShedLabel: fmt.Sprintf("%d Kandang", shedCount), + ShedCount: shedCount, + SalesPaidAmount: 21993726, + SalesRemainingAmount: 11075919, + SalesPaymentStatus: "Lunas", + ProjectStatus: projectStatus, + } +} + func maxPeriod(history []entity.ProjectFlockKandang) int { max := 0 for _, h := range history { diff --git a/internal/modules/closings/dto/sapronak.dto.go b/internal/modules/closings/dto/sapronak.dto.go index b83cb02d..50fc67cc 100644 --- a/internal/modules/closings/dto/sapronak.dto.go +++ b/internal/modules/closings/dto/sapronak.dto.go @@ -3,21 +3,21 @@ package dto import "time" type ClosingSapronakItemDTO struct { - Id uint64 `json:"id"` - Date string `json:"date"` - ReferenceNumber string `json:"reference_number"` - TransactionType string `json:"transaction_type"` - ProductName string `json:"product_name"` - ProductCategory string `json:"product_category"` - ProductSubCategory string `json:"product_sub_category"` - SourceWarehouse string `json:"source_warehouse"` - DestinationWarehouse string `json:"destination_warehouse,omitempty"` - Destination string `json:"destination,omitempty"` - Quantity float64 `json:"quantity"` - Unit string `json:"unit"` - FormattedQuantity string `json:"formatted_quantity"` - Notes string `json:"notes"` - SortDate time.Time `json:"-"` + Id uint64 `json:"id"` + Date string `json:"date"` + ReferenceNumber string `json:"reference_number"` + TransactionType string `json:"transaction_type"` + ProductName string `json:"product_name"` + ProductCategory string `json:"product_category"` + ProductSubCategory string `json:"product_sub_category"` + SourceWarehouse string `json:"source_warehouse"` + DestinationWarehouse string `json:"destination_warehouse,omitempty"` + // Destination string `json:"destination,omitempty"` + Quantity float64 `json:"quantity"` + Unit string `json:"unit"` + FormattedQuantity string `json:"formatted_quantity"` + Notes string `json:"notes"` + SortDate time.Time `json:"-"` } type ClosingSapronakDTO struct { diff --git a/internal/modules/closings/repositories/closing.repository.go b/internal/modules/closings/repositories/closing.repository.go index c81180b4..fe555378 100644 --- a/internal/modules/closings/repositories/closing.repository.go +++ b/internal/modules/closings/repositories/closing.repository.go @@ -112,7 +112,11 @@ SELECT 'Purchase' AS transaction_type, prod.name AS product_name, pc.name AS product_category, - pc.name AS product_sub_category, + COALESCE(( + SELECT string_agg(f.name, ' ') + FROM flags f + WHERE f.flagable_type = 'products' AND f.flagable_id = prod.id + ), '') AS product_sub_category, 'External Supplier' AS source_warehouse, w.name AS destination_warehouse, '' AS destination, @@ -137,7 +141,11 @@ SELECT 'Internal Transfer In' AS transaction_type, prod.name AS product_name, pc.name AS product_category, - pc.name AS product_sub_category, + COALESCE(( + SELECT string_agg(f.name, ' ') + FROM flags f + WHERE f.flagable_type = 'products' AND f.flagable_id = prod.id + ), '') AS product_sub_category, COALESCE(fw.name, '') AS source_warehouse, COALESCE(tw.name, '') AS destination_warehouse, '' AS destination, @@ -163,7 +171,11 @@ SELECT 'Internal Transfer Out' AS transaction_type, prod.name AS product_name, pc.name AS product_category, - pc.name AS product_sub_category, + COALESCE(( + SELECT string_agg(f.name, ' ') + FROM flags f + WHERE f.flagable_type = 'products' AND f.flagable_id = prod.id + ), '') AS product_sub_category, COALESCE(fw.name, '') AS source_warehouse, '' AS destination_warehouse, COALESCE(tw.name, '') AS destination, @@ -189,7 +201,11 @@ SELECT 'Trading Sales' AS transaction_type, prod.name AS product_name, pc.name AS product_category, - pc.name AS product_sub_category, + COALESCE(( + SELECT string_agg(f.name, ' ') + FROM flags f + WHERE f.flagable_type = 'products' AND f.flagable_id = prod.id + ), '') AS product_sub_category, w.name AS source_warehouse, '' AS destination_warehouse, 'RETAIL CUSTOMER' AS destination, diff --git a/internal/modules/closings/route.go b/internal/modules/closings/route.go index f04c14c4..8634df29 100644 --- a/internal/modules/closings/route.go +++ b/internal/modules/closings/route.go @@ -12,7 +12,7 @@ import ( func ClosingRoutes(v1 fiber.Router, u user.UserService, s closing.ClosingService) { ctrl := controller.NewClosingController(s) - route := v1.Group("/closing") + route := v1.Group("/closings") // route.Get("/", m.Auth(u), ctrl.GetAll) // route.Post("/", m.Auth(u), ctrl.CreateOne) diff --git a/internal/modules/closings/services/closing.service.go b/internal/modules/closings/services/closing.service.go index d59d2339..6640a6bd 100644 --- a/internal/modules/closings/services/closing.service.go +++ b/internal/modules/closings/services/closing.service.go @@ -23,11 +23,11 @@ import ( ) type ClosingService interface { - GetAll(ctx *fiber.Ctx, params *validation.Query) ([]dto.ClosingSummaryDTO, int64, error) + GetAll(ctx *fiber.Ctx, params *validation.Query) ([]dto.ClosingListItemDTO, int64, error) GetProjectFlockByID(ctx *fiber.Ctx, id uint) (*entity.ProjectFlock, error) GetPenjualan(ctx *fiber.Ctx, projectFlockID uint) ([]entity.MarketingDeliveryProduct, error) GetClosingSummary(ctx *fiber.Ctx, projectFlockID uint) (*dto.ClosingSummaryDTO, error) - GetClosingSapronak(ctx *fiber.Ctx, projectFlockID uint, params *validation.SapronakQuery) (*dto.ClosingSapronakDTO, int64, error) + GetClosingSapronak(ctx *fiber.Ctx, projectFlockID uint, params *validation.SapronakQuery) ([]dto.ClosingSapronakItemDTO, int64, error) } type closingService struct { @@ -58,11 +58,12 @@ func (s closingService) withRelations(db *gorm.DB) *gorm.DB { func (s closingService) withClosingRelations(db *gorm.DB) *gorm.DB { return s.withRelations(db). + Preload("Location"). Preload("KandangHistory"). Preload("KandangHistory.Chickins") } -func (s closingService) GetAll(c *fiber.Ctx, params *validation.Query) ([]dto.ClosingSummaryDTO, int64, error) { +func (s closingService) GetAll(c *fiber.Ctx, params *validation.Query) ([]dto.ClosingListItemDTO, int64, error) { if err := s.Validate.Struct(params); err != nil { return nil, 0, err } @@ -82,15 +83,15 @@ func (s closingService) GetAll(c *fiber.Ctx, params *validation.Query) ([]dto.Cl return nil, 0, err } - result := make([]dto.ClosingSummaryDTO, 0, len(closings)) + result := make([]dto.ClosingListItemDTO, 0, len(closings)) for _, closing := range closings { - statusProject, statusClosing, err := s.getApprovalStatuses(c.Context(), closing.Id) + statusProject, _, err := s.getApprovalStatuses(c.Context(), closing.Id) if err != nil { s.Log.Errorf("Failed to retrieve approval statuses for project flock %d: %+v", closing.Id, err) return nil, 0, fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch approval status") } - result = append(result, dto.ToClosingSummaryDTO(closing, statusProject, statusClosing)) + result = append(result, dto.ToClosingListItemDTO(closing, statusProject)) } return result, total, nil @@ -158,7 +159,7 @@ func (s closingService) GetClosingSummary(c *fiber.Ctx, projectFlockID uint) (*d return &summary, nil } -func (s closingService) GetClosingSapronak(c *fiber.Ctx, projectFlockID uint, params *validation.SapronakQuery) (*dto.ClosingSapronakDTO, int64, error) { +func (s closingService) GetClosingSapronak(c *fiber.Ctx, projectFlockID uint, params *validation.SapronakQuery) ([]dto.ClosingSapronakItemDTO, int64, error) { if projectFlockID == 0 { return nil, 0, fiber.NewError(fiber.StatusBadRequest, "Invalid project flock id") } @@ -234,27 +235,16 @@ func (s closingService) GetClosingSapronak(c *fiber.Ctx, projectFlockID uint, pa ProductSubCategory: row.ProductSubCategory, SourceWarehouse: row.SourceWarehouse, DestinationWarehouse: row.DestinationWarehouse, - Destination: row.Destination, - Quantity: row.Quantity, - Unit: row.Unit, - FormattedQuantity: formatQuantity(row.Quantity, row.Unit), - Notes: row.Notes, - SortDate: row.SortDate, + // Destination: row.Destination, + Quantity: row.Quantity, + Unit: row.Unit, + FormattedQuantity: formatQuantity(row.Quantity, row.Unit), + Notes: row.Notes, + SortDate: row.SortDate, }) } - result := dto.ClosingSapronakDTO{ - IncomingSapronak: []dto.ClosingSapronakItemDTO{}, - OutgoingSapronak: []dto.ClosingSapronakItemDTO{}, - } - - if params.Type == validation.SapronakTypeIncoming { - result.IncomingSapronak = items - } else { - result.OutgoingSapronak = items - } - - return &result, totalResults, nil + return items, totalResults, nil } func (s closingService) getWarehouseIDsByProjectFlock(ctx context.Context, projectFlockID uint) ([]uint, error) {