refact: stress refact collector and make average price for trashcategory

This commit is contained in:
pahmiudahgede 2025-05-22 00:03:16 +07:00
parent 6df861f776
commit 226d188ece
16 changed files with 967 additions and 545 deletions

View File

@ -43,6 +43,7 @@ func ConnectDatabase() {
// =>user preparation<= // =>user preparation<=
&model.User{}, &model.User{},
&model.Collector{}, &model.Collector{},
&model.AvaibleTrashByCollector{},
&model.Role{}, &model.Role{},
&model.UserPin{}, &model.UserPin{},
&model.Address{}, &model.Address{},

View File

@ -1,10 +1,22 @@
package dto package dto
import "strings" import (
"fmt"
"strings"
)
type RequestCollectorDTO struct { type RequestCollectorDTO struct {
UserId string `json:"user_id"` AddressId string `json:"address_id"`
AddressId string `json:"address_id"` AvaibleTrashbyCollector []RequestAvaibleTrashbyCollector `json:"avaible_trash"`
}
type RequestAvaibleTrashbyCollector struct {
TrashId string `json:"trash_id"`
TrashPrice float32 `json:"trash_price"`
}
type RequestAddAvaibleTrash struct {
AvaibleTrash []RequestAvaibleTrashbyCollector `json:"avaible_trash"`
} }
type SelectCollectorRequest struct { type SelectCollectorRequest struct {
@ -24,25 +36,65 @@ func (r *SelectCollectorRequest) ValidateSelectCollectorRequest() (map[string][]
return nil, true return nil, true
} }
type ResponseCollectorDTO struct { func (r *RequestAddAvaibleTrash) ValidateRequestAddAvaibleTrash() (map[string][]string, bool) {
ID string `json:"collector_id"` errors := make(map[string][]string)
UserId string `json:"user_id"`
User []UserResponseDTO `json:"user,omitempty"` if len(r.AvaibleTrash) == 0 {
AddressId string `json:"address_id"` errors["avaible_trash"] = append(errors["avaible_trash"], "tidak boleh kosong")
Address []AddressResponseDTO `json:"address,omitempty"` }
JobStatus *string `json:"job_status,omitempty"`
Rating float32 `json:"rating"` for i, trash := range r.AvaibleTrash {
if strings.TrimSpace(trash.TrashId) == "" {
errors[fmt.Sprintf("avaible_trash[%d].trash_id", i)] = append(errors[fmt.Sprintf("avaible_trash[%d].trash_id", i)], "trash_id tidak boleh kosong")
}
if trash.TrashPrice <= 0 {
errors[fmt.Sprintf("avaible_trash[%d].trash_price", i)] = append(errors[fmt.Sprintf("avaible_trash[%d].trash_price", i)], "trash_price harus lebih dari 0")
}
}
if len(errors) > 0 {
return errors, false
}
return nil, true
} }
func (r *RequestCollectorDTO) ValidateRequestColector() (map[string][]string, bool) { type ResponseCollectorDTO struct {
ID string `json:"collector_id"`
UserId string `json:"user_id"`
User *UserResponseDTO `json:"user,omitempty"`
AddressId string `json:"address_id"`
Address *AddressResponseDTO `json:"address,omitempty"`
JobStatus *string `json:"job_status,omitempty"`
Rating float32 `json:"rating"`
AvaibleTrashbyCollector []ResponseAvaibleTrashByCollector `json:"avaible_trash"`
}
type ResponseAvaibleTrashByCollector struct {
ID string `json:"id"`
TrashId string `json:"trash_id"`
TrashName string `json:"trash_name"`
TrashIcon string `json:"trash_icon"`
TrashPrice float32 `json:"trash_price"`
}
func (r *RequestCollectorDTO) ValidateRequestCollector() (map[string][]string, bool) {
errors := make(map[string][]string) errors := make(map[string][]string)
if strings.TrimSpace(r.AddressId) == "" { if strings.TrimSpace(r.AddressId) == "" {
errors["address_id"] = append(errors["address_id"], "address_id harus diisi") errors["address_id"] = append(errors["address_id"], "address_id harus diisi")
} }
for i, trash := range r.AvaibleTrashbyCollector {
if strings.TrimSpace(trash.TrashId) == "" {
errors[fmt.Sprintf("avaible_trash[%d].trash_id", i)] = append(errors[fmt.Sprintf("avaible_trash[%d].trash_id", i)], "trash_id tidak boleh kosong")
}
if trash.TrashPrice <= 0 {
errors[fmt.Sprintf("avaible_trash[%d].trash_price", i)] = append(errors[fmt.Sprintf("avaible_trash[%d].trash_price", i)], "trash_price harus lebih dari 0")
}
}
if len(errors) > 0 { if len(errors) > 0 {
return errors, false return errors, false
} }
return nil, true return nil, true
} }

View File

@ -33,14 +33,14 @@ type CartItemResponse struct {
} }
type RequestCartItems struct { type RequestCartItems struct {
TrashID string `json:"trashid"` TrashCategoryID string `json:"trashid"`
Amount float32 `json:"amount"` Amount float32 `json:"amount"`
} }
func (r *RequestCartItems) ValidateRequestCartItem() (map[string][]string, bool) { func (r *RequestCartItems) ValidateRequestCartItem() (map[string][]string, bool) {
errors := make(map[string][]string) errors := make(map[string][]string)
if strings.TrimSpace(r.TrashID) == "" { if strings.TrimSpace(r.TrashCategoryID) == "" {
errors["trashid"] = append(errors["trashid"], "trashid is required") errors["trashid"] = append(errors["trashid"], "trashid is required")
} }
@ -58,7 +58,7 @@ type BulkRequestCartItems struct {
func (b *BulkRequestCartItems) Validate() (map[string][]string, bool) { func (b *BulkRequestCartItems) Validate() (map[string][]string, bool) {
errors := make(map[string][]string) errors := make(map[string][]string)
for i, item := range b.Items { for i, item := range b.Items {
if strings.TrimSpace(item.TrashID) == "" { if strings.TrimSpace(item.TrashCategoryID) == "" {
errors[fmt.Sprintf("items[%d].trashid", i)] = append(errors[fmt.Sprintf("items[%d].trashid", i)], "trashid is required") errors[fmt.Sprintf("items[%d].trashid", i)] = append(errors[fmt.Sprintf("items[%d].trashid", i)], "trashid is required")
} }
} }

View File

@ -1,7 +1,7 @@
package handler package handler
import ( import (
"fmt" "context"
"rijig/dto" "rijig/dto"
"rijig/internal/services" "rijig/internal/services"
"rijig/utils" "rijig/utils"
@ -9,62 +9,244 @@ import (
"github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v2"
) )
type CollectorHandler struct { type CollectorHandler interface {
CreateCollector(c *fiber.Ctx) error
AddTrashToCollector(c *fiber.Ctx) error
GetCollectorByID(c *fiber.Ctx) error
GetCollectorByUserID(c *fiber.Ctx) error
UpdateCollector(c *fiber.Ctx) error
UpdateJobStatus(c *fiber.Ctx) error
UpdateTrash(c *fiber.Ctx) error
DeleteTrash(c *fiber.Ctx) error
}
type collectorHandler struct {
service services.CollectorService service services.CollectorService
} }
func NewCollectorHandler(service services.CollectorService) *CollectorHandler { func NewCollectorHandler(service services.CollectorService) CollectorHandler {
return &CollectorHandler{service} return &collectorHandler{service: service}
} }
func (h *CollectorHandler) ConfirmRequestPickup(c *fiber.Ctx) error { // func (h *CollectorHandler) ConfirmRequestPickup(c *fiber.Ctx) error {
collectorId, ok := c.Locals("userID").(string) // collectorId, ok := c.Locals("userID").(string)
if !ok || collectorId == "" { // if !ok || collectorId == "" {
// return utils.GenericResponse(c, fiber.StatusUnauthorized, "Unauthorized: User session not found")
// }
// requestPickupId := c.Params("id")
// if requestPickupId == "" {
// return utils.ErrorResponse(c, "RequestPickup ID is required")
// }
// req, err := h.service.ConfirmRequestPickup(requestPickupId, collectorId)
// if err != nil {
// return utils.ErrorResponse(c, err.Error())
// }
// return utils.SuccessResponse(c, req, "Request pickup confirmed successfully")
// }
// func (h *CollectorHandler) GetAvaibleCollector(c *fiber.Ctx) error {
// userId := c.Locals("userID").(string)
// requests, err := h.service.FindCollectorsNearby(userId)
// if err != nil {
// return utils.ErrorResponse(c, err.Error())
// }
// return utils.SuccessResponse(c, requests, "menampilkan data collector terdekat")
// }
// func (h *CollectorHandler) ConfirmRequestManualPickup(c *fiber.Ctx) error {
// userId := c.Locals("userID").(string)
// requestId := c.Params("request_id")
// if requestId == "" {
// fmt.Println("requestid dibutuhkan")
// }
// var request dto.SelectCollectorRequest
// if err := c.BodyParser(&request); err != nil {
// return fmt.Errorf("error parsing request body: %v", err)
// }
// message, err := h.service.ConfirmRequestManualPickup(requestId, userId)
// if err != nil {
// return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Error confirming pickup: %v", err))
// }
// return utils.SuccessResponse(c, message, "berhasil konfirmasi request")
// }
func (h *collectorHandler) CreateCollector(c *fiber.Ctx) error {
var req dto.RequestCollectorDTO
if err := c.BodyParser(&req); err != nil {
return utils.ValidationErrorResponse(c, map[string][]string{
"body": {"format JSON tidak valid"},
})
}
if errs, valid := req.ValidateRequestCollector(); !valid {
return utils.ValidationErrorResponse(c, errs)
}
userID := c.Locals("userID").(string)
err := h.service.CreateCollector(context.Background(), userID, req)
if err != nil {
return utils.InternalServerErrorResponse(c, err.Error())
}
return utils.CreateResponse(c, nil, "Collector berhasil dibuat")
}
// POST /collectors/:id/trash
func (h *collectorHandler) AddTrashToCollector(c *fiber.Ctx) error {
collectorID := c.Params("id")
var req dto.RequestAddAvaibleTrash
if err := c.BodyParser(&req); err != nil {
return utils.ValidationErrorResponse(c, map[string][]string{
"body": {"format JSON tidak valid"},
})
}
if errs, valid := req.ValidateRequestAddAvaibleTrash(); !valid {
return utils.ValidationErrorResponse(c, errs)
}
err := h.service.AddTrashToCollector(context.Background(), collectorID, req)
if err != nil {
return utils.InternalServerErrorResponse(c, err.Error())
}
return utils.SuccessResponse(c, nil, "Trash berhasil ditambahkan")
}
// GET /collectors/:id
func (h *collectorHandler) GetCollectorByID(c *fiber.Ctx) error {
collectorID := c.Params("id")
result, err := h.service.GetCollectorByID(context.Background(), collectorID)
if err != nil {
return utils.ErrorResponse(c, "Collector tidak ditemukan")
}
return utils.SuccessResponse(c, result, "Data collector berhasil diambil")
}
func (h *collectorHandler) GetCollectorByUserID(c *fiber.Ctx) error {
// collectorID := c.Params("id")
userID, ok := c.Locals("userID").(string)
if !ok || userID == "" {
return utils.GenericResponse(c, fiber.StatusUnauthorized, "Unauthorized: User session not found") return utils.GenericResponse(c, fiber.StatusUnauthorized, "Unauthorized: User session not found")
} }
requestPickupId := c.Params("id") result, err := h.service.GetCollectorByUserID(context.Background(), userID)
if requestPickupId == "" {
return utils.ErrorResponse(c, "RequestPickup ID is required")
}
req, err := h.service.ConfirmRequestPickup(requestPickupId, collectorId)
if err != nil { if err != nil {
return utils.ErrorResponse(c, err.Error()) return utils.ErrorResponse(c, "Collector tidak ditemukan")
} }
return utils.SuccessResponse(c, result, "Data collector berhasil diambil")
return utils.SuccessResponse(c, req, "Request pickup confirmed successfully")
} }
func (h *CollectorHandler) GetAvaibleCollector(c *fiber.Ctx) error { // PATCH /collectors/:id
func (h *collectorHandler) UpdateCollector(c *fiber.Ctx) error {
userId := c.Locals("userID").(string) collectorID := c.Params("id")
var req struct {
requests, err := h.service.FindCollectorsNearby(userId) JobStatus *string `json:"job_status"`
if err != nil { Rating float32 `json:"rating"`
return utils.ErrorResponse(c, err.Error()) AddressID string `json:"address_id"`
} }
return utils.SuccessResponse(c, requests, "menampilkan data collector terdekat") if err := c.BodyParser(&req); err != nil {
return utils.ValidationErrorResponse(c, map[string][]string{
"body": {"format JSON tidak valid"},
})
}
if req.AddressID == "" {
return utils.ValidationErrorResponse(c, map[string][]string{
"address_id": {"tidak boleh kosong"},
})
}
err := h.service.UpdateCollector(context.Background(), collectorID, req.JobStatus, req.Rating, req.AddressID)
if err != nil {
return utils.InternalServerErrorResponse(c, err.Error())
}
return utils.SuccessResponse(c, nil, "Collector berhasil diperbarui")
} }
func (h *CollectorHandler) ConfirmRequestManualPickup(c *fiber.Ctx) error { func (h *collectorHandler) UpdateJobStatus(c *fiber.Ctx) error {
userId := c.Locals("userID").(string) collectorID := c.Params("id")
requestId := c.Params("request_id") var req struct {
if requestId == "" { JobStatus string `json:"job_status"`
fmt.Println("requestid dibutuhkan")
} }
var request dto.SelectCollectorRequest if err := c.BodyParser(&req); err != nil {
if err := c.BodyParser(&request); err != nil { return utils.ValidationErrorResponse(c, map[string][]string{
return fmt.Errorf("error parsing request body: %v", err) "body": {"format JSON tidak valid"},
})
} }
message, err := h.service.ConfirmRequestManualPickup(requestId, userId) if req.JobStatus != "active" && req.JobStatus != "inactive" {
return utils.ValidationErrorResponse(c, map[string][]string{
"job_status": {"harus bernilai 'active' atau 'inactive'"},
})
}
err := h.service.UpdateCollector(c.Context(), collectorID, &req.JobStatus, 0, "")
if err != nil { if err != nil {
return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Error confirming pickup: %v", err)) return utils.InternalServerErrorResponse(c, err.Error())
} }
return utils.SuccessResponse(c, message, "berhasil konfirmasi request") return utils.SuccessResponse(c, nil, "Status collector berhasil diperbarui")
}
// PATCH /collectors/:id/trash
func (h *collectorHandler) UpdateTrash(c *fiber.Ctx) error {
collectorID := c.Params("id")
var req []dto.RequestAvaibleTrashbyCollector
if err := c.BodyParser(&req); err != nil {
return utils.ValidationErrorResponse(c, map[string][]string{
"body": {"format JSON tidak valid"},
})
}
for i, t := range req {
if t.TrashId == "" {
return utils.ValidationErrorResponse(c, map[string][]string{
"trash_id": {t.TrashId, "trash_id tidak boleh kosong pada item ke " + string(rune(i))},
})
}
if t.TrashPrice <= 0 {
return utils.ValidationErrorResponse(c, map[string][]string{
"trash_price": {"trash_price harus lebih dari 0 pada item ke " + string(rune(i))},
})
}
}
err := h.service.UpdateAvaibleTrashByCollector(context.Background(), collectorID, req)
if err != nil {
return utils.InternalServerErrorResponse(c, err.Error())
}
return utils.SuccessResponse(c, nil, "Trash berhasil diperbarui")
}
// DELETE /collectors/trash/:id
func (h *collectorHandler) DeleteTrash(c *fiber.Ctx) error {
trashID := c.Params("id")
if trashID == "" {
return utils.ValidationErrorResponse(c, map[string][]string{
"trash_id": {"tidak boleh kosong"},
})
}
err := h.service.DeleteAvaibleTrash(context.Background(), trashID)
if err != nil {
return utils.InternalServerErrorResponse(c, err.Error())
}
return utils.SuccessResponse(c, nil, "Trash berhasil dihapus")
} }

View File

@ -1,92 +1,92 @@
package handler package handler
import ( // import (
"fmt" // "fmt"
"rijig/dto" // "rijig/dto"
"rijig/internal/services" // "rijig/internal/services"
"rijig/utils" // "rijig/utils"
"github.com/gofiber/fiber/v2" // "github.com/gofiber/fiber/v2"
) // )
type RequestPickupHandler struct { // type RequestPickupHandler struct {
service services.RequestPickupService // service services.RequestPickupService
} // }
func NewRequestPickupHandler(service services.RequestPickupService) *RequestPickupHandler { // func NewRequestPickupHandler(service services.RequestPickupService) *RequestPickupHandler {
return &RequestPickupHandler{service: service} // return &RequestPickupHandler{service: service}
} // }
func (h *RequestPickupHandler) CreateRequestPickup(c *fiber.Ctx) error { // func (h *RequestPickupHandler) CreateRequestPickup(c *fiber.Ctx) error {
userID, ok := c.Locals("userID").(string) // userID, ok := c.Locals("userID").(string)
if !ok || userID == "" { // if !ok || userID == "" {
return utils.GenericResponse(c, fiber.StatusUnauthorized, "Unauthorized: User session not found") // return utils.GenericResponse(c, fiber.StatusUnauthorized, "Unauthorized: User session not found")
} // }
var request dto.RequestPickup // var request dto.RequestPickup
if err := c.BodyParser(&request); err != nil { // if err := c.BodyParser(&request); err != nil {
return utils.GenericResponse(c, fiber.StatusBadRequest, "Invalid request body") // return utils.GenericResponse(c, fiber.StatusBadRequest, "Invalid request body")
} // }
errors, valid := request.ValidateRequestPickup() // errors, valid := request.ValidateRequestPickup()
if !valid { // if !valid {
return utils.ValidationErrorResponse(c, errors) // return utils.ValidationErrorResponse(c, errors)
} // }
response, err := h.service.CreateRequestPickup(request, userID) // response, err := h.service.CreateRequestPickup(request, userID)
if err != nil { // if err != nil {
return utils.InternalServerErrorResponse(c, fmt.Sprintf("Error creating request pickup: %v", err)) // return utils.InternalServerErrorResponse(c, fmt.Sprintf("Error creating request pickup: %v", err))
} // }
return utils.SuccessResponse(c, response, "Request pickup created successfully") // return utils.SuccessResponse(c, response, "Request pickup created successfully")
} // }
func (h *RequestPickupHandler) GetRequestPickupByID(c *fiber.Ctx) error { // func (h *RequestPickupHandler) GetRequestPickupByID(c *fiber.Ctx) error {
id := c.Params("id") // id := c.Params("id")
response, err := h.service.GetRequestPickupByID(id) // response, err := h.service.GetRequestPickupByID(id)
if err != nil { // if err != nil {
return utils.GenericResponse(c, fiber.StatusNotFound, fmt.Sprintf("Request pickup with ID %s not found: %v", id, err)) // return utils.GenericResponse(c, fiber.StatusNotFound, fmt.Sprintf("Request pickup with ID %s not found: %v", id, err))
} // }
return utils.SuccessResponse(c, response, "Request pickup retrieved successfully") // return utils.SuccessResponse(c, response, "Request pickup retrieved successfully")
} // }
func (h *RequestPickupHandler) GetRequestPickups(c *fiber.Ctx) error { // func (h *RequestPickupHandler) GetRequestPickups(c *fiber.Ctx) error {
collectorId := c.Locals("userID").(string) // collectorId := c.Locals("userID").(string)
requests, err := h.service.GetRequestPickupsForCollector(collectorId) // requests, err := h.service.GetRequestPickupsForCollector(collectorId)
if err != nil { // if err != nil {
return utils.ErrorResponse(c, err.Error()) // return utils.ErrorResponse(c, err.Error())
} // }
return utils.SuccessResponse(c, requests, "Automatic request pickups retrieved successfully") // return utils.SuccessResponse(c, requests, "Automatic request pickups retrieved successfully")
} // }
func (h *RequestPickupHandler) AssignCollectorToRequest(c *fiber.Ctx) error { // func (h *RequestPickupHandler) AssignCollectorToRequest(c *fiber.Ctx) error {
userId, ok := c.Locals("userID").(string) // userId, ok := c.Locals("userID").(string)
if !ok || userId == "" { // if !ok || userId == "" {
return utils.GenericResponse(c, fiber.StatusUnauthorized, "Unauthorized: User session not found") // return utils.GenericResponse(c, fiber.StatusUnauthorized, "Unauthorized: User session not found")
} // }
var request dto.SelectCollectorRequest // var request dto.SelectCollectorRequest
errors, valid := request.ValidateSelectCollectorRequest() // errors, valid := request.ValidateSelectCollectorRequest()
if !valid { // if !valid {
return utils.ValidationErrorResponse(c, errors) // return utils.ValidationErrorResponse(c, errors)
} // }
if err := c.BodyParser(&request); err != nil { // if err := c.BodyParser(&request); err != nil {
return fmt.Errorf("error parsing request body: %v", err) // return fmt.Errorf("error parsing request body: %v", err)
} // }
err := h.service.SelectCollectorInRequest(userId, request.Collector_id) // err := h.service.SelectCollectorInRequest(userId, request.Collector_id)
if err != nil { // if err != nil {
return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Error assigning collector: %v", err)) // return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Error assigning collector: %v", err))
} // }
return utils.GenericResponse(c, fiber.StatusOK, "berhasil memilih collector") // return utils.GenericResponse(c, fiber.StatusOK, "berhasil memilih collector")
} // }

View File

@ -1,115 +1,177 @@
package repositories package repositories
import ( import (
"context"
"errors" "errors"
"fmt"
"log"
"rijig/model"
"gorm.io/gorm" // "fmt"
// "log"
"rijig/config"
"rijig/model"
// "gorm.io/gorm"
) )
type CollectorRepository interface { type CollectorRepository interface {
FindActiveCollectors() ([]model.Collector, error) // FindActiveCollectors() ([]model.Collector, error)
FindCollectorById(collector_id string) (*model.Collector, error) // FindCollectorById(collector_id string) (*model.Collector, error)
FindCollectorByIdWithoutAddr(collector_id string) (*model.Collector, error) // FindCollectorByIdWithoutAddr(collector_id string) (*model.Collector, error)
CreateCollector(collector *model.Collector) error // CreateCollector(collector *model.Collector) error
UpdateCollector(userId string, jobStatus string) (*model.Collector, error) // UpdateCollector(userId string, jobStatus string) (*model.Collector, error)
// FindAllAutomaticMethodRequestWithDistance(requestMethod, statuspickup string, collectorLat, collectorLon float64, maxDistance float64) ([]model.RequestPickup, error)
CreateCollector(ctx context.Context, collector *model.Collector) error
AddAvaibleTrash(ctx context.Context, trashItems []model.AvaibleTrashByCollector) error
GetCollectorByID(ctx context.Context, collectorID string) (*model.Collector, error)
GetCollectorByUserID(ctx context.Context, userID string) (*model.Collector, error)
GetTrashItemByID(ctx context.Context, id string) (*model.AvaibleTrashByCollector, error)
UpdateCollector(ctx context.Context, collector *model.Collector, updates map[string]interface{}) error
UpdateAvaibleTrashByCollector(ctx context.Context, collectorID string, updatedTrash []model.AvaibleTrashByCollector) error
DeleteAvaibleTrash(ctx context.Context, trashID string) error
} }
type collectorRepository struct { type collectorRepository struct {
DB *gorm.DB // DB *gorm.DB
} }
func NewCollectorRepository(db *gorm.DB) CollectorRepository { // func NewCollectorRepository(db *gorm.DB) CollectorRepository {
return &collectorRepository{DB: db} // return &collectorRepository{DB: db}
// }
func NewCollectorRepository() CollectorRepository {
return &collectorRepository{}
} }
func (r *collectorRepository) FindActiveCollectors() ([]model.Collector, error) { // func (r *collectorRepository) FindActiveCollectors() ([]model.Collector, error) {
var collectors []model.Collector // var collectors []model.Collector
err := r.DB.Preload("Address").Where("job_status = ?", "active").First(&collectors).Error // err := r.DB.Preload("Address").Where("job_status = ?", "active").First(&collectors).Error
if err != nil { // if err != nil {
return nil, fmt.Errorf("failed to fetch active collectors: %v", err) // return nil, fmt.Errorf("failed to fetch active collectors: %v", err)
// }
// return collectors, nil
// }
// func (r *collectorRepository) FindCollectorById(collector_id string) (*model.Collector, error) {
// var collector model.Collector
// err := r.DB.Preload("Address").Where("user_id = ?", collector_id).First(&collector).Error
// if err != nil {
// return nil, fmt.Errorf("error fetching collector: %v", err)
// }
// fmt.Printf("menampilkan data collector %v", &collector)
// return &collector, nil
// }
// func (r *collectorRepository) FindCollectorByIdWithoutAddr(collector_id string) (*model.Collector, error) {
// var collector model.Collector
// err := r.DB.Where("user_id = ?", collector_id).First(&collector).Error
// if err != nil {
// return nil, fmt.Errorf("error fetching collector: %v", err)
// }
// fmt.Printf("menampilkan data collector %v", &collector)
// return &collector, nil
// }
// func (r *collectorRepository) CreateCollector(collector *model.Collector) error {
// if err := r.DB.Create(collector).Error; err != nil {
// return fmt.Errorf("failed to create collector: %v", err)
// }
// return nil
// }
// func (r *collectorRepository) UpdateCollector(userId string, jobStatus string) (*model.Collector, error) {
// var existingCollector model.Collector
// if err := r.DB.Where("user_id = ?", userId).First(&existingCollector).Error; err != nil {
// if errors.Is(err, gorm.ErrRecordNotFound) {
// return nil, fmt.Errorf("collector dengan user_id %s tidak ditemukan", userId)
// }
// log.Printf("Gagal mencari collector: %v", err)
// return nil, fmt.Errorf("gagal fetching collector: %w", err)
// }
// if jobStatus != "active" && jobStatus != "nonactive" {
// return nil, fmt.Errorf("invalid job status: %v", jobStatus)
// }
// if err := r.DB.Model(&existingCollector).Update("jobstatus", jobStatus).Error; err != nil {
// log.Printf("Gagal mengupdate data collector: %v", err)
// return nil, fmt.Errorf("gagal mengupdate job status untuk collector: %w", err)
// }
// return &existingCollector, nil
// }
func (r *collectorRepository) CreateCollector(ctx context.Context, collector *model.Collector) error {
return config.DB.WithContext(ctx).Create(collector).Error
}
func (r *collectorRepository) AddAvaibleTrash(ctx context.Context, trashItems []model.AvaibleTrashByCollector) error {
if len(trashItems) == 0 {
return nil
} }
return config.DB.WithContext(ctx).Create(&trashItems).Error
return collectors, nil
} }
func (r *collectorRepository) FindCollectorById(collector_id string) (*model.Collector, error) { func (r *collectorRepository) GetCollectorByID(ctx context.Context, collectorID string) (*model.Collector, error) {
var collector model.Collector var collector model.Collector
err := r.DB.Preload("Address").Where("user_id = ?", collector_id).First(&collector).Error err := config.DB.WithContext(ctx).
Preload("User").
Preload("Address").
Preload("AvaibleTrashByCollector.TrashCategory").
First(&collector, "id = ?", collectorID).Error
if err != nil { if err != nil {
return nil, fmt.Errorf("error fetching collector: %v", err) return nil, err
} }
fmt.Printf("menampilkan data collector %v", &collector)
return &collector, nil return &collector, nil
} }
func (r *collectorRepository) FindCollectorByIdWithoutAddr(collector_id string) (*model.Collector, error) { func (r *collectorRepository) GetCollectorByUserID(ctx context.Context, userID string) (*model.Collector, error) {
var collector model.Collector var collector model.Collector
err := r.DB.Where("user_id = ?", collector_id).First(&collector).Error err := config.DB.WithContext(ctx).
Preload("User").
Preload("Address").
Preload("AvaibleTrashByCollector.TrashCategory").
First(&collector, "user_id = ?", userID).Error
if err != nil { if err != nil {
return nil, fmt.Errorf("error fetching collector: %v", err) return nil, err
} }
fmt.Printf("menampilkan data collector %v", &collector)
return &collector, nil return &collector, nil
} }
func (r *collectorRepository) CreateCollector(collector *model.Collector) error { func (r *collectorRepository) GetTrashItemByID(ctx context.Context, id string) (*model.AvaibleTrashByCollector, error) {
if err := r.DB.Create(collector).Error; err != nil { var item model.AvaibleTrashByCollector
return fmt.Errorf("failed to create collector: %v", err) if err := config.DB.WithContext(ctx).First(&item, "id = ?", id).Error; err != nil {
return nil, err
}
return &item, nil
}
func (r *collectorRepository) UpdateCollector(ctx context.Context, collector *model.Collector, updates map[string]interface{}) error {
return config.DB.WithContext(ctx).
Model(&model.Collector{}).
Where("id = ?", collector.ID).
Updates(updates).Error
}
func (r *collectorRepository) UpdateAvaibleTrashByCollector(ctx context.Context, collectorID string, updatedTrash []model.AvaibleTrashByCollector) error {
for _, trash := range updatedTrash {
err := config.DB.WithContext(ctx).
Model(&model.AvaibleTrashByCollector{}).
Where("collector_id = ? AND trash_category_id = ?", collectorID, trash.TrashCategoryID).
Update("price", trash.Price).Error
if err != nil {
return err
}
} }
return nil return nil
} }
func (r *collectorRepository) UpdateCollector(userId string, jobStatus string) (*model.Collector, error) { func (r *collectorRepository) DeleteAvaibleTrash(ctx context.Context, trashID string) error {
var existingCollector model.Collector if trashID == "" {
return errors.New("trash_id cannot be empty")
if err := r.DB.Where("user_id = ?", userId).First(&existingCollector).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, fmt.Errorf("collector dengan user_id %s tidak ditemukan", userId)
}
log.Printf("Gagal mencari collector: %v", err)
return nil, fmt.Errorf("gagal fetching collector: %w", err)
} }
return config.DB.WithContext(ctx).
if jobStatus != "active" && jobStatus != "nonactive" { Delete(&model.AvaibleTrashByCollector{}, "id = ?", trashID).Error
return nil, fmt.Errorf("invalid job status: %v", jobStatus)
}
if err := r.DB.Model(&existingCollector).Update("jobstatus", jobStatus).Error; err != nil {
log.Printf("Gagal mengupdate data collector: %v", err)
return nil, fmt.Errorf("gagal mengupdate job status untuk collector: %w", err)
}
return &existingCollector, nil
} }
// // #====experimen====#
// func (r *collectorRepository) FindAllAutomaticMethodRequestWithDistance(requestMethod, statuspickup string, collectorLat, collectorLon float64, maxDistance float64) ([]model.RequestPickup, error) {
// var requests []model.RequestPickup
// err := r.DB.Preload("RequestItems").
// Where("request_method = ? AND status_pickup = ?", requestMethod, statuspickup).
// Find(&requests).Error
// if err != nil {
// return nil, fmt.Errorf("error fetching request pickups with request_method '%s' and status '%s': %v", requestMethod, statuspickup, err)
// }
// var nearbyRequests []model.RequestPickup
// for _, request := range requests {
// address := request.Address
// requestCoord := utils.Coord{Lat: address.Latitude, Lon: address.Longitude}
// collectorCoord := utils.Coord{Lat: collectorLat, Lon: collectorLon}
// _, km := utils.Distance(requestCoord, collectorCoord)
// if km <= maxDistance {
// nearbyRequests = append(nearbyRequests, request)
// }
// }
// return nearbyRequests, nil
// }

View File

@ -1,10 +1,12 @@
package repositories package repositories
import ( import (
"context"
"errors" "errors"
"fmt" "fmt"
"log" "log"
"rijig/config"
"rijig/model" "rijig/model"
"gorm.io/gorm" "gorm.io/gorm"
@ -22,6 +24,7 @@ type TrashRepository interface {
UpdateCategoryName(id string, newName string) error UpdateCategoryName(id string, newName string) error
UpdateCategory(id string, updateTrashCategory *model.TrashCategory) (*model.TrashCategory, error) UpdateCategory(id string, updateTrashCategory *model.TrashCategory) (*model.TrashCategory, error)
UpdateTrashDetail(id string, description string, price float64) error UpdateTrashDetail(id string, description string, price float64) error
UpdateEstimatedPrice(ctx context.Context, trashCategoryID string) error
DeleteCategory(id string) error DeleteCategory(id string) error
DeleteTrashDetail(id string) error DeleteTrashDetail(id string) error
} }
@ -131,6 +134,23 @@ func (r *trashRepository) UpdateTrashDetail(id string, description string, price
return nil return nil
} }
func (r *trashRepository) UpdateEstimatedPrice(ctx context.Context, trashCategoryID string) error {
var avg float64
err := config.DB.WithContext(ctx).
Model(&model.AvaibleTrashByCollector{}).
Where("trash_category_id = ?", trashCategoryID).
Select("AVG(price)").Scan(&avg).Error
if err != nil {
return err
}
return config.DB.WithContext(ctx).
Model(&model.TrashCategory{}).
Where("id = ?", trashCategoryID).
Update("estimated_price", avg).Error
}
func (r *trashRepository) DeleteCategory(id string) error { func (r *trashRepository) DeleteCategory(id string) error {
if err := r.DB.Delete(&model.TrashCategory{}, "id = ?", id).Error; err != nil { if err := r.DB.Delete(&model.TrashCategory{}, "id = ?", id).Error; err != nil {
return fmt.Errorf("failed to delete category: %v", err) return fmt.Errorf("failed to delete category: %v", err)

View File

@ -1,151 +1,224 @@
package services package services
import ( import (
"fmt" "context"
"errors"
"rijig/dto" "rijig/dto"
"rijig/internal/repositories" "rijig/internal/repositories"
"rijig/utils" "rijig/model"
"time"
) )
type CollectorService interface { type CollectorService interface {
FindCollectorsNearby(userId string) ([]dto.ResponseCollectorDTO, error) CreateCollector(ctx context.Context, userID string, req dto.RequestCollectorDTO) error
ConfirmRequestPickup(requestId, collectorId string) (*dto.ResponseRequestPickup, error) AddTrashToCollector(ctx context.Context, collectorID string, req dto.RequestAddAvaibleTrash) error
ConfirmRequestManualPickup(requestId, collectorId string) (any, error) GetCollectorByID(ctx context.Context, collectorID string) (*dto.ResponseCollectorDTO, error)
GetCollectorByUserID(ctx context.Context, userID string) (*dto.ResponseCollectorDTO, error)
UpdateCollector(ctx context.Context, collectorID string, jobStatus *string, rating float32, addressID string) error
UpdateAvaibleTrashByCollector(ctx context.Context, collectorID string, updatedTrash []dto.RequestAvaibleTrashbyCollector) error
DeleteAvaibleTrash(ctx context.Context, trashID string) error
} }
type collectorService struct { type collectorService struct {
repo repositories.CollectorRepository repo repositories.CollectorRepository
repoColl repositories.RequestPickupRepository trashRepo repositories.TrashRepository
repoAddress repositories.AddressRepository
repoUser repositories.UserProfilRepository
} }
func NewCollectorService(repo repositories.CollectorRepository, func NewCollectorService(repo repositories.CollectorRepository, trashRepo repositories.TrashRepository,
repoColl repositories.RequestPickupRepository,
repoAddress repositories.AddressRepository, ) CollectorService {
repoUser repositories.UserProfilRepository) CollectorService {
return &collectorService{repo: repo, repoColl: repoColl, repoAddress: repoAddress, repoUser: repoUser} return &collectorService{repo: repo, trashRepo: trashRepo}
} }
func (s *collectorService) FindCollectorsNearby(userId string) ([]dto.ResponseCollectorDTO, error) { func (s *collectorService) CreateCollector(ctx context.Context, userID string, req dto.RequestCollectorDTO) error {
collectors, err := s.repo.FindActiveCollectors() collector := &model.Collector{
if err != nil { UserID: userID,
return nil, fmt.Errorf("error fetching active collectors: %v", err) AddressID: req.AddressId,
JobStatus: "inactive",
Rating: 5,
} }
var avaibleCollectResp []dto.ResponseCollectorDTO if err := s.repo.CreateCollector(ctx, collector); err != nil {
return err
for _, collector := range collectors {
request, err := s.repoColl.FindRequestPickupByAddressAndStatus(userId, "waiting_collector", "otomatis")
if err != nil {
return nil, fmt.Errorf("gagal mendapatkan data request pickup dengan userid: %v", err)
}
_, distance := utils.Distance(
utils.Coord{Lat: request.Address.Latitude, Lon: request.Address.Longitude},
utils.Coord{Lat: collector.Address.Latitude, Lon: collector.Address.Longitude},
)
if distance <= 20 {
mappedRequest := dto.ResponseCollectorDTO{
ID: collector.ID,
UserId: collector.UserID,
AddressId: collector.AddressId,
Rating: collector.Rating,
}
user, err := s.repoUser.FindByID(collector.UserID)
if err != nil {
return nil, fmt.Errorf("error fetching user data: %v", err)
}
mappedRequest.User = []dto.UserResponseDTO{
{
Name: user.Name,
Phone: user.Phone,
},
}
address, err := s.repoAddress.FindAddressByID(collector.AddressId)
if err != nil {
return nil, fmt.Errorf("error fetching address data: %v", err)
}
mappedRequest.Address = []dto.AddressResponseDTO{
{
District: address.District,
Village: address.Village,
Detail: address.Detail,
},
}
avaibleCollectResp = append(avaibleCollectResp, mappedRequest)
}
} }
return avaibleCollectResp, nil var trashItems []model.AvaibleTrashByCollector
for _, item := range req.AvaibleTrashbyCollector {
trashItems = append(trashItems, model.AvaibleTrashByCollector{
CollectorID: collector.ID,
TrashCategoryID: item.TrashId,
Price: item.TrashPrice,
})
}
if err := s.repo.AddAvaibleTrash(ctx, trashItems); err != nil {
return err
}
for _, t := range trashItems {
_ = s.trashRepo.UpdateEstimatedPrice(ctx, t.TrashCategoryID)
}
return nil
} }
func (s *collectorService) ConfirmRequestPickup(requestId, collectorId string) (*dto.ResponseRequestPickup, error) { func (s *collectorService) AddTrashToCollector(ctx context.Context, collectorID string, req dto.RequestAddAvaibleTrash) error {
request, err := s.repoColl.FindRequestPickupByID(requestId) var trashItems []model.AvaibleTrashByCollector
if err != nil { for _, item := range req.AvaibleTrash {
return nil, fmt.Errorf("request pickup not found: %v", err) trashItems = append(trashItems, model.AvaibleTrashByCollector{
CollectorID: collectorID,
TrashCategoryID: item.TrashId,
Price: item.TrashPrice,
})
}
if err := s.repo.AddAvaibleTrash(ctx, trashItems); err != nil {
return err
} }
if request.StatusPickup != "waiting_collector" { for _, t := range trashItems {
return nil, fmt.Errorf("pickup request is not in 'waiting_collector' status") _ = s.trashRepo.UpdateEstimatedPrice(ctx, t.TrashCategoryID)
} }
collector, err := s.repo.FindCollectorById(collectorId) return nil
if err != nil {
return nil, fmt.Errorf("collector tidak ditemukan: %v", err)
}
request.StatusPickup = "confirmed"
request.CollectorID = &collector.ID
*request.ConfirmedByCollectorAt = time.Now()
err = s.repoColl.UpdateRequestPickup(requestId, request)
if err != nil {
return nil, fmt.Errorf("failed to update request pickup: %v", err)
}
confirmedAt, _ := utils.FormatDateToIndonesianFormat(*request.ConfirmedByCollectorAt)
response := dto.ResponseRequestPickup{
StatusPickup: request.StatusPickup,
CollectorID: *request.CollectorID,
ConfirmedByCollectorAt: confirmedAt,
}
return &response, nil
} }
func (s *collectorService) ConfirmRequestManualPickup(requestId, collectorId string) (any, error) { func (s *collectorService) GetCollectorByID(ctx context.Context, collectorID string) (*dto.ResponseCollectorDTO, error) {
collector, err := s.repo.GetCollectorByID(ctx, collectorID)
request, err := s.repoColl.FindRequestPickupByID(requestId)
if err != nil { if err != nil {
return nil, fmt.Errorf("collector tidak ditemukan: %v", err) return nil, err
} }
coll, err := s.repo.FindCollectorByIdWithoutAddr(collectorId) response := &dto.ResponseCollectorDTO{
if err != nil { ID: collector.ID,
return nil, fmt.Errorf("%v", err) UserId: collector.UserID,
AddressId: collector.AddressID,
JobStatus: &collector.JobStatus,
Rating: collector.Rating,
User: &dto.UserResponseDTO{
ID: collector.User.ID,
Name: collector.User.Name,
Phone: collector.User.Phone,
},
Address: &dto.AddressResponseDTO{
Province: collector.Address.Province,
District: collector.Address.District,
Regency: collector.Address.Regency,
Village: collector.Address.Village,
PostalCode: collector.Address.PostalCode,
Latitude: collector.Address.Latitude,
Longitude: collector.Address.Longitude,
},
} }
if coll.ID != *request.CollectorID { for _, item := range collector.AvaibleTrashByCollector {
return nil, fmt.Errorf("collectorid tidak sesuai dengan request") response.AvaibleTrashbyCollector = append(response.AvaibleTrashbyCollector, dto.ResponseAvaibleTrashByCollector{
ID: item.ID,
TrashId: item.TrashCategory.ID,
TrashName: item.TrashCategory.Name,
TrashIcon: item.TrashCategory.Icon,
TrashPrice: item.Price,
})
} }
request.StatusPickup = "confirmed" return response, nil
*request.ConfirmedByCollectorAt = time.Now() }
err = s.repoColl.UpdateRequestPickup(requestId, request) func (s *collectorService) GetCollectorByUserID(ctx context.Context, userID string) (*dto.ResponseCollectorDTO, error) {
if err != nil { collector, err := s.repo.GetCollectorByUserID(ctx, userID)
return nil, fmt.Errorf("failed to update request pickup: %v", err) if err != nil {
} return nil, err
}
return "berhasil konfirmasi request pickup", nil
response := &dto.ResponseCollectorDTO{
ID: collector.ID,
UserId: collector.UserID,
AddressId: collector.AddressID,
JobStatus: &collector.JobStatus,
Rating: collector.Rating,
User: &dto.UserResponseDTO{
ID: collector.User.ID,
Name: collector.User.Name,
Phone: collector.User.Phone,
},
Address: &dto.AddressResponseDTO{
Province: collector.Address.Province,
District: collector.Address.District,
Regency: collector.Address.Regency,
Village: collector.Address.Village,
PostalCode: collector.Address.PostalCode,
Latitude: collector.Address.Latitude,
Longitude: collector.Address.Longitude,
},
}
for _, item := range collector.AvaibleTrashByCollector {
response.AvaibleTrashbyCollector = append(response.AvaibleTrashbyCollector, dto.ResponseAvaibleTrashByCollector{
ID: item.ID,
TrashId: item.TrashCategory.ID,
TrashName: item.TrashCategory.Name,
TrashIcon: item.TrashCategory.Icon,
TrashPrice: item.Price,
})
}
return response, nil
}
func (s *collectorService) UpdateCollector(ctx context.Context, collectorID string, jobStatus *string, rating float32, addressID string) error {
updates := make(map[string]interface{})
if jobStatus != nil {
updates["job_status"] = *jobStatus
}
if rating > 0 {
updates["rating"] = rating
}
if addressID != "" {
updates["address_id"] = addressID
}
if len(updates) == 0 {
return errors.New("tidak ada data yang diubah")
}
return s.repo.UpdateCollector(ctx, &model.Collector{ID: collectorID}, updates)
}
func (s *collectorService) UpdateAvaibleTrashByCollector(ctx context.Context, collectorID string, updatedTrash []dto.RequestAvaibleTrashbyCollector) error {
var updated []model.AvaibleTrashByCollector
for _, item := range updatedTrash {
updated = append(updated, model.AvaibleTrashByCollector{
CollectorID: collectorID,
TrashCategoryID: item.TrashId,
Price: item.TrashPrice,
})
}
if err := s.repo.UpdateAvaibleTrashByCollector(ctx, collectorID, updated); err != nil {
return err
}
for _, item := range updated {
_ = s.trashRepo.UpdateEstimatedPrice(ctx, item.TrashCategoryID)
}
return nil
}
func (s *collectorService) DeleteAvaibleTrash(ctx context.Context, trashID string) error {
if trashID == "" {
return errors.New("trash_id tidak boleh kosong")
}
item, err := s.repo.GetTrashItemByID(ctx, trashID)
if err != nil {
return err
}
if err := s.repo.DeleteAvaibleTrash(ctx, trashID); err != nil {
return err
}
return s.trashRepo.UpdateEstimatedPrice(ctx, item.TrashCategoryID)
} }

View File

@ -9,11 +9,11 @@ import (
) )
type RequestPickupService interface { type RequestPickupService interface {
CreateRequestPickup(request dto.RequestPickup, UserId string) (*dto.ResponseRequestPickup, error) // CreateRequestPickup(request dto.RequestPickup, UserId string) (*dto.ResponseRequestPickup, error)
GetRequestPickupByID(id string) (*dto.ResponseRequestPickup, error) // GetRequestPickupByID(id string) (*dto.ResponseRequestPickup, error)
GetAllRequestPickups(userid string) ([]dto.ResponseRequestPickup, error) // GetAllRequestPickups(userid string) ([]dto.ResponseRequestPickup, error)
GetRequestPickupsForCollector(collectorId string) ([]dto.ResponseRequestPickup, error) // GetRequestPickupsForCollector(collectorId string) ([]dto.ResponseRequestPickup, error)
SelectCollectorInRequest(userId, collectorId string) error // SelectCollectorInRequest(userId, collectorId string) error
} }
type requestPickupService struct { type requestPickupService struct {
@ -152,198 +152,198 @@ func (s *requestPickupService) GetAllRequestPickups(userid string) ([]dto.Respon
return response, nil return response, nil
} }
func (s *requestPickupService) GetRequestPickupsForCollector(collectorId string) ([]dto.ResponseRequestPickup, error) { // func (s *requestPickupService) GetRequestPickupsForCollector(collectorId string) ([]dto.ResponseRequestPickup, error) {
requests, err := s.repo.GetAutomaticRequestPickupsForCollector() // requests, err := s.repo.GetAutomaticRequestPickupsForCollector()
if err != nil { // if err != nil {
return nil, fmt.Errorf("error retrieving automatic pickup requests: %v", err) // return nil, fmt.Errorf("error retrieving automatic pickup requests: %v", err)
} // }
var response []dto.ResponseRequestPickup // var response []dto.ResponseRequestPickup
for _, req := range requests { // for _, req := range requests {
collector, err := s.repoColl.FindCollectorById(collectorId) // collector, err := s.repoColl.FindCollectorById(collectorId)
if err != nil { // if err != nil {
return nil, fmt.Errorf("error fetching collector data: %v", err) // return nil, fmt.Errorf("error fetching collector data: %v", err)
} // }
_, distance := utils.Distance( // _, distance := utils.Distance(
utils.Coord{Lat: collector.Address.Latitude, Lon: collector.Address.Longitude}, // utils.Coord{Lat: collector.Address.Latitude, Lon: collector.Address.Longitude},
utils.Coord{Lat: req.Address.Latitude, Lon: req.Address.Longitude}, // utils.Coord{Lat: req.Address.Latitude, Lon: req.Address.Longitude},
) // )
if distance <= 20 { // if distance <= 20 {
mappedRequest := dto.ResponseRequestPickup{ // mappedRequest := dto.ResponseRequestPickup{
ID: req.ID, // ID: req.ID,
UserId: req.UserId, // UserId: req.UserId,
AddressID: req.AddressId, // AddressID: req.AddressId,
EvidenceImage: req.EvidenceImage, // EvidenceImage: req.EvidenceImage,
StatusPickup: req.StatusPickup, // StatusPickup: req.StatusPickup,
CreatedAt: req.CreatedAt.Format("2006-01-02 15:04:05"), // CreatedAt: req.CreatedAt.Format("2006-01-02 15:04:05"),
UpdatedAt: req.UpdatedAt.Format("2006-01-02 15:04:05"), // UpdatedAt: req.UpdatedAt.Format("2006-01-02 15:04:05"),
} // }
user, err := s.repoUser.FindByID(req.UserId) // user, err := s.repoUser.FindByID(req.UserId)
if err != nil { // if err != nil {
return nil, fmt.Errorf("error fetching user data: %v", err) // return nil, fmt.Errorf("error fetching user data: %v", err)
} // }
mappedRequest.User = []dto.UserResponseDTO{ // mappedRequest.User = []dto.UserResponseDTO{
{ // {
Name: user.Name, // Name: user.Name,
Phone: user.Phone, // Phone: user.Phone,
}, // },
} // }
address, err := s.repoAddress.FindAddressByID(req.AddressId) // address, err := s.repoAddress.FindAddressByID(req.AddressId)
if err != nil { // if err != nil {
return nil, fmt.Errorf("error fetching address data: %v", err) // return nil, fmt.Errorf("error fetching address data: %v", err)
} // }
mappedRequest.Address = []dto.AddressResponseDTO{ // mappedRequest.Address = []dto.AddressResponseDTO{
{ // {
District: address.District, // District: address.District,
Village: address.Village, // Village: address.Village,
Detail: address.Detail, // Detail: address.Detail,
}, // },
} // }
requestItems, err := s.repo.GetRequestPickupItems(req.ID) // requestItems, err := s.repo.GetRequestPickupItems(req.ID)
if err != nil { // if err != nil {
return nil, fmt.Errorf("error fetching request items: %v", err) // return nil, fmt.Errorf("error fetching request items: %v", err)
} // }
var mappedRequestItems []dto.ResponseRequestPickupItem // var mappedRequestItems []dto.ResponseRequestPickupItem
for _, item := range requestItems { // for _, item := range requestItems {
trashCategory, err := s.repoTrash.GetCategoryByID(item.TrashCategoryId) // trashCategory, err := s.repoTrash.GetCategoryByID(item.TrashCategoryId)
if err != nil { // if err != nil {
return nil, fmt.Errorf("error fetching trash category: %v", err) // return nil, fmt.Errorf("error fetching trash category: %v", err)
} // }
mappedRequestItems = append(mappedRequestItems, dto.ResponseRequestPickupItem{ // mappedRequestItems = append(mappedRequestItems, dto.ResponseRequestPickupItem{
ID: item.ID, // ID: item.ID,
TrashCategory: []dto.ResponseTrashCategoryDTO{{ // TrashCategory: []dto.ResponseTrashCategoryDTO{{
Name: trashCategory.Name, // Name: trashCategory.Name,
Icon: trashCategory.Icon, // Icon: trashCategory.Icon,
}}, // }},
EstimatedAmount: item.EstimatedAmount, // EstimatedAmount: item.EstimatedAmount,
}) // })
} // }
mappedRequest.RequestItems = mappedRequestItems // mappedRequest.RequestItems = mappedRequestItems
response = append(response, mappedRequest) // response = append(response, mappedRequest)
} // }
} // }
return response, nil // return response, nil
} // }
func (s *requestPickupService) GetManualRequestPickupsForCollector(collectorId string) ([]dto.ResponseRequestPickup, error) { // func (s *requestPickupService) GetManualRequestPickupsForCollector(collectorId string) ([]dto.ResponseRequestPickup, error) {
collector, err := s.repoColl.FindCollectorById(collectorId) // collector, err := s.repoColl.FindCollectorById(collectorId)
if err != nil { // if err != nil {
return nil, fmt.Errorf("error fetching collector data: %v", err) // return nil, fmt.Errorf("error fetching collector data: %v", err)
} // }
requests, err := s.repo.GetManualReqMethodforCollect(collector.ID) // requests, err := s.repo.GetManualReqMethodforCollect(collector.ID)
if err != nil { // if err != nil {
return nil, fmt.Errorf("error retrieving manual pickup requests: %v", err) // return nil, fmt.Errorf("error retrieving manual pickup requests: %v", err)
} // }
var response []dto.ResponseRequestPickup // var response []dto.ResponseRequestPickup
for _, req := range requests { // for _, req := range requests {
createdAt, _ := utils.FormatDateToIndonesianFormat(req.CreatedAt) // createdAt, _ := utils.FormatDateToIndonesianFormat(req.CreatedAt)
updatedAt, _ := utils.FormatDateToIndonesianFormat(req.UpdatedAt) // updatedAt, _ := utils.FormatDateToIndonesianFormat(req.UpdatedAt)
mappedRequest := dto.ResponseRequestPickup{ // mappedRequest := dto.ResponseRequestPickup{
ID: req.ID, // ID: req.ID,
UserId: req.UserId, // UserId: req.UserId,
AddressID: req.AddressId, // AddressID: req.AddressId,
EvidenceImage: req.EvidenceImage, // EvidenceImage: req.EvidenceImage,
StatusPickup: req.StatusPickup, // StatusPickup: req.StatusPickup,
CreatedAt: createdAt, // CreatedAt: createdAt,
UpdatedAt: updatedAt, // UpdatedAt: updatedAt,
} // }
user, err := s.repoUser.FindByID(req.UserId) // user, err := s.repoUser.FindByID(req.UserId)
if err != nil { // if err != nil {
return nil, fmt.Errorf("error fetching user data: %v", err) // return nil, fmt.Errorf("error fetching user data: %v", err)
} // }
mappedRequest.User = []dto.UserResponseDTO{ // mappedRequest.User = []dto.UserResponseDTO{
{ // {
Name: user.Name, // Name: user.Name,
Phone: user.Phone, // Phone: user.Phone,
}, // },
} // }
address, err := s.repoAddress.FindAddressByID(req.AddressId) // address, err := s.repoAddress.FindAddressByID(req.AddressId)
if err != nil { // if err != nil {
return nil, fmt.Errorf("error fetching address data: %v", err) // return nil, fmt.Errorf("error fetching address data: %v", err)
} // }
mappedRequest.Address = []dto.AddressResponseDTO{ // mappedRequest.Address = []dto.AddressResponseDTO{
{ // {
District: address.District, // District: address.District,
Village: address.Village, // Village: address.Village,
Detail: address.Detail, // Detail: address.Detail,
}, // },
} // }
requestItems, err := s.repo.GetRequestPickupItems(req.ID) // requestItems, err := s.repo.GetRequestPickupItems(req.ID)
if err != nil { // if err != nil {
return nil, fmt.Errorf("error fetching request items: %v", err) // return nil, fmt.Errorf("error fetching request items: %v", err)
} // }
var mappedRequestItems []dto.ResponseRequestPickupItem // var mappedRequestItems []dto.ResponseRequestPickupItem
for _, item := range requestItems { // for _, item := range requestItems {
trashCategory, err := s.repoTrash.GetCategoryByID(item.TrashCategoryId) // trashCategory, err := s.repoTrash.GetCategoryByID(item.TrashCategoryId)
if err != nil { // if err != nil {
return nil, fmt.Errorf("error fetching trash category: %v", err) // return nil, fmt.Errorf("error fetching trash category: %v", err)
} // }
mappedRequestItems = append(mappedRequestItems, dto.ResponseRequestPickupItem{ // mappedRequestItems = append(mappedRequestItems, dto.ResponseRequestPickupItem{
ID: item.ID, // ID: item.ID,
TrashCategory: []dto.ResponseTrashCategoryDTO{{ // TrashCategory: []dto.ResponseTrashCategoryDTO{{
Name: trashCategory.Name, // Name: trashCategory.Name,
Icon: trashCategory.Icon, // Icon: trashCategory.Icon,
}}, // }},
EstimatedAmount: item.EstimatedAmount, // EstimatedAmount: item.EstimatedAmount,
}) // })
} // }
mappedRequest.RequestItems = mappedRequestItems // mappedRequest.RequestItems = mappedRequestItems
response = append(response, mappedRequest) // response = append(response, mappedRequest)
} // }
return response, nil // return response, nil
} // }
func (s *requestPickupService) SelectCollectorInRequest(userId, collectorId string) error { // func (s *requestPickupService) SelectCollectorInRequest(userId, collectorId string) error {
request, err := s.repo.FindRequestPickupByStatus(userId, "waiting_collector", "manual") // request, err := s.repo.FindRequestPickupByStatus(userId, "waiting_collector", "manual")
if err != nil { // if err != nil {
return fmt.Errorf("request pickup not found: %v", err) // return fmt.Errorf("request pickup not found: %v", err)
} // }
if request.StatusPickup != "waiting_collector" && request.RequestMethod != "manual" { // if request.StatusPickup != "waiting_collector" && request.RequestMethod != "manual" {
return fmt.Errorf("pickup request is not in 'waiting_collector' status and not 'manual' method") // return fmt.Errorf("pickup request is not in 'waiting_collector' status and not 'manual' method")
} // }
collector, err := s.repoColl.FindCollectorByIdWithoutAddr(collectorId) // collector, err := s.repoColl.FindCollectorByIdWithoutAddr(collectorId)
if err != nil { // if err != nil {
return fmt.Errorf("collector tidak ditemukan: %v", err) // return fmt.Errorf("collector tidak ditemukan: %v", err)
} // }
request.CollectorID = &collector.ID // request.CollectorID = &collector.ID
err = s.repo.UpdateRequestPickup(request.ID, request) // err = s.repo.UpdateRequestPickup(request.ID, request)
if err != nil { // if err != nil {
return fmt.Errorf("failed to update request pickup: %v", err) // return fmt.Errorf("failed to update request pickup: %v", err)
} // }
return nil // return nil
} // }

View File

@ -45,7 +45,7 @@ func AddOrUpdateCartItem(userID string, newItem dto.RequestCartItems) error {
updated := false updated := false
for i, item := range cartItems { for i, item := range cartItems {
if item.TrashID == newItem.TrashID { if item.TrashCategoryID == newItem.TrashCategoryID {
if newItem.Amount == 0 { if newItem.Amount == 0 {
cartItems = append(cartItems[:i], cartItems[i+1:]...) cartItems = append(cartItems[:i], cartItems[i+1:]...)
} else { } else {
@ -80,14 +80,14 @@ func DeleteCartItem(userID, trashID string) error {
index := -1 index := -1
for i, item := range items { for i, item := range items {
if item.TrashID == trashID { if item.TrashCategoryID == trashID {
index = i index = i
break break
} }
} }
if index == -1 { if index == -1 {
log.Printf("TrashID %s not found in cart for user %s", trashID, userID) log.Printf("TrashCategoryID %s not found in cart for user %s", trashID, userID)
return fmt.Errorf("trashid not found") return fmt.Errorf("trashid not found")
} }

View File

@ -31,9 +31,9 @@ func (s *CartService) CommitCartToDatabase(userID string) error {
var estimatedTotal float32 var estimatedTotal float32
for _, item := range items { for _, item := range items {
trash, err := s.Repo.GetTrashCategoryByID(item.TrashID) trash, err := s.Repo.GetTrashCategoryByID(item.TrashCategoryID)
if err != nil { if err != nil {
log.Printf("Trash category not found for trashID: %s", item.TrashID) log.Printf("Trash category not found for trashID: %s", item.TrashCategoryID)
continue continue
} }
@ -43,7 +43,7 @@ func (s *CartService) CommitCartToDatabase(userID string) error {
cartItems = append(cartItems, model.CartItem{ cartItems = append(cartItems, model.CartItem{
ID: uuid.NewString(), ID: uuid.NewString(),
TrashID: item.TrashID, TrashCategoryID: item.TrashCategoryID,
Amount: item.Amount, Amount: item.Amount,
SubTotalEstimatedPrice: subTotal, SubTotalEstimatedPrice: subTotal,
}) })
@ -87,7 +87,7 @@ func (s *CartService) GetCartFromRedis(userID string) (*dto.CartResponse, error)
var cartItemDTOs []dto.CartItemResponse var cartItemDTOs []dto.CartItemResponse
for _, item := range items { for _, item := range items {
trash, err := s.Repo.GetTrashCategoryByID(item.TrashID) trash, err := s.Repo.GetTrashCategoryByID(item.TrashCategoryID)
if err != nil { if err != nil {
continue continue
} }
@ -133,7 +133,7 @@ func (s *CartService) GetCart(userID string) (*dto.CartResponse, error) {
for _, item := range cartDB.CartItems { for _, item := range cartDB.CartItems {
items = append(items, dto.CartItemResponse{ items = append(items, dto.CartItemResponse{
ItemId: item.ID, ItemId: item.ID,
TrashId: item.TrashID, TrashId: item.TrashCategoryID,
TrashIcon: item.TrashCategory.Icon, TrashIcon: item.TrashCategory.Icon,
TrashName: item.TrashCategory.Name, TrashName: item.TrashCategory.Name,
Amount: item.Amount, Amount: item.Amount,

View File

@ -1,16 +1,25 @@
package model package model
import "time"
type Collector struct { type Collector struct {
ID string `gorm:"primaryKey;type:uuid;default:uuid_generate_v4();unique;not null" json:"id"` ID string `gorm:"primaryKey;type:uuid;default:uuid_generate_v4();unique;not null" json:"id"`
UserID string `gorm:"not null" json:"userId"` UserID string `gorm:"not null" json:"user_id"`
User User `gorm:"foreignKey:UserID;constraint:OnUpdate:CASCADE,OnDelete:CASCADE;" json:"user"` User User `gorm:"foreignKey:UserID;constraint:OnUpdate:CASCADE,OnDelete:CASCADE;" json:"-"`
JobStatus string `gorm:"default:inactive" json:"jobstatus"` JobStatus string `gorm:"default:inactive" json:"jobstatus"`
Rating float32 `gorm:"default:5" json:"rating"` Rating float32 `gorm:"default:5" json:"rating"`
AddressId string `gorm:"not null" json:"address_id"` AddressID string `gorm:"not null" json:"address_id"`
Address Address `gorm:"foreignKey:AddressId;constraint:OnUpdate:CASCADE,OnDelete:CASCADE;" json:"address"` Address Address `gorm:"foreignKey:AddressID;constraint:OnUpdate:CASCADE,OnDelete:CASCADE;" json:"address"`
AvaibleTrashByCollector []AvaibleTrashByCollector `gorm:"foreignKey:CollectorID;constraint:OnDelete:CASCADE;" json:"avaible_trash"`
CreatedAt time.Time `gorm:"default:current_timestamp" json:"created_at"`
UpdatedAt time.Time `gorm:"default:current_timestamp" json:"updated_at"`
} }
// job_status { type AvaibleTrashByCollector struct {
// "active", ID string `gorm:"primaryKey;type:uuid;default:uuid_generate_v4();unique;not null" json:"id"`
// "inactive" CollectorID string `gorm:"not null" json:"collector_id"`
// } Collector *Collector `gorm:"foreignKey:CollectorID;constraint:OnDelete:CASCADE;" json:"-"`
TrashCategoryID string `gorm:"not null" json:"trash_id"`
TrashCategory TrashCategory `gorm:"foreignKey:TrashCategoryID;constraint:OnUpdate:CASCADE,OnDelete:CASCADE;" json:"trash_category"`
Price float32 `json:"price"`
}

View File

@ -11,17 +11,18 @@ type Cart struct {
CartItems []CartItem `gorm:"foreignKey:CartID;constraint:OnDelete:CASCADE;" json:"cartitems"` CartItems []CartItem `gorm:"foreignKey:CartID;constraint:OnDelete:CASCADE;" json:"cartitems"`
TotalAmount float32 `json:"totalamount"` TotalAmount float32 `json:"totalamount"`
EstimatedTotalPrice float32 `json:"estimated_totalprice"` EstimatedTotalPrice float32 `json:"estimated_totalprice"`
CreatedAt time.Time `gorm:"autoCreateTime" json:"createdAt"` CreatedAt time.Time `gorm:"default:current_timestamp" json:"created_at"`
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updatedAt"` UpdatedAt time.Time `gorm:"default:current_timestamp" json:"updated_at"`
} }
type CartItem struct { type CartItem struct {
ID string `gorm:"primaryKey;type:uuid;default:uuid_generate_v4()" json:"id"` ID string `gorm:"primaryKey;type:uuid;default:uuid_generate_v4()" json:"id"`
CartID string `gorm:"not null" json:"-"` CartID string `gorm:"not null" json:"-"`
TrashID string `gorm:"not null" json:"trashid"` Cart *Cart `gorm:"foreignKey:CartID;constraint:OnDelete:CASCADE;" json:"-"`
TrashCategory TrashCategory `gorm:"foreignKey:TrashID;constraint:OnDelete:CASCADE;" json:"trash"` TrashCategoryID string `gorm:"not null" json:"trash_id"`
TrashCategory TrashCategory `gorm:"foreignKey:TrashCategoryID;constraint:OnUpdate:CASCADE,OnDelete:CASCADE;" json:"trash_category"`
Amount float32 `json:"amount"` Amount float32 `json:"amount"`
SubTotalEstimatedPrice float32 `json:"subtotalestimatedprice"` SubTotalEstimatedPrice float32 `json:"subtotalestimatedprice"`
CreatedAt time.Time `gorm:"autoCreateTime" json:"createdAt"` CreatedAt time.Time `gorm:"default:current_timestamp" json:"created_at"`
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updatedAt"` UpdatedAt time.Time `gorm:"default:current_timestamp" json:"updated_at"`
} }

View File

@ -13,18 +13,39 @@ import (
) )
func CollectorRouter(api fiber.Router) { func CollectorRouter(api fiber.Router) {
repo := repositories.NewCollectorRepository(config.DB) // repo := repositories.NewCollectorRepository(config.DB)
repoReq := repositories.NewRequestPickupRepository(config.DB) // repoReq := repositories.NewRequestPickupRepository(config.DB)
repoAddress := repositories.NewAddressRepository(config.DB) // repoAddress := repositories.NewAddressRepository(config.DB)
repoUser := repositories.NewUserProfilRepository(config.DB) // repoUser := repositories.NewUserProfilRepository(config.DB)
colectorService := services.NewCollectorService(repo, repoReq, repoAddress, repoUser) // colectorService := services.NewCollectorService(repo, repoReq, repoAddress, repoUser)
collectorHandler := handler.NewCollectorHandler(colectorService) // collectorHandler := handler.NewCollectorHandler(colectorService)
collector := api.Group("/collector") // collector := api.Group("/collector")
collector.Use(middleware.AuthMiddleware) // collector.Use(middleware.AuthMiddleware)
collector.Put("confirmrequest/:id", collectorHandler.ConfirmRequestPickup) // collector.Put("confirmrequest/:id", collectorHandler.ConfirmRequestPickup)
collector.Put("confirm-manual/request/:request_id", collectorHandler.ConfirmRequestManualPickup) // collector.Put("confirm-manual/request/:request_id", collectorHandler.ConfirmRequestManualPickup)
collector.Get("/avaible", collectorHandler.GetAvaibleCollector) // collector.Get("/avaible", collectorHandler.GetAvaibleCollector)
// Middleware Auth dan Role
// Inisialisasi repository dan service
collectorRepo := repositories.NewCollectorRepository()
trashRepo := repositories.NewTrashRepository(config.DB)
collectorService := services.NewCollectorService(collectorRepo, trashRepo)
collectorHandler := handler.NewCollectorHandler(collectorService)
// Group collector
collectors := api.Group("/collectors")
collectors.Use(middleware.AuthMiddleware)
// === Collector routes ===
collectors.Post("/", collectorHandler.CreateCollector) // Create collector
collectors.Post("/:id/trash", collectorHandler.AddTrashToCollector) // Add trash to collector
collectors.Get("/:id", collectorHandler.GetCollectorByID) // Get collector by ID
collectors.Get("/", collectorHandler.GetCollectorByUserID) // Get collector by ID
collectors.Patch("/:id", collectorHandler.UpdateCollector) // Update collector fields
collectors.Patch("/:id/trash", collectorHandler.UpdateTrash)
collectors.Patch("/:id/job-status", collectorHandler.UpdateJobStatus)
collectors.Delete("/trash/:id", collectorHandler.DeleteTrash)
} }

View File

@ -1,45 +1,46 @@
package presentation package presentation
import ( // import (
"rijig/config" // "rijig/config"
"rijig/internal/handler" // "rijig/internal/handler"
"rijig/internal/repositories" // "rijig/internal/repositories"
"rijig/internal/services" // "rijig/internal/services"
"rijig/middleware" // "rijig/middleware"
"github.com/gofiber/fiber/v2" // "github.com/gofiber/fiber/v2"
) // )
func RequestPickupRouter(api fiber.Router) { // func RequestPickupRouter(api fiber.Router) {
// repo repositories.RequestPickupRepository // // repo repositories.RequestPickupRepository
// repoColl repositories.CollectorRepository // // repoColl repositories.CollectorRepository
// repoAddress repositories.AddressRepository // // repoAddress repositories.AddressRepository
// repoTrash repositories.TrashRepository // // repoTrash repositories.TrashRepository
// repoUser repositories.UserProfilRepository // // repoUser repositories.UserProfilRepository
requestRepo := repositories.NewRequestPickupRepository(config.DB) // requestRepo := repositories.NewRequestPickupRepository(config.DB)
repoColl := repositories.NewCollectorRepository(config.DB) // // repoColl := repositories.NewCollectorRepository(config.DB)
repoAddress := repositories.NewAddressRepository(config.DB) // repoColl := repositories.NewCollectorRepository()
Trashrepo := repositories.NewTrashRepository(config.DB) // repoAddress := repositories.NewAddressRepository(config.DB)
repouser := repositories.NewUserProfilRepository(config.DB) // Trashrepo := repositories.NewTrashRepository(config.DB)
// collectorRepo := repositories.NewCollectorRepository(config.DB) // repouser := repositories.NewUserProfilRepository(config.DB)
// // collectorRepo := repositories.NewCollectorRepository(config.DB)
requestPickupServices := services.NewRequestPickupService(requestRepo, repoColl, repoAddress, Trashrepo, repouser) // requestPickupServices := services.NewRequestPickupService(requestRepo, repoColl, repoAddress, Trashrepo, repouser)
// collectorService := services.NewCollectorService(collectorRepo, requestRepo, repoAddress) // // collectorService := services.NewCollectorService(collectorRepo, requestRepo, repoAddress)
// service services.RequestPickupService, // // service services.RequestPickupService,
// collectorService services.CollectorService // // collectorService services.CollectorService
requestPickupHandler := handler.NewRequestPickupHandler(requestPickupServices) // requestPickupHandler := handler.NewRequestPickupHandler(requestPickupServices)
requestPickupAPI := api.Group("/requestpickup") // requestPickupAPI := api.Group("/requestpickup")
requestPickupAPI.Use(middleware.AuthMiddleware) // requestPickupAPI.Use(middleware.AuthMiddleware)
requestPickupAPI.Post("/", requestPickupHandler.CreateRequestPickup) // requestPickupAPI.Post("/", requestPickupHandler.CreateRequestPickup)
// requestPickupAPI.Get("/get", middleware.AuthMiddleware, requestPickupHandler.GetAutomaticRequestByUser) // // requestPickupAPI.Get("/get", middleware.AuthMiddleware, requestPickupHandler.GetAutomaticRequestByUser)
requestPickupAPI.Get("/get-allrequest", requestPickupHandler.GetRequestPickups) // requestPickupAPI.Get("/get-allrequest", requestPickupHandler.GetRequestPickups)
requestPickupAPI.Patch("/select-collector", requestPickupHandler.AssignCollectorToRequest) // requestPickupAPI.Patch("/select-collector", requestPickupHandler.AssignCollectorToRequest)
// requestPickupAPI.Get("/:id", requestPickupHandler.GetRequestPickupByID) // // requestPickupAPI.Get("/:id", requestPickupHandler.GetRequestPickupByID)
// requestPickupAPI.Get("/", requestPickupHandler.GetAllRequestPickups) // // requestPickupAPI.Get("/", requestPickupHandler.GetAllRequestPickups)
// requestPickupAPI.Put("/:id", requestPickupHandler.UpdateRequestPickup) // // requestPickupAPI.Put("/:id", requestPickupHandler.UpdateRequestPickup)
// requestPickupAPI.Delete("/:id", requestPickupHandler.DeleteRequestPickup) // // requestPickupAPI.Delete("/:id", requestPickupHandler.DeleteRequestPickup)
} // }

View File

@ -26,7 +26,7 @@ func SetupRoutes(app *fiber.App) {
// || auth router || // // || auth router || //
presentation.IdentityCardRouter(api) presentation.IdentityCardRouter(api)
presentation.CompanyProfileRouter(api) presentation.CompanyProfileRouter(api)
presentation.RequestPickupRouter(api) // presentation.RequestPickupRouter(api)
presentation.CollectorRouter(api) presentation.CollectorRouter(api)
presentation.TrashCartRouter(api) presentation.TrashCartRouter(api)