Add callback and update user role

This commit is contained in:
aditya.siregar
2024-06-05 00:24:53 +07:00
parent 4d402e32c9
commit 04a89c5508
27 changed files with 388 additions and 49 deletions
+94 -17
View File
@@ -1,8 +1,10 @@
package order
import (
"database/sql"
"encoding/json"
"errors"
"fmt"
"furtuna-be/internal/common/logger"
order2 "furtuna-be/internal/constants/order"
"furtuna-be/internal/entity"
@@ -16,21 +18,29 @@ import (
)
type OrderService struct {
repo repository.Order
crypt repository.Crypto
product repository.Product
midtrans repository.Midtrans
payment repository.Payment
repo repository.Order
crypt repository.Crypto
product repository.Product
midtrans repository.Midtrans
payment repository.Payment
txmanager repository.TransactionManager
wallet repository.WalletRepository
}
func NewOrderService(repo repository.Order, product repository.Product, crypt repository.Crypto,
midtrans repository.Midtrans, payment repository.Payment) *OrderService {
func NewOrderService(
repo repository.Order,
product repository.Product, crypt repository.Crypto,
midtrans repository.Midtrans, payment repository.Payment,
txmanager repository.TransactionManager,
wallet repository.WalletRepository) *OrderService {
return &OrderService{
repo: repo,
product: product,
crypt: crypt,
midtrans: midtrans,
payment: payment,
repo: repo,
product: product,
crypt: crypt,
midtrans: midtrans,
payment: payment,
txmanager: txmanager,
wallet: wallet,
}
}
@@ -78,6 +88,7 @@ func (s *OrderService) CreateOrder(ctx context.Context, req *entity.OrderRequest
Price: productMap[item.ProductID].Price,
Quantity: item.Quantity,
CreatedBy: req.CreatedBy,
Product: productMap[item.ProductID].ToProduct(),
})
}
@@ -116,7 +127,6 @@ func (s *OrderService) Execute(ctx context.Context, req *entity.OrderExecuteRequ
return nil, err
}
// Check for existing payment to handle idempotency
payment, err := s.payment.FindByOrderAndPartnerID(ctx, orderID, partnerID)
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
logger.ContextLogger(ctx).Error("error getting payment data from db", zap.Error(err))
@@ -199,13 +209,13 @@ func (s *OrderService) processNonCashPayment(ctx context.Context, order *entity.
}
payment := &entity.Payment{
PartnerID: strconv.FormatInt(partnerID, 10),
OrderID: strconv.FormatInt(order.ID, 10),
PartnerID: partnerID,
OrderID: order.ID,
ReferenceID: paymentRequest.PaymentReferenceID,
Channel: "xendit",
Channel: "XENDIT",
PaymentType: order.PaymentType,
Amount: order.Amount,
State: "pending",
State: "PENDING",
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
RequestMetadata: requestMetadata,
@@ -219,3 +229,70 @@ func (s *OrderService) processNonCashPayment(ctx context.Context, order *entity.
return paymentResponse, nil
}
func (s *OrderService) ProcessCallback(ctx context.Context, req *entity.CallbackRequest) error {
tx, err := s.txmanager.Begin(ctx, &sql.TxOptions{Isolation: sql.LevelSerializable})
if err != nil {
return fmt.Errorf("failed to begin transaction: %w", err)
}
defer tx.Rollback()
err = s.processPayment(ctx, tx, req)
if err != nil {
return fmt.Errorf("failed to process payment: %w", err)
}
return tx.Commit().Error
}
func (s *OrderService) processPayment(ctx context.Context, tx *gorm.DB, req *entity.CallbackRequest) error {
existingPayment, err := s.payment.FindByReferenceID(ctx, tx, req.TransactionID)
if err != nil {
return fmt.Errorf("failed to retrieve payment: %w", err)
}
existingPayment.State = updatePaymentState(req.TransactionStatus)
_, err = s.payment.UpdateWithTx(ctx, tx, existingPayment)
if err != nil {
return fmt.Errorf("failed to update payment: %w", err)
}
if err := s.updateOrderStatus(ctx, tx, existingPayment.State, existingPayment.OrderID); err != nil {
return fmt.Errorf("failed to update order status: %w", err)
}
if existingPayment.State == "PAID" {
if err := s.updateWalletBalance(ctx, tx, existingPayment.PartnerID, existingPayment.Amount); err != nil {
return fmt.Errorf("failed to update wallet balance: %w", err)
}
}
return nil
}
func updatePaymentState(status string) string {
switch status {
case "settlement", "capture":
return "PAID"
case "expire", "deny", "cancel", "failure":
return "EXPIRED"
default:
return status
}
}
func (s *OrderService) updateOrderStatus(ctx context.Context, tx *gorm.DB, status string, orderID int64) error {
if status != "PENDING" {
return s.repo.SetOrderStatus(ctx, tx, orderID, status)
}
return nil
}
func (s *OrderService) updateWalletBalance(ctx context.Context, tx *gorm.DB, partnerID int64, amount float64) error {
wallet, err := s.wallet.GetByPartnerID(ctx, tx, partnerID)
if err != nil {
return fmt.Errorf("failed to get wallet: %w", err)
}
wallet.Balance += amount
_, err = s.wallet.Update(ctx, tx, wallet)
return err
}