mirror of
https://gitlab.com/mbugroup/lti-api.git
synced 2026-05-20 13:31:56 +00:00
feat(BE):Rekapitulasi hutang supplier
This commit is contained in:
@@ -16,6 +16,7 @@ require (
|
|||||||
github.com/golang-jwt/jwt/v5 v5.2.1
|
github.com/golang-jwt/jwt/v5 v5.2.1
|
||||||
github.com/google/uuid v1.6.0
|
github.com/google/uuid v1.6.0
|
||||||
github.com/jackc/pgconn v1.14.1
|
github.com/jackc/pgconn v1.14.1
|
||||||
|
github.com/jackc/pgx/v5 v5.5.5
|
||||||
github.com/redis/go-redis/v9 v9.14.0
|
github.com/redis/go-redis/v9 v9.14.0
|
||||||
github.com/sirupsen/logrus v1.9.3
|
github.com/sirupsen/logrus v1.9.3
|
||||||
github.com/spf13/viper v1.19.0
|
github.com/spf13/viper v1.19.0
|
||||||
@@ -60,7 +61,6 @@ require (
|
|||||||
github.com/jackc/pgpassfile v1.0.0 // indirect
|
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||||
github.com/jackc/pgproto3/v2 v2.3.2 // indirect
|
github.com/jackc/pgproto3/v2 v2.3.2 // indirect
|
||||||
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
|
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
|
||||||
github.com/jackc/pgx/v5 v5.5.5 // indirect
|
|
||||||
github.com/jackc/puddle/v2 v2.2.1 // indirect
|
github.com/jackc/puddle/v2 v2.2.1 // indirect
|
||||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||||
github.com/jinzhu/now v1.1.5 // indirect
|
github.com/jinzhu/now v1.1.5 // indirect
|
||||||
|
|||||||
@@ -262,14 +262,10 @@ github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVS
|
|||||||
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
|
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
|
||||||
github.com/xuri/efp v0.0.0-20240408161823-9ad904a10d6d h1:llb0neMWDQe87IzJLS4Ci7psK/lVsjIS2otl+1WyRyY=
|
github.com/xuri/efp v0.0.0-20240408161823-9ad904a10d6d h1:llb0neMWDQe87IzJLS4Ci7psK/lVsjIS2otl+1WyRyY=
|
||||||
github.com/xuri/efp v0.0.0-20240408161823-9ad904a10d6d/go.mod h1:ybY/Jr0T0GTCnYjKqmdwxyxn2BQf2RcQIIvex5QldPI=
|
github.com/xuri/efp v0.0.0-20240408161823-9ad904a10d6d/go.mod h1:ybY/Jr0T0GTCnYjKqmdwxyxn2BQf2RcQIIvex5QldPI=
|
||||||
github.com/xuri/efp v0.0.1 h1:fws5Rv3myXyYni8uwj2qKjVaRP30PdjeYe2Y6FDsCL8=
|
|
||||||
github.com/xuri/efp v0.0.1/go.mod h1:ybY/Jr0T0GTCnYjKqmdwxyxn2BQf2RcQIIvex5QldPI=
|
|
||||||
github.com/xuri/excelize/v2 v2.9.0 h1:1tgOaEq92IOEumR1/JfYS/eR0KHOCsRv/rYXXh6YJQE=
|
github.com/xuri/excelize/v2 v2.9.0 h1:1tgOaEq92IOEumR1/JfYS/eR0KHOCsRv/rYXXh6YJQE=
|
||||||
github.com/xuri/excelize/v2 v2.9.0/go.mod h1:uqey4QBZ9gdMeWApPLdhm9x+9o2lq4iVmjiLfBS5hdE=
|
github.com/xuri/excelize/v2 v2.9.0/go.mod h1:uqey4QBZ9gdMeWApPLdhm9x+9o2lq4iVmjiLfBS5hdE=
|
||||||
github.com/xuri/nfp v0.0.0-20240318013403-ab9948c2c4a7 h1:hPVCafDV85blFTabnqKgNhDCkJX25eik94Si9cTER4A=
|
github.com/xuri/nfp v0.0.0-20240318013403-ab9948c2c4a7 h1:hPVCafDV85blFTabnqKgNhDCkJX25eik94Si9cTER4A=
|
||||||
github.com/xuri/nfp v0.0.0-20240318013403-ab9948c2c4a7/go.mod h1:WwHg+CVyzlv/TX9xqBFXEZAuxOPxn2k1GNHwG41IIUQ=
|
github.com/xuri/nfp v0.0.0-20240318013403-ab9948c2c4a7/go.mod h1:WwHg+CVyzlv/TX9xqBFXEZAuxOPxn2k1GNHwG41IIUQ=
|
||||||
github.com/xuri/nfp v0.0.2-0.20250530014748-2ddeb826f9a9 h1:+C0TIdyyYmzadGaL/HBLbf3WdLgC29pgyhTjAT/0nuE=
|
|
||||||
github.com/xuri/nfp v0.0.2-0.20250530014748-2ddeb826f9a9/go.mod h1:WwHg+CVyzlv/TX9xqBFXEZAuxOPxn2k1GNHwG41IIUQ=
|
|
||||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||||
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
|
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
|
||||||
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||||
|
|||||||
@@ -44,7 +44,9 @@ const (
|
|||||||
P_ReportExpenseGetAll = "lti.repport.expense.list"
|
P_ReportExpenseGetAll = "lti.repport.expense.list"
|
||||||
P_ReportDeliveryGetAll = "lti.repport.delivery.list"
|
P_ReportDeliveryGetAll = "lti.repport.delivery.list"
|
||||||
P_ReportPurchaseSupplierGetAll = "lti.repport.purchasesupplier.list"
|
P_ReportPurchaseSupplierGetAll = "lti.repport.purchasesupplier.list"
|
||||||
|
P_ReportDebtSupplierGetAll = "lti.repport.debtsupplier.list"
|
||||||
P_ReportHppPerKandangGetAll = "lti.repport.gethppperkandang.list"
|
P_ReportHppPerKandangGetAll = "lti.repport.gethppperkandang.list"
|
||||||
|
P_ReportProductionResultGetAll = "lti.repport.production_result.list"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -134,18 +136,18 @@ const (
|
|||||||
P_NonstocksUpdateOne = "lti.master.nonstocks.update"
|
P_NonstocksUpdateOne = "lti.master.nonstocks.update"
|
||||||
P_NonstocksDeleteOne = "lti.master.nonstocks.delete"
|
P_NonstocksDeleteOne = "lti.master.nonstocks.delete"
|
||||||
|
|
||||||
P_ProductCategoriesGetAll = "lti.master.Product_categories.list"
|
P_ProductCategoriesGetAll = "lti.master.product_categories.list"
|
||||||
P_ProductCategoriesGetOne = "lti.master.Product_categories.detail"
|
P_ProductCategoriesGetOne = "lti.master.product_categories.detail"
|
||||||
P_ProductCategoriesCreateOne = "lti.master.Product_categories.create"
|
P_ProductCategoriesCreateOne = "lti.master.product_categories.create"
|
||||||
P_ProductCategoriesUpdateOne = "lti.master.Product_categories.update"
|
P_ProductCategoriesUpdateOne = "lti.master.product_categories.update"
|
||||||
P_ProductCategoriesDeleteOne = "lti.master.Product_categories.delete"
|
P_ProductCategoriesDeleteOne = "lti.master.product_categories.delete"
|
||||||
|
|
||||||
P_ProductsGetAll = "lti.master.Products.list"
|
|
||||||
P_ProductsGetOne = "lti.master.Products.detail"
|
|
||||||
P_ProductsCreateOne = "lti.master.Products.create"
|
|
||||||
P_ProductsUpdateOne = "lti.master.Products.update"
|
|
||||||
P_ProductsDeleteOne = "lti.master.Products.delete"
|
|
||||||
|
|
||||||
|
P_ProductsGetAll = "lti.master.products.list"
|
||||||
|
P_ProductsGetOne = "lti.master.products.detail"
|
||||||
|
P_ProductsCreateOne = "lti.master.products.create"
|
||||||
|
P_ProductsUpdateOne = "lti.master.products.update"
|
||||||
|
P_ProductsDeleteOne = "lti.master.products.delete"
|
||||||
|
|
||||||
P_SuppliersGetAll = "lti.master.suppliers.list"
|
P_SuppliersGetAll = "lti.master.suppliers.list"
|
||||||
P_SuppliersGetOne = "lti.master.suppliers.detail"
|
P_SuppliersGetOne = "lti.master.suppliers.detail"
|
||||||
P_SuppliersCreateOne = "lti.master.suppliers.create"
|
P_SuppliersCreateOne = "lti.master.suppliers.create"
|
||||||
@@ -207,15 +209,15 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
P_PurchaseGetAll = "lti.Purchase.list"
|
P_PurchaseGetAll = "lti.purchase.list"
|
||||||
P_PurchaseGetOne = "lti.Purchase.detail"
|
P_PurchaseGetOne = "lti.purchase.detail"
|
||||||
P_PurchaseCreateOne = "lti.Purchase.create"
|
P_PurchaseCreateOne = "lti.purchase.create"
|
||||||
P_PurchaseUpdateOne = "lti.Purchase.update"
|
P_PurchaseUpdateOne = "lti.purchase.update"
|
||||||
P_PurchaseDeleteOne = "lti.Purchase.delete"
|
P_PurchaseDeleteOne = "lti.purchase.delete"
|
||||||
P_PurchaseItemDeleteOne = "lti.Purchase.delete.item"
|
P_PurchaseItemDeleteOne = "lti.purchase.delete.item"
|
||||||
P_PurchaseReceive = "lti.Purchase.receive"
|
P_PurchaseReceive = "lti.purchase.receive"
|
||||||
P_PurchaseApprovalStaff = "lti.Purchase.approve.staff"
|
P_PurchaseApprovalStaff = "lti.purchase.approve.staff"
|
||||||
P_PurchaseApprovalManager = "lti.Purchase.approve.manager"
|
P_PurchaseApprovalManager = "lti.purchase.approve.manager"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|||||||
@@ -15,15 +15,9 @@ func UomRoutes(v1 fiber.Router, u user.UserService, s uom.UomService) {
|
|||||||
route := v1.Group("/uoms")
|
route := v1.Group("/uoms")
|
||||||
route.Use(m.Auth(u))
|
route.Use(m.Auth(u))
|
||||||
|
|
||||||
route.Get("/", ctrl.GetAll)
|
route.Get("/", m.RequirePermissions(m.P_UomsGetAll), ctrl.GetAll)
|
||||||
route.Post("/", ctrl.CreateOne)
|
route.Post("/", m.RequirePermissions(m.P_UomsCreateOne), ctrl.CreateOne)
|
||||||
route.Get("/:id", ctrl.GetOne)
|
route.Get("/:id", m.RequirePermissions(m.P_UomsGetOne), ctrl.GetOne)
|
||||||
route.Patch("/:id", ctrl.UpdateOne)
|
route.Patch("/:id", m.RequirePermissions(m.P_UomsUpdateOne), ctrl.UpdateOne)
|
||||||
route.Delete("/:id", ctrl.DeleteOne)
|
route.Delete("/:id", m.RequirePermissions(m.P_UomsDeleteOne), ctrl.DeleteOne)
|
||||||
|
|
||||||
route.Get("/",m.RequirePermissions(m.P_AreaGetAll), ctrl.GetAll)
|
|
||||||
route.Post("/",m.RequirePermissions(m.P_AreaCreateOne), ctrl.CreateOne)
|
|
||||||
route.Get("/:id",m.RequirePermissions(m.P_AreaGetOne), ctrl.GetOne)
|
|
||||||
route.Patch("/:id",m.RequirePermissions(m.P_AreaUpdateOne), ctrl.UpdateOne)
|
|
||||||
route.Delete("/:id",m.RequirePermissions(m.P_AreaDeleteOne), ctrl.DeleteOne)
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,12 +15,12 @@ func Routes(router fiber.Router, purchaseService service.PurchaseService, userSe
|
|||||||
route := router.Group("/purchases")
|
route := router.Group("/purchases")
|
||||||
route.Use(m.Auth(userService))
|
route.Use(m.Auth(userService))
|
||||||
|
|
||||||
route.Get("/",m.RequirePermissions(m.P_PurchaseGetAll), ctrl.GetAll)
|
route.Get("/", m.RequirePermissions(m.P_PurchaseGetAll), ctrl.GetAll)
|
||||||
route.Get("/:id",m.RequirePermissions(m.P_PurchaseGetOne), ctrl.GetOne)
|
route.Get("/:id", m.RequirePermissions(m.P_PurchaseGetOne), ctrl.GetOne)
|
||||||
route.Post("/", ctrl.CreateOne)
|
route.Post("/", m.RequirePermissions(m.P_PurchaseCreateOne), ctrl.CreateOne)
|
||||||
route.Post("/:id/approvals/staff", ctrl.ApproveStaffPurchase)
|
route.Post("/:id/approvals/staff", m.RequirePermissions(m.P_PurchaseApprovalStaff), ctrl.ApproveStaffPurchase)
|
||||||
route.Post("/:id/approvals/manager", ctrl.ApproveManagerPurchase)
|
route.Post("/:id/approvals/manager", m.RequirePermissions(m.P_PurchaseApprovalManager), ctrl.ApproveManagerPurchase)
|
||||||
route.Post("/:id/receipts",ctrl.ReceiveProducts)
|
route.Post("/:id/receipts", m.RequirePermissions(m.P_PurchaseReceive), ctrl.ReceiveProducts)
|
||||||
route.Delete("/:id", ctrl.DeletePurchase)
|
route.Delete("/:id", m.RequirePermissions(m.P_PurchaseDeleteOne), ctrl.DeletePurchase)
|
||||||
route.Delete("/:id/items", ctrl.DeleteItems)
|
route.Delete("/:id/items", m.RequirePermissions(m.P_PurchaseItemDeleteOne), ctrl.DeleteItems)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package controller
|
|||||||
import (
|
import (
|
||||||
"math"
|
"math"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"gitlab.com/mbugroup/lti-api.git/internal/modules/repports/dto"
|
"gitlab.com/mbugroup/lti-api.git/internal/modules/repports/dto"
|
||||||
service "gitlab.com/mbugroup/lti-api.git/internal/modules/repports/services"
|
service "gitlab.com/mbugroup/lti-api.git/internal/modules/repports/services"
|
||||||
@@ -164,6 +165,59 @@ func (c *RepportController) GetPurchaseSupplier(ctx *fiber.Ctx) error {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *RepportController) GetDebtSupplier(ctx *fiber.Ctx) error {
|
||||||
|
supplierIDs, err := parseCommaSeparatedInt64s(ctx.Query("supplier_ids", ""))
|
||||||
|
if err != nil {
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
query := &validation.DebtSupplierQuery{
|
||||||
|
Page: ctx.QueryInt("page", 1),
|
||||||
|
Limit: ctx.QueryInt("limit", 10),
|
||||||
|
SupplierIDs: supplierIDs,
|
||||||
|
StartDate: ctx.Query("start_date", ""),
|
||||||
|
EndDate: ctx.Query("end_date", ""),
|
||||||
|
FilterBy: ctx.Query("filter_by", ""),
|
||||||
|
SortOrder: ctx.Query("sort_order", ""),
|
||||||
|
}
|
||||||
|
|
||||||
|
if query.Page < 1 || query.Limit < 1 {
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, "page and limit must be greater than 0")
|
||||||
|
}
|
||||||
|
|
||||||
|
result, totalResults, err := c.RepportService.GetDebtSupplier(ctx, query)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
supplierIDs = query.SupplierIDs
|
||||||
|
if supplierIDs == nil {
|
||||||
|
supplierIDs = []int64{}
|
||||||
|
}
|
||||||
|
|
||||||
|
filters := map[string]interface{}{
|
||||||
|
"start_date": query.StartDate,
|
||||||
|
"end_date": query.EndDate,
|
||||||
|
"supplier_ids": supplierIDs,
|
||||||
|
"filter_by": query.FilterBy,
|
||||||
|
}
|
||||||
|
|
||||||
|
return ctx.Status(fiber.StatusOK).
|
||||||
|
JSON(response.SuccessWithPaginate[dto.DebtSupplierDTO]{
|
||||||
|
Code: fiber.StatusOK,
|
||||||
|
Status: "success",
|
||||||
|
Message: "Get supplier debt recap successfully",
|
||||||
|
Meta: response.Meta{
|
||||||
|
Page: query.Page,
|
||||||
|
Limit: query.Limit,
|
||||||
|
TotalPages: int64(math.Ceil(float64(totalResults) / float64(query.Limit))),
|
||||||
|
TotalResults: totalResults,
|
||||||
|
Filters: filters,
|
||||||
|
},
|
||||||
|
Data: result,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func (c *RepportController) GetHppPerKandang(ctx *fiber.Ctx) error {
|
func (c *RepportController) GetHppPerKandang(ctx *fiber.Ctx) error {
|
||||||
data, meta, err := c.RepportService.GetHppPerKandang(ctx)
|
data, meta, err := c.RepportService.GetHppPerKandang(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -227,3 +281,27 @@ func (c *RepportController) GetProductionResult(ctx *fiber.Ctx) error {
|
|||||||
Data: data,
|
Data: data,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func parseCommaSeparatedInt64s(raw string) ([]int64, error) {
|
||||||
|
raw = strings.TrimSpace(raw)
|
||||||
|
if raw == "" {
|
||||||
|
return []int64{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
parts := strings.Split(raw, ",")
|
||||||
|
result := make([]int64, 0, len(parts))
|
||||||
|
for _, part := range parts {
|
||||||
|
part = strings.TrimSpace(part)
|
||||||
|
if part == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
id, err := strconv.ParseInt(part, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fiber.NewError(fiber.StatusBadRequest, "supplier_ids must be comma separated integers")
|
||||||
|
}
|
||||||
|
result = append(result, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package dto
|
||||||
|
|
||||||
|
import (
|
||||||
|
areaDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/areas/dto"
|
||||||
|
supplierDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/suppliers/dto"
|
||||||
|
warehouseDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/warehouses/dto"
|
||||||
|
)
|
||||||
|
|
||||||
|
type DebtSupplierRowDTO struct {
|
||||||
|
PrNumber string `json:"pr_number"`
|
||||||
|
PoNumber string `json:"po_number"`
|
||||||
|
PrDate string `json:"pr_date"`
|
||||||
|
PoDate string `json:"po_date"`
|
||||||
|
Aging int `json:"aging"`
|
||||||
|
Area *areaDTO.AreaRelationDTO `json:"area,omitempty"`
|
||||||
|
Warehouse *warehouseDTO.WarehouseRelationDTO `json:"warehouse,omitempty"`
|
||||||
|
DueDate string `json:"due_date"`
|
||||||
|
DueStatus string `json:"due_status"`
|
||||||
|
TotalPrice float64 `json:"total_price"`
|
||||||
|
PaymentPrice float64 `json:"payment_price"`
|
||||||
|
DebtPrice float64 `json:"debt_price"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
TravelNumber string `json:"travel_number"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type DebtSupplierTotalDTO struct {
|
||||||
|
Aging int `json:"aging"`
|
||||||
|
TotalPrice float64 `json:"total_price"`
|
||||||
|
PaymentPrice float64 `json:"payment_price"`
|
||||||
|
DebtPrice float64 `json:"debt_price"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type DebtSupplierDTO struct {
|
||||||
|
Supplier *supplierDTO.SupplierRelationDTO `json:"supplier"`
|
||||||
|
Rows []DebtSupplierRowDTO `json:"rows"`
|
||||||
|
Total DebtSupplierTotalDTO `json:"total"`
|
||||||
|
}
|
||||||
@@ -31,12 +31,13 @@ func (RepportModule) RegisterRoutes(router fiber.Router, db *gorm.DB, validate *
|
|||||||
recordingRepository := recordingRepo.NewRecordingRepository(db)
|
recordingRepository := recordingRepo.NewRecordingRepository(db)
|
||||||
approvalRepository := commonRepo.NewApprovalRepository(db)
|
approvalRepository := commonRepo.NewApprovalRepository(db)
|
||||||
purchaseSupplierRepository := repportRepo.NewPurchaseSupplierRepository(db)
|
purchaseSupplierRepository := repportRepo.NewPurchaseSupplierRepository(db)
|
||||||
|
debtSupplierRepository := repportRepo.NewDebtSupplierRepository(db)
|
||||||
hppPerKandangRepository := repportRepo.NewHppPerKandangRepository(db)
|
hppPerKandangRepository := repportRepo.NewHppPerKandangRepository(db)
|
||||||
productionResultRepository := repportRepo.NewProductionResultRepository(db)
|
productionResultRepository := repportRepo.NewProductionResultRepository(db)
|
||||||
userRepository := rUser.NewUserRepository(db)
|
userRepository := rUser.NewUserRepository(db)
|
||||||
|
|
||||||
approvalSvc := approvalService.NewApprovalService(approvalRepository)
|
approvalSvc := approvalService.NewApprovalService(approvalRepository)
|
||||||
repportService := sRepport.NewRepportService(validate, expenseRealizationRepository, marketingDeliveryProductRepository, purchaseRepository, chickinRepository, recordingRepository, approvalSvc, purchaseSupplierRepository, hppPerKandangRepository, productionResultRepository)
|
repportService := sRepport.NewRepportService(validate, expenseRealizationRepository, marketingDeliveryProductRepository, purchaseRepository, chickinRepository, recordingRepository, approvalSvc, purchaseSupplierRepository, debtSupplierRepository, hppPerKandangRepository, productionResultRepository)
|
||||||
userService := sUser.NewUserService(userRepository, validate)
|
userService := sUser.NewUserService(userRepository, validate)
|
||||||
|
|
||||||
RepportRoutes(router, userService, repportService)
|
RepportRoutes(router, userService, repportService)
|
||||||
|
|||||||
@@ -0,0 +1,221 @@
|
|||||||
|
package repositories
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
entity "gitlab.com/mbugroup/lti-api.git/internal/entities"
|
||||||
|
validation "gitlab.com/mbugroup/lti-api.git/internal/modules/repports/validations"
|
||||||
|
"gitlab.com/mbugroup/lti-api.git/internal/utils"
|
||||||
|
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
type DebtSupplierRepository interface {
|
||||||
|
GetSuppliersWithPurchases(ctx context.Context, offset, limit int, filters *validation.DebtSupplierQuery) ([]entity.Supplier, int64, error)
|
||||||
|
GetPurchasesBySuppliers(ctx context.Context, supplierIDs []uint, filters *validation.DebtSupplierQuery) ([]entity.Purchase, error)
|
||||||
|
GetPaymentTotalsByReferences(ctx context.Context, supplierIDs []uint, references []string) (map[string]float64, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type debtSupplierRepositoryImpl struct {
|
||||||
|
db *gorm.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDebtSupplierRepository(db *gorm.DB) DebtSupplierRepository {
|
||||||
|
return &debtSupplierRepositoryImpl{db: db}
|
||||||
|
}
|
||||||
|
|
||||||
|
func resolveDebtSupplierDateColumn(filterBy string) string {
|
||||||
|
switch strings.ToLower(strings.TrimSpace(filterBy)) {
|
||||||
|
case "po_date":
|
||||||
|
return "purchases.po_date"
|
||||||
|
case "pr_date":
|
||||||
|
return "purchases.created_at"
|
||||||
|
case "do_date", "received_date", "":
|
||||||
|
return "purchase_items.received_date"
|
||||||
|
default:
|
||||||
|
return "purchase_items.received_date"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *debtSupplierRepositoryImpl) baseSupplierQuery(ctx context.Context, filters *validation.DebtSupplierQuery) *gorm.DB {
|
||||||
|
dateColumn := resolveDebtSupplierDateColumn(filters.FilterBy)
|
||||||
|
|
||||||
|
db := r.db.WithContext(ctx).
|
||||||
|
Model(&entity.Supplier{}).
|
||||||
|
Joins("JOIN purchases ON purchases.supplier_id = suppliers.id").
|
||||||
|
Joins("JOIN purchase_items ON purchase_items.purchase_id = purchases.id")
|
||||||
|
|
||||||
|
if len(filters.SupplierIDs) > 0 {
|
||||||
|
db = db.Where("suppliers.id IN ?", filters.SupplierIDs)
|
||||||
|
}
|
||||||
|
|
||||||
|
if filters.StartDate != "" {
|
||||||
|
if dateFrom, err := utils.ParseDateString(filters.StartDate); err == nil {
|
||||||
|
db = db.Where(fmt.Sprintf("DATE(%s) >= ?", dateColumn), dateFrom)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if filters.EndDate != "" {
|
||||||
|
if dateTo, err := utils.ParseDateString(filters.EndDate); err == nil {
|
||||||
|
db = db.Where(fmt.Sprintf("DATE(%s) <= ?", dateColumn), dateTo)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return db
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *debtSupplierRepositoryImpl) GetSuppliersWithPurchases(ctx context.Context, offset, limit int, filters *validation.DebtSupplierQuery) ([]entity.Supplier, int64, error) {
|
||||||
|
query := r.baseSupplierQuery(ctx, filters)
|
||||||
|
|
||||||
|
var totalSuppliers int64
|
||||||
|
if err := query.
|
||||||
|
Distinct("suppliers.id").
|
||||||
|
Count(&totalSuppliers).Error; err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if totalSuppliers == 0 {
|
||||||
|
return []entity.Supplier{}, 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if offset < 0 {
|
||||||
|
offset = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
var supplierIDs []uint
|
||||||
|
if err := query.
|
||||||
|
Select("suppliers.id").
|
||||||
|
Order("suppliers.id ASC").
|
||||||
|
Offset(offset).
|
||||||
|
Limit(limit).
|
||||||
|
Pluck("suppliers.id", &supplierIDs).Error; err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(supplierIDs) == 0 {
|
||||||
|
return []entity.Supplier{}, totalSuppliers, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var suppliers []entity.Supplier
|
||||||
|
if err := r.db.WithContext(ctx).
|
||||||
|
Where("id IN ?", supplierIDs).
|
||||||
|
Find(&suppliers).Error; err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return suppliers, totalSuppliers, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *debtSupplierRepositoryImpl) GetPurchasesBySuppliers(ctx context.Context, supplierIDs []uint, filters *validation.DebtSupplierQuery) ([]entity.Purchase, error) {
|
||||||
|
if len(supplierIDs) == 0 {
|
||||||
|
return []entity.Purchase{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
purchaseIDs, err := r.getPurchaseIDs(ctx, supplierIDs, filters)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(purchaseIDs) == 0 {
|
||||||
|
return []entity.Purchase{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
preloadItems := func(db *gorm.DB) *gorm.DB {
|
||||||
|
db = db.
|
||||||
|
Preload("Warehouse").
|
||||||
|
Preload("Warehouse.Area").
|
||||||
|
Order("purchase_items.id ASC")
|
||||||
|
|
||||||
|
if strings.EqualFold(strings.TrimSpace(filters.FilterBy), "do_date") || strings.EqualFold(strings.TrimSpace(filters.FilterBy), "received_date") || strings.TrimSpace(filters.FilterBy) == "" {
|
||||||
|
if filters.StartDate != "" {
|
||||||
|
if dateFrom, err := utils.ParseDateString(filters.StartDate); err == nil {
|
||||||
|
db = db.Where("DATE(purchase_items.received_date) >= ?", dateFrom)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if filters.EndDate != "" {
|
||||||
|
if dateTo, err := utils.ParseDateString(filters.EndDate); err == nil {
|
||||||
|
db = db.Where("DATE(purchase_items.received_date) <= ?", dateTo)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return db
|
||||||
|
}
|
||||||
|
|
||||||
|
var purchases []entity.Purchase
|
||||||
|
if err := r.db.WithContext(ctx).
|
||||||
|
Model(&entity.Purchase{}).
|
||||||
|
Preload("Supplier").
|
||||||
|
Preload("Items", preloadItems).
|
||||||
|
Where("purchases.id IN ?", purchaseIDs).
|
||||||
|
Order("purchases.id ASC").
|
||||||
|
Find(&purchases).Error; err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return purchases, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *debtSupplierRepositoryImpl) getPurchaseIDs(ctx context.Context, supplierIDs []uint, filters *validation.DebtSupplierQuery) ([]uint, error) {
|
||||||
|
dateColumn := resolveDebtSupplierDateColumn(filters.FilterBy)
|
||||||
|
|
||||||
|
db := r.db.WithContext(ctx).
|
||||||
|
Table("purchases").
|
||||||
|
Select("DISTINCT purchases.id").
|
||||||
|
Joins("JOIN purchase_items ON purchase_items.purchase_id = purchases.id").
|
||||||
|
Where("purchases.supplier_id IN ?", supplierIDs)
|
||||||
|
|
||||||
|
if filters.StartDate != "" {
|
||||||
|
if dateFrom, err := utils.ParseDateString(filters.StartDate); err == nil {
|
||||||
|
db = db.Where(fmt.Sprintf("DATE(%s) >= ?", dateColumn), dateFrom)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if filters.EndDate != "" {
|
||||||
|
if dateTo, err := utils.ParseDateString(filters.EndDate); err == nil {
|
||||||
|
db = db.Where(fmt.Sprintf("DATE(%s) <= ?", dateColumn), dateTo)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var purchaseIDs []uint
|
||||||
|
if err := db.Order("purchases.id ASC").Pluck("purchases.id", &purchaseIDs).Error; err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return purchaseIDs, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *debtSupplierRepositoryImpl) GetPaymentTotalsByReferences(ctx context.Context, supplierIDs []uint, references []string) (map[string]float64, error) {
|
||||||
|
if len(supplierIDs) == 0 || len(references) == 0 {
|
||||||
|
return map[string]float64{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type paymentRow struct {
|
||||||
|
ReferenceNumber *string `gorm:"column:reference_number"`
|
||||||
|
Total float64 `gorm:"column:total"`
|
||||||
|
}
|
||||||
|
|
||||||
|
rows := make([]paymentRow, 0)
|
||||||
|
if err := r.db.WithContext(ctx).
|
||||||
|
Model(&entity.Payment{}).
|
||||||
|
Select("reference_number, SUM(nominal) AS total").
|
||||||
|
Where("party_type = ?", string(utils.PaymentPartySupplier)).
|
||||||
|
Where("direction = ?", "OUT").
|
||||||
|
Where("party_id IN ?", supplierIDs).
|
||||||
|
Where("reference_number IN ?", references).
|
||||||
|
Group("reference_number").
|
||||||
|
Scan(&rows).Error; err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
result := make(map[string]float64, len(rows))
|
||||||
|
for _, row := range rows {
|
||||||
|
if row.ReferenceNumber == nil || strings.TrimSpace(*row.ReferenceNumber) == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
result[*row.ReferenceNumber] = row.Total
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
@@ -18,7 +18,8 @@ func RepportRoutes(v1 fiber.Router, u user.UserService, s repport.RepportService
|
|||||||
route.Get("/expense", m.RequirePermissions(m.P_ReportExpenseGetAll), ctrl.GetExpense)
|
route.Get("/expense", m.RequirePermissions(m.P_ReportExpenseGetAll), ctrl.GetExpense)
|
||||||
route.Get("/marketing", m.RequirePermissions(m.P_ReportDeliveryGetAll), ctrl.GetMarketing)
|
route.Get("/marketing", m.RequirePermissions(m.P_ReportDeliveryGetAll), ctrl.GetMarketing)
|
||||||
route.Get("/purchase-supplier", m.RequirePermissions(m.P_ReportPurchaseSupplierGetAll), ctrl.GetPurchaseSupplier)
|
route.Get("/purchase-supplier", m.RequirePermissions(m.P_ReportPurchaseSupplierGetAll), ctrl.GetPurchaseSupplier)
|
||||||
route.Get("/hpp-per-kandang", ctrl.GetHppPerKandang)
|
route.Get("/debt-supplier", m.RequirePermissions(m.P_ReportDebtSupplierGetAll), ctrl.GetDebtSupplier)
|
||||||
route.Get("/production-result/:idProjectFlockKandang", ctrl.GetProductionResult)
|
route.Get("/hpp-per-kandang", m.RequirePermissions(m.P_ReportHppPerKandangGetAll), ctrl.GetHppPerKandang)
|
||||||
|
route.Get("/production-result/:idProjectFlockKandang", m.RequirePermissions(m.P_ReportProductionResultGetAll), ctrl.GetProductionResult)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,9 @@ import (
|
|||||||
approvalDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/approvals/dto"
|
approvalDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/approvals/dto"
|
||||||
expenseRepo "gitlab.com/mbugroup/lti-api.git/internal/modules/expenses/repositories"
|
expenseRepo "gitlab.com/mbugroup/lti-api.git/internal/modules/expenses/repositories"
|
||||||
marketingRepo "gitlab.com/mbugroup/lti-api.git/internal/modules/marketing/repositories"
|
marketingRepo "gitlab.com/mbugroup/lti-api.git/internal/modules/marketing/repositories"
|
||||||
|
areaDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/areas/dto"
|
||||||
|
supplierDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/suppliers/dto"
|
||||||
|
warehouseDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/warehouses/dto"
|
||||||
chickinRepo "gitlab.com/mbugroup/lti-api.git/internal/modules/production/chickins/repositories"
|
chickinRepo "gitlab.com/mbugroup/lti-api.git/internal/modules/production/chickins/repositories"
|
||||||
recordingRepo "gitlab.com/mbugroup/lti-api.git/internal/modules/production/recordings/repositories"
|
recordingRepo "gitlab.com/mbugroup/lti-api.git/internal/modules/production/recordings/repositories"
|
||||||
purchaseRepo "gitlab.com/mbugroup/lti-api.git/internal/modules/purchases/repositories"
|
purchaseRepo "gitlab.com/mbugroup/lti-api.git/internal/modules/purchases/repositories"
|
||||||
@@ -34,6 +37,7 @@ type RepportService interface {
|
|||||||
GetExpense(ctx *fiber.Ctx, params *validation.ExpenseQuery) ([]dto.RepportExpenseListDTO, int64, error)
|
GetExpense(ctx *fiber.Ctx, params *validation.ExpenseQuery) ([]dto.RepportExpenseListDTO, int64, error)
|
||||||
GetMarketing(ctx *fiber.Ctx, params *validation.MarketingQuery) ([]dto.RepportMarketingItemDTO, int64, error)
|
GetMarketing(ctx *fiber.Ctx, params *validation.MarketingQuery) ([]dto.RepportMarketingItemDTO, int64, error)
|
||||||
GetPurchaseSupplier(ctx *fiber.Ctx, params *validation.PurchaseSupplierQuery) ([]dto.PurchaseSupplierDTO, int64, error)
|
GetPurchaseSupplier(ctx *fiber.Ctx, params *validation.PurchaseSupplierQuery) ([]dto.PurchaseSupplierDTO, int64, error)
|
||||||
|
GetDebtSupplier(ctx *fiber.Ctx, params *validation.DebtSupplierQuery) ([]dto.DebtSupplierDTO, int64, error)
|
||||||
GetHppPerKandang(ctx *fiber.Ctx) (*dto.HppPerKandangResponseData, *dto.HppPerKandangMetaDTO, error)
|
GetHppPerKandang(ctx *fiber.Ctx) (*dto.HppPerKandangResponseData, *dto.HppPerKandangMetaDTO, error)
|
||||||
GetProductionResult(ctx *fiber.Ctx, params *validation.ProductionResultQuery) ([]dto.ProductionResultDTO, int64, error)
|
GetProductionResult(ctx *fiber.Ctx, params *validation.ProductionResultQuery) ([]dto.ProductionResultDTO, int64, error)
|
||||||
}
|
}
|
||||||
@@ -48,6 +52,7 @@ type repportService struct {
|
|||||||
RecordingRepo recordingRepo.RecordingRepository
|
RecordingRepo recordingRepo.RecordingRepository
|
||||||
ApprovalSvc approvalService.ApprovalService
|
ApprovalSvc approvalService.ApprovalService
|
||||||
PurchaseSupplierRepo repportRepo.PurchaseSupplierRepository
|
PurchaseSupplierRepo repportRepo.PurchaseSupplierRepository
|
||||||
|
DebtSupplierRepo repportRepo.DebtSupplierRepository
|
||||||
HppPerKandangRepo repportRepo.HppPerKandangRepository
|
HppPerKandangRepo repportRepo.HppPerKandangRepository
|
||||||
ProductionResultRepo repportRepo.ProductionResultRepository
|
ProductionResultRepo repportRepo.ProductionResultRepository
|
||||||
}
|
}
|
||||||
@@ -70,6 +75,7 @@ func NewRepportService(
|
|||||||
recordingRepo recordingRepo.RecordingRepository,
|
recordingRepo recordingRepo.RecordingRepository,
|
||||||
approvalSvc approvalService.ApprovalService,
|
approvalSvc approvalService.ApprovalService,
|
||||||
purchaseSupplierRepo repportRepo.PurchaseSupplierRepository,
|
purchaseSupplierRepo repportRepo.PurchaseSupplierRepository,
|
||||||
|
debtSupplierRepo repportRepo.DebtSupplierRepository,
|
||||||
hppPerKandangRepo repportRepo.HppPerKandangRepository,
|
hppPerKandangRepo repportRepo.HppPerKandangRepository,
|
||||||
productionResultRepo repportRepo.ProductionResultRepository,
|
productionResultRepo repportRepo.ProductionResultRepository,
|
||||||
) RepportService {
|
) RepportService {
|
||||||
@@ -83,6 +89,7 @@ func NewRepportService(
|
|||||||
RecordingRepo: recordingRepo,
|
RecordingRepo: recordingRepo,
|
||||||
ApprovalSvc: approvalSvc,
|
ApprovalSvc: approvalSvc,
|
||||||
PurchaseSupplierRepo: purchaseSupplierRepo,
|
PurchaseSupplierRepo: purchaseSupplierRepo,
|
||||||
|
DebtSupplierRepo: debtSupplierRepo,
|
||||||
HppPerKandangRepo: hppPerKandangRepo,
|
HppPerKandangRepo: hppPerKandangRepo,
|
||||||
ProductionResultRepo: productionResultRepo,
|
ProductionResultRepo: productionResultRepo,
|
||||||
}
|
}
|
||||||
@@ -634,6 +641,200 @@ func (s *repportService) GetPurchaseSupplier(c *fiber.Ctx, params *validation.Pu
|
|||||||
return result, totalSuppliers, nil
|
return result, totalSuppliers, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *repportService) GetDebtSupplier(c *fiber.Ctx, params *validation.DebtSupplierQuery) ([]dto.DebtSupplierDTO, int64, error) {
|
||||||
|
if params.FilterBy == "" {
|
||||||
|
params.FilterBy = "do_date"
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := s.Validate.Struct(params); err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
offset := (params.Page - 1) * params.Limit
|
||||||
|
if offset < 0 {
|
||||||
|
offset = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
suppliers, totalSuppliers, err := s.DebtSupplierRepo.GetSuppliersWithPurchases(c.Context(), offset, params.Limit, params)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
if totalSuppliers == 0 || len(suppliers) == 0 {
|
||||||
|
return []dto.DebtSupplierDTO{}, totalSuppliers, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
supplierMap := make(map[uint]entity.Supplier, len(suppliers))
|
||||||
|
supplierIDs := make([]uint, 0, len(suppliers))
|
||||||
|
for _, supplier := range suppliers {
|
||||||
|
supplierMap[supplier.Id] = supplier
|
||||||
|
supplierIDs = append(supplierIDs, supplier.Id)
|
||||||
|
}
|
||||||
|
|
||||||
|
purchases, err := s.DebtSupplierRepo.GetPurchasesBySuppliers(c.Context(), supplierIDs, params)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
purchasesBySupplier := make(map[uint][]entity.Purchase, len(supplierIDs))
|
||||||
|
references := make([]string, 0)
|
||||||
|
seenRefs := make(map[string]struct{})
|
||||||
|
for _, purchase := range purchases {
|
||||||
|
supplierID := purchase.SupplierId
|
||||||
|
purchasesBySupplier[supplierID] = append(purchasesBySupplier[supplierID], purchase)
|
||||||
|
|
||||||
|
reference := purchase.PrNumber
|
||||||
|
if purchase.PoNumber != nil && strings.TrimSpace(*purchase.PoNumber) != "" {
|
||||||
|
reference = *purchase.PoNumber
|
||||||
|
}
|
||||||
|
if _, exists := seenRefs[reference]; !exists {
|
||||||
|
seenRefs[reference] = struct{}{}
|
||||||
|
references = append(references, reference)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
paymentTotals, err := s.DebtSupplierRepo.GetPaymentTotalsByReferences(c.Context(), supplierIDs, references)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
location, err := time.LoadLocation("Asia/Jakarta")
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, fiber.NewError(fiber.StatusInternalServerError, "failed to load timezone configuration")
|
||||||
|
}
|
||||||
|
now := time.Now().In(location)
|
||||||
|
|
||||||
|
result := make([]dto.DebtSupplierDTO, 0, len(supplierIDs))
|
||||||
|
for _, supplierID := range supplierIDs {
|
||||||
|
supplier, exists := supplierMap[supplierID]
|
||||||
|
if !exists {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
items := purchasesBySupplier[supplierID]
|
||||||
|
rows := make([]dto.DebtSupplierRowDTO, 0, len(items))
|
||||||
|
total := dto.DebtSupplierTotalDTO{}
|
||||||
|
|
||||||
|
for _, purchase := range items {
|
||||||
|
row := buildDebtSupplierRow(purchase, paymentTotals, now, location)
|
||||||
|
rows = append(rows, row)
|
||||||
|
|
||||||
|
if row.Aging > total.Aging {
|
||||||
|
total.Aging = row.Aging
|
||||||
|
}
|
||||||
|
total.TotalPrice += row.TotalPrice
|
||||||
|
total.PaymentPrice += row.PaymentPrice
|
||||||
|
total.DebtPrice += row.DebtPrice
|
||||||
|
}
|
||||||
|
|
||||||
|
sortDesc := strings.EqualFold(params.SortOrder, "desc")
|
||||||
|
sort.SliceStable(rows, func(i, j int) bool {
|
||||||
|
if sortDesc {
|
||||||
|
return rows[i].PrDate > rows[j].PrDate
|
||||||
|
}
|
||||||
|
return rows[i].PrDate < rows[j].PrDate
|
||||||
|
})
|
||||||
|
|
||||||
|
var supplierDTORef *supplierDTO.SupplierRelationDTO
|
||||||
|
if supplier.Id != 0 {
|
||||||
|
mapped := supplierDTO.ToSupplierRelationDTO(supplier)
|
||||||
|
supplierDTORef = &mapped
|
||||||
|
}
|
||||||
|
|
||||||
|
result = append(result, dto.DebtSupplierDTO{
|
||||||
|
Supplier: supplierDTORef,
|
||||||
|
Rows: rows,
|
||||||
|
Total: total,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, totalSuppliers, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildDebtSupplierRow(purchase entity.Purchase, paymentTotals map[string]float64, now time.Time, loc *time.Location) dto.DebtSupplierRowDTO {
|
||||||
|
prNumber := purchase.PrNumber
|
||||||
|
poNumber := ""
|
||||||
|
if purchase.PoNumber != nil {
|
||||||
|
poNumber = *purchase.PoNumber
|
||||||
|
}
|
||||||
|
|
||||||
|
reference := prNumber
|
||||||
|
if strings.TrimSpace(poNumber) != "" {
|
||||||
|
reference = poNumber
|
||||||
|
}
|
||||||
|
|
||||||
|
prDate := purchase.CreatedAt.In(loc)
|
||||||
|
startDate := time.Date(prDate.Year(), prDate.Month(), prDate.Day(), 0, 0, 0, 0, loc)
|
||||||
|
endDate := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, loc)
|
||||||
|
aging := int(endDate.Sub(startDate).Hours() / 24)
|
||||||
|
|
||||||
|
totalPrice := 0.0
|
||||||
|
travelNumber := "-"
|
||||||
|
var area *areaDTO.AreaRelationDTO
|
||||||
|
var warehouse *warehouseDTO.WarehouseRelationDTO
|
||||||
|
|
||||||
|
if len(purchase.Items) > 0 {
|
||||||
|
firstItem := purchase.Items[0]
|
||||||
|
if firstItem.TravelNumber != nil && strings.TrimSpace(*firstItem.TravelNumber) != "" {
|
||||||
|
travelNumber = *firstItem.TravelNumber
|
||||||
|
}
|
||||||
|
|
||||||
|
if firstItem.Warehouse != nil && firstItem.Warehouse.Id != 0 {
|
||||||
|
mappedWarehouse := warehouseDTO.ToWarehouseRelationDTO(*firstItem.Warehouse)
|
||||||
|
warehouse = &mappedWarehouse
|
||||||
|
if firstItem.Warehouse.Area.Id != 0 {
|
||||||
|
mappedArea := areaDTO.ToAreaRelationDTO(firstItem.Warehouse.Area)
|
||||||
|
area = &mappedArea
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, item := range purchase.Items {
|
||||||
|
totalPrice += item.TotalPrice
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
paymentPrice := paymentTotals[reference]
|
||||||
|
debtPrice := paymentPrice - totalPrice
|
||||||
|
|
||||||
|
dueDate := ""
|
||||||
|
dueStatus := "-"
|
||||||
|
if purchase.DueDate != nil && !purchase.DueDate.IsZero() {
|
||||||
|
due := purchase.DueDate.In(loc)
|
||||||
|
dueDate = due.Format("2006-01-02")
|
||||||
|
if now.After(due) {
|
||||||
|
dueStatus = "Sudah Jatuh Tempo"
|
||||||
|
} else {
|
||||||
|
dueStatus = "Mendekati Jatuh Tempo"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
status := "Belum Lunas"
|
||||||
|
if debtPrice >= 0 {
|
||||||
|
status = "Lunas"
|
||||||
|
}
|
||||||
|
|
||||||
|
poDate := ""
|
||||||
|
if purchase.PoDate != nil && !purchase.PoDate.IsZero() {
|
||||||
|
poDate = purchase.PoDate.In(loc).Format("2006-01-02")
|
||||||
|
}
|
||||||
|
|
||||||
|
return dto.DebtSupplierRowDTO{
|
||||||
|
PrNumber: prNumber,
|
||||||
|
PoNumber: poNumber,
|
||||||
|
PrDate: prDate.Format("2006-01-02"),
|
||||||
|
PoDate: poDate,
|
||||||
|
Aging: aging,
|
||||||
|
Area: area,
|
||||||
|
Warehouse: warehouse,
|
||||||
|
DueDate: dueDate,
|
||||||
|
DueStatus: dueStatus,
|
||||||
|
TotalPrice: totalPrice,
|
||||||
|
PaymentPrice: paymentPrice,
|
||||||
|
DebtPrice: debtPrice,
|
||||||
|
Status: status,
|
||||||
|
TravelNumber: travelNumber,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (s *repportService) GetHppPerKandang(ctx *fiber.Ctx) (*dto.HppPerKandangResponseData, *dto.HppPerKandangMetaDTO, error) {
|
func (s *repportService) GetHppPerKandang(ctx *fiber.Ctx) (*dto.HppPerKandangResponseData, *dto.HppPerKandangMetaDTO, error) {
|
||||||
params, filters, err := s.parseHppPerKandangQuery(ctx)
|
params, filters, err := s.parseHppPerKandangQuery(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -43,6 +43,16 @@ type PurchaseSupplierQuery struct {
|
|||||||
FilterBy string `query:"filter_by" validate:"omitempty"`
|
FilterBy string `query:"filter_by" validate:"omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type DebtSupplierQuery struct {
|
||||||
|
Page int `query:"page" validate:"omitempty,min=1,gt=0"`
|
||||||
|
Limit int `query:"limit" validate:"omitempty,min=1,gt=0"`
|
||||||
|
SupplierIDs []int64 `query:"-" validate:"omitempty,dive,gt=0"`
|
||||||
|
StartDate string `query:"start_date" validate:"omitempty,datetime=2006-01-02"`
|
||||||
|
EndDate string `query:"end_date" validate:"omitempty,datetime=2006-01-02"`
|
||||||
|
FilterBy string `query:"filter_by" validate:"omitempty,oneof=do_date po_date pr_date"`
|
||||||
|
SortOrder string `query:"sort_order" validate:"omitempty,oneof=asc desc"`
|
||||||
|
}
|
||||||
|
|
||||||
type HppPerKandangQuery struct {
|
type HppPerKandangQuery struct {
|
||||||
Page int `query:"page" validate:"omitempty,min=1,gt=0"`
|
Page int `query:"page" validate:"omitempty,min=1,gt=0"`
|
||||||
Limit int `query:"limit" validate:"omitempty,min=1,max=100,gt=0"`
|
Limit int `query:"limit" validate:"omitempty,min=1,max=100,gt=0"`
|
||||||
|
|||||||
Reference in New Issue
Block a user