package dto import ( "encoding/json" "time" entity "gitlab.com/mbugroup/lti-api.git/internal/entities" approvalDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/approvals/dto" locationDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/locations/dto" nonstockDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/nonstocks/dto" supplierDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/suppliers/dto" userDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/users/dto" ) // === DTO Structs === type ExpenseRelationDTO struct { Id uint64 `json:"id"` PoNumber string `json:"po_number"` ExpenseDate time.Time `json:"expense_date"` GrandTotal float64 `json:"grand_total"` } type ExpenseBaseDTO struct { Id uint64 `json:"id"` ReferenceNumber string `json:"reference_number"` PoNumber string `json:"po_number"` Category string `json:"category"` Supplier *supplierDTO.SupplierRelationDTO `json:"supplier,omitempty"` RealizationDate *time.Time `json:"realization_date,omitempty"` ExpenseDate time.Time `json:"expense_date"` GrandTotal float64 `json:"grand_total"` Location *locationDTO.LocationRelationDTO `json:"location,omitempty"` } type ExpenseListDTO struct { ExpenseBaseDTO CreatedUser *userDTO.UserRelationDTO `json:"created_user,omitempty"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` LatestApproval *approvalDTO.ApprovalRelationDTO `json:"latest_approval,omitempty"` } type ExpenseDetailDTO struct { ExpenseBaseDTO Documents []DocumentDTO `json:"documents,omitempty"` RealizationDocs []DocumentDTO `json:"realization_docs,omitempty"` Kandangs []KandangGroupDTO `json:"kandangs,omitempty"` TotalPengajuan float64 `json:"total_pengajuan"` TotalRealisasi float64 `json:"total_realisasi"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` CreatedUser *userDTO.UserRelationDTO `json:"created_user,omitempty"` LatestApproval *approvalDTO.ApprovalRelationDTO `json:"latest_approval,omitempty"` } type ExpenseNonstockDTO struct { Id uint64 `json:"id"` Qty float64 `json:"qty"` UnitPrice float64 `json:"unit_price"` TotalPrice float64 `json:"total_price"` Note *string `json:"note,omitempty"` Nonstock *nonstockDTO.NonstockRelationDTO `json:"nonstock,omitempty"` } type ExpenseRealizationDTO struct { Id uint64 `json:"id"` Qty float64 `json:"qty"` UnitPrice float64 `json:"unit_price"` TotalPrice float64 `json:"total_price"` Note *string `json:"note,omitempty"` Nonstock *nonstockDTO.NonstockRelationDTO `json:"nonstock,omitempty"` } type KandangGroupDTO struct { Id uint64 `json:"id"` KandangId uint64 `json:"kandang_id"` Name string `json:"name,omitempty"` Pengajuans []ExpenseNonstockDTO `json:"pengajuans,omitempty"` Realisasi []ExpenseRealizationDTO `json:"realisasi,omitempty"` } type DocumentDTO struct { ID uint64 `json:"id"` Path string `json:"path"` } // === MAPPERS === func ToExpenseRelationDTO(e entity.Expense) ExpenseRelationDTO { return ExpenseRelationDTO{ Id: e.Id, PoNumber: e.PoNumber, ExpenseDate: e.ExpenseDate, GrandTotal: e.GrandTotal, } } func ToExpenseBaseDTO(e *entity.Expense) ExpenseBaseDTO { var location *locationDTO.LocationRelationDTO var supplier *supplierDTO.SupplierRelationDTO var realizationDate *time.Time if !e.RealizationDate.IsZero() { realizationDate = &e.RealizationDate } if len(e.Nonstocks) > 0 && e.Nonstocks[0].Kandang != nil { if e.Nonstocks[0].Kandang.Location.Id != 0 { mapped := locationDTO.ToLocationRelationDTO(e.Nonstocks[0].Kandang.Location) location = &mapped } } if e.Supplier != nil && e.Supplier.Id != 0 { mapped := supplierDTO.ToSupplierRelationDTO(*e.Supplier) supplier = &mapped } return ExpenseBaseDTO{ Id: e.Id, ReferenceNumber: e.ReferenceNumber, PoNumber: e.PoNumber, Category: e.Category, Supplier: supplier, RealizationDate: realizationDate, ExpenseDate: e.ExpenseDate, GrandTotal: e.GrandTotal, Location: location, } } func ToExpenseListDTO(e entity.Expense) ExpenseListDTO { var createdUser *userDTO.UserRelationDTO if e.CreatedUser.Id != 0 { mapped := userDTO.ToUserRelationDTO(*e.CreatedUser) createdUser = &mapped } var latestApproval *approvalDTO.ApprovalRelationDTO if e.LatestApproval != nil { mapped := approvalDTO.ToApprovalDTO(*e.LatestApproval) latestApproval = &mapped } return ExpenseListDTO{ ExpenseBaseDTO: ToExpenseBaseDTO(&e), CreatedUser: createdUser, CreatedAt: e.CreatedAt, UpdatedAt: e.UpdatedAt, LatestApproval: latestApproval, } } func ToExpenseListDTOs(expenses []entity.Expense) []ExpenseListDTO { result := make([]ExpenseListDTO, len(expenses)) for i, expense := range expenses { result[i] = ToExpenseListDTO(expense) } return result } func ToExpenseDetailDTO(e *entity.Expense) ExpenseDetailDTO { var documents []DocumentDTO var realizationDocs []DocumentDTO var createdUser *userDTO.UserRelationDTO if e.CreatedUser != nil && e.CreatedUser.Id != 0 { mapped := userDTO.ToUserRelationDTO(*e.CreatedUser) createdUser = &mapped } var latestApproval *approvalDTO.ApprovalRelationDTO if e.LatestApproval != nil { mapped := approvalDTO.ToApprovalDTO(*e.LatestApproval) latestApproval = &mapped } var pengajuans []ExpenseNonstockDTO var realisasi []ExpenseRealizationDTO if e.DocumentPath.Valid && e.DocumentPath.String != "" { json.Unmarshal([]byte(e.DocumentPath.String), &documents) } if e.RealizationDocumentPath.Valid && e.RealizationDocumentPath.String != "" { json.Unmarshal([]byte(e.RealizationDocumentPath.String), &realizationDocs) } if len(e.Nonstocks) > 0 { pengajuans = make([]ExpenseNonstockDTO, 0) realisasi = make([]ExpenseRealizationDTO, 0) for _, ns := range e.Nonstocks { pengajuanDTO := ToExpenseNonstockDTO(ns) pengajuans = append(pengajuans, pengajuanDTO) if ns.Realization != nil && ns.Realization.Id != 0 { var nonstock *nonstockDTO.NonstockRelationDTO if ns.Nonstock != nil && ns.Nonstock.Id != 0 { mapped := nonstockDTO.ToNonstockRelationDTO(*ns.Nonstock) nonstock = &mapped } realisasiDTO := ExpenseRealizationDTO{ Id: ns.Realization.Id, Qty: ns.Realization.RealizationQty, UnitPrice: ns.Realization.RealizationUnitPrice, TotalPrice: ns.Realization.RealizationTotalPrice, Note: ns.Realization.Note, Nonstock: nonstock, } realisasi = append(realisasi, realisasiDTO) } } } var totalPengajuan float64 for _, p := range pengajuans { totalPengajuan += p.TotalPrice } var totalRealisasi float64 for _, r := range realisasi { totalRealisasi += r.TotalPrice } kandangs := ToKandangGroupDTO(pengajuans, realisasi, e.Nonstocks) return ExpenseDetailDTO{ ExpenseBaseDTO: ToExpenseBaseDTO(e), Documents: documents, RealizationDocs: realizationDocs, CreatedUser: createdUser, Kandangs: kandangs, TotalPengajuan: totalPengajuan, TotalRealisasi: totalRealisasi, CreatedAt: e.CreatedAt, UpdatedAt: e.UpdatedAt, LatestApproval: latestApproval, } } func ToExpenseNonstockDTO(ns entity.ExpenseNonstock) ExpenseNonstockDTO { var nonstock *nonstockDTO.NonstockRelationDTO if ns.Nonstock != nil && ns.Nonstock.Id != 0 { mapped := nonstockDTO.ToNonstockRelationDTO(*ns.Nonstock) nonstock = &mapped } return ExpenseNonstockDTO{ Id: ns.Id, Qty: ns.Qty, UnitPrice: ns.UnitPrice, TotalPrice: ns.TotalPrice, Note: &ns.Note, Nonstock: nonstock, } } func ToKandangGroupDTO(pengajuans []ExpenseNonstockDTO, realisasi []ExpenseRealizationDTO, nonstocks []entity.ExpenseNonstock) []KandangGroupDTO { kandangMap := make(map[uint64]*KandangGroupDTO) for _, p := range pengajuans { var kandangId uint64 var kandangName string for _, ns := range nonstocks { if ns.Id == p.Id && ns.Kandang != nil { kandangId = uint64(ns.Kandang.Id) kandangName = ns.Kandang.Name break } } if kandangId > 0 { if kandangMap[kandangId] == nil { kandangMap[kandangId] = &KandangGroupDTO{ Id: kandangId, KandangId: kandangId, Name: kandangName, Pengajuans: []ExpenseNonstockDTO{}, Realisasi: []ExpenseRealizationDTO{}, } } kandangMap[kandangId].Pengajuans = append(kandangMap[kandangId].Pengajuans, p) } } for _, r := range realisasi { var kandangId uint64 var kandangName string for _, ns := range nonstocks { if ns.Realization != nil && ns.Realization.Id == r.Id && ns.Kandang != nil { kandangId = uint64(ns.Kandang.Id) kandangName = ns.Kandang.Name break } } if kandangId > 0 { if kandangMap[kandangId] == nil { kandangMap[kandangId] = &KandangGroupDTO{ Id: kandangId, KandangId: kandangId, Name: kandangName, Pengajuans: []ExpenseNonstockDTO{}, Realisasi: []ExpenseRealizationDTO{}, } } kandangMap[kandangId].Realisasi = append(kandangMap[kandangId].Realisasi, r) } } var kandangs []KandangGroupDTO for _, k := range kandangMap { kandangs = append(kandangs, *k) } return kandangs }