From 490c7fc9fd746051726db8792cee13b74343b559 Mon Sep 17 00:00:00 2001 From: giovanni Date: Wed, 13 May 2026 13:28:37 +0700 Subject: [PATCH] add sorting server side po and expense --- .../controllers/expense.controller.go | 2 + .../expenses/services/expense.service.go | 35 +++++++++++++++- .../validations/expense.validation.go | 2 + .../controllers/purchase.controller.go | 2 + .../purchases/services/purchase.service.go | 41 ++++++++++++++++++- .../validations/purchase.validation.go | 2 + 6 files changed, 82 insertions(+), 2 deletions(-) diff --git a/internal/modules/expenses/controllers/expense.controller.go b/internal/modules/expenses/controllers/expense.controller.go index fddd4356..c7258c3d 100644 --- a/internal/modules/expenses/controllers/expense.controller.go +++ b/internal/modules/expenses/controllers/expense.controller.go @@ -65,6 +65,8 @@ func (u *ExpenseController) GetAll(c *fiber.Ctx) error { RealizationStatus: strings.TrimSpace(c.Query("realization_status", "")), ProjectFlockID: uint64(c.QueryInt("project_flock_id", 0)), ProjectFlockKandangID: uint64(c.QueryInt("project_flock_kandang_id", 0)), + SortBy: strings.TrimSpace(c.Query("sort_by", "")), + SortOrder: strings.TrimSpace(c.Query("sort_order", "")), } if isAllExpenseExcelExportRequest(c) { diff --git a/internal/modules/expenses/services/expense.service.go b/internal/modules/expenses/services/expense.service.go index 48a18042..37806d44 100644 --- a/internal/modules/expenses/services/expense.service.go +++ b/internal/modules/expenses/services/expense.service.go @@ -289,7 +289,40 @@ func (s expenseService) GetAll(c *fiber.Ctx, params *validation.Query) ([]expens like, ) } - return db.Order("expenses.created_at DESC").Order("expenses.updated_at DESC") + sortBy := strings.TrimSpace(params.SortBy) + sortOrder := strings.ToUpper(strings.TrimSpace(params.SortOrder)) + if sortOrder == "" { + sortOrder = "DESC" + } + + switch sortBy { + case "reference_number": + return db.Order("expenses.reference_number " + sortOrder) + case "transaction_date": + return db.Order("expenses.transaction_date " + sortOrder) + case "realization_date": + return db.Order("expenses.realization_date " + sortOrder) + case "location": + return db.Order("(SELECT COALESCE(name,'') FROM locations WHERE id = expenses.location_id) " + sortOrder) + case "created_user": + return db.Order("(SELECT COALESCE(name,'') FROM users WHERE id = expenses.created_by) " + sortOrder) + case "supplier": + return db.Order("(SELECT COALESCE(name,'') FROM suppliers WHERE id = expenses.supplier_id) " + sortOrder) + case "grand_total": + return db.Order(`(SELECT COALESCE( + (SELECT SUM(er.qty * er.price) FROM expense_realizations er + JOIN expense_nonstocks en ON en.id = er.expense_nonstock_id + WHERE en.expense_id = expenses.id), + (SELECT SUM(en2.qty * en2.price) FROM expense_nonstocks en2 + WHERE en2.expense_id = expenses.id), + 0)) ` + sortOrder) + case "is_paid": + return db.Order("expenses.is_paid " + sortOrder) + case "created_at": + return db.Order("expenses.created_at " + sortOrder) + default: + return db.Order("expenses.created_at DESC").Order("expenses.updated_at DESC") + } }) if scopeErr != nil { diff --git a/internal/modules/expenses/validations/expense.validation.go b/internal/modules/expenses/validations/expense.validation.go index 0046ce7f..9311e42d 100644 --- a/internal/modules/expenses/validations/expense.validation.go +++ b/internal/modules/expenses/validations/expense.validation.go @@ -54,6 +54,8 @@ type Query struct { RealizationStatus string `query:"realization_status" validate:"omitempty,max=100"` ProjectFlockID uint64 `query:"project_flock_id" validate:"omitempty,gt=0"` ProjectFlockKandangID uint64 `query:"project_flock_kandang_id" validate:"omitempty,gt=0"` + SortBy string `query:"sort_by" validate:"omitempty,oneof=reference_number transaction_date realization_date location created_user supplier grand_total is_paid created_at"` + SortOrder string `query:"sort_order" validate:"omitempty,oneof=asc desc ASC DESC"` } type CreateRealization struct { diff --git a/internal/modules/purchases/controllers/purchase.controller.go b/internal/modules/purchases/controllers/purchase.controller.go index e3bce86f..9906523e 100644 --- a/internal/modules/purchases/controllers/purchase.controller.go +++ b/internal/modules/purchases/controllers/purchase.controller.go @@ -102,6 +102,8 @@ func buildPurchaseQuery(c *fiber.Ctx) *validation.Query { ProjectFlockID: uint(c.QueryInt("project_flock_id", 0)), ProjectFlockKandangID: uint(c.QueryInt("project_flock_kandang_id", 0)), ProductCategoryID: strings.TrimSpace(c.Query("product_category_id")), + SortBy: strings.TrimSpace(c.Query("sort_by", "")), + SortOrder: strings.TrimSpace(c.Query("sort_order", "")), } } diff --git a/internal/modules/purchases/services/purchase.service.go b/internal/modules/purchases/services/purchase.service.go index 61285a6c..3e524054 100644 --- a/internal/modules/purchases/services/purchase.service.go +++ b/internal/modules/purchases/services/purchase.service.go @@ -261,7 +261,46 @@ func (s *purchaseService) GetAll(c *fiber.Ctx, params *validation.Query) ([]enti db = applyPurchaseApprovalStatusFilter(db, approvalStatuses) db = applyPurchaseSearchFilter(db, search) - return db.Order("created_at DESC").Order("purchases.id DESC") + sortBy := strings.TrimSpace(params.SortBy) + sortOrder := strings.ToUpper(strings.TrimSpace(params.SortOrder)) + if sortOrder == "" { + sortOrder = "DESC" + } + + switch sortBy { + case "po_expedition": + return db.Order(`(SELECT MIN(e.reference_number) FROM purchase_items pi + LEFT JOIN expense_nonstocks en ON en.id = pi.expense_nonstock_id + LEFT JOIN expenses e ON e.id = en.expense_id + WHERE pi.purchase_id = purchases.id) ` + sortOrder + " NULLS LAST") + case "supplier": + return db.Order(`(SELECT COALESCE(s.name, '') FROM suppliers s WHERE s.id = purchases.supplier_id) ` + sortOrder) + case "requester_name": + return db.Order(`(SELECT COALESCE(u.name, '') FROM users u WHERE u.id = purchases.created_by) ` + sortOrder) + case "products": + return db.Order(`(SELECT MIN(COALESCE(p.name, '')) FROM purchase_items pi + JOIN products p ON p.id = pi.product_id + WHERE pi.purchase_id = purchases.id) ` + sortOrder) + case "location": + return db.Order(`(SELECT MIN(COALESCE(l.name, '')) FROM purchase_items pi + JOIN warehouses w ON w.id = pi.warehouse_id + JOIN locations l ON l.id = w.location_id + WHERE pi.purchase_id = purchases.id) ` + sortOrder) + case "po_date": + return db.Order("purchases.po_date " + sortOrder) + case "received_date": + return db.Order(`(SELECT MIN(pi2.received_date) FROM purchase_items pi2 WHERE pi2.purchase_id = purchases.id) ` + sortOrder) + case "due_date": + return db.Order("purchases.due_date " + sortOrder) + case "status": + return db.Order(`(SELECT COALESCE(a.step_name, '') FROM approvals a + WHERE a.approvable_type = 'purchase' AND a.approvable_id = purchases.id + ORDER BY a.action_at DESC, a.id DESC LIMIT 1) ` + sortOrder) + case "created_at": + return db.Order("purchases.created_at " + sortOrder) + default: + return db.Order("created_at DESC").Order("purchases.id DESC") + } }) if err != nil { diff --git a/internal/modules/purchases/validations/purchase.validation.go b/internal/modules/purchases/validations/purchase.validation.go index cc467b8f..e8337493 100644 --- a/internal/modules/purchases/validations/purchase.validation.go +++ b/internal/modules/purchases/validations/purchase.validation.go @@ -81,4 +81,6 @@ type Query struct { Search string `query:"search" validate:"omitempty,max=100"` CreatedFrom string `query:"created_from" validate:"omitempty,datetime=2006-01-02"` CreatedTo string `query:"created_to" validate:"omitempty,datetime=2006-01-02"` + SortBy string `query:"sort_by" validate:"omitempty,oneof=po_expedition supplier requester_name products location po_date received_date due_date status created_at"` + SortOrder string `query:"sort_order" validate:"omitempty,oneof=asc desc ASC DESC"` }