diff --git a/api/handlers.go b/api/handlers.go deleted file mode 100644 index 0a4d0c4..0000000 --- a/api/handlers.go +++ /dev/null @@ -1,20 +0,0 @@ -package api - -import ( - "github.com/gofiber/fiber/v2" -) - -type Handler struct { - // dependencies -} - -func NewHandler() *Handler { - return &Handler{} -} - -func (h *Handler) HealthCheck(c *fiber.Ctx) error { - return c.JSON(fiber.Map{ - "status": "success", - "message": "Server is running", - }) -} diff --git a/api/routes.go b/api/routes.go new file mode 100644 index 0000000..ba5ec5a --- /dev/null +++ b/api/routes.go @@ -0,0 +1,15 @@ +package api + +import ( + "BE-MiniERP/modules/auth" + "BE-MiniERP/modules/inventory" + "BE-MiniERP/modules/sales" + + "github.com/gofiber/fiber/v2" +) + +func SetupRoutes(app *fiber.App) { + auth.RegisterRoutes(app.Group("/auth")) + inventory.RegisterRoutes(app.Group("/inventory")) + sales.RegisterRoutes(app.Group("/sales")) +} diff --git a/cmd/main.go b/cmd/main.go new file mode 100644 index 0000000..b66cde3 --- /dev/null +++ b/cmd/main.go @@ -0,0 +1,26 @@ +package main + +import ( + "log" + + "BE-MiniERP/api" + "BE-MiniERP/database" // pastikan ini sesuai dengan module di go.mod + + "github.com/gofiber/fiber/v2" +) + +func main() { + // Koneksi database + database.Connect() + + // Inisialisasi Fiber + app := fiber.New() + + // Setup semua routing dari API + api.SetupRoutes(app) + + // Jalankan server + if err := app.Listen(":3000"); err != nil { + log.Fatal("Gagal menjalankan server:", err) + } +} diff --git a/config/config.go b/config/config.go new file mode 100644 index 0000000..a2d6483 --- /dev/null +++ b/config/config.go @@ -0,0 +1,15 @@ +package config + +import "os" + +type Config struct { + DBUrl string + JWTSecret string +} + +func GetConfig() Config { + return Config{ + DBUrl: os.Getenv("DB_URL"), + JWTSecret: os.Getenv("JWT_SECRET"), + } +} diff --git a/database/database.go b/database/database.go index 5591fe5..c78a3e4 100644 --- a/database/database.go +++ b/database/database.go @@ -1,6 +1,8 @@ package database import ( + "log" + "gorm.io/driver/postgres" "gorm.io/gorm" ) @@ -8,16 +10,10 @@ import ( var DB *gorm.DB func Connect() { - dsn := "host=10.5.50.9 user=probindo password=probindo dbname=minierp port=5432 sslmode=disable TimeZone=Asia/Jakarta" - db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{}) + dsn := "host=10.5.50.9 user=probindo password=Pr08ind0 dbname=erp port=5432 sslmode=disable" + var err error + DB, err = gorm.Open(postgres.Open(dsn), &gorm.Config{}) if err != nil { - panic("failed to connect database") + log.Fatal("Failed to connect to DB:", err) } - - DB = db -} - -func AutoMigrate() { - // Tambahkan model-model di sini untuk auto migration - // DB.AutoMigrate(&models.User{}, &models.Product{}) } diff --git a/go.mod b/go.mod index eba5ad9..5b1a5e4 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module fiber-demo +module BE-MiniERP go 1.24.4 @@ -6,6 +6,7 @@ require github.com/gofiber/fiber/v2 v2.52.8 require ( github.com/andybalholm/brotli v1.1.0 // indirect + github.com/golang-jwt/jwt/v4 v4.5.2 github.com/google/uuid v1.6.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect diff --git a/go.sum b/go.sum index f96df41..12de186 100644 --- a/go.sum +++ b/go.sum @@ -3,6 +3,8 @@ github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer5 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/gofiber/fiber/v2 v2.52.8 h1:xl4jJQ0BV5EJTA2aWiKw/VddRpHrKeZLF0QPUxqn0x4= github.com/gofiber/fiber/v2 v2.52.8/go.mod h1:YEcBbO/FB+5M1IZNBP9FO3J9281zgPAreiI1oqg8nDw= +github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI= +github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= diff --git a/main.go b/main.go deleted file mode 100644 index 2b3269e..0000000 --- a/main.go +++ /dev/null @@ -1,50 +0,0 @@ -package main - -import ( - "fiber-demo/database" - "log" - - "github.com/gofiber/fiber/v2" -) - -func main() { - database.Connect() - database.AutoMigrate() - // Inisialisasi aplikasi Fiber - app := fiber.New() - - // Route untuk halaman utama - app.Get("/", func(c *fiber.Ctx) error { - return c.SendString("Hello, World! 👋") - }) - - // Route untuk GET /api/greeting - app.Get("/api/greeting", func(c *fiber.Ctx) error { - return c.JSON(fiber.Map{ - "message": "Hello from Fiber API!", - "status": "success", - }) - }) - - // Route untuk POST /api/greeting - app.Post("/api/greeting", func(c *fiber.Ctx) error { - type Request struct { - Name string `json:"name"` - } - - var body Request - if err := c.BodyParser(&body); err != nil { - return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{ - "error": "Cannot parse JSON", - }) - } - - return c.JSON(fiber.Map{ - "message": "Hello, " + body.Name + "!", - "status": "success", - }) - }) - - // Menjalankan server di port 3000 - log.Fatal(app.Listen(":3000")) -} diff --git a/middlewares/jwt.go b/middlewares/jwt.go new file mode 100644 index 0000000..3dcb893 --- /dev/null +++ b/middlewares/jwt.go @@ -0,0 +1,30 @@ +package middlewares + +import ( + "BE-MiniERP/config" + "strings" + + "github.com/gofiber/fiber/v2" + "github.com/golang-jwt/jwt/v4" +) + +func JWTProtected() fiber.Handler { + return func(c *fiber.Ctx) error { + authHeader := c.Get("Authorization") + if authHeader == "" { + return c.SendStatus(fiber.StatusUnauthorized) + } + + tokenString := strings.TrimPrefix(authHeader, "Bearer ") + token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) { + return []byte(config.GetConfig().JWTSecret), nil + }) + + if err != nil || !token.Valid { + return c.SendStatus(fiber.StatusUnauthorized) + } + + c.Locals("user", token.Claims) + return c.Next() + } +} diff --git a/middlewares/logger.go b/middlewares/logger.go new file mode 100644 index 0000000..85dbcf7 --- /dev/null +++ b/middlewares/logger.go @@ -0,0 +1,18 @@ +package middlewares + +import ( + "fmt" + "time" + + "github.com/gofiber/fiber/v2" +) + +func Logger() fiber.Handler { + return func(c *fiber.Ctx) error { + start := time.Now() + err := c.Next() + duration := time.Since(start) + fmt.Printf("[%s] %s %s (%v)\n", c.Method(), c.Path(), c.IP(), duration) + return err + } +} diff --git a/modules/auth/handler/auth_handler.go b/modules/auth/handler/auth_handler.go new file mode 100644 index 0000000..167bb6a --- /dev/null +++ b/modules/auth/handler/auth_handler.go @@ -0,0 +1,72 @@ +package handler + +import ( + "BE-MiniERP/database" + "BE-MiniERP/modules/auth/models" + "BE-MiniERP/modules/auth/repository" + "BE-MiniERP/modules/auth/service" + + "github.com/gofiber/fiber/v2" +) + +type AuthHandler struct { + Repo *repository.UserRepository +} + +func NewAuthHandler() *AuthHandler { + return &AuthHandler{ + Repo: repository.NewUserRepository(database.DB), + } +} + +func (h *AuthHandler) Register(c *fiber.Ctx) error { + var input struct { + Username string `json:"username"` + Password string `json:"password"` + Role string `json:"role"` + } + + if err := c.BodyParser(&input); err != nil { + return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "invalid input"}) + } + + hash, err := service.HashPassword(input.Password) + if err != nil { + return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "failed to hash password"}) + } + + user := &models.User{ + Username: input.Username, + PasswordHash: hash, + Role: input.Role, + } + + if err := h.Repo.Create(user); err != nil { + return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "failed to create user"}) + } + + return c.JSON(fiber.Map{"message": "user registered"}) +} + +func (h *AuthHandler) Login(c *fiber.Ctx) error { + var input struct { + Username string `json:"username"` + Password string `json:"password"` + } + + if err := c.BodyParser(&input); err != nil { + return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "invalid input"}) + } + + user, err := h.Repo.FindByUsername(input.Username) + if err != nil || !service.CheckPasswordHash(input.Password, user.PasswordHash) { + return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{"error": "invalid credentials"}) + } + + token, err := service.GenerateJWT(user.ID, user.Role) + if err != nil { + return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "failed to generate token"}) + } + + return c.JSON(fiber.Map{"token": token, "role": user.Role}) +} diff --git a/modules/auth/models/user.go b/modules/auth/models/user.go new file mode 100644 index 0000000..c2b649b --- /dev/null +++ b/modules/auth/models/user.go @@ -0,0 +1,12 @@ +package models + +import "time" + +type User struct { + ID uint `gorm:"primaryKey" json:"id"` + Username string `gorm:"unique" json:"username"` + PasswordHash string `json:"-"` + Role string `json:"role"` // admin, sales, warehouse, etc + CreatedAt time.Time + UpdatedAt time.Time +} diff --git a/modules/auth/repository/user_repo.go b/modules/auth/repository/user_repo.go new file mode 100644 index 0000000..9176e33 --- /dev/null +++ b/modules/auth/repository/user_repo.go @@ -0,0 +1,25 @@ +package repository + +import ( + "BE-MiniERP/modules/auth/models" + + "gorm.io/gorm" +) + +type UserRepository struct { + DB *gorm.DB +} + +func NewUserRepository(db *gorm.DB) *UserRepository { + return &UserRepository{DB: db} +} + +func (r *UserRepository) Create(user *models.User) error { + return r.DB.Create(user).Error +} + +func (r *UserRepository) FindByUsername(username string) (*models.User, error) { + var user models.User + result := r.DB.Where("username = ?", username).First(&user) + return &user, result.Error +} diff --git a/modules/auth/routes.go b/modules/auth/routes.go new file mode 100644 index 0000000..0724e89 --- /dev/null +++ b/modules/auth/routes.go @@ -0,0 +1,13 @@ +package auth + +import ( + "BE-MiniERP/modules/auth/handler" + + "github.com/gofiber/fiber/v2" +) + +func RegisterRoutes(r fiber.Router) { + h := handler.NewAuthHandler() + r.Post("/register", h.Register) + r.Post("/login", h.Login) +} diff --git a/modules/auth/service/auth_logic.go b/modules/auth/service/auth_logic.go new file mode 100644 index 0000000..43cfb37 --- /dev/null +++ b/modules/auth/service/auth_logic.go @@ -0,0 +1,15 @@ +package service + +import ( + "golang.org/x/crypto/bcrypt" +) + +func HashPassword(password string) (string, error) { + bytes, err := bcrypt.GenerateFromPassword([]byte(password), 14) + return string(bytes), err +} + +func CheckPasswordHash(password, hash string) bool { + err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password)) + return err == nil +} diff --git a/modules/auth/service/jwt.go b/modules/auth/service/jwt.go new file mode 100644 index 0000000..3565292 --- /dev/null +++ b/modules/auth/service/jwt.go @@ -0,0 +1,27 @@ +package service + +import ( + "time" + + "github.com/golang-jwt/jwt/v4" +) + +var jwtKey = []byte("supersecret") // sebaiknya dari env + +type Claims struct { + UserID uint `json:"user_id"` + Role string `json:"role"` + jwt.RegisteredClaims +} + +func GenerateJWT(userID uint, role string) (string, error) { + claims := &Claims{ + UserID: userID, + Role: role, + RegisteredClaims: jwt.RegisteredClaims{ + ExpiresAt: jwt.NewNumericDate(time.Now().Add(24 * time.Hour)), + }, + } + token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) + return token.SignedString(jwtKey) +} diff --git a/modules/inventory/handler/collection_handler.go b/modules/inventory/handler/collection_handler.go new file mode 100644 index 0000000..00da454 --- /dev/null +++ b/modules/inventory/handler/collection_handler.go @@ -0,0 +1,59 @@ +package handler + +import ( + "BE-MiniERP/database" + "BE-MiniERP/modules/inventory/models" + "BE-MiniERP/modules/inventory/repository" + "strconv" + + "github.com/gofiber/fiber/v2" +) + +type CollectionHandler struct { + Repo *repository.CollectionRepository +} + +func NewCollectionHandler() *CollectionHandler { + return &CollectionHandler{ + Repo: repository.NewCollectionRepository(database.DB), + } +} + +func (h *CollectionHandler) GetAll(c *fiber.Ctx) error { + collections, err := h.Repo.FindAll() + if err != nil { + return c.Status(500).JSON(fiber.Map{"error": "Failed to fetch collections"}) + } + return c.JSON(collections) +} + +func (h *CollectionHandler) Create(c *fiber.Ctx) error { + var input models.Collection + if err := c.BodyParser(&input); err != nil { + return c.Status(400).JSON(fiber.Map{"error": "Invalid input"}) + } + if err := h.Repo.Create(&input); err != nil { + return c.Status(500).JSON(fiber.Map{"error": "Failed to create collection"}) + } + return c.JSON(input) +} + +func (h *CollectionHandler) Update(c *fiber.Ctx) error { + id, _ := strconv.Atoi(c.Params("id")) + var input models.Collection + if err := c.BodyParser(&input); err != nil { + return c.Status(400).JSON(fiber.Map{"error": "Invalid input"}) + } + if err := h.Repo.Update(uint(id), &input); err != nil { + return c.Status(500).JSON(fiber.Map{"error": "Failed to update collection"}) + } + return c.JSON(fiber.Map{"message": "Collection updated"}) +} + +func (h *CollectionHandler) Delete(c *fiber.Ctx) error { + id, _ := strconv.Atoi(c.Params("id")) + if err := h.Repo.Delete(uint(id)); err != nil { + return c.Status(500).JSON(fiber.Map{"error": "Failed to delete collection"}) + } + return c.JSON(fiber.Map{"message": "Collection deleted"}) +} diff --git a/modules/inventory/handler/colour_handler.go b/modules/inventory/handler/colour_handler.go new file mode 100644 index 0000000..71c1a0c --- /dev/null +++ b/modules/inventory/handler/colour_handler.go @@ -0,0 +1,59 @@ +package handler + +import ( + "BE-MiniERP/database" + "BE-MiniERP/modules/inventory/models" + "BE-MiniERP/modules/inventory/repository" + "strconv" + + "github.com/gofiber/fiber/v2" +) + +type ColourHandler struct { + Repo *repository.ColourRepository +} + +func NewColourHandler() *ColourHandler { + return &ColourHandler{ + Repo: repository.NewColourRepository(database.DB), + } +} + +func (h *ColourHandler) GetAll(c *fiber.Ctx) error { + colours, err := h.Repo.FindAll() + if err != nil { + return c.Status(500).JSON(fiber.Map{"error": "Failed to fetch colours"}) + } + return c.JSON(colours) +} + +func (h *ColourHandler) Create(c *fiber.Ctx) error { + var input models.Colour + if err := c.BodyParser(&input); err != nil { + return c.Status(400).JSON(fiber.Map{"error": "Invalid input"}) + } + if err := h.Repo.Create(&input); err != nil { + return c.Status(500).JSON(fiber.Map{"error": "Failed to create colour"}) + } + return c.JSON(input) +} + +func (h *ColourHandler) Update(c *fiber.Ctx) error { + id, _ := strconv.Atoi(c.Params("id")) + var input models.Colour + if err := c.BodyParser(&input); err != nil { + return c.Status(400).JSON(fiber.Map{"error": "Invalid input"}) + } + if err := h.Repo.Update(uint(id), &input); err != nil { + return c.Status(500).JSON(fiber.Map{"error": "Failed to update colour"}) + } + return c.JSON(fiber.Map{"message": "Colour updated"}) +} + +func (h *ColourHandler) Delete(c *fiber.Ctx) error { + id, _ := strconv.Atoi(c.Params("id")) + if err := h.Repo.Delete(uint(id)); err != nil { + return c.Status(500).JSON(fiber.Map{"error": "Failed to delete colour"}) + } + return c.JSON(fiber.Map{"message": "Colour deleted"}) +} diff --git a/modules/inventory/handler/product_category_handler.go b/modules/inventory/handler/product_category_handler.go new file mode 100644 index 0000000..84d876b --- /dev/null +++ b/modules/inventory/handler/product_category_handler.go @@ -0,0 +1,59 @@ +package handler + +import ( + "BE-MiniERP/database" + "BE-MiniERP/modules/inventory/models" + "BE-MiniERP/modules/inventory/repository" + "strconv" + + "github.com/gofiber/fiber/v2" +) + +type CategoryHandler struct { + Repo *repository.CategoryRepository +} + +func NewCategoryHandler() *CategoryHandler { + return &CategoryHandler{ + Repo: repository.NewCategoryRepository(database.DB), + } +} + +func (h *CategoryHandler) GetAll(c *fiber.Ctx) error { + categories, err := h.Repo.FindAll() + if err != nil { + return c.Status(500).JSON(fiber.Map{"error": "Failed to fetch categories"}) + } + return c.JSON(categories) +} + +func (h *CategoryHandler) Create(c *fiber.Ctx) error { + var input models.ProductCategory + if err := c.BodyParser(&input); err != nil { + return c.Status(400).JSON(fiber.Map{"error": "Invalid input"}) + } + if err := h.Repo.Create(&input); err != nil { + return c.Status(500).JSON(fiber.Map{"error": "Failed to create category"}) + } + return c.JSON(input) +} + +func (h *CategoryHandler) Update(c *fiber.Ctx) error { + id, _ := strconv.Atoi(c.Params("id")) + var input models.ProductCategory + if err := c.BodyParser(&input); err != nil { + return c.Status(400).JSON(fiber.Map{"error": "Invalid input"}) + } + if err := h.Repo.Update(uint(id), &input); err != nil { + return c.Status(500).JSON(fiber.Map{"error": "Failed to update category"}) + } + return c.JSON(fiber.Map{"message": "Category updated"}) +} + +func (h *CategoryHandler) Delete(c *fiber.Ctx) error { + id, _ := strconv.Atoi(c.Params("id")) + if err := h.Repo.Delete(uint(id)); err != nil { + return c.Status(500).JSON(fiber.Map{"error": "Failed to delete category"}) + } + return c.JSON(fiber.Map{"message": "Category deleted"}) +} diff --git a/modules/inventory/handler/product_component_handler.go b/modules/inventory/handler/product_component_handler.go new file mode 100644 index 0000000..a801a5a --- /dev/null +++ b/modules/inventory/handler/product_component_handler.go @@ -0,0 +1,47 @@ +package handler + +import ( + "BE-MiniERP/database" + "BE-MiniERP/modules/inventory/models" + "BE-MiniERP/modules/inventory/repository" + "strconv" + + "github.com/gofiber/fiber/v2" +) + +type ProductComponentHandler struct { + Repo *repository.ProductComponentRepository +} + +func NewProductComponentHandler() *ProductComponentHandler { + return &ProductComponentHandler{ + Repo: repository.NewProductComponentRepository(database.DB), + } +} + +func (h *ProductComponentHandler) GetAll(c *fiber.Ctx) error { + result, err := h.Repo.FindAll() + if err != nil { + return c.Status(500).JSON(fiber.Map{"error": "Failed to fetch components"}) + } + return c.JSON(result) +} + +func (h *ProductComponentHandler) Create(c *fiber.Ctx) error { + var input models.ProductComponent + if err := c.BodyParser(&input); err != nil { + return c.Status(400).JSON(fiber.Map{"error": "Invalid input"}) + } + if err := h.Repo.Create(&input); err != nil { + return c.Status(500).JSON(fiber.Map{"error": "Failed to create component entry"}) + } + return c.JSON(input) +} + +func (h *ProductComponentHandler) Delete(c *fiber.Ctx) error { + id, _ := strconv.Atoi(c.Params("id")) + if err := h.Repo.Delete(uint(id)); err != nil { + return c.Status(500).JSON(fiber.Map{"error": "Failed to delete component entry"}) + } + return c.JSON(fiber.Map{"message": "Deleted successfully"}) +} diff --git a/modules/inventory/handler/product_handler.go b/modules/inventory/handler/product_handler.go new file mode 100644 index 0000000..5037cbb --- /dev/null +++ b/modules/inventory/handler/product_handler.go @@ -0,0 +1,59 @@ +package handler + +import ( + "BE-MiniERP/database" + "BE-MiniERP/modules/inventory/models" + "BE-MiniERP/modules/inventory/repository" + "strconv" + + "github.com/gofiber/fiber/v2" +) + +type ProductHandler struct { + Repo *repository.ProductRepository +} + +func NewProductHandler() *ProductHandler { + return &ProductHandler{ + Repo: repository.NewProductRepository(database.DB), + } +} + +func (h *ProductHandler) GetAll(c *fiber.Ctx) error { + products, err := h.Repo.FindAll() + if err != nil { + return c.Status(500).JSON(fiber.Map{"error": "Failed to fetch products"}) + } + return c.JSON(products) +} + +func (h *ProductHandler) Create(c *fiber.Ctx) error { + var input models.Product + if err := c.BodyParser(&input); err != nil { + return c.Status(400).JSON(fiber.Map{"error": "Invalid input"}) + } + if err := h.Repo.Create(&input); err != nil { + return c.Status(500).JSON(fiber.Map{"error": "Failed to create product"}) + } + return c.JSON(input) +} + +func (h *ProductHandler) Update(c *fiber.Ctx) error { + id, _ := strconv.Atoi(c.Params("id")) + var input models.Product + if err := c.BodyParser(&input); err != nil { + return c.Status(400).JSON(fiber.Map{"error": "Invalid input"}) + } + if err := h.Repo.Update(uint(id), &input); err != nil { + return c.Status(500).JSON(fiber.Map{"error": "Failed to update product"}) + } + return c.JSON(fiber.Map{"message": "Product updated"}) +} + +func (h *ProductHandler) Delete(c *fiber.Ctx) error { + id, _ := strconv.Atoi(c.Params("id")) + if err := h.Repo.Delete(uint(id)); err != nil { + return c.Status(500).JSON(fiber.Map{"error": "Failed to delete product"}) + } + return c.JSON(fiber.Map{"message": "Product deleted"}) +} diff --git a/modules/inventory/handler/production_order_handler.go b/modules/inventory/handler/production_order_handler.go new file mode 100644 index 0000000..be829f4 --- /dev/null +++ b/modules/inventory/handler/production_order_handler.go @@ -0,0 +1,59 @@ +package handler + +import ( + "BE-MiniERP/database" + "BE-MiniERP/modules/inventory/models" + "BE-MiniERP/modules/inventory/repository" + "strconv" + + "github.com/gofiber/fiber/v2" +) + +type ProductionOrderHandler struct { + Repo *repository.ProductionOrderRepository +} + +func NewProductionOrderHandler() *ProductionOrderHandler { + return &ProductionOrderHandler{ + Repo: repository.NewProductionOrderRepository(database.DB), + } +} + +func (h *ProductionOrderHandler) GetAll(c *fiber.Ctx) error { + data, err := h.Repo.FindAll() + if err != nil { + return c.Status(500).JSON(fiber.Map{"error": "Failed to fetch production orders"}) + } + return c.JSON(data) +} + +func (h *ProductionOrderHandler) Create(c *fiber.Ctx) error { + var input models.ProductionOrder + if err := c.BodyParser(&input); err != nil { + return c.Status(400).JSON(fiber.Map{"error": "Invalid input"}) + } + if err := h.Repo.Create(&input); err != nil { + return c.Status(500).JSON(fiber.Map{"error": "Failed to create production order"}) + } + return c.JSON(input) +} + +func (h *ProductionOrderHandler) Update(c *fiber.Ctx) error { + id, _ := strconv.Atoi(c.Params("id")) + var input models.ProductionOrder + if err := c.BodyParser(&input); err != nil { + return c.Status(400).JSON(fiber.Map{"error": "Invalid input"}) + } + if err := h.Repo.Update(uint(id), &input); err != nil { + return c.Status(500).JSON(fiber.Map{"error": "Failed to update production order"}) + } + return c.JSON(fiber.Map{"message": "Updated"}) +} + +func (h *ProductionOrderHandler) Delete(c *fiber.Ctx) error { + id, _ := strconv.Atoi(c.Params("id")) + if err := h.Repo.Delete(uint(id)); err != nil { + return c.Status(500).JSON(fiber.Map{"error": "Failed to delete production order"}) + } + return c.JSON(fiber.Map{"message": "Deleted"}) +} diff --git a/modules/inventory/handler/size_handler.go b/modules/inventory/handler/size_handler.go new file mode 100644 index 0000000..175bbab --- /dev/null +++ b/modules/inventory/handler/size_handler.go @@ -0,0 +1,59 @@ +package handler + +import ( + "BE-MiniERP/database" + "BE-MiniERP/modules/inventory/models" + "BE-MiniERP/modules/inventory/repository" + "strconv" + + "github.com/gofiber/fiber/v2" +) + +type SizeHandler struct { + Repo *repository.SizeRepository +} + +func NewSizeHandler() *SizeHandler { + return &SizeHandler{ + Repo: repository.NewSizeRepository(database.DB), + } +} + +func (h *SizeHandler) GetAll(c *fiber.Ctx) error { + sizes, err := h.Repo.FindAll() + if err != nil { + return c.Status(500).JSON(fiber.Map{"error": "Failed to fetch sizes"}) + } + return c.JSON(sizes) +} + +func (h *SizeHandler) Create(c *fiber.Ctx) error { + var input models.Size + if err := c.BodyParser(&input); err != nil { + return c.Status(400).JSON(fiber.Map{"error": "Invalid input"}) + } + if err := h.Repo.Create(&input); err != nil { + return c.Status(500).JSON(fiber.Map{"error": "Failed to create size"}) + } + return c.JSON(input) +} + +func (h *SizeHandler) Update(c *fiber.Ctx) error { + id, _ := strconv.Atoi(c.Params("id")) + var input models.Size + if err := c.BodyParser(&input); err != nil { + return c.Status(400).JSON(fiber.Map{"error": "Invalid input"}) + } + if err := h.Repo.Update(uint(id), &input); err != nil { + return c.Status(500).JSON(fiber.Map{"error": "Failed to update size"}) + } + return c.JSON(fiber.Map{"message": "Size updated"}) +} + +func (h *SizeHandler) Delete(c *fiber.Ctx) error { + id, _ := strconv.Atoi(c.Params("id")) + if err := h.Repo.Delete(uint(id)); err != nil { + return c.Status(500).JSON(fiber.Map{"error": "Failed to delete size"}) + } + return c.JSON(fiber.Map{"message": "Size deleted"}) +} diff --git a/modules/inventory/handler/stock_movement_handler.go b/modules/inventory/handler/stock_movement_handler.go new file mode 100644 index 0000000..e8e4040 --- /dev/null +++ b/modules/inventory/handler/stock_movement_handler.go @@ -0,0 +1,40 @@ +package handler + +import ( + "BE-MiniERP/database" + "BE-MiniERP/modules/inventory/models" + "BE-MiniERP/modules/inventory/repository" + + "github.com/gofiber/fiber/v2" +) + +type StockMovementHandler struct { + Repo *repository.StockMovementRepository +} + +func NewStockMovementHandler() *StockMovementHandler { + return &StockMovementHandler{ + Repo: repository.NewStockMovementRepository(database.DB), + } +} + +func (h *StockMovementHandler) GetAll(c *fiber.Ctx) error { + data, err := h.Repo.FindAll() + if err != nil { + return c.Status(500).JSON(fiber.Map{"error": "Failed to fetch stock movements"}) + } + return c.JSON(data) +} + +func (h *StockMovementHandler) Create(c *fiber.Ctx) error { + var input models.StockMovement + if err := c.BodyParser(&input); err != nil { + return c.Status(400).JSON(fiber.Map{"error": "Invalid input"}) + } + + if err := h.Repo.Create(&input); err != nil { + return c.Status(500).JSON(fiber.Map{"error": "Failed to create stock movement"}) + } + + return c.JSON(input) +} diff --git a/modules/inventory/handler/warehouse_handler.go b/modules/inventory/handler/warehouse_handler.go new file mode 100644 index 0000000..879af0b --- /dev/null +++ b/modules/inventory/handler/warehouse_handler.go @@ -0,0 +1,59 @@ +package handler + +import ( + "BE-MiniERP/database" + "BE-MiniERP/modules/inventory/models" + "BE-MiniERP/modules/inventory/repository" + "strconv" + + "github.com/gofiber/fiber/v2" +) + +type WarehouseHandler struct { + Repo *repository.WarehouseRepository +} + +func NewWarehouseHandler() *WarehouseHandler { + return &WarehouseHandler{ + Repo: repository.NewWarehouseRepository(database.DB), + } +} + +func (h *WarehouseHandler) GetAll(c *fiber.Ctx) error { + warehouses, err := h.Repo.FindAll() + if err != nil { + return c.Status(500).JSON(fiber.Map{"error": "Failed to fetch warehouses"}) + } + return c.JSON(warehouses) +} + +func (h *WarehouseHandler) Create(c *fiber.Ctx) error { + var input models.Warehouse + if err := c.BodyParser(&input); err != nil { + return c.Status(400).JSON(fiber.Map{"error": "Invalid input"}) + } + if err := h.Repo.Create(&input); err != nil { + return c.Status(500).JSON(fiber.Map{"error": "Failed to create warehouse"}) + } + return c.JSON(input) +} + +func (h *WarehouseHandler) Update(c *fiber.Ctx) error { + id, _ := strconv.Atoi(c.Params("id")) + var input models.Warehouse + if err := c.BodyParser(&input); err != nil { + return c.Status(400).JSON(fiber.Map{"error": "Invalid input"}) + } + if err := h.Repo.Update(uint(id), &input); err != nil { + return c.Status(500).JSON(fiber.Map{"error": "Failed to update warehouse"}) + } + return c.JSON(fiber.Map{"message": "Warehouse updated"}) +} + +func (h *WarehouseHandler) Delete(c *fiber.Ctx) error { + id, _ := strconv.Atoi(c.Params("id")) + if err := h.Repo.Delete(uint(id)); err != nil { + return c.Status(500).JSON(fiber.Map{"error": "Failed to delete warehouse"}) + } + return c.JSON(fiber.Map{"message": "Warehouse deleted"}) +} diff --git a/modules/inventory/models/collection.go b/modules/inventory/models/collection.go new file mode 100644 index 0000000..540061e --- /dev/null +++ b/modules/inventory/models/collection.go @@ -0,0 +1,10 @@ +package models + +import "time" + +type Collection struct { + ID uint `gorm:"primaryKey" json:"id"` + Name string `gorm:"not null" json:"name"` + CreatedAt time.Time + UpdatedAt time.Time +} diff --git a/modules/inventory/models/colour.go b/modules/inventory/models/colour.go new file mode 100644 index 0000000..173bdcd --- /dev/null +++ b/modules/inventory/models/colour.go @@ -0,0 +1,11 @@ +package models + +import "time" + +type Colour struct { + ID uint `gorm:"primaryKey" json:"id"` + Name string `gorm:"not null" json:"name"` + Code string `json:"code"` // contoh: HEX (#000000) atau RGB + CreatedAt time.Time + UpdatedAt time.Time +} diff --git a/modules/inventory/models/product.go b/modules/inventory/models/product.go new file mode 100644 index 0000000..8156b68 --- /dev/null +++ b/modules/inventory/models/product.go @@ -0,0 +1,29 @@ +package models + +import "time" + +type Product struct { + ID uint `gorm:"primaryKey" json:"id"` + CategoryID uint `json:"category_id"` + Category ProductCategory `gorm:"foreignKey:CategoryID" json:"category"` + + CollectionID uint `json:"collection_id"` + Collection Collection `gorm:"foreignKey:CollectionID" json:"collection"` + + ColourID uint `json:"colour_id"` + Colour Colour `gorm:"foreignKey:ColourID" json:"colour"` + + SizeID uint `json:"size_id"` + Size Size `gorm:"foreignKey:SizeID" json:"size"` + + SKU string `gorm:"not null;unique" json:"sku"` + Name string `gorm:"not null" json:"name"` + Description string `json:"description"` + UnitOfMeasure string `json:"unit_of_measure"` + + IsRawMaterial bool `json:"is_raw_material"` + IsFinishedGood bool `json:"is_finished_good"` + + CreatedAt time.Time + UpdatedAt time.Time +} diff --git a/modules/inventory/models/product_category.go b/modules/inventory/models/product_category.go new file mode 100644 index 0000000..1f2c85e --- /dev/null +++ b/modules/inventory/models/product_category.go @@ -0,0 +1,10 @@ +package models + +import "time" + +type ProductCategory struct { + ID uint `gorm:"primaryKey" json:"id"` + Name string `gorm:"not null" json:"name"` + CreatedAt time.Time + UpdatedAt time.Time +} diff --git a/modules/inventory/models/product_component.go b/modules/inventory/models/product_component.go new file mode 100644 index 0000000..e075fa5 --- /dev/null +++ b/modules/inventory/models/product_component.go @@ -0,0 +1,18 @@ +package models + +import "time" + +type ProductComponent struct { + ID uint `gorm:"primaryKey" json:"id"` + + ProductID uint `json:"product_id"` // Produk utama + Product Product `gorm:"foreignKey:ProductID" json:"product"` + + ComponenID uint `json:"componen_id"` // Komponen produk + Component Product `gorm:"foreignKey:ComponenID" json:"component"` + + Quantity float64 `json:"quantity"` + + CreatedAt time.Time + UpdatedAt time.Time +} diff --git a/modules/inventory/models/production_order.go b/modules/inventory/models/production_order.go new file mode 100644 index 0000000..de9031a --- /dev/null +++ b/modules/inventory/models/production_order.go @@ -0,0 +1,21 @@ +package models + +import "time" + +type ProductionOrder struct { + ID uint `gorm:"primaryKey" json:"id"` + + ProductID uint `json:"product_id"` + Product Product `gorm:"foreignKey:ProductID" json:"product"` + + ProductionID string `gorm:"not null;unique" json:"production_id"` // kode batch + + TargetQuantity float64 `json:"target_quantity"` + Status string `json:"status"` // contoh: "planned", "in_progress", "done" + StartDate time.Time `json:"start_date"` + EndDate time.Time `json:"end_date"` + Note string `json:"note"` + + CreatedAt time.Time + UpdatedAt time.Time +} diff --git a/modules/inventory/models/size.go b/modules/inventory/models/size.go new file mode 100644 index 0000000..1a3ddb5 --- /dev/null +++ b/modules/inventory/models/size.go @@ -0,0 +1,11 @@ +package models + +import "time" + +type Size struct { + ID uint `gorm:"primaryKey" json:"id"` + Name string `gorm:"not null" json:"name"` // contoh: S, M, L, XL + Description string `json:"description"` // opsional, seperti "Small", "Large" + CreatedAt time.Time + UpdatedAt time.Time +} diff --git a/modules/inventory/models/stock_movement.go b/modules/inventory/models/stock_movement.go new file mode 100644 index 0000000..b7de6e6 --- /dev/null +++ b/modules/inventory/models/stock_movement.go @@ -0,0 +1,24 @@ +package models + +import "time" + +type StockMovement struct { + ID uint `gorm:"primaryKey" json:"id"` + + ProductID uint `json:"product_id"` + Product Product `gorm:"foreignKey:ProductID" json:"product"` + + OriginWarehouseID uint `json:"origin_warehouse_id"` + OriginWarehouse Warehouse `gorm:"foreignKey:OriginWarehouseID" json:"origin_warehouse"` + + StockType string `json:"stock_type"` // contoh: "in", "out", "transfer" + + DestinationWarehouseID *uint `json:"destination_warehouse_id"` + DestinationWarehouse *Warehouse `gorm:"foreignKey:DestinationWarehouseID" json:"destination_warehouse"` + + Date time.Time `json:"date"` + Note string `json:"note"` + + CreatedAt time.Time + UpdatedAt time.Time +} diff --git a/modules/inventory/models/warehouse.go b/modules/inventory/models/warehouse.go new file mode 100644 index 0000000..b93aeea --- /dev/null +++ b/modules/inventory/models/warehouse.go @@ -0,0 +1,15 @@ +package models + +import "time" + +type Warehouse struct { + ID uint `gorm:"primaryKey" json:"id"` + Kode string `gorm:"not null;unique" json:"kode"` + Name string `gorm:"not null" json:"name"` + Address string `json:"address"` + Stackholder string `json:"stackholder"` + Number string `json:"number"` + Description string `json:"description"` + CreatedAt time.Time + UpdatedAt time.Time +} diff --git a/modules/inventory/repository/collection_repo.go b/modules/inventory/repository/collection_repo.go new file mode 100644 index 0000000..1bc94fe --- /dev/null +++ b/modules/inventory/repository/collection_repo.go @@ -0,0 +1,33 @@ +package repository + +import ( + "BE-MiniERP/modules/inventory/models" + + "gorm.io/gorm" +) + +type CollectionRepository struct { + DB *gorm.DB +} + +func NewCollectionRepository(db *gorm.DB) *CollectionRepository { + return &CollectionRepository{DB: db} +} + +func (r *CollectionRepository) FindAll() ([]models.Collection, error) { + var collections []models.Collection + err := r.DB.Find(&collections).Error + return collections, err +} + +func (r *CollectionRepository) Create(col *models.Collection) error { + return r.DB.Create(col).Error +} + +func (r *CollectionRepository) Update(id uint, data *models.Collection) error { + return r.DB.Model(&models.Collection{}).Where("id = ?", id).Updates(data).Error +} + +func (r *CollectionRepository) Delete(id uint) error { + return r.DB.Delete(&models.Collection{}, id).Error +} diff --git a/modules/inventory/repository/colour__repo.go b/modules/inventory/repository/colour__repo.go new file mode 100644 index 0000000..93ff9ee --- /dev/null +++ b/modules/inventory/repository/colour__repo.go @@ -0,0 +1,33 @@ +package repository + +import ( + "BE-MiniERP/modules/inventory/models" + + "gorm.io/gorm" +) + +type ColourRepository struct { + DB *gorm.DB +} + +func NewColourRepository(db *gorm.DB) *ColourRepository { + return &ColourRepository{DB: db} +} + +func (r *ColourRepository) FindAll() ([]models.Colour, error) { + var colours []models.Colour + err := r.DB.Find(&colours).Error + return colours, err +} + +func (r *ColourRepository) Create(colour *models.Colour) error { + return r.DB.Create(colour).Error +} + +func (r *ColourRepository) Update(id uint, data *models.Colour) error { + return r.DB.Model(&models.Colour{}).Where("id = ?", id).Updates(data).Error +} + +func (r *ColourRepository) Delete(id uint) error { + return r.DB.Delete(&models.Colour{}, id).Error +} diff --git a/modules/inventory/repository/product__repo.go b/modules/inventory/repository/product__repo.go new file mode 100644 index 0000000..370d41b --- /dev/null +++ b/modules/inventory/repository/product__repo.go @@ -0,0 +1,38 @@ +package repository + +import ( + "BE-MiniERP/modules/inventory/models" + + "gorm.io/gorm" +) + +type ProductRepository struct { + DB *gorm.DB +} + +func NewProductRepository(db *gorm.DB) *ProductRepository { + return &ProductRepository{DB: db} +} + +func (r *ProductRepository) FindAll() ([]models.Product, error) { + var products []models.Product + err := r.DB. + Preload("Category"). + Preload("Collection"). + Preload("Colour"). + Preload("Size"). + Find(&products).Error + return products, err +} + +func (r *ProductRepository) Create(product *models.Product) error { + return r.DB.Create(product).Error +} + +func (r *ProductRepository) Update(id uint, product *models.Product) error { + return r.DB.Model(&models.Product{}).Where("id = ?", id).Updates(product).Error +} + +func (r *ProductRepository) Delete(id uint) error { + return r.DB.Delete(&models.Product{}, id).Error +} diff --git a/modules/inventory/repository/product_category_repo.go b/modules/inventory/repository/product_category_repo.go new file mode 100644 index 0000000..7c4c11c --- /dev/null +++ b/modules/inventory/repository/product_category_repo.go @@ -0,0 +1,33 @@ +package repository + +import ( + "BE-MiniERP/modules/inventory/models" + + "gorm.io/gorm" +) + +type CategoryRepository struct { + DB *gorm.DB +} + +func NewCategoryRepository(db *gorm.DB) *CategoryRepository { + return &CategoryRepository{DB: db} +} + +func (r *CategoryRepository) FindAll() ([]models.ProductCategory, error) { + var categories []models.ProductCategory + err := r.DB.Find(&categories).Error + return categories, err +} + +func (r *CategoryRepository) Create(cat *models.ProductCategory) error { + return r.DB.Create(cat).Error +} + +func (r *CategoryRepository) Update(id uint, data *models.ProductCategory) error { + return r.DB.Model(&models.ProductCategory{}).Where("id = ?", id).Updates(data).Error +} + +func (r *CategoryRepository) Delete(id uint) error { + return r.DB.Delete(&models.ProductCategory{}, id).Error +} diff --git a/modules/inventory/repository/product_component__repo.go b/modules/inventory/repository/product_component__repo.go new file mode 100644 index 0000000..a7ed63c --- /dev/null +++ b/modules/inventory/repository/product_component__repo.go @@ -0,0 +1,32 @@ +package repository + +import ( + "BE-MiniERP/modules/inventory/models" + + "gorm.io/gorm" +) + +type ProductComponentRepository struct { + DB *gorm.DB +} + +func NewProductComponentRepository(db *gorm.DB) *ProductComponentRepository { + return &ProductComponentRepository{DB: db} +} + +func (r *ProductComponentRepository) FindAll() ([]models.ProductComponent, error) { + var data []models.ProductComponent + err := r.DB. + Preload("Product"). + Preload("Component"). + Find(&data).Error + return data, err +} + +func (r *ProductComponentRepository) Create(pc *models.ProductComponent) error { + return r.DB.Create(pc).Error +} + +func (r *ProductComponentRepository) Delete(id uint) error { + return r.DB.Delete(&models.ProductComponent{}, id).Error +} diff --git a/modules/inventory/repository/production_order_repo.go b/modules/inventory/repository/production_order_repo.go new file mode 100644 index 0000000..592ff20 --- /dev/null +++ b/modules/inventory/repository/production_order_repo.go @@ -0,0 +1,33 @@ +package repository + +import ( + "BE-MiniERP/modules/inventory/models" + + "gorm.io/gorm" +) + +type ProductionOrderRepository struct { + DB *gorm.DB +} + +func NewProductionOrderRepository(db *gorm.DB) *ProductionOrderRepository { + return &ProductionOrderRepository{DB: db} +} + +func (r *ProductionOrderRepository) FindAll() ([]models.ProductionOrder, error) { + var orders []models.ProductionOrder + err := r.DB.Preload("Product").Find(&orders).Error + return orders, err +} + +func (r *ProductionOrderRepository) Create(order *models.ProductionOrder) error { + return r.DB.Create(order).Error +} + +func (r *ProductionOrderRepository) Update(id uint, data *models.ProductionOrder) error { + return r.DB.Model(&models.ProductionOrder{}).Where("id = ?", id).Updates(data).Error +} + +func (r *ProductionOrderRepository) Delete(id uint) error { + return r.DB.Delete(&models.ProductionOrder{}, id).Error +} diff --git a/modules/inventory/repository/size_repo.go b/modules/inventory/repository/size_repo.go new file mode 100644 index 0000000..9a1028c --- /dev/null +++ b/modules/inventory/repository/size_repo.go @@ -0,0 +1,33 @@ +package repository + +import ( + "BE-MiniERP/modules/inventory/models" + + "gorm.io/gorm" +) + +type SizeRepository struct { + DB *gorm.DB +} + +func NewSizeRepository(db *gorm.DB) *SizeRepository { + return &SizeRepository{DB: db} +} + +func (r *SizeRepository) FindAll() ([]models.Size, error) { + var sizes []models.Size + err := r.DB.Find(&sizes).Error + return sizes, err +} + +func (r *SizeRepository) Create(size *models.Size) error { + return r.DB.Create(size).Error +} + +func (r *SizeRepository) Update(id uint, data *models.Size) error { + return r.DB.Model(&models.Size{}).Where("id = ?", id).Updates(data).Error +} + +func (r *SizeRepository) Delete(id uint) error { + return r.DB.Delete(&models.Size{}, id).Error +} diff --git a/modules/inventory/repository/stock_movement_repo.go b/modules/inventory/repository/stock_movement_repo.go new file mode 100644 index 0000000..accb1d5 --- /dev/null +++ b/modules/inventory/repository/stock_movement_repo.go @@ -0,0 +1,29 @@ +package repository + +import ( + "BE-MiniERP/modules/inventory/models" + + "gorm.io/gorm" +) + +type StockMovementRepository struct { + DB *gorm.DB +} + +func NewStockMovementRepository(db *gorm.DB) *StockMovementRepository { + return &StockMovementRepository{DB: db} +} + +func (r *StockMovementRepository) FindAll() ([]models.StockMovement, error) { + var movements []models.StockMovement + err := r.DB. + Preload("Product"). + Preload("OriginWarehouse"). + Preload("DestinationWarehouse"). + Find(&movements).Error + return movements, err +} + +func (r *StockMovementRepository) Create(movement *models.StockMovement) error { + return r.DB.Create(movement).Error +} diff --git a/modules/inventory/repository/warehouse_repo.go b/modules/inventory/repository/warehouse_repo.go new file mode 100644 index 0000000..ed3949d --- /dev/null +++ b/modules/inventory/repository/warehouse_repo.go @@ -0,0 +1,33 @@ +package repository + +import ( + "BE-MiniERP/modules/inventory/models" + + "gorm.io/gorm" +) + +type WarehouseRepository struct { + DB *gorm.DB +} + +func NewWarehouseRepository(db *gorm.DB) *WarehouseRepository { + return &WarehouseRepository{DB: db} +} + +func (r *WarehouseRepository) FindAll() ([]models.Warehouse, error) { + var warehouses []models.Warehouse + err := r.DB.Find(&warehouses).Error + return warehouses, err +} + +func (r *WarehouseRepository) Create(wh *models.Warehouse) error { + return r.DB.Create(wh).Error +} + +func (r *WarehouseRepository) Update(id uint, wh *models.Warehouse) error { + return r.DB.Model(&models.Warehouse{}).Where("id = ?", id).Updates(wh).Error +} + +func (r *WarehouseRepository) Delete(id uint) error { + return r.DB.Delete(&models.Warehouse{}, id).Error +} diff --git a/modules/inventory/routes.go b/modules/inventory/routes.go new file mode 100644 index 0000000..bb51a6d --- /dev/null +++ b/modules/inventory/routes.go @@ -0,0 +1,60 @@ +package inventory + +import ( + "BE-MiniERP/modules/inventory/handler" + + "github.com/gofiber/fiber/v2" +) + +func RegisterRoutes(r fiber.Router) { + category := handler.NewCategoryHandler() + r.Get("/categories", category.GetAll) + r.Post("/categories", category.Create) + r.Put("/categories/:id", category.Update) + r.Delete("/categories/:id", category.Delete) + + collection := handler.NewCollectionHandler() + r.Get("/collections", collection.GetAll) + r.Post("/collections", collection.Create) + r.Put("/collections/:id", collection.Update) + r.Delete("/collections/:id", collection.Delete) + + colour := handler.NewColourHandler() + r.Get("/colours", colour.GetAll) + r.Post("/colours", colour.Create) + r.Put("/colours/:id", colour.Update) + r.Delete("/colours/:id", colour.Delete) + + size := handler.NewSizeHandler() + r.Get("/sizes", size.GetAll) + r.Post("/sizes", size.Create) + r.Put("/sizes/:id", size.Update) + r.Delete("/sizes/:id", size.Delete) + + product := handler.NewProductHandler() + r.Get("/products", product.GetAll) + r.Post("/products", product.Create) + r.Put("/products/:id", product.Update) + r.Delete("/products/:id", product.Delete) + + warehouse := handler.NewWarehouseHandler() + r.Get("/warehouses", warehouse.GetAll) + r.Post("/warehouses", warehouse.Create) + r.Put("/warehouses/:id", warehouse.Update) + r.Delete("/warehouses/:id", warehouse.Delete) + + stock := handler.NewStockMovementHandler() + r.Get("/stock-movements", stock.GetAll) + r.Post("/stock-movements", stock.Create) + + component := handler.NewProductComponentHandler() + r.Get("/product-components", component.GetAll) + r.Post("/product-components", component.Create) + r.Delete("/product-components/:id", component.Delete) + + po := handler.NewProductionOrderHandler() + r.Get("/production-orders", po.GetAll) + r.Post("/production-orders", po.Create) + r.Put("/production-orders/:id", po.Update) + r.Delete("/production-orders/:id", po.Delete) +} diff --git a/modules/sales/handler/customer_handler.go b/modules/sales/handler/customer_handler.go new file mode 100644 index 0000000..5cad684 --- /dev/null +++ b/modules/sales/handler/customer_handler.go @@ -0,0 +1,59 @@ +package handler + +import ( + "BE-MiniERP/database" + "BE-MiniERP/modules/sales/models" + "BE-MiniERP/modules/sales/repository" + "strconv" + + "github.com/gofiber/fiber/v2" +) + +type CustomerHandler struct { + Repo *repository.CustomerRepository +} + +func NewCustomerHandler() *CustomerHandler { + return &CustomerHandler{ + Repo: repository.NewCustomerRepository(database.DB), + } +} + +func (h *CustomerHandler) GetAll(c *fiber.Ctx) error { + customers, err := h.Repo.FindAll() + if err != nil { + return c.Status(500).JSON(fiber.Map{"error": "Failed to fetch customers"}) + } + return c.JSON(customers) +} + +func (h *CustomerHandler) Create(c *fiber.Ctx) error { + var input models.Customer + if err := c.BodyParser(&input); err != nil { + return c.Status(400).JSON(fiber.Map{"error": "Invalid input"}) + } + if err := h.Repo.Create(&input); err != nil { + return c.Status(500).JSON(fiber.Map{"error": "Failed to create customer"}) + } + return c.JSON(input) +} + +func (h *CustomerHandler) Update(c *fiber.Ctx) error { + id, _ := strconv.Atoi(c.Params("id")) + var input models.Customer + if err := c.BodyParser(&input); err != nil { + return c.Status(400).JSON(fiber.Map{"error": "Invalid input"}) + } + if err := h.Repo.Update(uint(id), &input); err != nil { + return c.Status(500).JSON(fiber.Map{"error": "Failed to update customer"}) + } + return c.JSON(fiber.Map{"message": "Updated"}) +} + +func (h *CustomerHandler) Delete(c *fiber.Ctx) error { + id, _ := strconv.Atoi(c.Params("id")) + if err := h.Repo.Delete(uint(id)); err != nil { + return c.Status(500).JSON(fiber.Map{"error": "Failed to delete customer"}) + } + return c.JSON(fiber.Map{"message": "Deleted"}) +} diff --git a/modules/sales/handler/invoice_handler.go b/modules/sales/handler/invoice_handler.go new file mode 100644 index 0000000..e505b95 --- /dev/null +++ b/modules/sales/handler/invoice_handler.go @@ -0,0 +1,59 @@ +package handler + +import ( + "BE-MiniERP/database" + "BE-MiniERP/modules/sales/models" + "BE-MiniERP/modules/sales/repository" + "strconv" + + "github.com/gofiber/fiber/v2" +) + +type InvoiceHandler struct { + Repo *repository.InvoiceRepository +} + +func NewInvoiceHandler() *InvoiceHandler { + return &InvoiceHandler{ + Repo: repository.NewInvoiceRepository(database.DB), + } +} + +func (h *InvoiceHandler) GetAll(c *fiber.Ctx) error { + result, err := h.Repo.FindAll() + if err != nil { + return c.Status(500).JSON(fiber.Map{"error": "Failed to fetch invoices"}) + } + return c.JSON(result) +} + +func (h *InvoiceHandler) Create(c *fiber.Ctx) error { + var input models.Invoice + if err := c.BodyParser(&input); err != nil { + return c.Status(400).JSON(fiber.Map{"error": "Invalid input"}) + } + if err := h.Repo.Create(&input); err != nil { + return c.Status(500).JSON(fiber.Map{"error": "Failed to create invoice"}) + } + return c.JSON(input) +} + +func (h *InvoiceHandler) Update(c *fiber.Ctx) error { + id, _ := strconv.Atoi(c.Params("id")) + var input models.Invoice + if err := c.BodyParser(&input); err != nil { + return c.Status(400).JSON(fiber.Map{"error": "Invalid input"}) + } + if err := h.Repo.Update(uint(id), &input); err != nil { + return c.Status(500).JSON(fiber.Map{"error": "Failed to update invoice"}) + } + return c.JSON(fiber.Map{"message": "Updated"}) +} + +func (h *InvoiceHandler) Delete(c *fiber.Ctx) error { + id, _ := strconv.Atoi(c.Params("id")) + if err := h.Repo.Delete(uint(id)); err != nil { + return c.Status(500).JSON(fiber.Map{"error": "Failed to delete invoice"}) + } + return c.JSON(fiber.Map{"message": "Deleted"}) +} diff --git a/modules/sales/handler/invoice_line_handler.go b/modules/sales/handler/invoice_line_handler.go new file mode 100644 index 0000000..701f85e --- /dev/null +++ b/modules/sales/handler/invoice_line_handler.go @@ -0,0 +1,59 @@ +package handler + +import ( + "BE-MiniERP/database" + "BE-MiniERP/modules/sales/models" + "BE-MiniERP/modules/sales/repository" + "strconv" + + "github.com/gofiber/fiber/v2" +) + +type InvoiceLineHandler struct { + Repo *repository.InvoiceLineRepository +} + +func NewInvoiceLineHandler() *InvoiceLineHandler { + return &InvoiceLineHandler{ + Repo: repository.NewInvoiceLineRepository(database.DB), + } +} + +func (h *InvoiceLineHandler) GetAll(c *fiber.Ctx) error { + data, err := h.Repo.FindAll() + if err != nil { + return c.Status(500).JSON(fiber.Map{"error": "Failed to fetch invoice lines"}) + } + return c.JSON(data) +} + +func (h *InvoiceLineHandler) Create(c *fiber.Ctx) error { + var input models.InvoiceLine + if err := c.BodyParser(&input); err != nil { + return c.Status(400).JSON(fiber.Map{"error": "Invalid input"}) + } + if err := h.Repo.Create(&input); err != nil { + return c.Status(500).JSON(fiber.Map{"error": "Failed to create invoice line"}) + } + return c.JSON(input) +} + +func (h *InvoiceLineHandler) Update(c *fiber.Ctx) error { + id, _ := strconv.Atoi(c.Params("id")) + var input models.InvoiceLine + if err := c.BodyParser(&input); err != nil { + return c.Status(400).JSON(fiber.Map{"error": "Invalid input"}) + } + if err := h.Repo.Update(uint(id), &input); err != nil { + return c.Status(500).JSON(fiber.Map{"error": "Failed to update invoice line"}) + } + return c.JSON(fiber.Map{"message": "Updated"}) +} + +func (h *InvoiceLineHandler) Delete(c *fiber.Ctx) error { + id, _ := strconv.Atoi(c.Params("id")) + if err := h.Repo.Delete(uint(id)); err != nil { + return c.Status(500).JSON(fiber.Map{"error": "Failed to delete invoice line"}) + } + return c.JSON(fiber.Map{"message": "Deleted"}) +} diff --git a/modules/sales/handler/payment_handler.go b/modules/sales/handler/payment_handler.go new file mode 100644 index 0000000..7ce7177 --- /dev/null +++ b/modules/sales/handler/payment_handler.go @@ -0,0 +1,59 @@ +package handler + +import ( + "BE-MiniERP/database" + "BE-MiniERP/modules/sales/models" + "BE-MiniERP/modules/sales/repository" + "strconv" + + "github.com/gofiber/fiber/v2" +) + +type PaymentHandler struct { + Repo *repository.PaymentRepository +} + +func NewPaymentHandler() *PaymentHandler { + return &PaymentHandler{ + Repo: repository.NewPaymentRepository(database.DB), + } +} + +func (h *PaymentHandler) GetAll(c *fiber.Ctx) error { + result, err := h.Repo.FindAll() + if err != nil { + return c.Status(500).JSON(fiber.Map{"error": "Failed to fetch payments"}) + } + return c.JSON(result) +} + +func (h *PaymentHandler) Create(c *fiber.Ctx) error { + var input models.Payment + if err := c.BodyParser(&input); err != nil { + return c.Status(400).JSON(fiber.Map{"error": "Invalid input"}) + } + if err := h.Repo.Create(&input); err != nil { + return c.Status(500).JSON(fiber.Map{"error": "Failed to create payment"}) + } + return c.JSON(input) +} + +func (h *PaymentHandler) Update(c *fiber.Ctx) error { + id, _ := strconv.Atoi(c.Params("id")) + var input models.Payment + if err := c.BodyParser(&input); err != nil { + return c.Status(400).JSON(fiber.Map{"error": "Invalid input"}) + } + if err := h.Repo.Update(uint(id), &input); err != nil { + return c.Status(500).JSON(fiber.Map{"error": "Failed to update payment"}) + } + return c.JSON(fiber.Map{"message": "Updated"}) +} + +func (h *PaymentHandler) Delete(c *fiber.Ctx) error { + id, _ := strconv.Atoi(c.Params("id")) + if err := h.Repo.Delete(uint(id)); err != nil { + return c.Status(500).JSON(fiber.Map{"error": "Failed to delete payment"}) + } + return c.JSON(fiber.Map{"message": "Deleted"}) +} diff --git a/modules/sales/handler/sales_order_handler.go b/modules/sales/handler/sales_order_handler.go new file mode 100644 index 0000000..28134ed --- /dev/null +++ b/modules/sales/handler/sales_order_handler.go @@ -0,0 +1,59 @@ +package handler + +import ( + "BE-MiniERP/database" + "BE-MiniERP/modules/sales/models" + "BE-MiniERP/modules/sales/repository" + "strconv" + + "github.com/gofiber/fiber/v2" +) + +type SalesOrderHandler struct { + Repo *repository.SalesOrderRepository +} + +func NewSalesOrderHandler() *SalesOrderHandler { + return &SalesOrderHandler{ + Repo: repository.NewSalesOrderRepository(database.DB), + } +} + +func (h *SalesOrderHandler) GetAll(c *fiber.Ctx) error { + data, err := h.Repo.FindAll() + if err != nil { + return c.Status(500).JSON(fiber.Map{"error": "Failed to fetch sales orders"}) + } + return c.JSON(data) +} + +func (h *SalesOrderHandler) Create(c *fiber.Ctx) error { + var input models.SalesOrder + if err := c.BodyParser(&input); err != nil { + return c.Status(400).JSON(fiber.Map{"error": "Invalid input"}) + } + if err := h.Repo.Create(&input); err != nil { + return c.Status(500).JSON(fiber.Map{"error": "Failed to create sales order"}) + } + return c.JSON(input) +} + +func (h *SalesOrderHandler) Update(c *fiber.Ctx) error { + id, _ := strconv.Atoi(c.Params("id")) + var input models.SalesOrder + if err := c.BodyParser(&input); err != nil { + return c.Status(400).JSON(fiber.Map{"error": "Invalid input"}) + } + if err := h.Repo.Update(uint(id), &input); err != nil { + return c.Status(500).JSON(fiber.Map{"error": "Failed to update sales order"}) + } + return c.JSON(fiber.Map{"message": "Updated"}) +} + +func (h *SalesOrderHandler) Delete(c *fiber.Ctx) error { + id, _ := strconv.Atoi(c.Params("id")) + if err := h.Repo.Delete(uint(id)); err != nil { + return c.Status(500).JSON(fiber.Map{"error": "Failed to delete sales order"}) + } + return c.JSON(fiber.Map{"message": "Deleted"}) +} diff --git a/modules/sales/handler/sales_order_item_handler.go b/modules/sales/handler/sales_order_item_handler.go new file mode 100644 index 0000000..7401f7f --- /dev/null +++ b/modules/sales/handler/sales_order_item_handler.go @@ -0,0 +1,59 @@ +package handler + +import ( + "BE-MiniERP/database" + "BE-MiniERP/modules/sales/models" + "BE-MiniERP/modules/sales/repository" + "strconv" + + "github.com/gofiber/fiber/v2" +) + +type SalesOrderItemHandler struct { + Repo *repository.SalesOrderItemRepository +} + +func NewSalesOrderItemHandler() *SalesOrderItemHandler { + return &SalesOrderItemHandler{ + Repo: repository.NewSalesOrderItemRepository(database.DB), + } +} + +func (h *SalesOrderItemHandler) GetAll(c *fiber.Ctx) error { + data, err := h.Repo.FindAll() + if err != nil { + return c.Status(500).JSON(fiber.Map{"error": "Failed to fetch items"}) + } + return c.JSON(data) +} + +func (h *SalesOrderItemHandler) Create(c *fiber.Ctx) error { + var input models.SalesOrderItem + if err := c.BodyParser(&input); err != nil { + return c.Status(400).JSON(fiber.Map{"error": "Invalid input"}) + } + if err := h.Repo.Create(&input); err != nil { + return c.Status(500).JSON(fiber.Map{"error": "Failed to create item"}) + } + return c.JSON(input) +} + +func (h *SalesOrderItemHandler) Update(c *fiber.Ctx) error { + id, _ := strconv.Atoi(c.Params("id")) + var input models.SalesOrderItem + if err := c.BodyParser(&input); err != nil { + return c.Status(400).JSON(fiber.Map{"error": "Invalid input"}) + } + if err := h.Repo.Update(uint(id), &input); err != nil { + return c.Status(500).JSON(fiber.Map{"error": "Failed to update item"}) + } + return c.JSON(fiber.Map{"message": "Updated"}) +} + +func (h *SalesOrderItemHandler) Delete(c *fiber.Ctx) error { + id, _ := strconv.Atoi(c.Params("id")) + if err := h.Repo.Delete(uint(id)); err != nil { + return c.Status(500).JSON(fiber.Map{"error": "Failed to delete item"}) + } + return c.JSON(fiber.Map{"message": "Deleted"}) +} diff --git a/modules/sales/models/customer.go b/modules/sales/models/customer.go new file mode 100644 index 0000000..a8eb595 --- /dev/null +++ b/modules/sales/models/customer.go @@ -0,0 +1,14 @@ +package models + +import "time" + +type Customer struct { + ID uint `gorm:"primaryKey" json:"id"` + Name string `json:"name"` + Address string `json:"address"` + Phone string `json:"phone"` + Email string `json:"email"` + + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` +} diff --git a/modules/sales/models/invoice.go b/modules/sales/models/invoice.go new file mode 100644 index 0000000..7c53f67 --- /dev/null +++ b/modules/sales/models/invoice.go @@ -0,0 +1,16 @@ +package models + +import "time" + +type Invoice struct { + ID uint `gorm:"primaryKey" json:"id"` + SalesOrderID uint `json:"sales_order_id"` + InvoiceDate time.Time `json:"invoice_date"` + DueDate time.Time `json:"due_date"` + TotalAmount float64 `json:"total_amount"` + Status string `json:"status"` // contoh: unpaid, partial, paid + Note string `json:"note"` + + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` +} diff --git a/modules/sales/models/invoice_line.go b/modules/sales/models/invoice_line.go new file mode 100644 index 0000000..f4cd338 --- /dev/null +++ b/modules/sales/models/invoice_line.go @@ -0,0 +1,15 @@ +package models + +import "time" + +type InvoiceLine struct { + ID uint `gorm:"primaryKey" json:"id"` + InvoiceID uint `json:"invoice_id"` + ProductID uint `json:"product_id"` + Quantity float64 `json:"quantity"` + UnitPrice float64 `json:"unit_price"` + Subtotal float64 `json:"subtotal"` + + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` +} diff --git a/modules/sales/models/payment.go b/modules/sales/models/payment.go new file mode 100644 index 0000000..f775c4f --- /dev/null +++ b/modules/sales/models/payment.go @@ -0,0 +1,15 @@ +package models + +import "time" + +type Payment struct { + ID uint `gorm:"primaryKey" json:"id"` + InvoiceID uint `json:"invoice_id"` + Amount float64 `json:"amount"` + PaidAt time.Time `json:"paid_at"` + Method string `json:"method"` // contoh: cash, bank transfer, credit card + Note string `json:"note"` + + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` +} diff --git a/modules/sales/models/sales_order.go b/modules/sales/models/sales_order.go new file mode 100644 index 0000000..c958f77 --- /dev/null +++ b/modules/sales/models/sales_order.go @@ -0,0 +1,19 @@ +package models + +import "time" + +type SalesOrder struct { + ID uint `gorm:"primaryKey" json:"id"` + CustomerID uint `json:"customer_id"` + OrderDate time.Time `json:"order_date"` + Status string `json:"status"` + TotalAmount float64 `json:"total_amount"` + Note string `json:"note"` + PaymentTerms string `json:"payment_terms"` + DueDate time.Time `json:"due_date"` + DPAmount float64 `json:"dp_amount"` + DPPaid float64 `json:"dp_paid"` + + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` +} diff --git a/modules/sales/models/sales_order_item.go b/modules/sales/models/sales_order_item.go new file mode 100644 index 0000000..0ac4828 --- /dev/null +++ b/modules/sales/models/sales_order_item.go @@ -0,0 +1,15 @@ +package models + +import "time" + +type SalesOrderItem struct { + ID uint `gorm:"primaryKey" json:"id"` + SalesOrderID uint `json:"sales_order_id"` + ProductID uint `json:"product_id"` + Quantity float64 `json:"quantity"` + UnitPrice float64 `json:"unit_price"` + Subtotal float64 `json:"subtotal"` + + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` +} diff --git a/modules/sales/repository/customer_repo.go b/modules/sales/repository/customer_repo.go new file mode 100644 index 0000000..6225f78 --- /dev/null +++ b/modules/sales/repository/customer_repo.go @@ -0,0 +1,33 @@ +package repository + +import ( + "BE-MiniERP/modules/sales/models" + + "gorm.io/gorm" +) + +type CustomerRepository struct { + DB *gorm.DB +} + +func NewCustomerRepository(db *gorm.DB) *CustomerRepository { + return &CustomerRepository{DB: db} +} + +func (r *CustomerRepository) FindAll() ([]models.Customer, error) { + var customers []models.Customer + err := r.DB.Find(&customers).Error + return customers, err +} + +func (r *CustomerRepository) Create(customer *models.Customer) error { + return r.DB.Create(customer).Error +} + +func (r *CustomerRepository) Update(id uint, data *models.Customer) error { + return r.DB.Model(&models.Customer{}).Where("id = ?", id).Updates(data).Error +} + +func (r *CustomerRepository) Delete(id uint) error { + return r.DB.Delete(&models.Customer{}, id).Error +} diff --git a/modules/sales/repository/invoice_line_repo.go b/modules/sales/repository/invoice_line_repo.go new file mode 100644 index 0000000..99e47d3 --- /dev/null +++ b/modules/sales/repository/invoice_line_repo.go @@ -0,0 +1,33 @@ +package repository + +import ( + "BE-MiniERP/modules/sales/models" + + "gorm.io/gorm" +) + +type InvoiceLineRepository struct { + DB *gorm.DB +} + +func NewInvoiceLineRepository(db *gorm.DB) *InvoiceLineRepository { + return &InvoiceLineRepository{DB: db} +} + +func (r *InvoiceLineRepository) FindAll() ([]models.InvoiceLine, error) { + var result []models.InvoiceLine + err := r.DB.Find(&result).Error + return result, err +} + +func (r *InvoiceLineRepository) Create(data *models.InvoiceLine) error { + return r.DB.Create(data).Error +} + +func (r *InvoiceLineRepository) Update(id uint, data *models.InvoiceLine) error { + return r.DB.Model(&models.InvoiceLine{}).Where("id = ?", id).Updates(data).Error +} + +func (r *InvoiceLineRepository) Delete(id uint) error { + return r.DB.Delete(&models.InvoiceLine{}, id).Error +} diff --git a/modules/sales/repository/invoice_repo.go b/modules/sales/repository/invoice_repo.go new file mode 100644 index 0000000..1af0c7d --- /dev/null +++ b/modules/sales/repository/invoice_repo.go @@ -0,0 +1,33 @@ +package repository + +import ( + "BE-MiniERP/modules/sales/models" + + "gorm.io/gorm" +) + +type InvoiceRepository struct { + DB *gorm.DB +} + +func NewInvoiceRepository(db *gorm.DB) *InvoiceRepository { + return &InvoiceRepository{DB: db} +} + +func (r *InvoiceRepository) FindAll() ([]models.Invoice, error) { + var result []models.Invoice + err := r.DB.Find(&result).Error + return result, err +} + +func (r *InvoiceRepository) Create(data *models.Invoice) error { + return r.DB.Create(data).Error +} + +func (r *InvoiceRepository) Update(id uint, data *models.Invoice) error { + return r.DB.Model(&models.Invoice{}).Where("id = ?", id).Updates(data).Error +} + +func (r *InvoiceRepository) Delete(id uint) error { + return r.DB.Delete(&models.Invoice{}, id).Error +} diff --git a/modules/sales/repository/payment_repo.go b/modules/sales/repository/payment_repo.go new file mode 100644 index 0000000..c45b074 --- /dev/null +++ b/modules/sales/repository/payment_repo.go @@ -0,0 +1,33 @@ +package repository + +import ( + "BE-MiniERP/modules/sales/models" + + "gorm.io/gorm" +) + +type PaymentRepository struct { + DB *gorm.DB +} + +func NewPaymentRepository(db *gorm.DB) *PaymentRepository { + return &PaymentRepository{DB: db} +} + +func (r *PaymentRepository) FindAll() ([]models.Payment, error) { + var result []models.Payment + err := r.DB.Find(&result).Error + return result, err +} + +func (r *PaymentRepository) Create(data *models.Payment) error { + return r.DB.Create(data).Error +} + +func (r *PaymentRepository) Update(id uint, data *models.Payment) error { + return r.DB.Model(&models.Payment{}).Where("id = ?", id).Updates(data).Error +} + +func (r *PaymentRepository) Delete(id uint) error { + return r.DB.Delete(&models.Payment{}, id).Error +} diff --git a/modules/sales/repository/sales_order_item_repo.go b/modules/sales/repository/sales_order_item_repo.go new file mode 100644 index 0000000..a5d470f --- /dev/null +++ b/modules/sales/repository/sales_order_item_repo.go @@ -0,0 +1,33 @@ +package repository + +import ( + "BE-MiniERP/modules/sales/models" + + "gorm.io/gorm" +) + +type SalesOrderItemRepository struct { + DB *gorm.DB +} + +func NewSalesOrderItemRepository(db *gorm.DB) *SalesOrderItemRepository { + return &SalesOrderItemRepository{DB: db} +} + +func (r *SalesOrderItemRepository) FindAll() ([]models.SalesOrderItem, error) { + var result []models.SalesOrderItem + err := r.DB.Find(&result).Error + return result, err +} + +func (r *SalesOrderItemRepository) Create(data *models.SalesOrderItem) error { + return r.DB.Create(data).Error +} + +func (r *SalesOrderItemRepository) Update(id uint, data *models.SalesOrderItem) error { + return r.DB.Model(&models.SalesOrderItem{}).Where("id = ?", id).Updates(data).Error +} + +func (r *SalesOrderItemRepository) Delete(id uint) error { + return r.DB.Delete(&models.SalesOrderItem{}, id).Error +} diff --git a/modules/sales/repository/sales_order_repo.go b/modules/sales/repository/sales_order_repo.go new file mode 100644 index 0000000..d3fc695 --- /dev/null +++ b/modules/sales/repository/sales_order_repo.go @@ -0,0 +1,33 @@ +package repository + +import ( + "BE-MiniERP/modules/sales/models" + + "gorm.io/gorm" +) + +type SalesOrderRepository struct { + DB *gorm.DB +} + +func NewSalesOrderRepository(db *gorm.DB) *SalesOrderRepository { + return &SalesOrderRepository{DB: db} +} + +func (r *SalesOrderRepository) FindAll() ([]models.SalesOrder, error) { + var result []models.SalesOrder + err := r.DB.Find(&result).Error + return result, err +} + +func (r *SalesOrderRepository) Create(data *models.SalesOrder) error { + return r.DB.Create(data).Error +} + +func (r *SalesOrderRepository) Update(id uint, data *models.SalesOrder) error { + return r.DB.Model(&models.SalesOrder{}).Where("id = ?", id).Updates(data).Error +} + +func (r *SalesOrderRepository) Delete(id uint) error { + return r.DB.Delete(&models.SalesOrder{}, id).Error +} diff --git a/modules/sales/routes.go b/modules/sales/routes.go new file mode 100644 index 0000000..ba28a56 --- /dev/null +++ b/modules/sales/routes.go @@ -0,0 +1,46 @@ +package sales + +import ( + "BE-MiniERP/modules/sales/handler" + + "github.com/gofiber/fiber/v2" +) + +func RegisterRoutes(router fiber.Router) { + customer := handler.NewCustomerHandler() + salesOrder := handler.NewSalesOrderHandler() + salesOrderItem := handler.NewSalesOrderItemHandler() + invoice := handler.NewInvoiceHandler() + invoiceLine := handler.NewInvoiceLineHandler() + payment := handler.NewPaymentHandler() + + router.Get("/customers", customer.GetAll) + router.Post("/customers", customer.Create) + router.Put("/customers/:id", customer.Update) + router.Delete("/customers/:id", customer.Delete) + + router.Get("/sales-orders", salesOrder.GetAll) + router.Post("/sales-orders", salesOrder.Create) + router.Put("/sales-orders/:id", salesOrder.Update) + router.Delete("/sales-orders/:id", salesOrder.Delete) + + router.Get("/sales-order-items", salesOrderItem.GetAll) + router.Post("/sales-order-items", salesOrderItem.Create) + router.Put("/sales-order-items/:id", salesOrderItem.Update) + router.Delete("/sales-order-items/:id", salesOrderItem.Delete) + + router.Get("/invoices", invoice.GetAll) + router.Post("/invoices", invoice.Create) + router.Put("/invoices/:id", invoice.Update) + router.Delete("/invoices/:id", invoice.Delete) + + router.Get("/invoice-lines", invoiceLine.GetAll) + router.Post("/invoice-lines", invoiceLine.Create) + router.Put("/invoice-lines/:id", invoiceLine.Update) + router.Delete("/invoice-lines/:id", invoiceLine.Delete) + + router.Get("/payments", payment.GetAll) + router.Post("/payments", payment.Create) + router.Put("/payments/:id", payment.Update) + router.Delete("/payments/:id", payment.Delete) +}