Update API

This commit is contained in:
ahmadafriadi 2025-06-22 23:23:26 +07:00
parent b077ef9f06
commit 40705fbf3b
63 changed files with 1976 additions and 81 deletions

View File

@ -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",
})
}

15
api/routes.go Normal file
View File

@ -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"))
}

26
cmd/main.go Normal file
View File

@ -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)
}
}

15
config/config.go Normal file
View File

@ -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"),
}
}

View File

@ -1,6 +1,8 @@
package database package database
import ( import (
"log"
"gorm.io/driver/postgres" "gorm.io/driver/postgres"
"gorm.io/gorm" "gorm.io/gorm"
) )
@ -8,16 +10,10 @@ import (
var DB *gorm.DB var DB *gorm.DB
func Connect() { func Connect() {
dsn := "host=10.5.50.9 user=probindo password=probindo dbname=minierp port=5432 sslmode=disable TimeZone=Asia/Jakarta" dsn := "host=10.5.50.9 user=probindo password=Pr08ind0 dbname=erp port=5432 sslmode=disable"
db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{}) var err error
DB, err = gorm.Open(postgres.Open(dsn), &gorm.Config{})
if err != nil { 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{})
} }

3
go.mod
View File

@ -1,4 +1,4 @@
module fiber-demo module BE-MiniERP
go 1.24.4 go 1.24.4
@ -6,6 +6,7 @@ require github.com/gofiber/fiber/v2 v2.52.8
require ( require (
github.com/andybalholm/brotli v1.1.0 // indirect 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/google/uuid v1.6.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect

2
go.sum
View File

@ -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/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 h1:xl4jJQ0BV5EJTA2aWiKw/VddRpHrKeZLF0QPUxqn0x4=
github.com/gofiber/fiber/v2 v2.52.8/go.mod h1:YEcBbO/FB+5M1IZNBP9FO3J9281zgPAreiI1oqg8nDw= 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 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=

50
main.go
View File

@ -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"))
}

30
middlewares/jwt.go Normal file
View File

@ -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()
}
}

18
middlewares/logger.go Normal file
View File

@ -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
}
}

View File

@ -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})
}

View File

@ -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
}

View File

@ -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
}

13
modules/auth/routes.go Normal file
View File

@ -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)
}

View File

@ -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
}

View File

@ -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)
}

View File

@ -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"})
}

View File

@ -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"})
}

View File

@ -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"})
}

View File

@ -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"})
}

View File

@ -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"})
}

View File

@ -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"})
}

View File

@ -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"})
}

View File

@ -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)
}

View File

@ -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"})
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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)
}

View File

@ -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"})
}

View File

@ -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"})
}

View File

@ -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"})
}

View File

@ -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"})
}

View File

@ -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"})
}

View File

@ -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"})
}

View File

@ -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"`
}

View File

@ -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"`
}

View File

@ -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"`
}

View File

@ -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"`
}

View File

@ -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"`
}

View File

@ -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"`
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

46
modules/sales/routes.go Normal file
View File

@ -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)
}