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:
@@ -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
|
||||
}
|
||||
Reference in New Issue
Block a user