fix: next period,purchase before bop, integration auth module,fix validation-master data

This commit is contained in:
ragilap
2025-11-25 10:32:15 +07:00
parent 8881be2a22
commit c02f72c5e5
63 changed files with 838 additions and 864 deletions
@@ -18,14 +18,11 @@ import (
type PurchaseRepository interface {
repository.BaseRepository[entity.Purchase]
CreateWithItems(ctx context.Context, purchase *entity.Purchase, items []*entity.PurchaseItem) error
CreateItems(ctx context.Context, purchaseID uint64, items []*entity.PurchaseItem) error
GetByIDWithRelations(ctx context.Context, id uint64) (*entity.Purchase, error)
GetAllWithFilters(ctx context.Context, offset, limit int, filter *PurchaseListFilter) ([]entity.Purchase, int64, error)
UpdatePricing(ctx context.Context, purchaseID uint64, updates []PurchasePricingUpdate, grandTotal float64) error
UpdateReceivingDetails(ctx context.Context, purchaseID uint64, updates []PurchaseReceivingUpdate) error
DeleteItems(ctx context.Context, purchaseID uint64, itemIDs []uint64) error
WithListRelations() func(*gorm.DB) *gorm.DB
UpdateGrandTotal(ctx context.Context, purchaseID uint64, grandTotal float64) error
CreateItems(ctx context.Context, purchaseID uint, items []*entity.PurchaseItem) error
UpdatePricing(ctx context.Context, purchaseID uint, updates []PurchasePricingUpdate, grandTotal float64) error
UpdateReceivingDetails(ctx context.Context, purchaseID uint, updates []PurchaseReceivingUpdate) error
DeleteItems(ctx context.Context, purchaseID uint, itemIDs []uint) error
UpdateGrandTotal(ctx context.Context, purchaseID uint, grandTotal float64) error
NextPrNumber(ctx context.Context, tx *gorm.DB) (string, error)
NextPoNumber(ctx context.Context, tx *gorm.DB) (string, error)
}
@@ -40,19 +37,10 @@ func NewPurchaseRepository(db *gorm.DB) PurchaseRepository {
}
}
type PurchaseListFilter struct {
SupplierID uint
Search string
PrNumber string
CreatedFrom *time.Time
CreatedTo *time.Time
Status *entity.ApprovalAction
CompletedOnly bool
}
func (r *PurchaseRepositoryImpl) CreateWithItems(ctx context.Context, purchase *entity.Purchase, items []*entity.PurchaseItem) error {
db := r.DB().WithContext(ctx)
//ambil dari base repository
if err := db.Create(purchase).Error; err != nil {
return err
}
@@ -71,7 +59,7 @@ func (r *PurchaseRepositoryImpl) CreateWithItems(ctx context.Context, purchase *
return nil
}
func (r *PurchaseRepositoryImpl) CreateItems(ctx context.Context, purchaseID uint64, items []*entity.PurchaseItem) error {
func (r *PurchaseRepositoryImpl) CreateItems(ctx context.Context, purchaseID uint, items []*entity.PurchaseItem) error {
if len(items) == 0 {
return nil
}
@@ -86,52 +74,9 @@ func (r *PurchaseRepositoryImpl) CreateItems(ctx context.Context, purchaseID uin
return r.DB().WithContext(ctx).Create(&items).Error
}
func (r *PurchaseRepositoryImpl) GetByIDWithRelations(ctx context.Context, id uint64) (*entity.Purchase, error) {
var purchase entity.Purchase
err := r.DB().WithContext(ctx).
Scopes(r.withDetailRelations).
First(&purchase, id).Error
if err != nil {
return nil, err
}
return &purchase, nil
}
func (r *PurchaseRepositoryImpl) GetAllWithFilters(ctx context.Context, offset, limit int, filter *PurchaseListFilter) ([]entity.Purchase, int64, error) {
return r.GetAll(ctx, offset, limit, func(db *gorm.DB) *gorm.DB {
db = r.withListRelations(db)
return r.applyListFilters(db, filter)
})
}
func (r *PurchaseRepositoryImpl) WithListRelations() func(*gorm.DB) *gorm.DB {
return func(db *gorm.DB) *gorm.DB {
return r.withListRelations(db)
}
}
func (r *PurchaseRepositoryImpl) withDetailRelations(db *gorm.DB) *gorm.DB {
return db.
Preload("Supplier").
Preload("Items", func(db *gorm.DB) *gorm.DB {
return db.Order("id ASC")
}).
Preload("Items.Product").
Preload("Items.Warehouse").
Preload("Items.Warehouse.Area").
Preload("Items.Warehouse.Location").
Preload("Items.ProductWarehouse")
}
func (r *PurchaseRepositoryImpl) WithDetailRelations() func(*gorm.DB) *gorm.DB {
return func(db *gorm.DB) *gorm.DB {
return r.withDetailRelations(db)
}
}
type PurchasePricingUpdate struct {
ItemID uint64
ProductID *uint64
ItemID uint
ProductID *uint
Price float64
TotalPrice float64
Quantity *float64
@@ -139,7 +84,7 @@ type PurchasePricingUpdate struct {
}
type PurchaseReceivingUpdate struct {
ItemID uint64
ItemID uint
ReceivedDate *time.Time
TravelNumber *string
TravelDocumentPath *string
@@ -152,7 +97,7 @@ type PurchaseReceivingUpdate struct {
func (r *PurchaseRepositoryImpl) UpdatePricing(
ctx context.Context,
purchaseID uint64,
purchaseID uint,
updates []PurchasePricingUpdate,
grandTotal float64,
) error {
@@ -192,7 +137,6 @@ func (r *PurchaseRepositoryImpl) UpdatePricing(
Where("id = ?", purchaseID).
Updates(map[string]interface{}{
"grand_total": grandTotal,
"updated_at": gorm.Expr("NOW()"),
}).Error; err != nil {
return err
}
@@ -202,7 +146,7 @@ func (r *PurchaseRepositoryImpl) UpdatePricing(
func (r *PurchaseRepositoryImpl) UpdateReceivingDetails(
ctx context.Context,
purchaseID uint64,
purchaseID uint,
updates []PurchaseReceivingUpdate,
) error {
if len(updates) == 0 {
@@ -259,7 +203,7 @@ func (r *PurchaseRepositoryImpl) UpdateReceivingDetails(
func (r *PurchaseRepositoryImpl) UpdateGrandTotal(
ctx context.Context,
purchaseID uint64,
purchaseID uint,
grandTotal float64,
) error {
return r.DB().WithContext(ctx).
@@ -271,7 +215,7 @@ func (r *PurchaseRepositoryImpl) UpdateGrandTotal(
}).Error
}
func (r *PurchaseRepositoryImpl) DeleteItems(ctx context.Context, purchaseID uint64, itemIDs []uint64) error {
func (r *PurchaseRepositoryImpl) DeleteItems(ctx context.Context, purchaseID uint, itemIDs []uint) error {
if len(itemIDs) == 0 {
return errors.New("itemIDs cannot be empty")
}
@@ -361,63 +305,3 @@ func parseNumericSuffix(value, prefix string) (int, bool) {
}
return number, true
}
func (r *PurchaseRepositoryImpl) withListRelations(db *gorm.DB) *gorm.DB {
return db.Preload("Supplier")
}
func (r *PurchaseRepositoryImpl) applyListFilters(db *gorm.DB, filter *PurchaseListFilter) *gorm.DB {
if filter == nil {
return db
}
if filter.SupplierID > 0 {
db = db.Where("purchases.supplier_id = ?", filter.SupplierID)
}
if search := strings.ToLower(strings.TrimSpace(filter.Search)); search != "" {
like := "%" + search + "%"
db = db.Where("(LOWER(purchases.pr_number) LIKE ? OR LOWER(COALESCE(purchases.notes, '')) LIKE ?)", like, like)
}
if pr := strings.TrimSpace(filter.PrNumber); pr != "" {
db = db.Where("purchases.pr_number ILIKE ?", "%"+pr+"%")
}
if filter.CreatedFrom != nil {
db = db.Where("purchases.created_at >= ?", *filter.CreatedFrom)
}
if filter.CreatedTo != nil {
db = db.Where("purchases.created_at < ?", *filter.CreatedTo)
}
if filter.CompletedOnly {
step := uint16(utils.PurchaseStepCompleted)
db = r.applyLatestApprovalFilter(db, entity.ApprovalActionApproved, &step)
} else if filter.Status != nil {
db = r.applyLatestApprovalFilter(db, *filter.Status, nil)
}
return db.Order("purchases.created_at DESC").Order("purchases.id DESC")
}
func (r *PurchaseRepositoryImpl) applyLatestApprovalFilter(db *gorm.DB, action entity.ApprovalAction, minStep *uint16) *gorm.DB {
latestSub := r.DB().
Model(&entity.Approval{}).
Select("approvable_id, MAX(action_at) AS latest_action_at").
Where("approvable_type = ?", utils.ApprovalWorkflowPurchase.String()).
Group("approvable_id")
db = db.
Joins("LEFT JOIN (?) AS latest_purchase_approvals ON latest_purchase_approvals.approvable_id = purchases.id", latestSub).
Joins(
"LEFT JOIN approvals ON approvals.approvable_id = purchases.id AND approvals.approvable_type = ? AND approvals.action_at = latest_purchase_approvals.latest_action_at",
utils.ApprovalWorkflowPurchase.String(),
).
Where("approvals.action = ?", string(action))
if minStep != nil {
db = db.Where("approvals.step_number >= ?", *minStep)
}
return db
}