fixing report-counting-sapronak

This commit is contained in:
ragilap
2025-12-16 10:44:19 +07:00
parent f60564d673
commit cf7b3418a5
12 changed files with 593 additions and 589 deletions
+145 -4
View File
@@ -1,6 +1,9 @@
package dto
import "time"
import (
"strings"
"time"
)
type SapronakDetailDTO struct {
ProductID uint `json:"product_id"`
@@ -82,9 +85,10 @@ type SapronakCategoryDTO struct {
}
type SapronakProjectAggregatedDTO struct {
Doc *SapronakCategoryDTO `json:"doc,omitempty"`
Ovk *SapronakCategoryDTO `json:"ovk,omitempty"`
Pakan *SapronakCategoryDTO `json:"pakan,omitempty"`
Doc *SapronakCategoryDTO `json:"doc,omitempty"`
Ovk *SapronakCategoryDTO `json:"ovk,omitempty"`
Pakan *SapronakCategoryDTO `json:"pakan,omitempty"`
Pullet *SapronakCategoryDTO `json:"pullet,omitempty"`
}
type ClosingSapronakItemDTO struct {
@@ -109,3 +113,140 @@ type ClosingSapronakDTO struct {
IncomingSapronak []ClosingSapronakItemDTO `json:"incoming_sapronak"`
OutgoingSapronak []ClosingSapronakItemDTO `json:"outgoing_sapronak"`
}
// === Mapper Functions for Aggregated Sapronak Response ===
func ToSapronakProjectAggregatedFromReports(reports []SapronakReportDTO, flag string) SapronakProjectAggregatedDTO {
result := SapronakProjectAggregatedDTO{}
if len(reports) == 0 {
return result
}
rep := reports[0]
return ToSapronakProjectAggregatedFromReport(&rep, flag)
}
func ToSapronakProjectAggregatedFromReport(report *SapronakReportDTO, flag string) SapronakProjectAggregatedDTO {
result := SapronakProjectAggregatedDTO{}
if report == nil {
report = &SapronakReportDTO{}
}
filter := strings.ToUpper(strings.TrimSpace(flag))
byFlag := map[string]**SapronakCategoryDTO{}
if filter == "" || filter == "DOC" {
result.Doc = &SapronakCategoryDTO{Rows: make([]SapronakCategoryRowDTO, 0)}
byFlag["DOC"] = &result.Doc
}
if filter == "" || filter == "OVK" {
result.Ovk = &SapronakCategoryDTO{Rows: make([]SapronakCategoryRowDTO, 0)}
byFlag["OVK"] = &result.Ovk
}
if filter == "" || filter == "PAKAN" {
result.Pakan = &SapronakCategoryDTO{Rows: make([]SapronakCategoryRowDTO, 0)}
byFlag["PAKAN"] = &result.Pakan
}
if filter == "" || filter == "PULLET" {
result.Pullet = &SapronakCategoryDTO{Rows: make([]SapronakCategoryRowDTO, 0)}
byFlag["PULLET"] = &result.Pullet
}
formatDate := func(t *time.Time) string {
if t == nil {
return ""
}
return t.Format("02-Jan-2006")
}
for _, group := range report.Groups {
flagKey := strings.ToUpper(group.Flag)
ptr := byFlag[flagKey]
if ptr == nil || *ptr == nil {
continue
}
target := *ptr
rowIndexByProduct := make(map[string]int)
getOrCreateRow := func(productKey string, base SapronakCategoryRowDTO) *SapronakCategoryRowDTO {
if idx, ok := rowIndexByProduct[productKey]; ok {
return &target.Rows[idx]
}
target.Rows = append(target.Rows, base)
idx := len(target.Rows) - 1
rowIndexByProduct[productKey] = idx
return &target.Rows[idx]
}
for idx, item := range group.Items {
productKey := strings.ToUpper(group.Flag + "|" + item.ProductName)
baseRow := SapronakCategoryRowDTO{
ID: idx + 1,
Date: formatDate(item.Tanggal),
ReferenceNumber: item.NoReferensi,
Description: item.ProductName,
ProductCategory: item.ProductName,
UnitPrice: item.Harga,
Notes: "-",
}
row := getOrCreateRow(productKey, baseRow)
switch strings.ToLower(item.JenisTransaksi) {
case "pembelian", "adjustment masuk", "mutasi masuk":
row.QtyIn += item.QtyMasuk
row.TotalAmount += item.Nilai
case "pemakaian", "adjustment keluar":
row.QtyUsed += item.QtyKeluar
case "mutasi keluar":
row.QtyOut += item.QtyKeluar
default:
row.QtyIn += item.QtyMasuk
row.TotalAmount += item.Nilai
}
if row.QtyIn > 0 {
row.UnitPrice = row.TotalAmount / row.QtyIn
}
}
for i := range target.Rows {
target.Rows[i].ID = i + 1
}
}
buildTotals := func(cat *SapronakCategoryDTO, label string) {
if cat == nil {
return
}
var qtyIn, qtyOut, qtyUsed, total float64
for _, r := range cat.Rows {
qtyIn += r.QtyIn
qtyOut += r.QtyOut
qtyUsed += r.QtyUsed
total += r.TotalAmount
}
avg := 0.0
if qtyIn > 0 {
avg = total / qtyIn
}
cat.Total = SapronakCategoryTotalDTO{
Label: label,
QtyIn: qtyIn,
QtyOut: qtyOut,
QtyUsed: qtyUsed,
AvgUnitPrice: avg,
TotalAmount: total,
}
}
buildTotals(result.Doc, "TOTAL DOC")
buildTotals(result.Ovk, "TOTAL OVK")
buildTotals(result.Pakan, "TOTAL PAKAN")
buildTotals(result.Pullet, "TOTAL PULLET")
return result
}