feat: add feature cart worker and auto commit redis to Db

This commit is contained in:
pahmiudahgede 2025-05-19 02:16:24 +07:00
parent 043a2fe78e
commit 0467598e58
14 changed files with 719 additions and 39 deletions

51
cmd/cart_worker.go Normal file
View File

@ -0,0 +1,51 @@
package main
// import (
// "context"
// "log"
// "strings"
// "time"
// "rijig/config"
// "rijig/internal/services"
// )
// // func main() {
// // config.SetupConfig()
// // }
// func processCartKeys(ctx context.Context, cartService services.CartService) {
// pattern := "cart:user:*"
// iter := config.RedisClient.Scan(ctx, 0, pattern, 0).Iterator()
// for iter.Next(ctx) {
// key := iter.Val()
// ttl, err := config.RedisClient.TTL(ctx, key).Result()
// if err != nil {
// log.Printf("Failed to get TTL for key %s: %v", key, err)
// continue
// }
// if ttl <= time.Minute {
// log.Printf("🔄 Auto-committing key: %s", key)
// parts := strings.Split(key, ":")
// if len(parts) != 3 {
// log.Printf("Invalid key format: %s", key)
// continue
// }
// userID := parts[2]
// err := cartService.CommitCartFromRedis(userID)
// if err != nil {
// log.Printf("❌ Failed to commit cart for user %s: %v", userID, err)
// } else {
// log.Printf("✅ Cart for user %s committed successfully", userID)
// }
// }
// }
// if err := iter.Err(); err != nil {
// log.Printf("Error iterating keys: %v", err)
// }
// }

View File

@ -1,8 +1,14 @@
package main
import (
"context"
"log"
"rijig/config"
"rijig/internal/repositories"
"rijig/internal/services"
"rijig/router"
"strings"
"time"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/cors"
@ -11,37 +17,67 @@ import (
func main() {
config.SetupConfig()
app := fiber.New()
app.Use(cors.New(cors.Config{
AllowOrigins: "*",
AllowMethods: "GET,POST,PUT,PATCH,DELETE",
AllowHeaders: "Content-Type,x-api-key",
}))
// app.Use(cors.New(cors.Config{
// AllowOrigins: "http://localhost:3000",
// AllowMethods: "GET,POST,PUT,DELETE,OPTIONS",
// AllowHeaders: "Origin, Content-Type, Accept, Authorization, x-api-key",
// AllowCredentials: true,
// }))
// app.Use(func(c *fiber.Ctx) error {
// c.Set("Access-Control-Allow-Origin", "http://localhost:3000")
// c.Set("Access-Control-Allow-Methods", "GET,POST,PUT,DELETE,OPTIONS")
// c.Set("Access-Control-Allow-Headers", "Origin, Content-Type, Accept, Authorization, x-api-key")
// c.Set("Access-Control-Allow-Credentials", "true")
// return c.Next()
// })
// app.Options("*", func(c *fiber.Ctx) error {
// c.Set("Access-Control-Allow-Origin", "http://localhost:3000")
// c.Set("Access-Control-Allow-Methods", "GET,POST,PUT,DELETE,OPTIONS")
// c.Set("Access-Control-Allow-Headers", "Origin, Content-Type, Accept, Authorization, x-api-key")
// c.Set("Access-Control-Allow-Credentials", "true")
// return c.SendStatus(fiber.StatusNoContent)
// })
// Route setup
router.SetupRoutes(app)
// Siapkan dependency untuk worker
repoCart := repositories.NewCartRepository()
repoTrash := repositories.NewTrashRepository(config.DB)
cartService := services.NewCartService(repoCart, repoTrash)
ctx := context.Background()
// ✅ Jalankan worker di background
go func() {
ticker := time.NewTicker(30 * time.Second)
defer ticker.Stop()
log.Println("🛠️ Cart Worker is running in background...")
for range ticker.C {
processCartKeys(ctx, cartService)
}
}()
// 🚀 Jalankan server (blocking)
config.StartServer(app)
}
func processCartKeys(ctx context.Context, cartService services.CartService) {
pattern := "cart:user:*"
iter := config.RedisClient.Scan(ctx, 0, pattern, 0).Iterator()
for iter.Next(ctx) {
key := iter.Val()
ttl, err := config.RedisClient.TTL(ctx, key).Result()
if err != nil {
log.Printf("Failed to get TTL for key %s: %v", key, err)
continue
}
if ttl <= time.Minute {
log.Printf("🔄 Auto-committing key: %s", key)
parts := strings.Split(key, ":")
if len(parts) != 3 {
log.Printf("Invalid key format: %s", key)
continue
}
userID := parts[2]
err := cartService.CommitCartFromRedis(userID)
if err != nil {
log.Printf("❌ Failed to commit cart for user %s: %v", userID, err)
} else {
log.Printf("✅ Cart for user %s committed successfully", userID)
}
}
}
if err := iter.Err(); err != nil {
log.Printf("Error iterating keys: %v", err)
}
}

View File

@ -53,6 +53,9 @@ func ConnectDatabase() {
// =>requestpickup preparation<=
&model.RequestPickup{},
&model.RequestPickupItem{},
&model.Cart{},
&model.CartItem{},
// =>requestpickup preparation<=
// =>store preparation<=

50
dto/trashcart_dto.go Normal file
View File

@ -0,0 +1,50 @@
package dto
import (
"strings"
"time"
)
type ValidationErrors struct {
Errors map[string][]string
}
func (v ValidationErrors) Error() string {
return "validation error"
}
type CartResponse struct {
ID string `json:"id"`
UserID string `json:"userid"`
CartItems []CartItemResponse `json:"cartitems"`
TotalAmount float32 `json:"totalamount"`
EstimatedTotalPrice float32 `json:"estimated_totalprice"`
CreatedAt time.Time `json:"createdAt"`
UpdatedAt time.Time `json:"updatedAt"`
}
type CartItemResponse struct {
TrashIcon string `json:"trashicon"`
TrashName string `json:"trashname"`
Amount float32 `json:"amount"`
EstimatedSubTotalPrice float32 `json:"estimated_subtotalprice"`
}
type RequestCartItems struct {
TrashID string `json:"trashid"`
Amount float32 `json:"amount"`
}
func (r *RequestCartItems) ValidateRequestCartItem() (map[string][]string, bool) {
errors := make(map[string][]string)
if strings.TrimSpace(r.TrashID) == "" {
errors["trashid"] = append(errors["trashid"], "trashid is required")
}
if len(errors) > 0 {
return errors, false
}
return nil, true
}

1
go.mod
View File

@ -37,6 +37,7 @@ require (
github.com/mattn/go-runewidth v0.0.15 // indirect
github.com/mdp/qrterminal/v3 v3.2.0
github.com/rivo/uniseg v0.2.0 // indirect
github.com/robfig/cron/v3 v3.0.1
github.com/rs/zerolog v1.33.0 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasthttp v1.51.0 // indirect

2
go.sum
View File

@ -64,6 +64,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8=
github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=

View File

@ -0,0 +1,96 @@
package handler
import (
"rijig/dto"
"rijig/internal/services"
"rijig/utils"
"github.com/gofiber/fiber/v2"
)
type CartHandler struct {
CartService services.CartService
}
func NewCartHandler(service services.CartService) *CartHandler {
return &CartHandler{
CartService: service,
}
}
// GET /cart - Get cart by user ID
func (h *CartHandler) GetCart(c *fiber.Ctx) error {
userID, ok := c.Locals("userID").(string)
if !ok || userID == "" {
return utils.ErrorResponse(c, "unauthorized or invalid user")
}
cart, err := h.CartService.GetCartByUserID(userID)
if err != nil {
return utils.InternalServerErrorResponse(c, "failed to retrieve cart")
}
if cart == nil {
return utils.SuccessResponse(c, nil, "Cart is empty")
}
return utils.SuccessResponse(c, cart, "User cart data successfully fetched")
}
// POST /cart - Create new cart
func (h *CartHandler) CreateCart(c *fiber.Ctx) error {
userID, ok := c.Locals("userID").(string)
if !ok || userID == "" {
return utils.ErrorResponse(c, "unauthorized or invalid user")
}
var reqItems []dto.RequestCartItems
if err := c.BodyParser(&reqItems); err != nil {
return utils.ValidationErrorResponse(c, map[string][]string{
"body": {"invalid JSON format"},
})
}
// Logic dipindahkan ke service
if err := h.CartService.CreateCartFromDTO(userID, reqItems); err != nil {
if ve, ok := err.(dto.ValidationErrors); ok {
return utils.ValidationErrorResponse(c, ve.Errors)
}
return utils.InternalServerErrorResponse(c, "failed to create cart")
}
return utils.CreateResponse(c, nil, "Cart created successfully")
}
// DELETE /cart/:id - Delete cart by cartID
func (h *CartHandler) DeleteCart(c *fiber.Ctx) error {
cartID := c.Params("id")
if cartID == "" {
return utils.ErrorResponse(c, "Cart ID is required")
}
if err := h.CartService.DeleteCart(cartID); err != nil {
return utils.InternalServerErrorResponse(c, "failed to delete cart")
}
return utils.SuccessResponse(c, nil, "Cart deleted successfully")
}
// POST /cart/commit - Simpan cart dari Redis ke DB
func (h *CartHandler) CommitCart(c *fiber.Ctx) error {
userID, ok := c.Locals("userID").(string)
if !ok || userID == "" {
return utils.ErrorResponse(c, "unauthorized or invalid user")
}
err := h.CartService.CommitCartFromRedis(userID)
if err != nil {
if err.Error() == "cart not found in redis" {
return utils.ErrorResponse(c, "Cart tidak ditemukan atau sudah expired")
}
return utils.InternalServerErrorResponse(c, "Gagal menyimpan cart ke database")
}
return utils.SuccessResponse(c, nil, "Cart berhasil disimpan ke database")
}

View File

@ -15,6 +15,7 @@ type TrashRepository interface {
AddDetailToCategory(detail *model.TrashDetail) error
GetCategories() ([]model.TrashCategory, error)
GetCategoryByID(id string) (*model.TrashCategory, error)
GetTrashCategoryByName(name string) (*model.TrashCategory, error)
GetTrashDetailByID(id string) (*model.TrashDetail, error)
GetDetailsByCategoryID(categoryID string) ([]model.TrashDetail, error)
UpdateCategoryName(id string, newName string) error
@ -63,6 +64,15 @@ func (r *trashRepository) GetCategoryByID(id string) (*model.TrashCategory, erro
return &category, nil
}
func (r *trashRepository) GetTrashCategoryByName(name string) (*model.TrashCategory, error) {
var category model.TrashCategory
if err := r.DB.Find(&category, "name = ?", name).Error; err != nil {
return nil, fmt.Errorf("category not found: %v", err)
}
return &category, nil
}
func (r *trashRepository) GetTrashDetailByID(id string) (*model.TrashDetail, error) {
var detail model.TrashDetail
if err := r.DB.First(&detail, "id = ?", id).Error; err != nil {

View File

@ -0,0 +1,100 @@
package repositories
import (
"errors"
"log"
"rijig/config"
"rijig/model"
"gorm.io/gorm"
)
type CartRepository interface {
Create(cart *model.Cart) error
GetByUserID(userID string) (*model.Cart, error)
Update(cart *model.Cart) error
InsertCartItem(item *model.CartItem) error
UpdateCartItem(item *model.CartItem) error
DeleteCartItemByID(id string) error
Delete(cartID string) error
DeleteByUserID(userID string) error
}
type cartRepository struct {
db *gorm.DB
}
func NewCartRepository() CartRepository {
return &cartRepository{
db: config.DB,
}
}
func (r *cartRepository) Create(cart *model.Cart) error {
tx := r.db.Begin()
if err := tx.Create(cart).Error; err != nil {
tx.Rollback()
return err
}
return tx.Commit().Error
}
func (r *cartRepository) GetByUserID(userID string) (*model.Cart, error) {
var cart model.Cart
err := r.db.
Preload("CartItems.TrashCategory").
Where("user_id = ?", userID).
First(&cart).Error
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, nil
}
log.Printf("Error retrieving cart for user %s: %v", userID, err)
return nil, errors.New("failed to retrieve cart")
}
return &cart, nil
}
func (r *cartRepository) Update(cart *model.Cart) error {
err := r.db.Save(cart).Error
if err != nil {
log.Printf("Error updating cart %s: %v", cart.ID, err)
return errors.New("failed to update cart")
}
return nil
}
func (r *cartRepository) InsertCartItem(item *model.CartItem) error {
return r.db.Create(item).Error
}
func (r *cartRepository) UpdateCartItem(item *model.CartItem) error {
return r.db.Save(item).Error
}
func (r *cartRepository) DeleteCartItemByID(id string) error {
return r.db.Delete(&model.CartItem{}, "id = ?", id).Error
}
func (r *cartRepository) Delete(cartID string) error {
result := r.db.Where("id = ?", cartID).Delete(&model.Cart{})
if result.Error != nil {
log.Printf("Error deleting cart %s: %v", cartID, result.Error)
return errors.New("failed to delete cart")
}
if result.RowsAffected == 0 {
log.Printf("Cart with ID %s not found for deletion", cartID)
return errors.New("cart not found")
}
return nil
}
func (r *cartRepository) DeleteByUserID(userID string) error {
return r.db.Where("user_id = ?", userID).Delete(&model.Cart{}).Error
}

View File

@ -0,0 +1,240 @@
package services
import (
"encoding/json"
"errors"
"fmt"
"log"
"time"
"rijig/dto"
"rijig/internal/repositories"
"rijig/model"
"rijig/utils"
)
type CartService interface {
CreateCartFromDTO(userID string, items []dto.RequestCartItems) error
GetCartByUserID(userID string) (*dto.CartResponse, error)
CommitCartFromRedis(userID string) error
DeleteCart(cartID string) error
}
type cartService struct {
repo repositories.CartRepository
repoTrash repositories.TrashRepository
}
func NewCartService(repo repositories.CartRepository, repoTrash repositories.TrashRepository) CartService {
return &cartService{repo: repo, repoTrash: repoTrash}
}
func redisCartKey(userID string) string {
return fmt.Sprintf("cart:user:%s", userID)
}
func (s *cartService) CreateCartFromDTO(userID string, items []dto.RequestCartItems) error {
// Validasi semua item
for _, item := range items {
if errMap, valid := item.ValidateRequestCartItem(); !valid {
return dto.ValidationErrors{Errors: errMap}
}
}
// Ambil cart yang sudah ada dari Redis (jika ada)
var existingCart dto.CartResponse
val, err := utils.GetData(redisCartKey(userID))
if err == nil && val != "" {
if err := json.Unmarshal([]byte(val), &existingCart); err != nil {
log.Printf("Failed to unmarshal existing cart: %v", err)
}
}
// Buat map dari existing items untuk mempermudah update
itemMap := make(map[string]dto.CartItemResponse)
for _, item := range existingCart.CartItems {
itemMap[item.TrashName] = item
}
// Proses input baru
for _, input := range items {
trash, err := s.repoTrash.GetCategoryByID(input.TrashID)
if err != nil {
return fmt.Errorf("failed to retrieve trash category for id %s: %v", input.TrashID, err)
}
if input.Amount == 0 {
delete(itemMap, trash.Name) // hapus item
continue
}
subtotal := float32(trash.EstimatedPrice) * input.Amount
itemMap[trash.Name] = dto.CartItemResponse{
TrashIcon: trash.Icon,
TrashName: trash.Name,
Amount: input.Amount,
EstimatedSubTotalPrice: subtotal,
}
}
// Rekonstruksi cart
var finalItems []dto.CartItemResponse
var totalAmount float32
var totalPrice float32
for _, item := range itemMap {
finalItems = append(finalItems, item)
totalAmount += item.Amount
totalPrice += item.EstimatedSubTotalPrice
}
cart := dto.CartResponse{
ID: existingCart.ID,
UserID: userID,
TotalAmount: totalAmount,
EstimatedTotalPrice: totalPrice,
CartItems: finalItems,
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
}
// Simpan ulang ke Redis dengan TTL 10 menit
return utils.SetData(redisCartKey(userID), cart, 1*time.Minute)
}
func (s *cartService) GetCartByUserID(userID string) (*dto.CartResponse, error) {
val, err := utils.GetData(redisCartKey(userID))
if err != nil {
log.Printf("Redis get error: %v", err)
}
if val != "" {
var cached dto.CartResponse
if err := json.Unmarshal([]byte(val), &cached); err == nil {
return &cached, nil
}
}
cart, err := s.repo.GetByUserID(userID)
if err != nil {
return nil, err
}
if cart == nil {
return nil, nil
}
var items []dto.CartItemResponse
for _, item := range cart.CartItems {
items = append(items, dto.CartItemResponse{
TrashIcon: item.TrashCategory.Icon,
TrashName: item.TrashCategory.Name,
Amount: item.Amount,
EstimatedSubTotalPrice: item.SubTotalEstimatedPrice,
})
}
response := &dto.CartResponse{
ID: cart.ID,
UserID: cart.UserID,
TotalAmount: cart.TotalAmount,
EstimatedTotalPrice: cart.EstimatedTotalPrice,
CartItems: items,
CreatedAt: cart.CreatedAt,
UpdatedAt: cart.UpdatedAt,
}
return response, nil
}
func (s *cartService) CommitCartFromRedis(userID string) error {
val, err := utils.GetData(redisCartKey(userID))
if err != nil || val == "" {
return errors.New("no cart found in redis")
}
var cartDTO dto.CartResponse
if err := json.Unmarshal([]byte(val), &cartDTO); err != nil {
return errors.New("invalid cart data in Redis")
}
existingCart, err := s.repo.GetByUserID(userID)
if err != nil {
return fmt.Errorf("failed to get cart from db: %v", err)
}
if existingCart == nil {
// buat cart baru jika belum ada
var items []model.CartItem
for _, item := range cartDTO.CartItems {
trash, err := s.repoTrash.GetTrashCategoryByName(item.TrashName)
if err != nil {
continue
}
items = append(items, model.CartItem{
TrashID: trash.ID,
Amount: item.Amount,
SubTotalEstimatedPrice: item.EstimatedSubTotalPrice,
})
}
newCart := model.Cart{
UserID: userID,
TotalAmount: cartDTO.TotalAmount,
EstimatedTotalPrice: cartDTO.EstimatedTotalPrice,
CartItems: items,
}
return s.repo.Create(&newCart)
}
// buat map item lama (by trash_name)
existingItemMap := make(map[string]*model.CartItem)
for i := range existingCart.CartItems {
trashName := existingCart.CartItems[i].TrashCategory.Name
existingItemMap[trashName] = &existingCart.CartItems[i]
}
// proses update/hapus/tambah
for _, newItem := range cartDTO.CartItems {
if newItem.Amount == 0 {
if existing, ok := existingItemMap[newItem.TrashName]; ok {
_ = s.repo.DeleteCartItemByID(existing.ID)
}
continue
}
trash, err := s.repoTrash.GetTrashCategoryByName(newItem.TrashName)
if err != nil {
continue
}
if existing, ok := existingItemMap[newItem.TrashName]; ok {
existing.Amount = newItem.Amount
existing.SubTotalEstimatedPrice = newItem.EstimatedSubTotalPrice
_ = s.repo.UpdateCartItem(existing)
} else {
newModelItem := model.CartItem{
CartID: existingCart.ID,
TrashID: trash.ID,
Amount: newItem.Amount,
SubTotalEstimatedPrice: newItem.EstimatedSubTotalPrice,
}
_ = s.repo.InsertCartItem(&newModelItem)
}
}
// update cart total amount & price
existingCart.TotalAmount = cartDTO.TotalAmount
existingCart.EstimatedTotalPrice = cartDTO.EstimatedTotalPrice
if err := s.repo.Update(existingCart); err != nil {
return err
}
return utils.DeleteData(redisCartKey(userID))
}
func (s *cartService) DeleteCart(cartID string) error {
return s.repo.Delete(cartID)
}

View File

@ -0,0 +1,58 @@
package worker
import (
"context"
"encoding/json"
"log"
"rijig/config"
"rijig/internal/repositories"
"rijig/model"
)
type CartCommitter struct {
repo repositories.CartRepository
}
func NewCartCommitter(repo repositories.CartRepository) *CartCommitter {
return &CartCommitter{repo: repo}
}
func (cc *CartCommitter) RunAutoCommit() {
ctx := context.Background()
pattern := "cart:user:*"
iter := config.RedisClient.Scan(ctx, 0, pattern, 0).Iterator()
for iter.Next(ctx) {
key := iter.Val()
val, err := config.RedisClient.Get(ctx, key).Result()
if err != nil {
log.Printf("Error fetching key %s: %v", key, err)
continue
}
var cart model.Cart
if err := json.Unmarshal([]byte(val), &cart); err != nil {
log.Printf("Invalid cart format in key %s: %v", key, err)
continue
}
// Simpan ke DB
if err := cc.repo.Create(&cart); err != nil {
log.Printf("Failed to commit cart to DB from key %s: %v", key, err)
continue
}
// Delete from Redis
if err := config.RedisClient.Del(ctx, key).Err(); err != nil {
log.Printf("Failed to delete key %s after commit: %v", key, err)
} else {
log.Printf("Committed and deleted key %s successfully", key)
}
}
if err := iter.Err(); err != nil {
log.Printf("Redis scan error: %v", err)
}
}

View File

@ -1,21 +1,27 @@
package model
import "time"
import (
"time"
)
type Cart struct {
ID string `gorm:"primaryKey;type:uuid;default:uuid_generate_v4()" json:"id"`
UserId string `gorm:"not null" json:"userid"`
User User `gorm:"foreignKey:UserId;constraint:OnDelete:CASCADE;" json:"user"`
CartItem []CartItems `gorm:"foreignKey:CategoryID;constraint:OnDelete:CASCADE;" json:"cartitems"`
UserID string `gorm:"not null" json:"userid"`
User User `gorm:"foreignKey:UserID;constraint:OnDelete:CASCADE;" json:"-"`
CartItems []CartItem `gorm:"foreignKey:CartID;constraint:OnDelete:CASCADE;" json:"cartitems"`
TotalAmount float32 `json:"totalamount"`
EstimatedTotalPrice float32 `json:"estimated_totalprice"`
CreatedAt time.Time `gorm:"autoCreateTime" json:"createdAt"`
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updatedAt"`
}
type CartItems struct {
type CartItem struct {
ID string `gorm:"primaryKey;type:uuid;default:uuid_generate_v4()" json:"id"`
TrashId string `json:"trashid"`
TrashCategory TrashCategory `gorm:"foreignKey:TrashId;constraint:OnDelete:CASCADE;" json:"trash"`
CartID string `gorm:"not null" json:"-"`
TrashID string `gorm:"not null" json:"trashid"`
TrashCategory TrashCategory `gorm:"foreignKey:TrashID;constraint:OnDelete:CASCADE;" json:"trash"`
Amount float32 `json:"amount"`
CreaatedAt time.Time `gorm:"default:current_timestamp" json:"createdAt"`
UpdatedAt time.Time `gorm:"default:current_timestamp" json:"updatedAt"`
SubTotalEstimatedPrice float32 `json:"subtotalestimatedprice"`
CreatedAt time.Time `gorm:"autoCreateTime" json:"createdAt"`
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updatedAt"`
}

View File

@ -0,0 +1,26 @@
package presentation
import (
"rijig/config"
"rijig/internal/handler"
"rijig/internal/repositories"
"rijig/internal/services"
"rijig/middleware"
"github.com/gofiber/fiber/v2"
)
func TrashCartRouter(api fiber.Router) {
cartRepo := repositories.NewCartRepository()
trashRepo := repositories.NewTrashRepository(config.DB)
cartService := services.NewCartService(cartRepo, trashRepo)
cartHandler := handler.NewCartHandler(cartService)
cart := api.Group("/cart")
cart.Use(middleware.AuthMiddleware)
cart.Post("/", cartHandler.CreateCart)
cart.Get("/", cartHandler.GetCart)
cart.Post("/commit", cartHandler.CommitCart)
cart.Delete("/:id", cartHandler.DeleteCart)
}

View File

@ -28,6 +28,7 @@ func SetupRoutes(app *fiber.App) {
presentation.CompanyProfileRouter(api)
presentation.RequestPickupRouter(api)
presentation.CollectorRouter(api)
presentation.TrashCartRouter(api)
presentation.UserProfileRouter(api)
presentation.UserPinRouter(api)