mirror of
https://gitlab.com/mbugroup/lti-api.git
synced 2026-05-20 13:31:56 +00:00
fix(BE-273): add object nonstock and supplier in response get one and fix name base to relation in dto
This commit is contained in:
@@ -1,27 +0,0 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
func TestAreaIntegration(t *testing.T) {
|
||||
app, db := setupIntegrationApp(t)
|
||||
|
||||
t.Run("create area trims name", func(t *testing.T) {
|
||||
areaID := createArea(t, app, " Area Trim ")
|
||||
if got := fetchAreaName(t, db, areaID); got != "Area Trim" {
|
||||
t.Fatalf("expected trimmed name, got %q", got)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("duplicate area returns conflict", func(t *testing.T) {
|
||||
createArea(t, app, "Duplicate Area")
|
||||
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/areas", map[string]any{"name": "Duplicate Area"})
|
||||
if resp.StatusCode != fiber.StatusConflict {
|
||||
t.Fatalf("expected 409 conflict, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -1,127 +0,0 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"gitlab.com/mbugroup/lti-api.git/internal/entities"
|
||||
)
|
||||
|
||||
func TestBankIntegration(t *testing.T) {
|
||||
app, db := setupIntegrationApp(t)
|
||||
|
||||
const bankAlias = "BNI"
|
||||
const bankName = "Bank Negara Indonesia"
|
||||
const bankOwner = "John Doe"
|
||||
const bankAccountNumber = "1234567890"
|
||||
var bankID uint
|
||||
|
||||
t.Run("creating bank succeeds", func(t *testing.T) {
|
||||
bankID = createBank(t, app, bankName, bankAlias, bankAccountNumber, bankOwner)
|
||||
bank := fetchBank(t, db, bankID)
|
||||
if bank.Alias != bankAlias {
|
||||
t.Fatalf("expected alias %q, got %q", bankAlias, bank.Alias)
|
||||
}
|
||||
if bank.AccountNumber != bankAccountNumber {
|
||||
t.Fatalf("expected account number %q, got %q", bankAccountNumber, bank.AccountNumber)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("creating bank with duplicate name fails", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/banks", map[string]any{
|
||||
"name": bankName,
|
||||
"alias": "NEWALIAS",
|
||||
"owner": "Owner Name",
|
||||
"account_number": "1122334455",
|
||||
})
|
||||
if resp.StatusCode != fiber.StatusConflict {
|
||||
t.Fatalf("expected 409 when creating duplicate bank name, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("getting existing bank succeeds", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodGet, fmt.Sprintf("/api/master-data/banks/%d", bankID), nil)
|
||||
if resp.StatusCode != fiber.StatusOK {
|
||||
t.Fatalf("expected 200 when fetching bank, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
var payload struct {
|
||||
Data struct {
|
||||
Id uint `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Alias string `json:"alias"`
|
||||
AccountNumber string `json:"account_number"`
|
||||
} `json:"data"`
|
||||
}
|
||||
if err := json.Unmarshal(body, &payload); err != nil {
|
||||
t.Fatalf("failed to parse response: %v", err)
|
||||
}
|
||||
if payload.Data.Id != bankID {
|
||||
t.Fatalf("expected id %d, got %d", bankID, payload.Data.Id)
|
||||
}
|
||||
if payload.Data.Alias != bankAlias {
|
||||
t.Fatalf("expected alias %q, got %q", bankAlias, payload.Data.Alias)
|
||||
}
|
||||
if payload.Data.AccountNumber != bankAccountNumber {
|
||||
t.Fatalf("expected account number %q, got %q", bankAccountNumber, payload.Data.AccountNumber)
|
||||
}
|
||||
})
|
||||
|
||||
const updatedName = "BNI Updated"
|
||||
|
||||
t.Run("updating bank name succeeds", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodPatch, fmt.Sprintf("/api/master-data/banks/%d", bankID), map[string]any{
|
||||
"name": updatedName,
|
||||
})
|
||||
if resp.StatusCode != fiber.StatusOK {
|
||||
t.Fatalf("expected 200 when updating bank, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
var payload struct {
|
||||
Data struct {
|
||||
Name string `json:"name"`
|
||||
} `json:"data"`
|
||||
}
|
||||
if err := json.Unmarshal(body, &payload); err != nil {
|
||||
t.Fatalf("failed to parse response: %v", err)
|
||||
}
|
||||
if payload.Data.Name != updatedName {
|
||||
t.Fatalf("expected updated name %q, got %q", updatedName, payload.Data.Name)
|
||||
}
|
||||
bank := fetchBank(t, db, bankID)
|
||||
if bank.Name != updatedName {
|
||||
t.Fatalf("expected persisted name %q, got %q", updatedName, bank.Name)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("updating non existent bank returns 404", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodPatch, "/api/master-data/banks/9999", map[string]any{
|
||||
"name": "Does Not Matter",
|
||||
})
|
||||
if resp.StatusCode != fiber.StatusNotFound {
|
||||
t.Fatalf("expected 404 when updating missing bank, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("deleting bank succeeds", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodDelete, fmt.Sprintf("/api/master-data/banks/%d", bankID), nil)
|
||||
if resp.StatusCode != fiber.StatusOK {
|
||||
t.Fatalf("expected 200 when deleting bank, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
var bank entities.Bank
|
||||
if err := db.First(&bank, bankID).Error; !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
t.Fatalf("expected bank to be deleted, got error %v", err)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("deleting non existent bank returns 404", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodDelete, fmt.Sprintf("/api/master-data/banks/%d", bankID), nil)
|
||||
if resp.StatusCode != fiber.StatusNotFound {
|
||||
t.Fatalf("expected 404 when deleting missing bank, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -1,189 +0,0 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"gitlab.com/mbugroup/lti-api.git/internal/entities"
|
||||
"gitlab.com/mbugroup/lti-api.git/internal/utils"
|
||||
)
|
||||
|
||||
func TestCustomerIntegration(t *testing.T) {
|
||||
app, db := setupIntegrationApp(t)
|
||||
|
||||
t.Run("creating customer without existing pic fails", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/customers", map[string]any{
|
||||
"name": "Invalid Customer",
|
||||
"pic_id": 9999,
|
||||
"type": utils.CustomerSupplierTypeBisnis,
|
||||
"address": "Somewhere",
|
||||
"phone": "0800000000",
|
||||
"email": "Invalid@example.com",
|
||||
"account_number": "ACC-INVALID",
|
||||
})
|
||||
if resp.StatusCode != fiber.StatusNotFound {
|
||||
t.Fatalf("expected 404 when pic is missing, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("creating customer with Invalid type fails", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/customers", map[string]any{
|
||||
"name": "Invalid Type",
|
||||
"pic_id": 1,
|
||||
"type": "UNKNOWN",
|
||||
"address": "Somewhere",
|
||||
"phone": "081234567891",
|
||||
"email": "Invalid-type@example.com",
|
||||
"account_number": "ACC-INVALID-TYPE",
|
||||
})
|
||||
if resp.StatusCode != fiber.StatusBadRequest {
|
||||
t.Fatalf("expected 400 when type is Invalid, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
})
|
||||
|
||||
const customerName = "Customer Alpha"
|
||||
var customerID uint
|
||||
|
||||
t.Run("creating customer succeeds", func(t *testing.T) {
|
||||
customerID = createCustomer(t, app, customerName, 1)
|
||||
customer := fetchCustomer(t, db, customerID)
|
||||
if customer.Name != customerName {
|
||||
t.Fatalf("expected name %q, got %q", customerName, customer.Name)
|
||||
}
|
||||
if customer.PicId != 1 {
|
||||
t.Fatalf("expected pic id 1, got %d", customer.PicId)
|
||||
}
|
||||
if customer.Type != string(utils.CustomerSupplierTypeBisnis) {
|
||||
t.Fatalf("expected type %q, got %q", utils.CustomerSupplierTypeBisnis, customer.Type)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("creating customer with duplicate name fails", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/customers", map[string]any{
|
||||
"name": customerName,
|
||||
"pic_id": 1,
|
||||
"type": utils.CustomerSupplierTypeBisnis,
|
||||
"address": "Duplicate address",
|
||||
"phone": "0811111111",
|
||||
"email": "duplicate@example.com",
|
||||
"account_number": "ACC-DUP",
|
||||
})
|
||||
if resp.StatusCode != fiber.StatusConflict {
|
||||
t.Fatalf("expected 409 when creating duplicate customer, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("getting existing customer succeeds", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodGet, fmt.Sprintf("/api/master-data/customers/%d", customerID), nil)
|
||||
if resp.StatusCode != fiber.StatusOK {
|
||||
t.Fatalf("expected 200 when fetching customer, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
var payload struct {
|
||||
Data struct {
|
||||
Id uint `json:"id"`
|
||||
Name string `json:"name"`
|
||||
} `json:"data"`
|
||||
}
|
||||
if err := json.Unmarshal(body, &payload); err != nil {
|
||||
t.Fatalf("failed to parse customer response: %v", err)
|
||||
}
|
||||
if payload.Data.Id != customerID {
|
||||
t.Fatalf("expected id %d, got %d", customerID, payload.Data.Id)
|
||||
}
|
||||
if payload.Data.Name != customerName {
|
||||
t.Fatalf("expected name %q, got %q", customerName, payload.Data.Name)
|
||||
}
|
||||
})
|
||||
|
||||
const updatedName = "Customer Gamma"
|
||||
|
||||
t.Run("updating customer name succeeds", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodPatch, fmt.Sprintf("/api/master-data/customers/%d", customerID), map[string]any{
|
||||
"name": updatedName,
|
||||
})
|
||||
if resp.StatusCode != fiber.StatusOK {
|
||||
t.Fatalf("expected 200 when updating customer, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
var payload struct {
|
||||
Data struct {
|
||||
Name string `json:"name"`
|
||||
} `json:"data"`
|
||||
}
|
||||
if err := json.Unmarshal(body, &payload); err != nil {
|
||||
t.Fatalf("failed to parse update response: %v", err)
|
||||
}
|
||||
if payload.Data.Name != updatedName {
|
||||
t.Fatalf("expected updated name %q, got %q", updatedName, payload.Data.Name)
|
||||
}
|
||||
customer := fetchCustomer(t, db, customerID)
|
||||
if customer.Name != updatedName {
|
||||
t.Fatalf("expected persisted name %q, got %q", updatedName, customer.Name)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("updating customer type succeeds", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodPatch, fmt.Sprintf("/api/master-data/customers/%d", customerID), map[string]any{
|
||||
"type": utils.CustomerSupplierTypeIndividual,
|
||||
})
|
||||
if resp.StatusCode != fiber.StatusOK {
|
||||
t.Fatalf("expected 200 when updating customer type, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
customer := fetchCustomer(t, db, customerID)
|
||||
if customer.Type != string(utils.CustomerSupplierTypeIndividual) {
|
||||
t.Fatalf("expected persisted type %q, got %q", utils.CustomerSupplierTypeIndividual, customer.Type)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("updating customer with Invalid type fails", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodPatch, fmt.Sprintf("/api/master-data/customers/%d", customerID), map[string]any{
|
||||
"type": "random-type",
|
||||
})
|
||||
if resp.StatusCode != fiber.StatusBadRequest {
|
||||
t.Fatalf("expected 400 when updating with Invalid type, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
customer := fetchCustomer(t, db, customerID)
|
||||
if customer.Type != string(utils.CustomerSupplierTypeIndividual) {
|
||||
t.Fatalf("expected type to remain %q after Invalid update, got %q", utils.CustomerSupplierTypeIndividual, customer.Type)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("updating non existent customer returns 404", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodPatch, "/api/master-data/customers/9999", map[string]any{
|
||||
"name": "Does Not Matter",
|
||||
})
|
||||
if resp.StatusCode != fiber.StatusNotFound {
|
||||
t.Fatalf("expected 404 when updating missing customer, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("deleting customer succeeds", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodDelete, fmt.Sprintf("/api/master-data/customers/%d", customerID), nil)
|
||||
if resp.StatusCode != fiber.StatusOK {
|
||||
t.Fatalf("expected 200 when deleting customer, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
var customer entities.Customer
|
||||
if err := db.First(&customer, customerID).Error; !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
t.Fatalf("expected customer to be deleted, got error %v", err)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("deleting non existent customer returns 404", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodDelete, fmt.Sprintf("/api/master-data/customers/%d", customerID), nil)
|
||||
if resp.StatusCode != fiber.StatusNotFound {
|
||||
t.Fatalf("expected 404 when deleting missing customer, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("getting deleted customer returns 404", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodGet, fmt.Sprintf("/api/master-data/customers/%d", customerID), nil)
|
||||
if resp.StatusCode != fiber.StatusNotFound {
|
||||
t.Fatalf("expected 404 when fetching deleted customer, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -1,218 +0,0 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"gitlab.com/mbugroup/lti-api.git/internal/entities"
|
||||
)
|
||||
|
||||
func TestFcrIntegration(t *testing.T) {
|
||||
app, db := setupIntegrationApp(t)
|
||||
|
||||
t.Run("creating fcr without standards fails", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/fcrs", map[string]any{
|
||||
"name": "FCR Alpha",
|
||||
})
|
||||
if resp.StatusCode != fiber.StatusBadRequest {
|
||||
t.Fatalf("expected 400 when standards missing, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
})
|
||||
|
||||
initialStandards := []map[string]any{
|
||||
{
|
||||
"weight": 7.2,
|
||||
"fcr_number": 400.0,
|
||||
"mortality": 12.0,
|
||||
},
|
||||
{
|
||||
"weight": 7.4,
|
||||
"fcr_number": 410.0,
|
||||
"mortality": 11.5,
|
||||
},
|
||||
}
|
||||
|
||||
var fcrID uint
|
||||
|
||||
t.Run("creating fcr succeeds", func(t *testing.T) {
|
||||
fcrID = createFcr(t, app, "FCR Layer", initialStandards)
|
||||
fcr := fetchFcr(t, db, fcrID)
|
||||
if fcr.Name != "FCR Layer" {
|
||||
t.Fatalf("expected name FCR Layer, got %q", fcr.Name)
|
||||
}
|
||||
if len(fcr.Standards) != len(initialStandards) {
|
||||
t.Fatalf("expected %d standards, got %d", len(initialStandards), len(fcr.Standards))
|
||||
}
|
||||
if fcr.CreatedBy != 1 {
|
||||
t.Fatalf("expected created_by 1, got %d", fcr.CreatedBy)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("creating duplicate fcr name fails", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/fcrs", map[string]any{
|
||||
"name": "FCR Layer",
|
||||
"fcr_standards": initialStandards,
|
||||
})
|
||||
if resp.StatusCode != fiber.StatusConflict {
|
||||
t.Fatalf("expected 409 when creating duplicate, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("getting fcr detail succeeds", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodGet, fmt.Sprintf("/api/master-data/fcrs/%d", fcrID), nil)
|
||||
if resp.StatusCode != fiber.StatusOK {
|
||||
t.Fatalf("expected 200 when fetching fcr, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
var payload struct {
|
||||
Data struct {
|
||||
Id uint `json:"id"`
|
||||
Name string `json:"name"`
|
||||
FcrStandards []map[string]any `json:"fcr_standards"`
|
||||
} `json:"data"`
|
||||
}
|
||||
if err := json.Unmarshal(body, &payload); err != nil {
|
||||
t.Fatalf("failed to parse fcr detail: %v", err)
|
||||
}
|
||||
if payload.Data.Id != fcrID {
|
||||
t.Fatalf("expected id %d, got %d", fcrID, payload.Data.Id)
|
||||
}
|
||||
if len(payload.Data.FcrStandards) != len(initialStandards) {
|
||||
t.Fatalf("expected %d standards in response, got %d", len(initialStandards), len(payload.Data.FcrStandards))
|
||||
}
|
||||
})
|
||||
|
||||
updatedStandards := []map[string]any{
|
||||
{
|
||||
"weight": 7.2,
|
||||
"fcr_number": 395.0,
|
||||
"mortality": 10.0,
|
||||
},
|
||||
{
|
||||
"weight": 7.5,
|
||||
"fcr_number": 420.0,
|
||||
"mortality": 13.0,
|
||||
},
|
||||
}
|
||||
|
||||
t.Run("updating fcr name and standards succeeds", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodPatch, fmt.Sprintf("/api/master-data/fcrs/%d", fcrID), map[string]any{
|
||||
"name": "FCR Layer Updated",
|
||||
"fcr_standards": updatedStandards,
|
||||
})
|
||||
if resp.StatusCode != fiber.StatusOK {
|
||||
t.Fatalf("expected 200 when updating fcr, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
var payload struct {
|
||||
Data struct {
|
||||
Name string `json:"name"`
|
||||
FcrStandards []map[string]any `json:"fcr_standards"`
|
||||
} `json:"data"`
|
||||
}
|
||||
if err := json.Unmarshal(body, &payload); err != nil {
|
||||
t.Fatalf("failed to parse update response: %v", err)
|
||||
}
|
||||
if payload.Data.Name != "FCR Layer Updated" {
|
||||
t.Fatalf("expected updated name, got %q", payload.Data.Name)
|
||||
}
|
||||
if len(payload.Data.FcrStandards) != len(updatedStandards) {
|
||||
t.Fatalf("expected %d standards after update, got %d", len(updatedStandards), len(payload.Data.FcrStandards))
|
||||
}
|
||||
fcr := fetchFcr(t, db, fcrID)
|
||||
if fcr.Name != "FCR Layer Updated" {
|
||||
t.Fatalf("expected persisted name FCR Layer Updated, got %q", fcr.Name)
|
||||
}
|
||||
if len(fcr.Standards) != len(updatedStandards) {
|
||||
t.Fatalf("expected %d persisted standards, got %d", len(updatedStandards), len(fcr.Standards))
|
||||
}
|
||||
if fcr.Standards[0].FcrNumber != 395.0 {
|
||||
t.Fatalf("expected first standard fcr_number 395, got %f", fcr.Standards[0].FcrNumber)
|
||||
}
|
||||
})
|
||||
|
||||
var otherFcrID uint
|
||||
t.Run("creating another fcr for duplicate update", func(t *testing.T) {
|
||||
otherFcrID = createFcr(t, app, "FCR Grower", []map[string]any{
|
||||
{
|
||||
"weight": 8.0,
|
||||
"fcr_number": 430.0,
|
||||
"mortality": 9.0,
|
||||
},
|
||||
})
|
||||
if otherFcrID == 0 {
|
||||
t.Fatal("expected other fcr id to be non zero")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("updating fcr with duplicate name fails", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodPatch, fmt.Sprintf("/api/master-data/fcrs/%d", fcrID), map[string]any{
|
||||
"name": "FCR Grower",
|
||||
})
|
||||
if resp.StatusCode != fiber.StatusConflict {
|
||||
t.Fatalf("expected 409 when renaming to existing fcr, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
fcr := fetchFcr(t, db, fcrID)
|
||||
if fcr.Name != "FCR Layer Updated" {
|
||||
t.Fatalf("expected name unchanged after failed update, got %q", fcr.Name)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("updating fcr with invalid standards fails", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodPatch, fmt.Sprintf("/api/master-data/fcrs/%d", fcrID), map[string]any{
|
||||
"fcr_standards": []map[string]any{
|
||||
{
|
||||
"weight": -1,
|
||||
"fcr_number": 300,
|
||||
"mortality": 5,
|
||||
},
|
||||
},
|
||||
})
|
||||
if resp.StatusCode != fiber.StatusBadRequest {
|
||||
t.Fatalf("expected 400 when updating with invalid standard, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("deleting fcr succeeds", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodDelete, fmt.Sprintf("/api/master-data/fcrs/%d", fcrID), nil)
|
||||
if resp.StatusCode != fiber.StatusOK {
|
||||
t.Fatalf("expected 200 when deleting fcr, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
var fcr entities.Fcr
|
||||
if err := db.First(&fcr, fcrID).Error; !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
t.Fatalf("expected fcr to be deleted, got error %v", err)
|
||||
}
|
||||
var standardsCount int64
|
||||
if err := db.Model(&entities.FcrStandard{}).Where("fcr_id = ?", fcrID).Count(&standardsCount).Error; err != nil {
|
||||
t.Fatalf("failed counting standards: %v", err)
|
||||
}
|
||||
if standardsCount != 0 {
|
||||
t.Fatalf("expected standards removed, found %d", standardsCount)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("deleting fcr again returns 404", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodDelete, fmt.Sprintf("/api/master-data/fcrs/%d", fcrID), nil)
|
||||
if resp.StatusCode != fiber.StatusNotFound {
|
||||
t.Fatalf("expected 404 when deleting missing fcr, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("getting deleted fcr returns 404", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodGet, fmt.Sprintf("/api/master-data/fcrs/%d", fcrID), nil)
|
||||
if resp.StatusCode != fiber.StatusNotFound {
|
||||
t.Fatalf("expected 404 when fetching deleted fcr, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("cleanup other fcr", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodDelete, fmt.Sprintf("/api/master-data/fcrs/%d", otherFcrID), nil)
|
||||
if resp.StatusCode != fiber.StatusOK {
|
||||
t.Fatalf("expected 200 when deleting other fcr, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
|
||||
"gitlab.com/mbugroup/lti-api.git/internal/entities"
|
||||
"gitlab.com/mbugroup/lti-api.git/internal/utils"
|
||||
)
|
||||
|
||||
func TestKandangIntegration(t *testing.T) {
|
||||
app, db := setupIntegrationApp(t)
|
||||
areaID := createArea(t, app, "Area Kandang")
|
||||
locationID := createLocation(t, app, "Location For Kandang", "Address", areaID)
|
||||
|
||||
t.Run("create kandang success", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/kandangs", map[string]any{
|
||||
"name": "Kandang OK",
|
||||
"location_id": locationID,
|
||||
"pic_id": 1,
|
||||
})
|
||||
if resp.StatusCode != fiber.StatusCreated {
|
||||
t.Fatalf("expected 201, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
|
||||
var createResp struct {
|
||||
Data struct {
|
||||
Status string `json:"status"`
|
||||
} `json:"data"`
|
||||
}
|
||||
if err := json.Unmarshal(body, &createResp); err != nil {
|
||||
t.Fatalf("failed to parse create response: %v", err)
|
||||
}
|
||||
if createResp.Data.Status == "" {
|
||||
t.Fatalf("expected default status to be returned, got empty")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("create kandang with unknown location fails", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/kandangs", map[string]any{
|
||||
"name": "Kandang Fail",
|
||||
"status": "ACTIVE",
|
||||
"location_id": 999,
|
||||
"pic_id": 1,
|
||||
})
|
||||
if resp.StatusCode != fiber.StatusNotFound {
|
||||
t.Fatalf("expected 404, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("cannot assign project floc with existing active kandang", func(t *testing.T) {
|
||||
fcrID := createFcr(t, app, "FCR For Floc", []map[string]any{
|
||||
{"weight": 1.0, "fcr_number": 1.5, "mortality": 2.0},
|
||||
})
|
||||
flocID := createFlock(t, app, "Floc Test")
|
||||
|
||||
projectFloc := entities.ProjectFlock{
|
||||
FlockName: fmt.Sprintf("Project Flock %d", flocID),
|
||||
AreaId: areaID,
|
||||
Category: string(utils.ProjectFlockCategoryGrowing),
|
||||
FcrId: fcrID,
|
||||
LocationId: locationID,
|
||||
Period: 1,
|
||||
CreatedBy: 1,
|
||||
}
|
||||
if err := db.Create(&projectFloc).Error; err != nil {
|
||||
t.Fatalf("failed to seed project floc: %v", err)
|
||||
}
|
||||
|
||||
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/kandangs", map[string]any{
|
||||
"name": "Kandang Active 1",
|
||||
"status": "ACTIVE",
|
||||
"location_id": locationID,
|
||||
"pic_id": 1,
|
||||
"project_flock_id": projectFloc.Id,
|
||||
})
|
||||
if resp.StatusCode != fiber.StatusCreated {
|
||||
t.Fatalf("expected 201 when creating first kandang, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
|
||||
resp, body = doJSONRequest(t, app, http.MethodPost, "/api/master-data/kandangs", map[string]any{
|
||||
"name": "Kandang Active 2",
|
||||
"status": "ACTIVE",
|
||||
"location_id": locationID,
|
||||
"pic_id": 1,
|
||||
"project_flock_id": projectFloc.Id,
|
||||
})
|
||||
if resp.StatusCode != fiber.StatusConflict {
|
||||
t.Fatalf("expected 409 when creating second active kandang, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
func TestLocationIntegration(t *testing.T) {
|
||||
app, _ := setupIntegrationApp(t)
|
||||
|
||||
t.Run("creating location without existing area fails", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/locations", map[string]any{
|
||||
"name": "Loc A",
|
||||
"address": "Address",
|
||||
"area_id": 999, // non-existent
|
||||
})
|
||||
if resp.StatusCode != fiber.StatusNotFound {
|
||||
t.Fatalf("expected 404, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("creating location succeeds", func(t *testing.T) {
|
||||
areaID := createArea(t, app, "Area For Location")
|
||||
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/locations", map[string]any{
|
||||
"name": "Location OK",
|
||||
"address": "Addr",
|
||||
"area_id": areaID,
|
||||
})
|
||||
if resp.StatusCode != fiber.StatusCreated {
|
||||
t.Fatalf("expected 201, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -1,401 +0,0 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/glebarez/sqlite"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/logger"
|
||||
|
||||
"gitlab.com/mbugroup/lti-api.git/internal/entities"
|
||||
"gitlab.com/mbugroup/lti-api.git/internal/route"
|
||||
"gitlab.com/mbugroup/lti-api.git/internal/utils"
|
||||
)
|
||||
|
||||
func setupIntegrationApp(t *testing.T) (*fiber.App, *gorm.DB) {
|
||||
t.Helper()
|
||||
dir := t.TempDir()
|
||||
dsn := filepath.Join(dir, "integration.db")
|
||||
|
||||
db, err := gorm.Open(sqlite.Open(dsn), &gorm.Config{Logger: logger.Default.LogMode(logger.Silent)})
|
||||
if err != nil {
|
||||
t.Fatalf("failed to open sqlite database: %v", err)
|
||||
}
|
||||
|
||||
if err := db.Exec("PRAGMA foreign_keys = ON").Error; err != nil {
|
||||
t.Fatalf("failed to enable foreign keys: %v", err)
|
||||
}
|
||||
|
||||
if err := db.AutoMigrate(
|
||||
&entities.User{},
|
||||
&entities.Area{},
|
||||
&entities.Location{},
|
||||
&entities.Flock{},
|
||||
&entities.ProjectFlock{},
|
||||
&entities.ProjectFlockKandang{},
|
||||
&entities.Kandang{},
|
||||
&entities.Warehouse{},
|
||||
&entities.Uom{},
|
||||
&entities.Customer{},
|
||||
&entities.Supplier{},
|
||||
&entities.Flag{},
|
||||
&entities.ProductCategory{},
|
||||
&entities.Nonstock{},
|
||||
&entities.NonstockSupplier{},
|
||||
&entities.Product{},
|
||||
&entities.ProductSupplier{},
|
||||
&entities.Fcr{},
|
||||
&entities.FcrStandard{},
|
||||
&entities.Bank{},
|
||||
); err != nil {
|
||||
t.Fatalf("auto migrate failed: %v", err)
|
||||
}
|
||||
|
||||
seedUser := entities.User{
|
||||
Id: 1,
|
||||
IdUser: 1001,
|
||||
Email: "tester@example.com",
|
||||
Name: "Tester",
|
||||
CreatedAt: time.Now(),
|
||||
UpdatedAt: time.Now(),
|
||||
}
|
||||
if err := db.Create(&seedUser).Error; err != nil {
|
||||
t.Fatalf("failed to seed user: %v", err)
|
||||
}
|
||||
|
||||
app := fiber.New(fiber.Config{ErrorHandler: utils.ErrorHandler})
|
||||
route.Routes(app, db)
|
||||
return app, db
|
||||
}
|
||||
|
||||
func doJSONRequest(t *testing.T, app *fiber.App, method, path string, payload any) (*http.Response, []byte) {
|
||||
t.Helper()
|
||||
|
||||
var body io.Reader
|
||||
if payload != nil {
|
||||
buf := &bytes.Buffer{}
|
||||
if err := json.NewEncoder(buf).Encode(payload); err != nil {
|
||||
t.Fatalf("failed to encode payload: %v", err)
|
||||
}
|
||||
body = buf
|
||||
}
|
||||
|
||||
req := httptest.NewRequest(method, path, body)
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
req.Header.Set("Accept", "application/json")
|
||||
|
||||
resp, err := app.Test(req, -1)
|
||||
if err != nil {
|
||||
t.Fatalf("request failed: %v", err)
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
data, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to read response body: %v", err)
|
||||
}
|
||||
return resp, data
|
||||
}
|
||||
|
||||
func parseID(t *testing.T, body []byte) uint {
|
||||
t.Helper()
|
||||
var resp struct {
|
||||
Data struct {
|
||||
Id uint `json:"id"`
|
||||
} `json:"data"`
|
||||
}
|
||||
if err := json.Unmarshal(body, &resp); err != nil {
|
||||
t.Fatalf("failed to parse response: %v", err)
|
||||
}
|
||||
return resp.Data.Id
|
||||
}
|
||||
|
||||
func createArea(t *testing.T, app *fiber.App, name string) uint {
|
||||
t.Helper()
|
||||
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/areas", map[string]any{"name": name})
|
||||
if resp.StatusCode != fiber.StatusCreated {
|
||||
t.Fatalf("expected 201 when creating area, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
return parseID(t, body)
|
||||
}
|
||||
|
||||
func createLocation(t *testing.T, app *fiber.App, name, address string, areaID uint) uint {
|
||||
t.Helper()
|
||||
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/locations", map[string]any{
|
||||
"name": name,
|
||||
"address": address,
|
||||
"area_id": areaID,
|
||||
})
|
||||
if resp.StatusCode != fiber.StatusCreated {
|
||||
t.Fatalf("expected 201 when creating location, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
return parseID(t, body)
|
||||
}
|
||||
|
||||
func createUom(t *testing.T, app *fiber.App, name string) uint {
|
||||
t.Helper()
|
||||
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/uoms", map[string]any{"name": name})
|
||||
if resp.StatusCode != fiber.StatusCreated {
|
||||
t.Fatalf("expected 201 when creating uom, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
return parseID(t, body)
|
||||
}
|
||||
|
||||
func createKandang(t *testing.T, app *fiber.App, name string, locationID, picID uint) uint {
|
||||
t.Helper()
|
||||
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/kandangs", map[string]any{
|
||||
"name": name,
|
||||
"status": "ACTIVE",
|
||||
"location_id": locationID,
|
||||
"pic_id": picID,
|
||||
})
|
||||
if resp.StatusCode != fiber.StatusCreated {
|
||||
t.Fatalf("expected 201 when creating kandang, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
return parseID(t, body)
|
||||
}
|
||||
|
||||
func createCustomer(t *testing.T, app *fiber.App, name string, picID uint) uint {
|
||||
t.Helper()
|
||||
identifier := strings.ToLower(strings.ReplaceAll(name, " ", "_"))
|
||||
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/customers", map[string]any{
|
||||
"name": name,
|
||||
"pic_id": picID,
|
||||
"type": utils.CustomerSupplierTypeBisnis,
|
||||
"address": "Customer address",
|
||||
"phone": "081234567890",
|
||||
"email": fmt.Sprintf("%s@example.com", identifier),
|
||||
"account_number": fmt.Sprintf("ACC-%s", identifier),
|
||||
})
|
||||
if resp.StatusCode != fiber.StatusCreated {
|
||||
t.Fatalf("expected 201 when creating customer, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
return parseID(t, body)
|
||||
}
|
||||
|
||||
func fetchCustomer(t *testing.T, db *gorm.DB, id uint) entities.Customer {
|
||||
t.Helper()
|
||||
var customer entities.Customer
|
||||
if err := db.Preload("Pic").Preload("CreatedUser").First(&customer, id).Error; err != nil {
|
||||
t.Fatalf("failed to fetch customer: %v", err)
|
||||
}
|
||||
return customer
|
||||
}
|
||||
|
||||
func fetchKandang(t *testing.T, db *gorm.DB, id uint) entities.Kandang {
|
||||
t.Helper()
|
||||
var kandang entities.Kandang
|
||||
if err := db.Preload("ProjectFlock").First(&kandang, id).Error; err != nil {
|
||||
t.Fatalf("failed to fetch kandang: %v", err)
|
||||
}
|
||||
return kandang
|
||||
}
|
||||
|
||||
func createSupplier(t *testing.T, app *fiber.App, name, alias, category string) uint {
|
||||
t.Helper()
|
||||
identifier := strings.ToLower(strings.ReplaceAll(name, " ", "_"))
|
||||
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/suppliers", map[string]any{
|
||||
"name": name,
|
||||
"alias": alias,
|
||||
"pic": "John Doe",
|
||||
"type": utils.CustomerSupplierTypeBisnis,
|
||||
"category": category,
|
||||
"hatchery": "Hatchery A",
|
||||
"phone": "081234567890",
|
||||
"email": fmt.Sprintf("%s@supplier.com", identifier),
|
||||
"address": "Supplier address",
|
||||
"npwp": "NPWP-123",
|
||||
"account_number": "ACC-SUPPLIER",
|
||||
"due_date": 30,
|
||||
})
|
||||
if resp.StatusCode != fiber.StatusCreated {
|
||||
t.Fatalf("expected 201 when creating supplier, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
return parseID(t, body)
|
||||
}
|
||||
|
||||
func createProductCategory(t *testing.T, app *fiber.App, name, code string) uint {
|
||||
t.Helper()
|
||||
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/product-categories", map[string]any{
|
||||
"name": name,
|
||||
"code": code,
|
||||
})
|
||||
if resp.StatusCode != fiber.StatusCreated {
|
||||
t.Fatalf("expected 201 when creating product category, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
return parseID(t, body)
|
||||
}
|
||||
|
||||
func fetchProductCategory(t *testing.T, db *gorm.DB, id uint) entities.ProductCategory {
|
||||
t.Helper()
|
||||
var pc entities.ProductCategory
|
||||
if err := db.Preload("CreatedUser").First(&pc, id).Error; err != nil {
|
||||
t.Fatalf("failed to fetch product category: %v", err)
|
||||
}
|
||||
return pc
|
||||
}
|
||||
|
||||
func createProduct(t *testing.T, app *fiber.App, name, brand string, sku *string, uomID, categoryID uint, productPrice float64, supplierIDs []uint, flags []string) uint {
|
||||
t.Helper()
|
||||
payload := map[string]any{
|
||||
"name": name,
|
||||
"brand": brand,
|
||||
"uom_id": uomID,
|
||||
"product_category_id": categoryID,
|
||||
"product_price": productPrice,
|
||||
"supplier_ids": supplierIDs,
|
||||
}
|
||||
if sku != nil {
|
||||
payload["sku"] = *sku
|
||||
}
|
||||
if len(flags) > 0 {
|
||||
payload["flags"] = flags
|
||||
}
|
||||
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/products", payload)
|
||||
if resp.StatusCode != fiber.StatusCreated {
|
||||
t.Fatalf("expected 201 when creating product, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
return parseID(t, body)
|
||||
}
|
||||
|
||||
func fetchProduct(t *testing.T, db *gorm.DB, id uint) entities.Product {
|
||||
t.Helper()
|
||||
var product entities.Product
|
||||
if err := db.Preload("CreatedUser").
|
||||
Preload("Uom").
|
||||
Preload("ProductCategory").
|
||||
Preload("Suppliers", func(tx *gorm.DB) *gorm.DB { return tx.Order("suppliers.name ASC") }).
|
||||
Preload("Flags", func(tx *gorm.DB) *gorm.DB { return tx.Order("flags.name ASC") }).
|
||||
First(&product, id).Error; err != nil {
|
||||
t.Fatalf("failed to fetch product: %v", err)
|
||||
}
|
||||
return product
|
||||
}
|
||||
|
||||
func fetchSupplier(t *testing.T, db *gorm.DB, id uint) entities.Supplier {
|
||||
t.Helper()
|
||||
var supplier entities.Supplier
|
||||
if err := db.Preload("CreatedUser").First(&supplier, id).Error; err != nil {
|
||||
t.Fatalf("failed to fetch supplier: %v", err)
|
||||
}
|
||||
return supplier
|
||||
}
|
||||
|
||||
func createFcr(t *testing.T, app *fiber.App, name string, standards []map[string]any) uint {
|
||||
t.Helper()
|
||||
payload := map[string]any{
|
||||
"name": name,
|
||||
"fcr_standards": standards,
|
||||
}
|
||||
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/fcrs", payload)
|
||||
if resp.StatusCode != fiber.StatusCreated {
|
||||
t.Fatalf("expected 201 when creating fcr, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
return parseID(t, body)
|
||||
}
|
||||
|
||||
func createFlock(t *testing.T, app *fiber.App, name string) uint {
|
||||
t.Helper()
|
||||
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/flocks", map[string]any{
|
||||
"name": name,
|
||||
})
|
||||
if resp.StatusCode != fiber.StatusCreated {
|
||||
t.Fatalf("expected 201 when creating flock, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
return parseID(t, body)
|
||||
}
|
||||
|
||||
func fetchFcr(t *testing.T, db *gorm.DB, id uint) entities.Fcr {
|
||||
t.Helper()
|
||||
var fcr entities.Fcr
|
||||
if err := db.Preload("CreatedUser").
|
||||
Preload("Standards", func(tx *gorm.DB) *gorm.DB {
|
||||
return tx.Order("weight ASC")
|
||||
}).
|
||||
First(&fcr, id).Error; err != nil {
|
||||
t.Fatalf("failed to fetch fcr: %v", err)
|
||||
}
|
||||
return fcr
|
||||
}
|
||||
|
||||
func createNonstock(t *testing.T, app *fiber.App, name string, uomID uint, supplierIDs []uint, flags []string) uint {
|
||||
t.Helper()
|
||||
payload := map[string]any{
|
||||
"name": name,
|
||||
"uom_id": uomID,
|
||||
"supplier_ids": supplierIDs,
|
||||
}
|
||||
if len(flags) > 0 {
|
||||
payload["flags"] = flags
|
||||
}
|
||||
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/nonstocks", payload)
|
||||
if resp.StatusCode != fiber.StatusCreated {
|
||||
t.Fatalf("expected 201 when creating nonstock, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
return parseID(t, body)
|
||||
}
|
||||
|
||||
func fetchNonstock(t *testing.T, db *gorm.DB, id uint) entities.Nonstock {
|
||||
t.Helper()
|
||||
var nonstock entities.Nonstock
|
||||
if err := db.Preload("CreatedUser").
|
||||
Preload("Uom").
|
||||
Preload("Suppliers", func(tx *gorm.DB) *gorm.DB { return tx.Order("suppliers.name ASC") }).
|
||||
Preload("Flags", func(tx *gorm.DB) *gorm.DB { return tx.Order("flags.name ASC") }).
|
||||
First(&nonstock, id).Error; err != nil {
|
||||
t.Fatalf("failed to fetch nonstock: %v", err)
|
||||
}
|
||||
return nonstock
|
||||
}
|
||||
|
||||
func fetchAreaName(t *testing.T, db *gorm.DB, id uint) string {
|
||||
t.Helper()
|
||||
var area entities.Area
|
||||
if err := db.First(&area, id).Error; err != nil {
|
||||
t.Fatalf("failed to fetch area: %v", err)
|
||||
}
|
||||
return area.Name
|
||||
}
|
||||
|
||||
func fetchWarehouse(t *testing.T, db *gorm.DB, id uint) entities.Warehouse {
|
||||
t.Helper()
|
||||
var wh entities.Warehouse
|
||||
if err := db.First(&wh, id).Error; err != nil {
|
||||
t.Fatalf("failed to fetch warehouse: %v", err)
|
||||
}
|
||||
return wh
|
||||
}
|
||||
|
||||
func createBank(t *testing.T, app *fiber.App, name, alias, accountNumber string, owner any) uint {
|
||||
t.Helper()
|
||||
payload := map[string]any{
|
||||
"name": name,
|
||||
"alias": alias,
|
||||
"account_number": accountNumber,
|
||||
"owner": owner,
|
||||
}
|
||||
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/banks", payload)
|
||||
if resp.StatusCode != fiber.StatusCreated {
|
||||
t.Fatalf("expected 201 when creating bank, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
return parseID(t, body)
|
||||
}
|
||||
|
||||
func fetchBank(t *testing.T, db *gorm.DB, id uint) entities.Bank {
|
||||
t.Helper()
|
||||
var bank entities.Bank
|
||||
if err := db.Preload("CreatedUser").First(&bank, id).Error; err != nil {
|
||||
t.Fatalf("failed to fetch bank: %v", err)
|
||||
}
|
||||
return bank
|
||||
}
|
||||
@@ -1,309 +0,0 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"gitlab.com/mbugroup/lti-api.git/internal/entities"
|
||||
"gitlab.com/mbugroup/lti-api.git/internal/utils"
|
||||
)
|
||||
|
||||
func TestNonstockIntegration(t *testing.T) {
|
||||
app, db := setupIntegrationApp(t)
|
||||
|
||||
uomID := createUom(t, app, "Unit Piece")
|
||||
altUomID := createUom(t, app, "Unit Box")
|
||||
|
||||
supplierID1 := createSupplier(t, app, "Nonstock Supplier One", "ns1", string(utils.SupplierCategoryBOP))
|
||||
supplierID2 := createSupplier(t, app, "Nonstock Supplier Two", "ns2", string(utils.SupplierCategoryBOP))
|
||||
supplierID3 := createSupplier(t, app, "Nonstock Supplier Three", "ns3", string(utils.SupplierCategoryBOP))
|
||||
sapronakSupplierID := createSupplier(t, app, "SAPRONAK Supplier", "sap1", string(utils.SupplierCategorySapronak))
|
||||
|
||||
nonstockFlags := []string{string(utils.FlagEkspedisi)}
|
||||
|
||||
t.Run("create nonstock without suppliers succeeds with empty relations", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/nonstocks", map[string]any{
|
||||
"name": "Supplierless Nonstock",
|
||||
"uom_id": uomID,
|
||||
})
|
||||
if resp.StatusCode != fiber.StatusCreated {
|
||||
t.Fatalf("expected 201 when suppliers omitted, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
id := parseID(t, body)
|
||||
ns := fetchNonstock(t, db, id)
|
||||
if len(ns.Suppliers) != 0 {
|
||||
t.Fatalf("expected no suppliers persisted, found %d", len(ns.Suppliers))
|
||||
}
|
||||
if len(ns.Flags) != 0 {
|
||||
t.Fatalf("expected no flags persisted, found %d", len(ns.Flags))
|
||||
}
|
||||
resp, _ = doJSONRequest(t, app, http.MethodDelete, fmt.Sprintf("/api/master-data/nonstocks/%d", id), nil)
|
||||
if resp.StatusCode != fiber.StatusOK {
|
||||
t.Fatalf("expected cleanup delete to succeed, got %d", resp.StatusCode)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("create nonstock with unknown supplier fails", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/nonstocks", map[string]any{
|
||||
"name": "Unknown Supplier Nonstock",
|
||||
"uom_id": uomID,
|
||||
"supplier_ids": []uint{99999},
|
||||
})
|
||||
if resp.StatusCode != fiber.StatusNotFound {
|
||||
t.Fatalf("expected 404 when supplier missing, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("create nonstock with sapronak supplier fails", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/nonstocks", map[string]any{
|
||||
"name": "Invalid Category Nonstock",
|
||||
"uom_id": uomID,
|
||||
"supplier_ids": []uint{sapronakSupplierID},
|
||||
})
|
||||
if resp.StatusCode != fiber.StatusBadRequest {
|
||||
t.Fatalf("expected 400 when supplier category is not BOP, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("create nonstock with invalid flags fails", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/nonstocks", map[string]any{
|
||||
"name": "Invalid Flag Nonstock",
|
||||
"uom_id": uomID,
|
||||
"supplier_ids": []uint{supplierID1},
|
||||
"flags": []string{"UNKNOWN"},
|
||||
})
|
||||
if resp.StatusCode != fiber.StatusBadRequest {
|
||||
t.Fatalf("expected 400 when flags invalid, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
})
|
||||
|
||||
var nonstockID uint
|
||||
|
||||
t.Run("create nonstock succeeds", func(t *testing.T) {
|
||||
nonstockID = createNonstock(t, app, "Layer Feed", uomID, []uint{supplierID1, supplierID2, supplierID1}, nonstockFlags)
|
||||
if nonstockID == 0 {
|
||||
t.Fatal("expected nonstock id to be non zero")
|
||||
}
|
||||
ns := fetchNonstock(t, db, nonstockID)
|
||||
if ns.Name != "Layer Feed" {
|
||||
t.Fatalf("expected name Layer Feed, got %q", ns.Name)
|
||||
}
|
||||
if ns.UomId != uomID {
|
||||
t.Fatalf("expected uom_id %d, got %d", uomID, ns.UomId)
|
||||
}
|
||||
if ns.CreatedBy != 1 {
|
||||
t.Fatalf("expected created_by 1, got %d", ns.CreatedBy)
|
||||
}
|
||||
if len(ns.Suppliers) != 2 {
|
||||
t.Fatalf("expected 2 unique suppliers, got %d", len(ns.Suppliers))
|
||||
}
|
||||
if len(ns.Flags) != len(nonstockFlags) {
|
||||
t.Fatalf("expected %d flags, got %d", len(nonstockFlags), len(ns.Flags))
|
||||
}
|
||||
expectedFlags := make(map[string]struct{}, len(nonstockFlags))
|
||||
for _, flag := range nonstockFlags {
|
||||
expectedFlags[strings.ToUpper(flag)] = struct{}{}
|
||||
}
|
||||
for _, flag := range ns.Flags {
|
||||
upper := strings.ToUpper(flag.Name)
|
||||
if _, ok := expectedFlags[upper]; !ok {
|
||||
t.Fatalf("unexpected flag stored: %s", upper)
|
||||
}
|
||||
delete(expectedFlags, upper)
|
||||
}
|
||||
if len(expectedFlags) != 0 {
|
||||
t.Fatalf("missing flags after create: %v", expectedFlags)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("get nonstock detail includes suppliers", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodGet, fmt.Sprintf("/api/master-data/nonstocks/%d", nonstockID), nil)
|
||||
if resp.StatusCode != fiber.StatusOK {
|
||||
t.Fatalf("expected 200 when fetching nonstock, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
var payload struct {
|
||||
Data struct {
|
||||
Id uint `json:"id"`
|
||||
Name string `json:"name"`
|
||||
UomID uint `json:"uom_id"`
|
||||
Suppliers []map[string]any `json:"suppliers"`
|
||||
Flags []string `json:"flags"`
|
||||
} `json:"data"`
|
||||
}
|
||||
if err := json.Unmarshal(body, &payload); err != nil {
|
||||
t.Fatalf("failed to parse nonstock detail: %v", err)
|
||||
}
|
||||
if payload.Data.Id != nonstockID {
|
||||
t.Fatalf("expected id %d, got %d", nonstockID, payload.Data.Id)
|
||||
}
|
||||
if payload.Data.UomID != uomID {
|
||||
t.Fatalf("expected response uom_id %d, got %d", uomID, payload.Data.UomID)
|
||||
}
|
||||
if len(payload.Data.Suppliers) != 2 {
|
||||
t.Fatalf("expected 2 suppliers in response, got %d", len(payload.Data.Suppliers))
|
||||
}
|
||||
if len(payload.Data.Flags) != len(nonstockFlags) {
|
||||
t.Fatalf("expected %d flags in response, got %d", len(nonstockFlags), len(payload.Data.Flags))
|
||||
}
|
||||
expected := make(map[string]struct{}, len(nonstockFlags))
|
||||
for _, flag := range nonstockFlags {
|
||||
expected[strings.ToUpper(flag)] = struct{}{}
|
||||
}
|
||||
for _, flag := range payload.Data.Flags {
|
||||
flag = strings.ToUpper(flag)
|
||||
if _, ok := expected[flag]; !ok {
|
||||
t.Fatalf("unexpected flag %s returned", flag)
|
||||
}
|
||||
delete(expected, flag)
|
||||
}
|
||||
if len(expected) != 0 {
|
||||
t.Fatalf("missing flags in response: %v", expected)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("update nonstock with invalid uom fails", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodPatch, fmt.Sprintf("/api/master-data/nonstocks/%d", nonstockID), map[string]any{
|
||||
"uom_id": 99999,
|
||||
})
|
||||
if resp.StatusCode != fiber.StatusNotFound {
|
||||
t.Fatalf("expected 404 when updating with invalid uom, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("update nonstock with invalid supplier fails", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodPatch, fmt.Sprintf("/api/master-data/nonstocks/%d", nonstockID), map[string]any{
|
||||
"supplier_ids": []uint{supplierID1, 99999},
|
||||
})
|
||||
if resp.StatusCode != fiber.StatusNotFound {
|
||||
t.Fatalf("expected 404 when updating with invalid supplier, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("update nonstock with sapronak supplier fails", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodPatch, fmt.Sprintf("/api/master-data/nonstocks/%d", nonstockID), map[string]any{
|
||||
"supplier_ids": []uint{sapronakSupplierID},
|
||||
})
|
||||
if resp.StatusCode != fiber.StatusBadRequest {
|
||||
t.Fatalf("expected 400 when updating with non-BOP supplier, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("update nonstock with invalid flags fails", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodPatch, fmt.Sprintf("/api/master-data/nonstocks/%d", nonstockID), map[string]any{
|
||||
"flags": []string{"BAD"},
|
||||
})
|
||||
if resp.StatusCode != fiber.StatusBadRequest {
|
||||
t.Fatalf("expected 400 when updating flags invalid, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("update nonstock name uom and suppliers succeeds", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodPatch, fmt.Sprintf("/api/master-data/nonstocks/%d", nonstockID), map[string]any{
|
||||
"name": "Layer Feed Premium",
|
||||
"uom_id": altUomID,
|
||||
"supplier_ids": []uint{supplierID3},
|
||||
"flags": nonstockFlags,
|
||||
})
|
||||
if resp.StatusCode != fiber.StatusOK {
|
||||
t.Fatalf("expected 200 when updating nonstock, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
ns := fetchNonstock(t, db, nonstockID)
|
||||
if ns.Name != "Layer Feed Premium" {
|
||||
t.Fatalf("expected name Layer Feed Premium, got %q", ns.Name)
|
||||
}
|
||||
if ns.UomId != altUomID {
|
||||
t.Fatalf("expected uom_id %d, got %d", altUomID, ns.UomId)
|
||||
}
|
||||
if len(ns.Suppliers) != 1 || ns.Suppliers[0].Id != supplierID3 {
|
||||
t.Fatalf("expected suppliers to contain only %d", supplierID3)
|
||||
}
|
||||
if len(ns.Flags) != len(nonstockFlags) {
|
||||
t.Fatalf("expected flags retained, got %d", len(ns.Flags))
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("clear suppliers succeeds", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodPatch, fmt.Sprintf("/api/master-data/nonstocks/%d", nonstockID), map[string]any{
|
||||
"supplier_ids": []uint{},
|
||||
})
|
||||
if resp.StatusCode != fiber.StatusOK {
|
||||
t.Fatalf("expected 200 when clearing suppliers, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
ns := fetchNonstock(t, db, nonstockID)
|
||||
if len(ns.Suppliers) != 0 {
|
||||
t.Fatalf("expected suppliers to be cleared, got %d entries", len(ns.Suppliers))
|
||||
}
|
||||
if len(ns.Flags) != len(nonstockFlags) {
|
||||
t.Fatalf("expected flags unaffected, got %d", len(ns.Flags))
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("clear nonstock flags succeeds", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodPatch, fmt.Sprintf("/api/master-data/nonstocks/%d", nonstockID), map[string]any{
|
||||
"flags": []string{},
|
||||
})
|
||||
if resp.StatusCode != fiber.StatusOK {
|
||||
t.Fatalf("expected 200 when clearing nonstock flags, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
ns := fetchNonstock(t, db, nonstockID)
|
||||
if len(ns.Flags) != 0 {
|
||||
t.Fatalf("expected flags cleared, got %d", len(ns.Flags))
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("delete nonstock succeeds", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodDelete, fmt.Sprintf("/api/master-data/nonstocks/%d", nonstockID), nil)
|
||||
if resp.StatusCode != fiber.StatusOK {
|
||||
t.Fatalf("expected 200 when deleting nonstock, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
var ns entities.Nonstock
|
||||
if err := db.First(&ns, nonstockID).Error; !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
t.Fatalf("expected nonstock to be deleted, got error %v", err)
|
||||
}
|
||||
var links int64
|
||||
if err := db.Model(&entities.NonstockSupplier{}).Where("nonstock_id = ?", nonstockID).Count(&links).Error; err != nil {
|
||||
t.Fatalf("failed counting nonstock suppliers: %v", err)
|
||||
}
|
||||
if links != 0 {
|
||||
t.Fatalf("expected link table cleared, found %d rows", links)
|
||||
}
|
||||
var flagCount int64
|
||||
if err := db.Model(&entities.Flag{}).
|
||||
Where("flagable_id = ? AND flagable_type = ?", nonstockID, entities.FlagableTypeNonstock).
|
||||
Count(&flagCount).Error; err != nil {
|
||||
t.Fatalf("failed counting nonstock flags: %v", err)
|
||||
}
|
||||
if flagCount != 0 {
|
||||
t.Fatalf("expected flags removed, found %d", flagCount)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("deleting nonstock twice returns 404", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodDelete, fmt.Sprintf("/api/master-data/nonstocks/%d", nonstockID), nil)
|
||||
if resp.StatusCode != fiber.StatusNotFound {
|
||||
t.Fatalf("expected 404 when deleting missing nonstock, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("fetching deleted nonstock returns 404", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodGet, fmt.Sprintf("/api/master-data/nonstocks/%d", nonstockID), nil)
|
||||
if resp.StatusCode != fiber.StatusNotFound {
|
||||
t.Fatalf("expected 404 when fetching deleted nonstock, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("cleanup additional supplier references", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodDelete, fmt.Sprintf("/api/master-data/suppliers/%d", supplierID3), nil)
|
||||
if resp.StatusCode != fiber.StatusOK {
|
||||
t.Fatalf("expected 200 when deleting supplier, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
doJSONRequest(t, app, http.MethodDelete, fmt.Sprintf("/api/master-data/suppliers/%d", sapronakSupplierID), nil)
|
||||
})
|
||||
}
|
||||
@@ -1,150 +0,0 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"gitlab.com/mbugroup/lti-api.git/internal/entities"
|
||||
)
|
||||
|
||||
func TestProductCategoryIntegration(t *testing.T) {
|
||||
app, db := setupIntegrationApp(t)
|
||||
|
||||
t.Run("create product category missing code fails", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/product-categories", map[string]any{
|
||||
"name": "Layer Feed",
|
||||
})
|
||||
if resp.StatusCode != fiber.StatusBadRequest {
|
||||
t.Fatalf("expected 400 when code missing, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
})
|
||||
|
||||
var categoryID uint
|
||||
|
||||
t.Run("create product category succeeds", func(t *testing.T) {
|
||||
categoryID = createProductCategory(t, app, "Layer Feed", "LFD")
|
||||
pc := fetchProductCategory(t, db, categoryID)
|
||||
if pc.Name != "Layer Feed" {
|
||||
t.Fatalf("expected name Layer Feed, got %q", pc.Name)
|
||||
}
|
||||
if pc.Code != "LFD" {
|
||||
t.Fatalf("expected code LFD, got %q", pc.Code)
|
||||
}
|
||||
if pc.CreatedBy != 1 {
|
||||
t.Fatalf("expected created_by 1, got %d", pc.CreatedBy)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("creating duplicate name fails", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/product-categories", map[string]any{
|
||||
"name": "Layer Feed",
|
||||
"code": "LF2",
|
||||
})
|
||||
if resp.StatusCode != fiber.StatusConflict {
|
||||
t.Fatalf("expected 409 when creating duplicate name, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("creating duplicate code fails", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/product-categories", map[string]any{
|
||||
"name": "Layer Feed Premium",
|
||||
"code": "LFD",
|
||||
})
|
||||
if resp.StatusCode != fiber.StatusConflict {
|
||||
t.Fatalf("expected 409 when creating duplicate code, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("get product category detail", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodGet, fmt.Sprintf("/api/master-data/product-categories/%d", categoryID), nil)
|
||||
if resp.StatusCode != fiber.StatusOK {
|
||||
t.Fatalf("expected 200 when fetching product category, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
var payload struct {
|
||||
Data struct {
|
||||
Id uint `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Code string `json:"code"`
|
||||
} `json:"data"`
|
||||
}
|
||||
if err := json.Unmarshal(body, &payload); err != nil {
|
||||
t.Fatalf("failed to parse response: %v", err)
|
||||
}
|
||||
if payload.Data.Id != categoryID {
|
||||
t.Fatalf("expected id %d, got %d", categoryID, payload.Data.Id)
|
||||
}
|
||||
if payload.Data.Code != "LFD" {
|
||||
t.Fatalf("expected code LFD, got %q", payload.Data.Code)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("update product category with duplicate name fails", func(t *testing.T) {
|
||||
otherID := createProductCategory(t, app, "Layer Feed Alt", "LFA")
|
||||
resp, body := doJSONRequest(t, app, http.MethodPatch, fmt.Sprintf("/api/master-data/product-categories/%d", otherID), map[string]any{
|
||||
"name": "Layer Feed",
|
||||
})
|
||||
if resp.StatusCode != fiber.StatusConflict {
|
||||
t.Fatalf("expected 409 when updating with duplicate name, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("update product category succeeds", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodPatch, fmt.Sprintf("/api/master-data/product-categories/%d", categoryID), map[string]any{
|
||||
"name": "Layer Feed Updated",
|
||||
"code": "LFU",
|
||||
})
|
||||
if resp.StatusCode != fiber.StatusOK {
|
||||
t.Fatalf("expected 200 when updating product category, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
var payload struct {
|
||||
Data struct {
|
||||
Name string `json:"name"`
|
||||
Code string `json:"code"`
|
||||
} `json:"data"`
|
||||
}
|
||||
if err := json.Unmarshal(body, &payload); err != nil {
|
||||
t.Fatalf("failed to parse update response: %v", err)
|
||||
}
|
||||
if payload.Data.Name != "Layer Feed Updated" {
|
||||
t.Fatalf("expected updated name, got %q", payload.Data.Name)
|
||||
}
|
||||
if payload.Data.Code != "LFU" {
|
||||
t.Fatalf("expected code LFU, got %q", payload.Data.Code)
|
||||
}
|
||||
pc := fetchProductCategory(t, db, categoryID)
|
||||
if pc.Code != "LFU" {
|
||||
t.Fatalf("expected persisted code LFU, got %q", pc.Code)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("delete product category", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodDelete, fmt.Sprintf("/api/master-data/product-categories/%d", categoryID), nil)
|
||||
if resp.StatusCode != fiber.StatusOK {
|
||||
t.Fatalf("expected 200 when deleting product category, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
var pc entities.ProductCategory
|
||||
if err := db.First(&pc, categoryID).Error; !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
t.Fatalf("expected product category deleted, got error %v", err)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("delete non existing product category returns 404", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodDelete, fmt.Sprintf("/api/master-data/product-categories/%d", categoryID), nil)
|
||||
if resp.StatusCode != fiber.StatusNotFound {
|
||||
t.Fatalf("expected 404 when deleting missing product category, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("get deleted product category returns 404", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodGet, fmt.Sprintf("/api/master-data/product-categories/%d", categoryID), nil)
|
||||
if resp.StatusCode != fiber.StatusNotFound {
|
||||
t.Fatalf("expected 404 when fetching deleted product category, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -1,410 +0,0 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"gitlab.com/mbugroup/lti-api.git/internal/entities"
|
||||
"gitlab.com/mbugroup/lti-api.git/internal/utils"
|
||||
)
|
||||
|
||||
func TestProductIntegration(t *testing.T) {
|
||||
app, db := setupIntegrationApp(t)
|
||||
|
||||
uomID := createUom(t, app, "Kilogram")
|
||||
categoryID := createProductCategory(t, app, "Feed", "FED")
|
||||
|
||||
sapSupplier1 := createSupplier(t, app, "Feed Supplier One", "fs1", string(utils.SupplierCategorySapronak))
|
||||
sapSupplier2 := createSupplier(t, app, "Feed Supplier Two", "fs2", string(utils.SupplierCategorySapronak))
|
||||
bopSupplier := createSupplier(t, app, "BOP Supplier", "bop1", string(utils.SupplierCategoryBOP))
|
||||
|
||||
productFlags := []string{string(utils.FlagDOC), string(utils.FlagPakan)}
|
||||
updatedProductFlags := []string{string(utils.FlagFinisher), string(utils.FlagObat)}
|
||||
|
||||
t.Run("create product without suppliers succeeds with empty relations", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/products", map[string]any{
|
||||
"name": "Supplierless Product",
|
||||
"brand": "Brand A",
|
||||
"uom_id": uomID,
|
||||
"product_category_id": categoryID,
|
||||
"product_price": 12000,
|
||||
})
|
||||
if resp.StatusCode != fiber.StatusCreated {
|
||||
t.Fatalf("expected 201 when suppliers omitted, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
id := parseID(t, body)
|
||||
product := fetchProduct(t, db, id)
|
||||
if len(product.Suppliers) != 0 {
|
||||
t.Fatalf("expected no suppliers persisted, found %d", len(product.Suppliers))
|
||||
}
|
||||
if len(product.Flags) != 0 {
|
||||
t.Fatalf("expected no flags persisted, found %d", len(product.Flags))
|
||||
}
|
||||
resp, _ = doJSONRequest(t, app, http.MethodDelete, fmt.Sprintf("/api/master-data/products/%d", id), nil)
|
||||
if resp.StatusCode != fiber.StatusOK {
|
||||
t.Fatalf("expected cleanup delete to succeed, got %d", resp.StatusCode)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("create product with invalid uom fails", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/products", map[string]any{
|
||||
"name": "Layer Feed Invalid UOM",
|
||||
"brand": "Brand A",
|
||||
"uom_id": 9999,
|
||||
"product_category_id": categoryID,
|
||||
"product_price": 12000,
|
||||
"supplier_ids": []uint{sapSupplier1},
|
||||
})
|
||||
if resp.StatusCode != fiber.StatusNotFound {
|
||||
t.Fatalf("expected 404 when uom missing, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("create product with invalid category fails", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/products", map[string]any{
|
||||
"name": "Layer Feed Invalid Category",
|
||||
"brand": "Brand A",
|
||||
"uom_id": uomID,
|
||||
"product_category_id": 9999,
|
||||
"product_price": 12000,
|
||||
"supplier_ids": []uint{sapSupplier1},
|
||||
})
|
||||
if resp.StatusCode != fiber.StatusNotFound {
|
||||
t.Fatalf("expected 404 when category missing, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("create product with invalid supplier fails", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/products", map[string]any{
|
||||
"name": "Layer Feed Missing Supplier",
|
||||
"brand": "Brand A",
|
||||
"uom_id": uomID,
|
||||
"product_category_id": categoryID,
|
||||
"product_price": 12000,
|
||||
"supplier_ids": []uint{99999},
|
||||
})
|
||||
if resp.StatusCode != fiber.StatusNotFound {
|
||||
t.Fatalf("expected 404 when supplier missing, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("create product with BOP supplier fails", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/products", map[string]any{
|
||||
"name": "Layer Feed Wrong Supplier",
|
||||
"brand": "Brand A",
|
||||
"uom_id": uomID,
|
||||
"product_category_id": categoryID,
|
||||
"product_price": 12000,
|
||||
"supplier_ids": []uint{bopSupplier},
|
||||
})
|
||||
if resp.StatusCode != fiber.StatusBadRequest {
|
||||
t.Fatalf("expected 400 when supplier category invalid, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("create product with invalid flags fails", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/products", map[string]any{
|
||||
"name": "Layer Feed Invalid Flags",
|
||||
"brand": "Brand A",
|
||||
"uom_id": uomID,
|
||||
"product_category_id": categoryID,
|
||||
"product_price": 12000,
|
||||
"supplier_ids": []uint{sapSupplier1},
|
||||
"flags": []string{"INVALID"},
|
||||
})
|
||||
if resp.StatusCode != fiber.StatusBadRequest {
|
||||
t.Fatalf("expected 400 when flags invalid, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
})
|
||||
|
||||
var productID uint
|
||||
|
||||
t.Run("create product succeeds", func(t *testing.T) {
|
||||
sku := "lfd-001"
|
||||
productID = createProduct(t, app, "Layer Feed", "Brand A", &sku, uomID, categoryID, 15000, []uint{sapSupplier1, sapSupplier2}, productFlags)
|
||||
product := fetchProduct(t, db, productID)
|
||||
if product.Name != "Layer Feed" {
|
||||
t.Fatalf("expected name Layer Feed, got %q", product.Name)
|
||||
}
|
||||
if product.Brand != "Brand A" {
|
||||
t.Fatalf("expected brand Brand A, got %q", product.Brand)
|
||||
}
|
||||
if product.Sku == nil || *product.Sku != strings.ToUpper(sku) {
|
||||
t.Fatalf("expected sku %q, got %+v", strings.ToUpper(sku), product.Sku)
|
||||
}
|
||||
if product.UomId != uomID {
|
||||
t.Fatalf("expected uom_id %d, got %d", uomID, product.UomId)
|
||||
}
|
||||
if product.ProductCategoryId != categoryID {
|
||||
t.Fatalf("expected product_category_id %d, got %d", categoryID, product.ProductCategoryId)
|
||||
}
|
||||
if product.CreatedBy != 1 {
|
||||
t.Fatalf("expected created_by 1, got %d", product.CreatedBy)
|
||||
}
|
||||
if len(product.Suppliers) != 2 {
|
||||
t.Fatalf("expected 2 suppliers, got %d", len(product.Suppliers))
|
||||
}
|
||||
if len(product.Flags) != len(productFlags) {
|
||||
t.Fatalf("expected %d flags, got %d", len(productFlags), len(product.Flags))
|
||||
}
|
||||
expectedFlags := make(map[string]struct{}, len(productFlags))
|
||||
for _, flag := range productFlags {
|
||||
expectedFlags[strings.ToUpper(flag)] = struct{}{}
|
||||
}
|
||||
for _, flag := range product.Flags {
|
||||
if _, ok := expectedFlags[strings.ToUpper(flag.Name)]; !ok {
|
||||
t.Fatalf("unexpected flag %s present", flag.Name)
|
||||
}
|
||||
delete(expectedFlags, strings.ToUpper(flag.Name))
|
||||
}
|
||||
if len(expectedFlags) != 0 {
|
||||
t.Fatalf("missing expected flags: %v", expectedFlags)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("creating duplicate name fails", func(t *testing.T) {
|
||||
sku := "lfd-002"
|
||||
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/products", map[string]any{
|
||||
"name": "Layer Feed",
|
||||
"brand": "Brand B",
|
||||
"sku": sku,
|
||||
"uom_id": uomID,
|
||||
"product_category_id": categoryID,
|
||||
"product_price": 16000,
|
||||
"supplier_ids": []uint{sapSupplier1},
|
||||
})
|
||||
if resp.StatusCode != fiber.StatusConflict {
|
||||
t.Fatalf("expected 409 when creating duplicate name, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("creating duplicate sku fails", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/products", map[string]any{
|
||||
"name": "Layer Feed Premium",
|
||||
"brand": "Brand B",
|
||||
"sku": "LFD-001",
|
||||
"uom_id": uomID,
|
||||
"product_category_id": categoryID,
|
||||
"product_price": 17000,
|
||||
"supplier_ids": []uint{sapSupplier1},
|
||||
})
|
||||
if resp.StatusCode != fiber.StatusConflict {
|
||||
t.Fatalf("expected 409 when creating duplicate sku, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("get product detail returns nested data", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodGet, fmt.Sprintf("/api/master-data/products/%d", productID), nil)
|
||||
if resp.StatusCode != fiber.StatusOK {
|
||||
t.Fatalf("expected 200 when fetching product, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
var payload struct {
|
||||
Data struct {
|
||||
Id uint `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Brand string `json:"brand"`
|
||||
Uom *struct {
|
||||
Id uint `json:"id"`
|
||||
} `json:"uom"`
|
||||
Suppliers []map[string]any `json:"suppliers"`
|
||||
Flags []string `json:"flags"`
|
||||
} `json:"data"`
|
||||
}
|
||||
if err := json.Unmarshal(body, &payload); err != nil {
|
||||
t.Fatalf("failed to parse product detail: %v", err)
|
||||
}
|
||||
if payload.Data.Id != productID {
|
||||
t.Fatalf("expected id %d, got %d", productID, payload.Data.Id)
|
||||
}
|
||||
if payload.Data.Uom == nil || payload.Data.Uom.Id != uomID {
|
||||
t.Fatalf("expected uom id %d, got %+v", uomID, payload.Data.Uom)
|
||||
}
|
||||
if len(payload.Data.Suppliers) != 2 {
|
||||
t.Fatalf("expected 2 suppliers in response, got %d", len(payload.Data.Suppliers))
|
||||
}
|
||||
if len(payload.Data.Flags) != len(productFlags) {
|
||||
t.Fatalf("expected %d flags in response, got %d", len(productFlags), len(payload.Data.Flags))
|
||||
}
|
||||
expected := make(map[string]struct{}, len(productFlags))
|
||||
for _, flag := range productFlags {
|
||||
expected[strings.ToUpper(flag)] = struct{}{}
|
||||
}
|
||||
for _, flag := range payload.Data.Flags {
|
||||
flag = strings.ToUpper(flag)
|
||||
if _, ok := expected[flag]; !ok {
|
||||
t.Fatalf("unexpected flag %s returned", flag)
|
||||
}
|
||||
delete(expected, flag)
|
||||
}
|
||||
if len(expected) != 0 {
|
||||
t.Fatalf("missing expected flags in response: %v", expected)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("update product with invalid supplier category fails", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodPatch, fmt.Sprintf("/api/master-data/products/%d", productID), map[string]any{
|
||||
"supplier_ids": []uint{bopSupplier},
|
||||
})
|
||||
if resp.StatusCode != fiber.StatusBadRequest {
|
||||
t.Fatalf("expected 400 when updating with non SAPRONAK supplier, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("update product with invalid flags fails", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodPatch, fmt.Sprintf("/api/master-data/products/%d", productID), map[string]any{
|
||||
"flags": []string{"UNKNOWN"},
|
||||
})
|
||||
if resp.StatusCode != fiber.StatusBadRequest {
|
||||
t.Fatalf("expected 400 when updating with invalid flags, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("update product succeeds", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodPatch, fmt.Sprintf("/api/master-data/products/%d", productID), map[string]any{
|
||||
"name": "Layer Feed Updated",
|
||||
"brand": "Brand C",
|
||||
"sku": "lfd-100",
|
||||
"product_price": 18000,
|
||||
"selling_price": 19000,
|
||||
"tax": 1000,
|
||||
"expiry_period": 30,
|
||||
"supplier_ids": []uint{sapSupplier1},
|
||||
"flags": updatedProductFlags,
|
||||
})
|
||||
if resp.StatusCode != fiber.StatusOK {
|
||||
t.Fatalf("expected 200 when updating product, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
var payload struct {
|
||||
Data struct {
|
||||
Name string `json:"name"`
|
||||
Brand string `json:"brand"`
|
||||
Sku *string `json:"sku"`
|
||||
ProductPrice float64 `json:"product_price"`
|
||||
SupplierIds []map[string]any `json:"suppliers"`
|
||||
Flags []string `json:"flags"`
|
||||
} `json:"data"`
|
||||
}
|
||||
if err := json.Unmarshal(body, &payload); err != nil {
|
||||
t.Fatalf("failed to parse update response: %v", err)
|
||||
}
|
||||
if payload.Data.Name != "Layer Feed Updated" {
|
||||
t.Fatalf("expected updated name, got %q", payload.Data.Name)
|
||||
}
|
||||
if len(payload.Data.Flags) != len(updatedProductFlags) {
|
||||
t.Fatalf("expected %d flags in response, got %d", len(updatedProductFlags), len(payload.Data.Flags))
|
||||
}
|
||||
respFlags := make(map[string]struct{}, len(payload.Data.Flags))
|
||||
for _, flag := range payload.Data.Flags {
|
||||
respFlags[strings.ToUpper(flag)] = struct{}{}
|
||||
}
|
||||
for _, flag := range updatedProductFlags {
|
||||
if _, ok := respFlags[strings.ToUpper(flag)]; !ok {
|
||||
t.Fatalf("missing flag %s in response", flag)
|
||||
}
|
||||
}
|
||||
product := fetchProduct(t, db, productID)
|
||||
if product.Brand != "Brand C" {
|
||||
t.Fatalf("expected persisted brand Brand C, got %q", product.Brand)
|
||||
}
|
||||
if product.Sku == nil || *product.Sku != "LFD-100" {
|
||||
t.Fatalf("expected persisted sku LFD-100, got %+v", product.Sku)
|
||||
}
|
||||
if len(product.Suppliers) != 1 || product.Suppliers[0].Id != sapSupplier1 {
|
||||
t.Fatalf("expected supplier to be %d", sapSupplier1)
|
||||
}
|
||||
if len(product.Flags) != len(updatedProductFlags) {
|
||||
t.Fatalf("expected %d flags after update, got %d", len(updatedProductFlags), len(product.Flags))
|
||||
}
|
||||
expectedFlags := make(map[string]struct{}, len(updatedProductFlags))
|
||||
for _, flag := range updatedProductFlags {
|
||||
expectedFlags[strings.ToUpper(flag)] = struct{}{}
|
||||
}
|
||||
for _, flag := range product.Flags {
|
||||
upper := strings.ToUpper(flag.Name)
|
||||
if _, ok := expectedFlags[upper]; !ok {
|
||||
t.Fatalf("unexpected flag after update: %s", upper)
|
||||
}
|
||||
delete(expectedFlags, upper)
|
||||
}
|
||||
if len(expectedFlags) != 0 {
|
||||
t.Fatalf("missing flags after update: %v", expectedFlags)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("clear suppliers succeeds", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodPatch, fmt.Sprintf("/api/master-data/products/%d", productID), map[string]any{
|
||||
"supplier_ids": []uint{},
|
||||
})
|
||||
if resp.StatusCode != fiber.StatusOK {
|
||||
t.Fatalf("expected 200 when clearing suppliers, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
product := fetchProduct(t, db, productID)
|
||||
if len(product.Suppliers) != 0 {
|
||||
t.Fatalf("expected no suppliers after clearing, got %d", len(product.Suppliers))
|
||||
}
|
||||
if len(product.Flags) != len(updatedProductFlags) {
|
||||
t.Fatalf("expected flags untouched after clearing suppliers, got %d", len(product.Flags))
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("clear flags succeeds", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodPatch, fmt.Sprintf("/api/master-data/products/%d", productID), map[string]any{
|
||||
"flags": []string{},
|
||||
})
|
||||
if resp.StatusCode != fiber.StatusOK {
|
||||
t.Fatalf("expected 200 when clearing flags, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
product := fetchProduct(t, db, productID)
|
||||
if len(product.Flags) != 0 {
|
||||
t.Fatalf("expected all flags cleared, got %d", len(product.Flags))
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("delete product succeeds", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodDelete, fmt.Sprintf("/api/master-data/products/%d", productID), nil)
|
||||
if resp.StatusCode != fiber.StatusOK {
|
||||
t.Fatalf("expected 200 when deleting product, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
var product entities.Product
|
||||
if err := db.First(&product, productID).Error; !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
t.Fatalf("expected product deleted, got error %v", err)
|
||||
}
|
||||
var links int64
|
||||
if err := db.Model(&entities.ProductSupplier{}).Where("product_id = ?", productID).Count(&links).Error; err != nil {
|
||||
t.Fatalf("failed counting product suppliers: %v", err)
|
||||
}
|
||||
if links != 0 {
|
||||
t.Fatalf("expected pivot cleared, found %d rows", links)
|
||||
}
|
||||
var flagCount int64
|
||||
if err := db.Model(&entities.Flag{}).
|
||||
Where("flagable_id = ? AND flagable_type = ?", productID, entities.FlagableTypeProduct).
|
||||
Count(&flagCount).Error; err != nil {
|
||||
t.Fatalf("failed counting product flags: %v", err)
|
||||
}
|
||||
if flagCount != 0 {
|
||||
t.Fatalf("expected flags removed, found %d", flagCount)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("delete missing product returns 404", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodDelete, fmt.Sprintf("/api/master-data/products/%d", productID), nil)
|
||||
if resp.StatusCode != fiber.StatusNotFound {
|
||||
t.Fatalf("expected 404 when deleting missing product, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("get deleted product returns 404", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodGet, fmt.Sprintf("/api/master-data/products/%d", productID), nil)
|
||||
if resp.StatusCode != fiber.StatusNotFound {
|
||||
t.Fatalf("expected 404 when fetching deleted product, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -1,417 +0,0 @@
|
||||
package test
|
||||
|
||||
// import (
|
||||
// "encoding/json"
|
||||
// "fmt"
|
||||
// "net/http"
|
||||
// "net/url"
|
||||
// "testing"
|
||||
|
||||
// "github.com/gofiber/fiber/v2"
|
||||
|
||||
// "gitlab.com/mbugroup/lti-api.git/internal/entities"
|
||||
// "gitlab.com/mbugroup/lti-api.git/internal/utils"
|
||||
// )
|
||||
|
||||
// func TestProjectFlockSummary(t *testing.T) {
|
||||
// app, db := setupIntegrationApp(t)
|
||||
|
||||
// areaID := createArea(t, app, "Area Project")
|
||||
// locationID := createLocation(t, app, "Location Project", "Address", areaID)
|
||||
// flockID := createFlock(t, app, "Flock Summary")
|
||||
// fcrID := createFcr(t, app, "FCR Summary", []map[string]any{
|
||||
// {"weight": 1.0, "fcr_number": 1.5, "mortality": 2.0},
|
||||
// })
|
||||
// kandangID := createKandang(t, app, "Kandang Summary", locationID, 1)
|
||||
|
||||
// createPayload := map[string]any{
|
||||
// "flock_id": flockID,
|
||||
// "area_id": areaID,
|
||||
// "category": "growing",
|
||||
// "fcr_id": fcrID,
|
||||
// "location_id": locationID,
|
||||
// "kandang_ids": []uint{kandangID},
|
||||
// }
|
||||
// resp, body := doJSONRequest(t, app, http.MethodPost, "/api/production/project_flocks", createPayload)
|
||||
// if resp.StatusCode != fiber.StatusCreated {
|
||||
// t.Fatalf("expected 201 when creating project flock, got %d: %s", resp.StatusCode, string(body))
|
||||
// }
|
||||
|
||||
// var createResp struct {
|
||||
// Data struct {
|
||||
// Id uint `json:"id"`
|
||||
// Period int `json:"period"`
|
||||
// Category string `json:"category"`
|
||||
// Flock struct {
|
||||
// Id uint `json:"id"`
|
||||
// Name string `json:"name"`
|
||||
// } `json:"flock"`
|
||||
// Area struct {
|
||||
// Id uint `json:"id"`
|
||||
// Name string `json:"name"`
|
||||
// } `json:"area"`
|
||||
// Fcr struct {
|
||||
// Id uint `json:"id"`
|
||||
// Name string `json:"name"`
|
||||
// } `json:"fcr"`
|
||||
// Location struct {
|
||||
// Id uint `json:"id"`
|
||||
// Name string `json:"name"`
|
||||
// Address string `json:"address"`
|
||||
// } `json:"location"`
|
||||
// Kandangs []struct {
|
||||
// Id uint `json:"id"`
|
||||
// Name string `json:"name"`
|
||||
// Status string `json:"status"`
|
||||
// } `json:"kandangs"`
|
||||
// CreatedUser struct {
|
||||
// Id uint `json:"id"`
|
||||
// IdUser uint `json:"id_user"`
|
||||
// Email string `json:"email"`
|
||||
// Name string `json:"name"`
|
||||
// } `json:"created_user"`
|
||||
// } `json:"data"`
|
||||
// }
|
||||
// if err := json.Unmarshal(body, &createResp); err != nil {
|
||||
// t.Fatalf("failed to parse create response: %v", err)
|
||||
// }
|
||||
// if createResp.Data.Flock.Id != flockID || createResp.Data.Flock.Name == "" {
|
||||
// t.Fatalf("expected flock detail to be present, got %+v", createResp.Data.Flock)
|
||||
// }
|
||||
// if createResp.Data.Area.Id != areaID || createResp.Data.Area.Name == "" {
|
||||
// t.Fatalf("expected area detail to be present, got %+v", createResp.Data.Area)
|
||||
// }
|
||||
// if createResp.Data.Category != string(utils.ProjectFlockCategoryGrowing) {
|
||||
// t.Fatalf("expected category to be %s, got %s", utils.ProjectFlockCategoryGrowing, createResp.Data.Category)
|
||||
// }
|
||||
// if createResp.Data.Location.Id != locationID || createResp.Data.Location.Name == "" {
|
||||
// t.Fatalf("expected location detail to be present, got %+v", createResp.Data.Location)
|
||||
// }
|
||||
// if len(createResp.Data.Kandangs) != 1 || createResp.Data.Kandangs[0].Id != kandangID {
|
||||
// t.Fatalf("expected kandang detail to be present, got %+v", createResp.Data.Kandangs)
|
||||
// }
|
||||
// if createResp.Data.Kandangs[0].Status != string(utils.KandangStatusPengajuan) {
|
||||
// t.Fatalf("expected kandang status to be PENGAJUAN, got %s", createResp.Data.Kandangs[0].Status)
|
||||
// }
|
||||
// if createResp.Data.Period != 1 {
|
||||
// t.Fatalf("expected period 1 to be assigned automatically, got %d", createResp.Data.Period)
|
||||
// }
|
||||
|
||||
// createdKandang := fetchKandang(t, db, kandangID)
|
||||
// if createdKandang.Status != string(utils.KandangStatusPengajuan) {
|
||||
// t.Fatalf("expected kandang status in DB to be PENGAJUAN, got %s", createdKandang.Status)
|
||||
// }
|
||||
|
||||
// var pivotRecords []entities.ProjectFlockKandang
|
||||
// if err := db.Where("project_flock_id = ?", createResp.Data.Id).Find(&pivotRecords).Error; err != nil {
|
||||
// t.Fatalf("failed to fetch pivot records: %v", err)
|
||||
// }
|
||||
// if len(pivotRecords) != 1 {
|
||||
// t.Fatalf("expected 1 pivot record, got %d", len(pivotRecords))
|
||||
// }
|
||||
// firstPivotRecord := pivotRecords[0]
|
||||
// if firstPivotRecord.KandangId != kandangID {
|
||||
// t.Fatalf("expected pivot kandang id %d, got %d", kandangID, firstPivotRecord.KandangId)
|
||||
// }
|
||||
|
||||
// secondKandangID := createKandang(t, app, "Kandang Summary 2", locationID, 1)
|
||||
// secondPayload := map[string]any{
|
||||
// "flock_id": flockID,
|
||||
// "area_id": areaID,
|
||||
// "category": "laying",
|
||||
// "fcr_id": fcrID,
|
||||
// "location_id": locationID,
|
||||
// "kandang_ids": []uint{secondKandangID},
|
||||
// }
|
||||
// resp, body = doJSONRequest(t, app, http.MethodPost, "/api/production/project_flocks", secondPayload)
|
||||
// if resp.StatusCode != fiber.StatusCreated {
|
||||
// t.Fatalf("expected 201 when creating second project flock, got %d: %s", resp.StatusCode, string(body))
|
||||
// }
|
||||
// var createRespSecond struct {
|
||||
// Data struct {
|
||||
// Id uint `json:"id"`
|
||||
// Period int `json:"period"`
|
||||
// Category string `json:"category"`
|
||||
// } `json:"data"`
|
||||
// }
|
||||
// if err := json.Unmarshal(body, &createRespSecond); err != nil {
|
||||
// t.Fatalf("failed to parse second create response: %v", err)
|
||||
// }
|
||||
// if createRespSecond.Data.Period != 2 {
|
||||
// t.Fatalf("expected second period to be 2, got %d", createRespSecond.Data.Period)
|
||||
// }
|
||||
// if createRespSecond.Data.Category != string(utils.ProjectFlockCategoryLaying) {
|
||||
// t.Fatalf("expected category to be %s, got %s", utils.ProjectFlockCategoryLaying, createRespSecond.Data.Category)
|
||||
// }
|
||||
|
||||
// pivotRecords = nil
|
||||
// if err := db.Where("project_flock_id = ?", createRespSecond.Data.Id).Find(&pivotRecords).Error; err != nil {
|
||||
// t.Fatalf("failed to fetch second pivot records: %v", err)
|
||||
// }
|
||||
// if len(pivotRecords) != 1 {
|
||||
// t.Fatalf("expected 1 pivot record for second project, got %d", len(pivotRecords))
|
||||
// }
|
||||
// secondPivotRecord := pivotRecords[0]
|
||||
// if secondPivotRecord.KandangId != secondKandangID {
|
||||
// t.Fatalf("expected second pivot kandang id %d, got %d", secondKandangID, secondPivotRecord.KandangId)
|
||||
// }
|
||||
|
||||
// secondKandang := fetchKandang(t, db, secondKandangID)
|
||||
// if secondKandang.Status != string(utils.KandangStatusPengajuan) {
|
||||
// t.Fatalf("expected second kandang status in DB to be PENGAJUAN, got %s", secondKandang.Status)
|
||||
// }
|
||||
|
||||
// resp, body = doJSONRequest(t, app, http.MethodGet, "/api/production/project_flocks/flocks/"+uintToString(flockID)+"/periods", nil)
|
||||
// if resp.StatusCode != fiber.StatusOK {
|
||||
// t.Fatalf("expected 200 when fetching summary, got %d: %s", resp.StatusCode, string(body))
|
||||
// }
|
||||
|
||||
// var summary struct {
|
||||
// Data struct {
|
||||
// NextPeriod int `json:"next_period"`
|
||||
// } `json:"data"`
|
||||
// }
|
||||
// if err := json.Unmarshal(body, &summary); err != nil {
|
||||
// t.Fatalf("failed to parse summary response: %v", err)
|
||||
// }
|
||||
|
||||
// if summary.Data.NextPeriod != 3 {
|
||||
// t.Fatalf("expected next_period 3, got %d", summary.Data.NextPeriod)
|
||||
// }
|
||||
|
||||
// resp, body = doJSONRequest(t, app, http.MethodDelete, "/api/production/project_flocks/"+uintToString(createResp.Data.Id), nil)
|
||||
// if resp.StatusCode != fiber.StatusOK {
|
||||
// t.Fatalf("expected 200 when deleting first project flock, got %d: %s", resp.StatusCode, string(body))
|
||||
// }
|
||||
|
||||
// firstKandang := fetchKandang(t, db, kandangID)
|
||||
// if firstKandang.ProjectFlockId != nil {
|
||||
// t.Fatalf("expected project_flock_id to be nil after delete, got %v", *firstKandang.ProjectFlockId)
|
||||
// }
|
||||
// if firstKandang.Status != string(utils.KandangStatusNonActive) {
|
||||
// t.Fatalf("expected kandang status to revert to NON_ACTIVE, got %s", firstKandang.Status)
|
||||
// }
|
||||
|
||||
// var remainingFirst int64
|
||||
// if err := db.Model(&entities.ProjectFlockKandang{}).
|
||||
// Where("project_flock_id = ? AND kandang_id = ?", createResp.Data.Id, kandangID).
|
||||
// Count(&remainingFirst).Error; err != nil {
|
||||
// t.Fatalf("failed to count first pivot records after delete: %v", err)
|
||||
// }
|
||||
// if remainingFirst != 0 {
|
||||
// t.Fatalf("expected no pivot records remaining after delete, found %d", remainingFirst)
|
||||
// }
|
||||
|
||||
// resp, body = doJSONRequest(t, app, http.MethodDelete, "/api/production/project_flocks/"+uintToString(createRespSecond.Data.Id), nil)
|
||||
// if resp.StatusCode != fiber.StatusOK {
|
||||
// t.Fatalf("expected 200 when deleting second project flock, got %d: %s", resp.StatusCode, string(body))
|
||||
// }
|
||||
|
||||
// secondKandang = fetchKandang(t, db, secondKandangID)
|
||||
// if secondKandang.ProjectFlockId != nil {
|
||||
// t.Fatalf("expected second project_flock_id to be nil after delete, got %v", *secondKandang.ProjectFlockId)
|
||||
// }
|
||||
// if secondKandang.Status != string(utils.KandangStatusNonActive) {
|
||||
// t.Fatalf("expected second kandang status to revert to NON_ACTIVE, got %s", secondKandang.Status)
|
||||
// }
|
||||
|
||||
// var remainingSecond int64
|
||||
// if err := db.Model(&entities.ProjectFlockKandang{}).
|
||||
// Where("project_flock_id = ? AND kandang_id = ?", createRespSecond.Data.Id, secondKandangID).
|
||||
// Count(&remainingSecond).Error; err != nil {
|
||||
// t.Fatalf("failed to count second pivot records after delete: %v", err)
|
||||
// }
|
||||
// if remainingSecond != 0 {
|
||||
// t.Fatalf("expected no second pivot records remaining after delete, found %d", remainingSecond)
|
||||
// }
|
||||
|
||||
// resp, body = doJSONRequest(t, app, http.MethodGet, "/api/production/project_flocks/flocks/"+uintToString(flockID)+"/periods", nil)
|
||||
// if resp.StatusCode != fiber.StatusOK {
|
||||
// t.Fatalf("expected 200 when fetching summary after delete, got %d: %s", resp.StatusCode, string(body))
|
||||
// }
|
||||
|
||||
// if err := json.Unmarshal(body, &summary); err != nil {
|
||||
// t.Fatalf("failed to parse summary response after delete: %v", err)
|
||||
// }
|
||||
|
||||
// if summary.Data.NextPeriod != 1 {
|
||||
// t.Fatalf("expected next_period 1 after soft deletes, got %d", summary.Data.NextPeriod)
|
||||
// }
|
||||
// }
|
||||
|
||||
// func uintToString(v uint) string {
|
||||
// return fmt.Sprintf("%d", v)
|
||||
// }
|
||||
|
||||
// func TestProjectFlockSearchByRelatedFields(t *testing.T) {
|
||||
// app, _ := setupIntegrationApp(t)
|
||||
|
||||
// areaID := createArea(t, app, "Area Search Target")
|
||||
// locationID := createLocation(t, app, "Location Search Target", "Location Address Target", areaID)
|
||||
// flockID := createFlock(t, app, "Flock Search Target")
|
||||
// fcrID := createFcr(t, app, "FCR Search Target", []map[string]any{
|
||||
// {"weight": 1.0, "fcr_number": 1.5, "mortality": 2.0},
|
||||
// })
|
||||
// kandangID := createKandang(t, app, "Kandang Search Target", locationID, 1)
|
||||
|
||||
// createPayload := map[string]any{
|
||||
// "flock_id": flockID,
|
||||
// "area_id": areaID,
|
||||
// "category": "growing",
|
||||
// "fcr_id": fcrID,
|
||||
// "location_id": locationID,
|
||||
// "kandang_ids": []uint{kandangID},
|
||||
// }
|
||||
|
||||
// resp, body := doJSONRequest(t, app, http.MethodPost, "/api/production/project_flocks", createPayload)
|
||||
// if resp.StatusCode != fiber.StatusCreated {
|
||||
// t.Fatalf("expected 201 when creating project flock, got %d: %s", resp.StatusCode, string(body))
|
||||
// }
|
||||
|
||||
// var createResp struct {
|
||||
// Data struct {
|
||||
// Id uint `json:"id"`
|
||||
// } `json:"data"`
|
||||
// }
|
||||
// if err := json.Unmarshal(body, &createResp); err != nil {
|
||||
// t.Fatalf("failed to parse create response: %v", err)
|
||||
// }
|
||||
|
||||
// searchTerms := []string{
|
||||
// "Flock Search Target",
|
||||
// "Area Search Target",
|
||||
// string(utils.ProjectFlockCategoryGrowing),
|
||||
// "growing",
|
||||
// "FCR Search Target",
|
||||
// "Kandang Search Target",
|
||||
// "Location Search Target",
|
||||
// "Location Address Target",
|
||||
// "Tester",
|
||||
// "1",
|
||||
// }
|
||||
|
||||
// for _, term := range searchTerms {
|
||||
// path := "/api/production/project_flocks?search=" + url.QueryEscape(term)
|
||||
// resp, body := doJSONRequest(t, app, http.MethodGet, path, nil)
|
||||
// if resp.StatusCode != fiber.StatusOK {
|
||||
// t.Fatalf("expected 200 when searching for %q, got %d: %s", term, resp.StatusCode, string(body))
|
||||
// }
|
||||
|
||||
// var listResp struct {
|
||||
// Data []struct {
|
||||
// Id uint `json:"id"`
|
||||
// } `json:"data"`
|
||||
// Meta struct {
|
||||
// TotalResults int64 `json:"total_results"`
|
||||
// } `json:"meta"`
|
||||
// }
|
||||
// if err := json.Unmarshal(body, &listResp); err != nil {
|
||||
// t.Fatalf("failed to parse list response for %q: %v", term, err)
|
||||
// }
|
||||
// if listResp.Meta.TotalResults == 0 {
|
||||
// t.Fatalf("expected at least one result when searching for %q", term)
|
||||
// }
|
||||
// if len(listResp.Data) == 0 {
|
||||
// t.Fatalf("expected data when searching for %q", term)
|
||||
// }
|
||||
// if listResp.Data[0].Id != createResp.Data.Id {
|
||||
// t.Fatalf("expected project flock id %d for search term %q, got %d", createResp.Data.Id, term, listResp.Data[0].Id)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// func TestProjectFlockSorting(t *testing.T) {
|
||||
// app, _ := setupIntegrationApp(t)
|
||||
|
||||
// areaA := createArea(t, app, "Area Alpha")
|
||||
// areaB := createArea(t, app, "Area Beta")
|
||||
|
||||
// locationA := createLocation(t, app, "Location Alpha", "Address Alpha", areaA)
|
||||
// locationB := createLocation(t, app, "Location Beta", "Address Beta", areaB)
|
||||
|
||||
// flockOne := createFlock(t, app, "Flock Sort One")
|
||||
// flockTwo := createFlock(t, app, "Flock Sort Two")
|
||||
|
||||
// fcrID := createFcr(t, app, "FCR Sort", []map[string]any{
|
||||
// {"weight": 1.0, "fcr_number": 1.5, "mortality": 2.0},
|
||||
// })
|
||||
|
||||
// kandangOne := createKandang(t, app, "Kandang Sort One", locationA, 1)
|
||||
// kandangTwo := createKandang(t, app, "Kandang Sort Two", locationB, 1)
|
||||
// kandangThree := createKandang(t, app, "Kandang Sort Three", locationB, 1)
|
||||
|
||||
// projectOnePayload := map[string]any{
|
||||
// "flock_id": flockOne,
|
||||
// "area_id": areaA,
|
||||
// "category": "growing",
|
||||
// "fcr_id": fcrID,
|
||||
// "location_id": locationA,
|
||||
// "kandang_ids": []uint{kandangOne},
|
||||
// }
|
||||
// resp, body := doJSONRequest(t, app, http.MethodPost, "/api/production/project_flocks", projectOnePayload)
|
||||
// if resp.StatusCode != fiber.StatusCreated {
|
||||
// t.Fatalf("expected 201 for project one, got %d: %s", resp.StatusCode, string(body))
|
||||
// }
|
||||
// projectOneID := parseProjectFlockID(t, body)
|
||||
|
||||
// projectTwoPayload := map[string]any{
|
||||
// "flock_id": flockTwo,
|
||||
// "area_id": areaB,
|
||||
// "category": "laying",
|
||||
// "fcr_id": fcrID,
|
||||
// "location_id": locationB,
|
||||
// "kandang_ids": []uint{kandangTwo, kandangThree},
|
||||
// }
|
||||
// resp, body = doJSONRequest(t, app, http.MethodPost, "/api/production/project_flocks", projectTwoPayload)
|
||||
// if resp.StatusCode != fiber.StatusCreated {
|
||||
// t.Fatalf("expected 201 for project two, got %d: %s", resp.StatusCode, string(body))
|
||||
// }
|
||||
// projectTwoID := parseProjectFlockID(t, body)
|
||||
|
||||
// updatePeriodPayload := map[string]any{"period": 5}
|
||||
// resp, body = doJSONRequest(t, app, http.MethodPatch, "/api/production/project_flocks/"+uintToString(projectTwoID), updatePeriodPayload)
|
||||
// if resp.StatusCode != fiber.StatusOK {
|
||||
// t.Fatalf("expected 200 when updating period, got %d: %s", resp.StatusCode, string(body))
|
||||
// }
|
||||
|
||||
// assertOrder := func(t *testing.T, app *fiber.App, query string, expectedFirst uint) {
|
||||
// t.Helper()
|
||||
// resp, body := doJSONRequest(t, app, http.MethodGet, "/api/production/project_flocks?"+query, nil)
|
||||
// if resp.StatusCode != fiber.StatusOK {
|
||||
// t.Fatalf("expected 200 for query %q, got %d: %s", query, resp.StatusCode, string(body))
|
||||
// }
|
||||
// var listResp struct {
|
||||
// Data []struct {
|
||||
// Id uint `json:"id"`
|
||||
// } `json:"data"`
|
||||
// }
|
||||
// if err := json.Unmarshal(body, &listResp); err != nil {
|
||||
// t.Fatalf("failed to parse list response for %q: %v", query, err)
|
||||
// }
|
||||
// if len(listResp.Data) == 0 {
|
||||
// t.Fatalf("expected data for query %q", query)
|
||||
// }
|
||||
// if listResp.Data[0].Id != expectedFirst {
|
||||
// t.Fatalf("expected first id %d for query %q, got %d", expectedFirst, query, listResp.Data[0].Id)
|
||||
// }
|
||||
// }
|
||||
|
||||
// assertOrder(t, app, "sort_by=area&sort_order=asc", projectOneID)
|
||||
// assertOrder(t, app, "sort_by=location&sort_order=desc", projectTwoID)
|
||||
// assertOrder(t, app, "sort_by=period&sort_order=desc", projectTwoID)
|
||||
// assertOrder(t, app, "sort_by=kandangs&sort_order=desc", projectTwoID)
|
||||
// assertOrder(t, app, "sort_by=kandangs&sort_order=asc", projectOneID)
|
||||
// }
|
||||
|
||||
// func parseProjectFlockID(t *testing.T, body []byte) uint {
|
||||
// t.Helper()
|
||||
// var resp struct {
|
||||
// Data struct {
|
||||
// Id uint `json:"id"`
|
||||
// } `json:"data"`
|
||||
// }
|
||||
// if err := json.Unmarshal(body, &resp); err != nil {
|
||||
// t.Fatalf("failed to parse project flock response: %v", err)
|
||||
// }
|
||||
// return resp.Data.Id
|
||||
// }
|
||||
@@ -1,238 +0,0 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"gitlab.com/mbugroup/lti-api.git/internal/entities"
|
||||
"gitlab.com/mbugroup/lti-api.git/internal/utils"
|
||||
)
|
||||
|
||||
func TestSupplierIntegration(t *testing.T) {
|
||||
app, db := setupIntegrationApp(t)
|
||||
|
||||
t.Run("creating supplier with invalid type fails", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/suppliers", map[string]any{
|
||||
"name": "Invalid Supplier",
|
||||
"alias": "inv01",
|
||||
"pic": "Jane Doe",
|
||||
"type": "random-type",
|
||||
"category": utils.SupplierCategoryBOP,
|
||||
"hatchery": "Hatchery X",
|
||||
"phone": "081234567891",
|
||||
"email": "invalid@supplier.com",
|
||||
"address": "Somewhere",
|
||||
"npwp": "NPWP-INVALID",
|
||||
"account_number": "ACC-INVALID",
|
||||
"due_date": 30,
|
||||
})
|
||||
if resp.StatusCode != fiber.StatusBadRequest {
|
||||
t.Fatalf("expected 400 when type is invalid, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("creating supplier with invalid category fails", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/suppliers", map[string]any{
|
||||
"name": "Invalid Category Supplier",
|
||||
"alias": "cat01",
|
||||
"pic": "Jane Doe",
|
||||
"type": utils.CustomerSupplierTypeBisnis,
|
||||
"category": "invalid",
|
||||
"phone": "081234567892",
|
||||
"email": "invalid-category@supplier.com",
|
||||
"address": "Somewhere",
|
||||
"due_date": 30,
|
||||
})
|
||||
if resp.StatusCode != fiber.StatusBadRequest {
|
||||
t.Fatalf("expected 400 when category is invalid, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
})
|
||||
|
||||
const supplierName = "Supplier Alpha"
|
||||
const alias = "al001"
|
||||
var supplierID uint
|
||||
|
||||
t.Run("creating supplier succeeds", func(t *testing.T) {
|
||||
supplierID = createSupplier(t, app, supplierName, alias, string(utils.SupplierCategoryBOP))
|
||||
supplier := fetchSupplier(t, db, supplierID)
|
||||
if supplier.Name != supplierName {
|
||||
t.Fatalf("expected name %q, got %q", supplierName, supplier.Name)
|
||||
}
|
||||
if supplier.Alias != strings.ToUpper(alias) {
|
||||
t.Fatalf("expected alias %q, got %q", strings.ToUpper(alias), supplier.Alias)
|
||||
}
|
||||
if supplier.Type != string(utils.CustomerSupplierTypeBisnis) {
|
||||
t.Fatalf("expected type %q, got %q", utils.CustomerSupplierTypeBisnis, supplier.Type)
|
||||
}
|
||||
if supplier.Category != string(utils.SupplierCategoryBOP) {
|
||||
t.Fatalf("expected category %q, got %q", utils.SupplierCategoryBOP, supplier.Category)
|
||||
}
|
||||
if supplier.DueDate != 30 {
|
||||
t.Fatalf("expected due date 30, got %d", supplier.DueDate)
|
||||
}
|
||||
if supplier.CreatedUser.Id != 1 {
|
||||
t.Fatalf("expected created user id 1, got %d", supplier.CreatedUser.Id)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("creating supplier with duplicate name fails", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/suppliers", map[string]any{
|
||||
"name": supplierName,
|
||||
"alias": "dup01",
|
||||
"pic": "Jane Doe",
|
||||
"type": utils.CustomerSupplierTypeBisnis,
|
||||
"category": utils.SupplierCategoryBOP,
|
||||
"phone": "0811111111",
|
||||
"email": "duplicate@supplier.com",
|
||||
"address": "Duplicate address",
|
||||
"due_date": 15,
|
||||
})
|
||||
if resp.StatusCode != fiber.StatusConflict {
|
||||
t.Fatalf("expected 409 when creating duplicate supplier, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("getting existing supplier succeeds", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodGet, fmt.Sprintf("/api/master-data/suppliers/%d", supplierID), nil)
|
||||
if resp.StatusCode != fiber.StatusOK {
|
||||
t.Fatalf("expected 200 when fetching supplier, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
var payload struct {
|
||||
Data struct {
|
||||
Id uint `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Alias string `json:"alias"`
|
||||
Type string `json:"type"`
|
||||
Category string `json:"category"`
|
||||
CreatedUser *struct {
|
||||
Id uint `json:"id"`
|
||||
} `json:"created_user"`
|
||||
} `json:"data"`
|
||||
}
|
||||
if err := json.Unmarshal(body, &payload); err != nil {
|
||||
t.Fatalf("failed to parse supplier response: %v", err)
|
||||
}
|
||||
if payload.Data.Id != supplierID {
|
||||
t.Fatalf("expected id %d, got %d", supplierID, payload.Data.Id)
|
||||
}
|
||||
if payload.Data.Name != supplierName {
|
||||
t.Fatalf("expected name %q, got %q", supplierName, payload.Data.Name)
|
||||
}
|
||||
if payload.Data.Alias != strings.ToUpper(alias) {
|
||||
t.Fatalf("expected alias %q, got %q", strings.ToUpper(alias), payload.Data.Alias)
|
||||
}
|
||||
if payload.Data.Type != string(utils.CustomerSupplierTypeBisnis) {
|
||||
t.Fatalf("expected type %q, got %q", utils.CustomerSupplierTypeBisnis, payload.Data.Type)
|
||||
}
|
||||
if payload.Data.Category != string(utils.SupplierCategoryBOP) {
|
||||
t.Fatalf("expected category %q, got %q", utils.SupplierCategoryBOP, payload.Data.Category)
|
||||
}
|
||||
if payload.Data.CreatedUser == nil || payload.Data.CreatedUser.Id != 1 {
|
||||
t.Fatalf("expected created_user id 1, got %+v", payload.Data.CreatedUser)
|
||||
}
|
||||
})
|
||||
|
||||
const updatedAlias = "beta1"
|
||||
|
||||
t.Run("updating supplier fields succeeds", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodPatch, fmt.Sprintf("/api/master-data/suppliers/%d", supplierID), map[string]any{
|
||||
"alias": updatedAlias,
|
||||
"type": utils.CustomerSupplierTypeIndividual,
|
||||
"category": utils.SupplierCategorySapronak,
|
||||
"due_date": 45,
|
||||
})
|
||||
if resp.StatusCode != fiber.StatusOK {
|
||||
t.Fatalf("expected 200 when updating supplier, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
var payload struct {
|
||||
Data struct {
|
||||
Alias string `json:"alias"`
|
||||
Type string `json:"type"`
|
||||
Category string `json:"category"`
|
||||
} `json:"data"`
|
||||
}
|
||||
if err := json.Unmarshal(body, &payload); err != nil {
|
||||
t.Fatalf("failed to parse update response: %v", err)
|
||||
}
|
||||
if payload.Data.Alias != strings.ToUpper(updatedAlias) {
|
||||
t.Fatalf("expected alias %q, got %q", strings.ToUpper(updatedAlias), payload.Data.Alias)
|
||||
}
|
||||
if payload.Data.Type != string(utils.CustomerSupplierTypeIndividual) {
|
||||
t.Fatalf("expected type %q, got %q", utils.CustomerSupplierTypeIndividual, payload.Data.Type)
|
||||
}
|
||||
if payload.Data.Category != string(utils.SupplierCategorySapronak) {
|
||||
t.Fatalf("expected category %q, got %q", utils.SupplierCategorySapronak, payload.Data.Category)
|
||||
}
|
||||
supplier := fetchSupplier(t, db, supplierID)
|
||||
if supplier.Alias != strings.ToUpper(updatedAlias) {
|
||||
t.Fatalf("expected persisted alias %q, got %q", strings.ToUpper(updatedAlias), supplier.Alias)
|
||||
}
|
||||
if supplier.Type != string(utils.CustomerSupplierTypeIndividual) {
|
||||
t.Fatalf("expected persisted type %q, got %q", utils.CustomerSupplierTypeIndividual, supplier.Type)
|
||||
}
|
||||
if supplier.Category != string(utils.SupplierCategorySapronak) {
|
||||
t.Fatalf("expected persisted category %q, got %q", utils.SupplierCategorySapronak, supplier.Category)
|
||||
}
|
||||
if supplier.DueDate != 45 {
|
||||
t.Fatalf("expected due date 45, got %d", supplier.DueDate)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("updating supplier with invalid type fails", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodPatch, fmt.Sprintf("/api/master-data/suppliers/%d", supplierID), map[string]any{
|
||||
"type": "invalid-type",
|
||||
})
|
||||
if resp.StatusCode != fiber.StatusBadRequest {
|
||||
t.Fatalf("expected 400 when updating with invalid type, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
supplier := fetchSupplier(t, db, supplierID)
|
||||
if supplier.Type != string(utils.CustomerSupplierTypeIndividual) {
|
||||
t.Fatalf("expected type to remain %q after invalid update, got %q", utils.CustomerSupplierTypeIndividual, supplier.Type)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("updating supplier with invalid category fails", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodPatch, fmt.Sprintf("/api/master-data/suppliers/%d", supplierID), map[string]any{
|
||||
"category": "invalid",
|
||||
})
|
||||
if resp.StatusCode != fiber.StatusBadRequest {
|
||||
t.Fatalf("expected 400 when updating with invalid category, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
supplier := fetchSupplier(t, db, supplierID)
|
||||
if supplier.Category != string(utils.SupplierCategorySapronak) {
|
||||
t.Fatalf("expected category to remain %q after invalid update, got %q", utils.SupplierCategorySapronak, supplier.Category)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("deleting supplier succeeds", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodDelete, fmt.Sprintf("/api/master-data/suppliers/%d", supplierID), nil)
|
||||
if resp.StatusCode != fiber.StatusOK {
|
||||
t.Fatalf("expected 200 when deleting supplier, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
var supplier entities.Supplier
|
||||
if err := db.First(&supplier, supplierID).Error; !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
t.Fatalf("expected supplier to be deleted, got error %v", err)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("deleting non existent supplier returns 404", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodDelete, fmt.Sprintf("/api/master-data/suppliers/%d", supplierID), nil)
|
||||
if resp.StatusCode != fiber.StatusNotFound {
|
||||
t.Fatalf("expected 404 when deleting missing supplier, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("getting deleted supplier returns 404", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodGet, fmt.Sprintf("/api/master-data/suppliers/%d", supplierID), nil)
|
||||
if resp.StatusCode != fiber.StatusNotFound {
|
||||
t.Fatalf("expected 404 when fetching deleted supplier, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
func TestWarehouseIntegration(t *testing.T) {
|
||||
app, db := setupIntegrationApp(t)
|
||||
areaID := createArea(t, app, "Warehouse Area")
|
||||
locationID := createLocation(t, app, "Location WH", "Addr", areaID)
|
||||
kandangID := createKandang(t, app, "Kandang WH", locationID, 1)
|
||||
|
||||
t.Run("type AREA only needs area_id", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/warehouses", map[string]any{
|
||||
"name": "WH Area",
|
||||
"type": "AREA",
|
||||
"area_id": areaID,
|
||||
})
|
||||
if resp.StatusCode != fiber.StatusCreated {
|
||||
t.Fatalf("expected 201, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("type AREA rejects location_id", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/warehouses", map[string]any{
|
||||
"name": "WH Area Invalid",
|
||||
"type": "AREA",
|
||||
"area_id": areaID,
|
||||
"location_id": locationID,
|
||||
})
|
||||
if resp.StatusCode != fiber.StatusBadRequest {
|
||||
t.Fatalf("expected 400, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("type LOKASI requires location_id", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/warehouses", map[string]any{
|
||||
"name": "WH Lokasi Fail",
|
||||
"type": "LOKASI",
|
||||
"area_id": areaID,
|
||||
})
|
||||
if resp.StatusCode != fiber.StatusBadRequest {
|
||||
t.Fatalf("expected 400, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("type LOKASI success", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/warehouses", map[string]any{
|
||||
"name": "WH Lokasi",
|
||||
"type": "LOKASI",
|
||||
"area_id": areaID,
|
||||
"location_id": locationID,
|
||||
})
|
||||
if resp.StatusCode != fiber.StatusCreated {
|
||||
t.Fatalf("expected 201, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
whID := parseID(t, body)
|
||||
wh := fetchWarehouse(t, db, whID)
|
||||
if wh.LocationId == nil || *wh.LocationId != locationID {
|
||||
t.Fatalf("expected location_id %d, got %v", locationID, wh.LocationId)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("type KANDANG requires all ids", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/warehouses", map[string]any{
|
||||
"name": "WH Kandang Fail",
|
||||
"type": "KANDANG",
|
||||
"area_id": areaID,
|
||||
"location_id": locationID,
|
||||
})
|
||||
if resp.StatusCode != fiber.StatusBadRequest {
|
||||
t.Fatalf("expected 400, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("type KANDANG success", func(t *testing.T) {
|
||||
resp, body := doJSONRequest(t, app, http.MethodPost, "/api/master-data/warehouses", map[string]any{
|
||||
"name": "WH Kandang",
|
||||
"type": "KANDANG",
|
||||
"area_id": areaID,
|
||||
"location_id": locationID,
|
||||
"kandang_id": kandangID,
|
||||
})
|
||||
if resp.StatusCode != fiber.StatusCreated {
|
||||
t.Fatalf("expected 201, got %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
whID := parseID(t, body)
|
||||
wh := fetchWarehouse(t, db, whID)
|
||||
if wh.KandangId == nil || *wh.KandangId != kandangID {
|
||||
t.Fatalf("expected kandang_id %d, got %v", kandangID, wh.KandangId)
|
||||
}
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user