add feed use at export excel recording

This commit is contained in:
giovanni
2026-05-07 10:56:30 +07:00
parent 81b9e88bb6
commit 90ed035abd
3 changed files with 100 additions and 23 deletions
@@ -77,6 +77,10 @@ func setRecordingExportColumns(file *excelize.File, sheet string) error {
"Z": 22,
"AA": 16,
"AB": 18,
"AC": 24,
"AD": 18,
"AE": 18,
"AF": 18,
}
for col, width := range columnWidths {
@@ -96,7 +100,7 @@ func setRecordingExportColumns(file *excelize.File, sheet string) error {
}
func setRecordingExportHeaders(file *excelize.File, sheet string) error {
verticalHeaderCols := []string{"A", "B", "C", "D", "E", "F", "G", "H", "I", "Y", "Z", "AA", "AB"}
verticalHeaderCols := []string{"A", "B", "C", "D", "E", "F", "G", "H", "I", "Y", "Z", "AA", "AB", "AC", "AD", "AE", "AF"}
for _, col := range verticalHeaderCols {
if err := file.MergeCell(sheet, col+"1", col+"2"); err != nil {
return err
@@ -104,19 +108,23 @@ func setRecordingExportHeaders(file *excelize.File, sheet string) error {
}
headerValues := map[string]string{
"A1": "No",
"B1": "Lokasi",
"C1": "Flock",
"D1": "Kandang",
"E1": "Periode",
"F1": "Kategori",
"G1": "Umur (hari)",
"H1": "Waktu Recording",
"I1": "Populasi Akhir",
"Y1": "Status Approval",
"Z1": "Catatan Approval",
"AA1": "Dibuat Oleh",
"AB1": "Tanggal Submit",
"A1": "No",
"B1": "Lokasi",
"C1": "Flock",
"D1": "Kandang",
"E1": "Periode",
"F1": "Kategori",
"G1": "Umur (hari)",
"H1": "Waktu Recording",
"I1": "Populasi Akhir",
"Y1": "Status Approval",
"Z1": "Catatan Approval",
"AA1": "Dibuat Oleh",
"AB1": "Tanggal Submit",
"AC1": "Nama Pakan",
"AD1": "Jumlah Input Pakan",
"AE1": "Jumlah Penggunaan",
"AF1": "Pending Qty",
}
for cell, value := range headerValues {
if err := file.SetCellValue(sheet, cell, value); err != nil {
@@ -230,7 +238,7 @@ func setRecordingExportHeaders(file *excelize.File, sheet string) error {
return err
}
return file.SetCellStyle(sheet, "A1", "AB2", headerStyle)
return file.SetCellStyle(sheet, "A1", "AF2", headerStyle)
}
func setRecordingExportRows(file *excelize.File, sheet string, items []dto.RecordingListDTO) error {
@@ -241,6 +249,7 @@ func setRecordingExportRows(file *excelize.File, sheet string, items []dto.Recor
columns := []string{
"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N",
"O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "AA", "AB",
"AC", "AD", "AE", "AF",
}
for i, item := range items {
@@ -283,6 +292,29 @@ func setRecordingExportRows(file *excelize.File, sheet string, items []dto.Recor
createdBy = safeExportText(item.Approval.ActionBy.Name)
}
// Build feed usage columns — concatenate multiple feeds with newline
feedNames := make([]string, 0, len(item.FeedUsage))
usageAmounts := make([]string, 0, len(item.FeedUsage))
pendingQtys := make([]string, 0, len(item.FeedUsage))
inputQtys := make([]string, 0, len(item.FeedUsage))
for _, fu := range item.FeedUsage {
feedNames = append(feedNames, safeExportText(fu.ProductName))
usageAmounts = append(usageAmounts, formatNumberID(fu.UsageAmount, 2, true))
pendingQtys = append(pendingQtys, formatNumberID(fu.PendingQty, 2, true))
inputQtys = append(inputQtys, formatNumberID(fu.UsageAmount+fu.PendingQty, 2, true))
}
feedNameCol := "-"
usageCol := "-"
pendingCol := "-"
inputCol := "-"
if len(feedNames) > 0 {
feedNameCol = strings.Join(feedNames, "\n")
usageCol = strings.Join(usageAmounts, "\n")
pendingCol = strings.Join(pendingQtys, "\n")
inputCol = strings.Join(inputQtys, "\n")
}
rowValues := []interface{}{
i + 1,
locationName,
@@ -312,6 +344,10 @@ func setRecordingExportRows(file *excelize.File, sheet string, items []dto.Recor
safeExportText(pointerString(item.Approval.Notes)),
createdBy,
formatDateIndonesian(item.CreatedAt),
feedNameCol, // AC
inputCol, // AD - Jumlah Input Pakan
usageCol, // AE - Jumlah Penggunaan
pendingCol, // AF - Pending Qty
}
for idx, col := range columns {
@@ -339,7 +375,7 @@ func setRecordingExportRows(file *excelize.File, sheet string, items []dto.Recor
if err != nil {
return err
}
if err := file.SetCellStyle(sheet, "A3", fmt.Sprintf("AB%d", lastRow), dataCenterStyle); err != nil {
if err := file.SetCellStyle(sheet, "A3", fmt.Sprintf("AF%d", lastRow), dataCenterStyle); err != nil {
return err
}
@@ -360,7 +396,7 @@ func setRecordingExportRows(file *excelize.File, sheet string, items []dto.Recor
return err
}
leftColumns := []string{"B", "C", "D", "F", "G", "H", "Y", "Z", "AA", "AB"}
leftColumns := []string{"B", "C", "D", "F", "G", "H", "Y", "Z", "AA", "AB", "AC"}
for _, col := range leftColumns {
if err := file.SetCellStyle(sheet, col+"3", fmt.Sprintf("%s%d", col, lastRow), dataLeftStyle); err != nil {
return err
@@ -92,13 +92,20 @@ type RecordingRelationDTO struct {
Approval approvalDTO.ApprovalRelationDTO `json:"approval"`
}
type RecordingFeedUsageDTO struct {
ProductName string `json:"product_name"`
UsageAmount float64 `json:"usage_amount"`
PendingQty float64 `json:"pending_qty"`
}
type RecordingListDTO struct {
RecordingRelationDTO
CreatedUser *userDTO.UserRelationDTO `json:"created_user,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
Kandang *RecordingKandangDTO `json:"kandang,omitempty"`
Location *RecordingLocationDTO `json:"location,omitempty"`
CreatedUser *userDTO.UserRelationDTO `json:"created_user,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
Kandang *RecordingKandangDTO `json:"kandang,omitempty"`
Location *RecordingLocationDTO `json:"location,omitempty"`
FeedUsage []RecordingFeedUsageDTO `json:"feed_usage,omitempty"`
}
type RecordingDetailDTO struct {
@@ -192,6 +199,36 @@ func ToRecordingStockDTOs(stocks []entity.RecordingStock) []RecordingStockDTO {
return result
}
func ToRecordingFeedUsageDTOs(stocks []entity.RecordingStock) []RecordingFeedUsageDTO {
return toRecordingFeedUsageDTOs(stocks)
}
func toRecordingFeedUsageDTOs(stocks []entity.RecordingStock) []RecordingFeedUsageDTO {
result := make([]RecordingFeedUsageDTO, 0, len(stocks))
for _, s := range stocks {
productName := ""
if s.ProductWarehouse.Product.Id != 0 {
productName = s.ProductWarehouse.Product.Name
}
var usageAmount float64
if s.UsageQty != nil {
usageAmount = *s.UsageQty
}
var pendingQty float64
if s.PendingQty != nil {
pendingQty = *s.PendingQty
}
result = append(result, RecordingFeedUsageDTO{
ProductName: productName,
UsageAmount: usageAmount,
PendingQty: pendingQty,
})
}
return result
}
func ToRecordingEggDTOs(eggs []entity.RecordingEgg) []RecordingEggDTO {
result := make([]RecordingEggDTO, len(eggs))
for i, egg := range eggs {
@@ -222,6 +259,7 @@ func toRecordingListDTO(e entity.Recording) RecordingListDTO {
CreatedUser: createdUser,
Kandang: recordingKandangDTO(e),
Location: recordingKandangLocationDTO(e),
FeedUsage: toRecordingFeedUsageDTOs(e.Stocks),
}
}
@@ -147,7 +147,10 @@ func (r *RecordingRepositoryImpl) WithRelationsList(db *gorm.DB) *gorm.DB {
Preload("ProjectFlockKandang.Kandang").
Preload("ProjectFlockKandang.Kandang.Location").
Preload("ProjectFlockKandang.ProjectFlock").
Preload("ProjectFlockKandang.ProjectFlock.ProductionStandard")
Preload("ProjectFlockKandang.ProjectFlock.ProductionStandard").
Preload("Stocks").
Preload("Stocks.ProductWarehouse").
Preload("Stocks.ProductWarehouse.Product")
}
func (r *RecordingRepositoryImpl) latestApprovalSubQuery(db *gorm.DB) *gorm.DB {