Reapply "feat(loyalty): EnakPoint & EnakCoin" (#32)
This reverts commit 4e24f9bbb0.
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"github.com/google/uuid"
|
||||
|
||||
"apskel-pos-be/internal/constants"
|
||||
"apskel-pos-be/internal/contract"
|
||||
"apskel-pos-be/internal/models"
|
||||
"apskel-pos-be/internal/processor"
|
||||
"apskel-pos-be/internal/repository"
|
||||
)
|
||||
|
||||
// CustomerWalletService moves balance on the customer's own request: exchanging
|
||||
// EnakCoin into EnakPoint and sending either to another customer
|
||||
// (docs/prd-point-coin.md F4, F5).
|
||||
type CustomerWalletService interface {
|
||||
PreviewExchange(ctx context.Context, customerID uuid.UUID, coins int64) *contract.Response
|
||||
Exchange(ctx context.Context, customerID uuid.UUID, req *contract.ExchangeCoinsRequest, idempotencyKey string, info models.CustomerPinRequestInfo) *contract.Response
|
||||
TransferRecipient(ctx context.Context, customerID uuid.UUID, phoneNumber string) *contract.Response
|
||||
Transfer(ctx context.Context, customerID uuid.UUID, req *contract.TransferWalletRequest, idempotencyKey string, info models.CustomerPinRequestInfo) *contract.Response
|
||||
}
|
||||
|
||||
type CustomerWalletServiceImpl struct {
|
||||
exchanges *processor.WalletExchangeProcessor
|
||||
transfers *processor.WalletTransferProcessor
|
||||
}
|
||||
|
||||
func NewCustomerWalletService(exchanges *processor.WalletExchangeProcessor, transfers *processor.WalletTransferProcessor) *CustomerWalletServiceImpl {
|
||||
return &CustomerWalletServiceImpl{exchanges: exchanges, transfers: transfers}
|
||||
}
|
||||
|
||||
func (s *CustomerWalletServiceImpl) TransferRecipient(ctx context.Context, customerID uuid.UUID, phoneNumber string) *contract.Response {
|
||||
recipient, err := s.transfers.Recipient(ctx, customerID, phoneNumber)
|
||||
if err != nil {
|
||||
return walletMoveErrorResponse(err)
|
||||
}
|
||||
return contract.BuildSuccessResponse(recipient)
|
||||
}
|
||||
|
||||
func (s *CustomerWalletServiceImpl) Transfer(ctx context.Context, customerID uuid.UUID, req *contract.TransferWalletRequest, idempotencyKey string, info models.CustomerPinRequestInfo) *contract.Response {
|
||||
result, err := s.transfers.Transfer(ctx, customerID, models.WalletTransfer{
|
||||
Currency: req.Currency,
|
||||
Amount: req.Amount,
|
||||
RecipientPhone: req.RecipientPhone,
|
||||
}, req.Pin, idempotencyKey, info)
|
||||
if err != nil {
|
||||
return walletMoveErrorResponse(err)
|
||||
}
|
||||
return contract.BuildSuccessResponse(result)
|
||||
}
|
||||
|
||||
func (s *CustomerWalletServiceImpl) PreviewExchange(ctx context.Context, customerID uuid.UUID, coins int64) *contract.Response {
|
||||
preview, err := s.exchanges.Preview(ctx, customerID, coins)
|
||||
if err != nil {
|
||||
return walletMoveErrorResponse(err)
|
||||
}
|
||||
return contract.BuildSuccessResponse(preview)
|
||||
}
|
||||
|
||||
func (s *CustomerWalletServiceImpl) Exchange(ctx context.Context, customerID uuid.UUID, req *contract.ExchangeCoinsRequest, idempotencyKey string, info models.CustomerPinRequestInfo) *contract.Response {
|
||||
result, err := s.exchanges.Exchange(ctx, customerID, req.Coins, req.Pin, idempotencyKey, info)
|
||||
if err != nil {
|
||||
return walletMoveErrorResponse(err)
|
||||
}
|
||||
return contract.BuildSuccessResponse(result)
|
||||
}
|
||||
|
||||
// walletMoveErrorResponse keeps the PIN codes the apps act on, and tells a refused
|
||||
// request apart from a server failure.
|
||||
func walletMoveErrorResponse(err error) *contract.Response {
|
||||
var pinErr *processor.PinError
|
||||
if errors.As(err, &pinErr) {
|
||||
return PinErrorResponse(err)
|
||||
}
|
||||
code := constants.InternalServerErrorCode
|
||||
switch {
|
||||
case errors.Is(err, repository.ErrWalletNotFound),
|
||||
errors.Is(err, processor.ErrWalletRecipientNotFound):
|
||||
code = constants.NotFoundErrorCode
|
||||
case errors.Is(err, processor.ErrWalletMoveRejected),
|
||||
errors.Is(err, processor.ErrWalletIdempotencyConflict),
|
||||
errors.Is(err, processor.ErrWalletInvalidEntry):
|
||||
code = constants.ValidationErrorCode
|
||||
}
|
||||
return contract.BuildErrorResponse([]*contract.ResponseError{
|
||||
contract.NewResponseError(code, constants.WalletServiceEntity, err.Error()),
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user