Add callback and update user role
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user