mirror of
https://gitlab.com/mbugroup/lti-api.git
synced 2026-05-20 13:31:56 +00:00
203 lines
6.5 KiB
Go
203 lines
6.5 KiB
Go
package controller
|
|
|
|
import (
|
|
"bytes"
|
|
"io"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"reflect"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/gofiber/fiber/v2"
|
|
"github.com/xuri/excelize/v2"
|
|
"gorm.io/gorm"
|
|
|
|
approvalDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/approvals/dto"
|
|
kandangDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/kandangs/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"
|
|
"gitlab.com/mbugroup/lti-api.git/internal/modules/repports/dto"
|
|
service "gitlab.com/mbugroup/lti-api.git/internal/modules/repports/services"
|
|
validation "gitlab.com/mbugroup/lti-api.git/internal/modules/repports/validations"
|
|
)
|
|
|
|
type repportServiceStub struct {
|
|
service.RepportService
|
|
getExpenseCalls []validation.ExpenseQuery
|
|
}
|
|
|
|
func (s *repportServiceStub) GetExpense(_ *fiber.Ctx, params *validation.ExpenseQuery) ([]dto.RepportExpenseListDTO, int64, error) {
|
|
callCopy := *params
|
|
callCopy.AllowedAreaIDs = append([]int64(nil), params.AllowedAreaIDs...)
|
|
callCopy.AllowedLocationIDs = append([]int64(nil), params.AllowedLocationIDs...)
|
|
s.getExpenseCalls = append(s.getExpenseCalls, callCopy)
|
|
|
|
switch params.Page {
|
|
case 1:
|
|
return []dto.RepportExpenseListDTO{
|
|
buildExpenseListForControllerTest("REF-00001", "TRANSPORT 2"),
|
|
buildExpenseListForControllerTest("REF-00002", "TRANSPORT"),
|
|
}, 3, nil
|
|
case 2:
|
|
return []dto.RepportExpenseListDTO{
|
|
buildExpenseListForControllerTest("REF-00003", "TRANSPORT"),
|
|
}, 3, nil
|
|
default:
|
|
return []dto.RepportExpenseListDTO{}, 3, nil
|
|
}
|
|
}
|
|
|
|
func (s *repportServiceStub) DB() *gorm.DB {
|
|
return nil
|
|
}
|
|
|
|
func TestRepportControllerGetExpenseExportAllIgnoresRequestLimit(t *testing.T) {
|
|
app := fiber.New()
|
|
stub := &repportServiceStub{}
|
|
ctrl := NewRepportController(stub)
|
|
app.Get("/reports/expense", ctrl.GetExpense)
|
|
|
|
req := httptest.NewRequest(
|
|
http.MethodGet,
|
|
"/reports/expense?export=excel&type=all&page=9&limit=1&search=operasional&category=BOP&supplier_id=7&kandang_id=4&project_flock_kandang_id=2&nonstock_id=5&area_id=3&location_id=9&realization_date=2026-04-22",
|
|
nil,
|
|
)
|
|
resp, err := app.Test(req)
|
|
if err != nil {
|
|
t.Fatalf("unexpected app.Test error: %v", err)
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode != fiber.StatusOK {
|
|
t.Fatalf("expected status 200, got %d", resp.StatusCode)
|
|
}
|
|
|
|
contentType := resp.Header.Get("Content-Type")
|
|
if contentType != "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" {
|
|
t.Fatalf("unexpected content-type: %s", contentType)
|
|
}
|
|
|
|
disposition := resp.Header.Get("Content-Disposition")
|
|
if !bytes.Contains([]byte(disposition), []byte("reports_expense_all_")) {
|
|
t.Fatalf("unexpected content-disposition: %s", disposition)
|
|
}
|
|
|
|
if len(stub.getExpenseCalls) != 2 {
|
|
t.Fatalf("expected 2 GetExpense calls, got %d", len(stub.getExpenseCalls))
|
|
}
|
|
|
|
firstCall := stub.getExpenseCalls[0]
|
|
secondCall := stub.getExpenseCalls[1]
|
|
if firstCall.Page != 1 || secondCall.Page != 2 {
|
|
t.Fatalf("expected internal pages 1 and 2, got %d and %d", firstCall.Page, secondCall.Page)
|
|
}
|
|
if firstCall.Limit != expenseReportExcelExportFetchLimit || secondCall.Limit != expenseReportExcelExportFetchLimit {
|
|
t.Fatalf("expected internal limit %d, got %d and %d", expenseReportExcelExportFetchLimit, firstCall.Limit, secondCall.Limit)
|
|
}
|
|
|
|
if firstCall.Search != "operasional" ||
|
|
firstCall.Category != "BOP" ||
|
|
firstCall.SupplierId != 7 ||
|
|
firstCall.KandangId != 4 ||
|
|
firstCall.ProjectFlockKandangId != 2 ||
|
|
firstCall.NonstockId != 5 ||
|
|
firstCall.AreaId != 3 ||
|
|
firstCall.LocationId != 9 ||
|
|
firstCall.RealizationDate != "2026-04-22" {
|
|
t.Fatalf("unexpected forwarded filters: %+v", firstCall)
|
|
}
|
|
|
|
payload, err := io.ReadAll(resp.Body)
|
|
if err != nil {
|
|
t.Fatalf("failed to read excel payload: %v", err)
|
|
}
|
|
file, err := excelize.OpenReader(bytes.NewReader(payload))
|
|
if err != nil {
|
|
t.Fatalf("failed to parse excel payload: %v", err)
|
|
}
|
|
defer file.Close()
|
|
|
|
sheetList := file.GetSheetList()
|
|
expectedSheets := []string{"EKSPEDISI ADE", "EKSPEDISI LTI"}
|
|
if !reflect.DeepEqual(sheetList, expectedSheets) {
|
|
t.Fatalf("unexpected sheet list: got %v, expected %v", sheetList, expectedSheets)
|
|
}
|
|
|
|
if got, _ := file.GetCellValue("EKSPEDISI ADE", "A1"); got != "No" {
|
|
t.Fatalf("expected EKSPEDISI ADE A1 to be No, got %q", got)
|
|
}
|
|
if got, _ := file.GetCellValue("EKSPEDISI ADE", "G2"); got != "TRANSPORT 2" {
|
|
t.Fatalf("expected EKSPEDISI ADE G2 to be TRANSPORT 2, got %q", got)
|
|
}
|
|
if got, _ := file.GetCellValue("EKSPEDISI LTI", "G2"); got != "TRANSPORT" {
|
|
t.Fatalf("expected EKSPEDISI LTI G2 to be TRANSPORT, got %q", got)
|
|
}
|
|
if got, _ := file.GetCellValue("EKSPEDISI LTI", "A4"); got != "Total" {
|
|
t.Fatalf("expected EKSPEDISI LTI A4 to be Total, got %q", got)
|
|
}
|
|
}
|
|
|
|
func TestRepportControllerGetExpenseKeepsPaginationValidationForNonExportAll(t *testing.T) {
|
|
app := fiber.New()
|
|
stub := &repportServiceStub{}
|
|
ctrl := NewRepportController(stub)
|
|
app.Get("/reports/expense", ctrl.GetExpense)
|
|
|
|
req := httptest.NewRequest(http.MethodGet, "/reports/expense?page=1&limit=0", nil)
|
|
resp, err := app.Test(req)
|
|
if err != nil {
|
|
t.Fatalf("unexpected app.Test error: %v", err)
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode != fiber.StatusBadRequest {
|
|
t.Fatalf("expected status 400, got %d", resp.StatusCode)
|
|
}
|
|
}
|
|
|
|
func buildExpenseListForControllerTest(reference, product string) dto.RepportExpenseListDTO {
|
|
realizationDate := time.Date(2026, time.April, 22, 0, 0, 0, 0, time.UTC)
|
|
return dto.RepportExpenseListDTO{
|
|
RepportExpenseBaseDTO: dto.RepportExpenseBaseDTO{
|
|
ReferenceNumber: reference,
|
|
PoNumber: "PO-001",
|
|
Category: "BOP",
|
|
Notes: "catatan expense",
|
|
TransactionDate: time.Date(2026, time.April, 22, 0, 0, 0, 0, time.UTC),
|
|
RealizationDate: &realizationDate,
|
|
Supplier: &supplierDTO.SupplierRelationDTO{
|
|
Name: "Supplier A",
|
|
},
|
|
},
|
|
Kandang: &kandangDTO.KandangRelationDTO{
|
|
Name: "Kandang A",
|
|
Location: &locationDTO.LocationRelationDTO{
|
|
Name: "Darawati",
|
|
},
|
|
},
|
|
Pengajuan: dto.RepportExpensePengajuanDTO{
|
|
Qty: 1,
|
|
Price: 50000,
|
|
Notes: "catatan pengajuan",
|
|
Nonstock: &nonstockDTO.NonstockRelationDTO{
|
|
Name: product,
|
|
},
|
|
},
|
|
Realisasi: dto.RepportExpenseRealisasiDTO{
|
|
Qty: 1,
|
|
Price: 50000,
|
|
Notes: "catatan realisasi",
|
|
Nonstock: &nonstockDTO.NonstockRelationDTO{
|
|
Name: product,
|
|
},
|
|
},
|
|
TotalPengajuan: 50000,
|
|
TotalRealisasi: 50000,
|
|
LatestApproval: &approvalDTO.ApprovalRelationDTO{
|
|
StepName: "Realisasi",
|
|
},
|
|
}
|
|
}
|