Files
lti-api/internal/modules/purchases/controllers/purchase.export_test.go
T
2026-05-21 11:48:24 +07:00

214 lines
5.7 KiB
Go

package controller
import (
"bytes"
"testing"
"time"
entity "gitlab.com/mbugroup/lti-api.git/internal/entities"
"github.com/xuri/excelize/v2"
)
func TestBuildPurchaseExportWorkbookHeadersAndRows(t *testing.T) {
content, err := buildPurchaseExportWorkbook([]entity.Purchase{
buildPurchaseForExportTest(
1,
"PR-00011",
"PO-00011",
time.Date(2026, time.April, 22, 0, 0, 0, 0, time.UTC),
"Supplier A",
"Manager Purchase",
nil,
"catatan",
[]entity.PurchaseItem{
buildPurchaseItemForExportTest(11, "Pakan Starter", 500, 2, 1000000, "Location A", "kg"),
buildPurchaseItemForExportTest(12, "Vitamin A", 350, 1, 350000, "Location B", "botol"),
},
),
buildPurchaseForExportTest(
2,
"PR-00012",
"",
time.Time{},
"Supplier B",
"Manager Purchase",
ptrApprovalAction(entity.ApprovalActionRejected),
"",
[]entity.PurchaseItem{
buildPurchaseItemForExportTest(21, "Obat X", 75000, 1, 75000, "", ""),
},
),
})
if err != nil {
t.Fatalf("buildPurchaseExportWorkbook returned error: %v", err)
}
file, err := excelize.OpenReader(bytes.NewReader(content))
if err != nil {
t.Fatalf("failed to open workbook bytes: %v", err)
}
defer file.Close()
// Verify all 19 headers
expectedHeaders := map[string]string{
"A1": "PR Number",
"B1": "PO Number",
"C1": "Tanggal PO",
"D1": "Tanggal Terima",
"E1": "Supplier",
"F1": "Lokasi",
"G1": "Gudang",
"H1": "Product",
"I1": "Qty",
"J1": "Satuan",
"K1": "Price",
"L1": "Total Produk",
"M1": "Vendor Ekspedisi",
"N1": "Qty Ekspedisi",
"O1": "Price Ekspedisi",
"P1": "Total Ekspedisi",
"Q1": "Grand Total All",
"R1": "Status",
"S1": "Notes",
}
for cell, expected := range expectedHeaders {
got, err := file.GetCellValue(purchaseExportSheetName, cell)
if err != nil {
t.Fatalf("GetCellValue(%s) failed: %v", cell, err)
}
if got != expected {
t.Fatalf("expected %s=%q, got %q", cell, expected, got)
}
}
// Row 2: Purchase 1, Item 1 (Pakan Starter)
assertPurchaseCellEquals(t, file, "A2", "PR-00011")
assertPurchaseCellEquals(t, file, "B2", "PO-00011")
assertPurchaseCellEquals(t, file, "C2", "22-04-2026")
assertPurchaseCellEquals(t, file, "E2", "Supplier A")
assertPurchaseCellEquals(t, file, "F2", "Location A")
assertPurchaseCellEquals(t, file, "H2", "Pakan Starter")
assertPurchaseCellEquals(t, file, "J2", "kg")
assertPurchaseCellEquals(t, file, "K2", "500")
assertPurchaseCellEquals(t, file, "L2", "1000000")
assertPurchaseCellEquals(t, file, "M2", "-")
assertPurchaseCellEquals(t, file, "P2", "0")
assertPurchaseCellEquals(t, file, "Q2", "1000000")
assertPurchaseCellEquals(t, file, "R2", "Manager Purchase")
assertPurchaseCellEquals(t, file, "S2", "catatan")
// Row 3: Purchase 1, Item 2 (Vitamin A)
assertPurchaseCellEquals(t, file, "A3", "PR-00011")
assertPurchaseCellEquals(t, file, "H3", "Vitamin A")
assertPurchaseCellEquals(t, file, "J3", "botol")
assertPurchaseCellEquals(t, file, "L3", "350000")
assertPurchaseCellEquals(t, file, "Q3", "350000")
// Row 4: Purchase 2, Item 1 (Obat X) — no location, rejected
assertPurchaseCellEquals(t, file, "A4", "PR-00012")
assertPurchaseCellEquals(t, file, "B4", "-")
assertPurchaseCellEquals(t, file, "C4", "-")
assertPurchaseCellEquals(t, file, "F4", "-")
assertPurchaseCellEquals(t, file, "H4", "Obat X")
assertPurchaseCellEquals(t, file, "J4", "-")
assertPurchaseCellEquals(t, file, "L4", "75000")
assertPurchaseCellEquals(t, file, "Q4", "75000")
assertPurchaseCellEquals(t, file, "R4", "Ditolak")
assertPurchaseCellEquals(t, file, "S4", "-")
// Row 5: SUM row — total produk=1425000, ekspedisi=0, grand total all=1425000
assertPurchaseCellEquals(t, file, "A5", "TOTAL")
assertPurchaseCellEquals(t, file, "L5", "1425000")
assertPurchaseCellEquals(t, file, "P5", "0")
assertPurchaseCellEquals(t, file, "Q5", "1425000")
}
func assertPurchaseCellEquals(t *testing.T, file *excelize.File, cell, expected string) {
t.Helper()
got, err := file.GetCellValue(purchaseExportSheetName, cell)
if err != nil {
t.Fatalf("GetCellValue(%s) failed: %v", cell, err)
}
if got != expected {
t.Fatalf("expected %s=%q, got %q", cell, expected, got)
}
}
func buildPurchaseForExportTest(
id uint,
prNumber, poNumber string,
poDate time.Time,
supplierName, stepName string,
action *entity.ApprovalAction,
notes string,
items []entity.PurchaseItem,
) entity.Purchase {
var poNumberRef *string
if poNumber != "" {
poNumberRef = &poNumber
}
var poDateRef *time.Time
if !poDate.IsZero() {
poDateRef = &poDate
}
var notesRef *string
if notes != "" {
notesRef = &notes
}
return entity.Purchase{
Id: id,
PrNumber: prNumber,
PoNumber: poNumberRef,
PoDate: poDateRef,
Notes: notesRef,
Supplier: entity.Supplier{
Id: id + 100,
Name: supplierName,
},
LatestApproval: &entity.Approval{
Id: id + 1000,
StepName: stepName,
Action: action,
},
Items: items,
}
}
func buildPurchaseItemForExportTest(productID uint, productName string, price, totalQty, totalPrice float64, locationName, uomName string) entity.PurchaseItem {
uomID := uint(0)
if uomName != "" {
uomID = productID + 2000
}
item := entity.PurchaseItem{
ProductId: productID,
Price: price,
TotalQty: totalQty,
TotalPrice: totalPrice,
Product: &entity.Product{
Id: productID,
Name: productName,
Uom: entity.Uom{Id: uomID, Name: uomName},
},
}
if locationName != "" {
locationID := productID + 1000
warehouseID := productID + 500
item.Warehouse = &entity.Warehouse{
Id: warehouseID,
Location: &entity.Location{
Id: locationID,
Name: locationName,
},
}
}
return item
}
func ptrApprovalAction(value entity.ApprovalAction) *entity.ApprovalAction {
return &value
}