package service import ( "errors" "narasi-ahli-be/app/database/entity" "narasi-ahli-be/app/module/ebooks/mapper" "narasi-ahli-be/app/module/ebooks/repository" "narasi-ahli-be/app/module/ebooks/response" usersRepository "narasi-ahli-be/app/module/users/repository" "narasi-ahli-be/utils/paginator" utilSvc "narasi-ahli-be/utils/service" "time" "github.com/rs/zerolog" ) // EbookPurchasesService type ebookPurchasesService struct { Repo repository.EbookPurchasesRepository EbooksRepo repository.EbooksRepository Log zerolog.Logger UsersRepo usersRepository.UsersRepository } // EbookPurchasesService define interface of IEbookPurchasesService type EbookPurchasesService interface { GetByBuyerId(authToken string, pagination *paginator.Pagination) (purchases []*response.EbookPurchaseResponse, paging paginator.Pagination, err error) PurchaseEbook(authToken string, ebookId uint, paymentMethod string) (purchase *response.EbookPurchaseResponse, err error) UpdatePaymentStatus(purchaseId uint, paymentStatus string, transactionId string, paymentProof string) (err error) GetPurchaseById(purchaseId uint) (purchase *response.EbookPurchaseResponse, err error) ConfirmPayment(purchaseId uint) (err error) } // NewEbookPurchasesService init EbookPurchasesService func NewEbookPurchasesService( repo repository.EbookPurchasesRepository, ebooksRepo repository.EbooksRepository, log zerolog.Logger, usersRepo usersRepository.UsersRepository) EbookPurchasesService { return &ebookPurchasesService{ Repo: repo, EbooksRepo: ebooksRepo, Log: log, UsersRepo: usersRepo, } } // GetByBuyerId implement interface of EbookPurchasesService func (_i *ebookPurchasesService) GetByBuyerId(authToken string, pagination *paginator.Pagination) (purchases []*response.EbookPurchaseResponse, paging paginator.Pagination, err error) { user := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken) if user == nil { return nil, paginator.Pagination{}, errors.New("user not found") } purchasesData, paging, err := _i.Repo.GetByBuyerId(user.ID, pagination) if err != nil { return nil, paging, err } purchases = mapper.ToEbookPurchaseResponseList(purchasesData) return purchases, paging, nil } // PurchaseEbook implement interface of EbookPurchasesService func (_i *ebookPurchasesService) PurchaseEbook(authToken string, ebookId uint, paymentMethod string) (purchase *response.EbookPurchaseResponse, err error) { user := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken) if user == nil { return nil, errors.New("user not found") } // Check if ebook exists ebook, err := _i.EbooksRepo.FindOne(ebookId) if err != nil { return nil, errors.New("ebook not found") } // Check if already purchased existingPurchase, err := _i.Repo.FindByBuyerAndEbook(user.ID, ebookId) if err == nil && existingPurchase != nil { return nil, errors.New("ebook already purchased") } // Create purchase record purchaseEntity := &entity.EbookPurchases{ BuyerId: user.ID, EbookId: ebookId, PurchasePrice: ebook.Price, PaymentMethod: &paymentMethod, PaymentStatus: stringPtr("pending"), StatusId: intPtr(1), IsActive: boolPtr(true), } purchaseData, err := _i.Repo.Create(purchaseEntity) if err != nil { return nil, err } // Update purchase count err = _i.EbooksRepo.UpdatePurchaseCount(ebookId) if err != nil { _i.Log.Error().Err(err).Msg("Failed to update purchase count") } purchase = mapper.ToEbookPurchaseResponse(purchaseData) return purchase, nil } // UpdatePaymentStatus implement interface of EbookPurchasesService func (_i *ebookPurchasesService) UpdatePaymentStatus(purchaseId uint, paymentStatus string, transactionId string, paymentProof string) (err error) { _, err = _i.Repo.FindOne(purchaseId) if err != nil { return errors.New("purchase not found") } updateData := &entity.EbookPurchases{ PaymentStatus: &paymentStatus, TransactionId: &transactionId, PaymentProof: &paymentProof, } if paymentStatus == "paid" { now := time.Now() updateData.PaymentDate = &now } err = _i.Repo.Update(purchaseId, updateData) if err != nil { return err } return nil } // GetPurchaseById implement interface of EbookPurchasesService func (_i *ebookPurchasesService) GetPurchaseById(purchaseId uint) (purchase *response.EbookPurchaseResponse, err error) { purchaseData, err := _i.Repo.FindOne(purchaseId) if err != nil { return nil, err } purchase = mapper.ToEbookPurchaseResponse(purchaseData) return purchase, nil } // ConfirmPayment implement interface of EbookPurchasesService func (_i *ebookPurchasesService) ConfirmPayment(purchaseId uint) (err error) { purchase, err := _i.Repo.FindOne(purchaseId) if err != nil { return errors.New("purchase not found") } if purchase.PaymentStatus == nil || *purchase.PaymentStatus != "paid" { return errors.New("payment not completed") } // Update status to confirmed updateData := &entity.EbookPurchases{ StatusId: intPtr(2), // Assuming 2 is confirmed status } err = _i.Repo.Update(purchaseId, updateData) if err != nil { return err } return nil } // Helper functions func stringPtr(s string) *string { return &s } func intPtr(i int) *int { return &i } func boolPtr(b bool) *bool { return &b }