Skip to content

Commit

Permalink
extend payment_requests with paidNonce, status, modifietAt
Browse files Browse the repository at this point in the history
  • Loading branch information
volodymyr-basiuk committed Jan 27, 2025
1 parent b8cc99f commit 644dc09
Show file tree
Hide file tree
Showing 8 changed files with 207 additions and 20 deletions.
10 changes: 10 additions & 0 deletions api/api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2900,6 +2900,8 @@ components:
- paymentOptionID
- payments
- createdAt
- modifiedAt
- status
properties:
id:
type: string
Expand All @@ -2918,6 +2920,14 @@ components:
createdAt:
type: string
format: date-time
modifiedAt:
type: string
format: date-time
status:
type: string
enum: [ not-verified, success, failed, pending, canceled ]
paidNonce:
type: string

PaymentRequestInfo:
type: object
Expand Down
37 changes: 26 additions & 11 deletions internal/api/api.gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

30 changes: 30 additions & 0 deletions internal/api/responses.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package api

import (
"context"
"encoding/json"
"fmt"
"net/http"
Expand All @@ -12,6 +13,7 @@ import (
"github.com/polygonid/sh-id-platform/internal/core/domain"
"github.com/polygonid/sh-id-platform/internal/core/pagination"
"github.com/polygonid/sh-id-platform/internal/core/ports"
"github.com/polygonid/sh-id-platform/internal/log"
"github.com/polygonid/sh-id-platform/internal/schema"
"github.com/polygonid/sh-id-platform/internal/timeapi"
)
Expand Down Expand Up @@ -363,8 +365,19 @@ func toCreatePaymentRequestResponse(payReq *domain.PaymentRequest) CreatePayment
for i, pay := range payReq.Payments {
payment.Data[i] = pay.Payment
}
status, err := toCreatePaymentRequestResponseStatus(payReq.Status)
if err != nil {
log.Warn(context.Background(), "unknown payment status type in payment-request", "status", payReq.Status)
}
var paidNonce *string
if payReq.PaidNonce != nil {
paidNonce = common.ToPointer(payReq.PaidNonce.String())
}
resp := CreatePaymentRequestResponse{
CreatedAt: payReq.CreatedAt,
ModifiedAt: payReq.ModifietAt,
Status: status,
PaidNonce: paidNonce,
Id: payReq.ID,
IssuerDID: payReq.IssuerDID.String(),
UserDID: payReq.UserDID.String(),
Expand All @@ -388,3 +401,20 @@ func toVerifyPaymentResponse(status ports.BlockchainPaymentStatus) (VerifyPaymen
return VerifyPayment400JSONResponse{N400JSONResponse{Message: fmt.Sprintf("unknown blockchain payment status <%d>", status)}}, nil
}
}

func toCreatePaymentRequestResponseStatus(status domain.PaymentRequestStatus) (CreatePaymentRequestResponseStatus, error) {
switch status {
case domain.PaymentRequestStatusPending:
return CreatePaymentRequestResponseStatusPending, nil
case domain.PaymentRequestStatusSuccess:
return CreatePaymentRequestResponseStatusSuccess, nil
case domain.PaymentRequestStatusCanceled:
return CreatePaymentRequestResponseStatusCanceled, nil
case domain.PaymentRequestStatusFailed:
return CreatePaymentRequestResponseStatusFailed, nil
case domain.PaymentRequestStatusNotVerified:
return CreatePaymentRequestResponseStatusNotVerified, nil
default:
return CreatePaymentRequestResponseStatusNotVerified, fmt.Errorf("unknown payment status <%s>", status)
}
}
19 changes: 19 additions & 0 deletions internal/core/domain/payment.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,27 @@ type PaymentRequest struct {
PaymentOptionID uuid.UUID
Payments []PaymentRequestItem
CreatedAt time.Time
ModifietAt time.Time
Status PaymentRequestStatus
PaidNonce *big.Int
}

// PaymentRequestStatus represents the status of a payment request stored in the repository
type PaymentRequestStatus string

const (
// PaymentRequestStatusCanceled - Payment is cancelled
PaymentRequestStatusCanceled PaymentRequestStatus = "canceled"
// PaymentRequestStatusFailed - Payment is failed
PaymentRequestStatusFailed PaymentRequestStatus = "failed"
// PaymentRequestStatusNotVerified - Payment not verified
PaymentRequestStatusNotVerified PaymentRequestStatus = "not-verified"
// PaymentRequestStatusPending - Payment is pending
PaymentRequestStatusPending PaymentRequestStatus = "pending"
// PaymentRequestStatusSuccess - Payment is successful
PaymentRequestStatusSuccess PaymentRequestStatus = "success"
)

// PaymentRequestItem represents a payment request item
type PaymentRequestItem struct {
ID uuid.UUID
Expand Down
1 change: 1 addition & 0 deletions internal/core/ports/payments_repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,6 @@ type PaymentRepository interface {
GetPaymentRequestByID(ctx context.Context, issuerDID w3c.DID, id uuid.UUID) (*domain.PaymentRequest, error)
DeletePaymentRequest(ctx context.Context, issuerDID w3c.DID, id uuid.UUID) error
GetAllPaymentRequests(ctx context.Context, issuerDID w3c.DID) ([]domain.PaymentRequest, error)
UpdatePaymentRequestStatus(ctx context.Context, issuerDID w3c.DID, id uuid.UUID, status domain.PaymentRequestStatus, paidNonce *big.Int) error
GetPaymentRequestItem(ctx context.Context, issuerDID w3c.DID, nonce *big.Int) (*domain.PaymentRequestItem, error)
}
45 changes: 39 additions & 6 deletions internal/core/services/payment.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ func (p *payment) CreatePaymentRequest(ctx context.Context, req *ports.CreatePay
return nil, fmt.Errorf("failed to get schema: %w", err)
}

createTime := time.Now()
paymentRequest := &domain.PaymentRequest{
ID: uuid.New(),
IssuerDID: req.IssuerDID,
Expand All @@ -157,7 +158,9 @@ func (p *payment) CreatePaymentRequest(ctx context.Context, req *ports.CreatePay
},
Description: req.Description,
PaymentOptionID: req.OptionID,
CreatedAt: time.Now(),
CreatedAt: createTime,
ModifietAt: createTime,
Status: domain.PaymentRequestStatusNotVerified,
}
for _, chainConfig := range option.Config.PaymentOptions {
setting, found := p.settings[chainConfig.PaymentOptionID]
Expand Down Expand Up @@ -251,12 +254,12 @@ func (p *payment) VerifyPayment(ctx context.Context, issuerDID w3c.DID, nonce *b
return ports.BlockchainPaymentStatusPending, fmt.Errorf("failed to get payment request: %w", err)
}

if userDID != nil {
paymentReq, err := p.paymentsStore.GetPaymentRequestByID(ctx, issuerDID, paymentReqItem.PaymentRequestID)
if err != nil {
return ports.BlockchainPaymentStatusPending, fmt.Errorf("failed to get payment request: %w", err)
}
paymentReq, err := p.paymentsStore.GetPaymentRequestByID(ctx, issuerDID, paymentReqItem.PaymentRequestID)
if err != nil {
return ports.BlockchainPaymentStatusPending, fmt.Errorf("failed to get payment request: %w", err)
}

if userDID != nil {
if userDID.String() != paymentReq.UserDID.String() {
return ports.BlockchainPaymentStatusFailed, fmt.Errorf("userDID %s does not match to User DID %s in payment-request", userDID, paymentReq.UserDID)
}
Expand Down Expand Up @@ -289,9 +292,39 @@ func (p *payment) VerifyPayment(ctx context.Context, issuerDID w3c.DID, nonce *b
log.Error(ctx, "failed to verify payment on blockchain", "err", err, "txHash", txHash, "nonce", nonce)
return ports.BlockchainPaymentStatusPending, err
}

paymentReqStatus := getPaymentRequestStatusFromBlockChainStatus(status)
if paymentReqStatus != paymentReq.Status && paymentReq.Status != domain.PaymentRequestStatusSuccess {
var paidNonce *big.Int
if paymentReqStatus == domain.PaymentRequestStatusSuccess {
paidNonce = nonce
}
err = p.paymentsStore.UpdatePaymentRequestStatus(ctx, issuerDID, paymentReq.ID, paymentReqStatus, paidNonce)
if err != nil {
log.Error(ctx, "failed to update payment-request with new status", "err", err, "txHash", txHash, "nonce", nonce)
return status, err
}

}

return status, nil
}

func getPaymentRequestStatusFromBlockChainStatus(status ports.BlockchainPaymentStatus) domain.PaymentRequestStatus {
switch status {
case ports.BlockchainPaymentStatusPending:
return domain.PaymentRequestStatusPending
case ports.BlockchainPaymentStatusSuccess:
return domain.PaymentRequestStatusSuccess
case ports.BlockchainPaymentStatusCancelled:
return domain.PaymentRequestStatusCanceled
case ports.BlockchainPaymentStatusFailed:
return domain.PaymentRequestStatusFailed
default:
return domain.PaymentRequestStatusNotVerified
}
}

func (p *payment) verifyPaymentOnBlockchain(
ctx context.Context,
client *eth.Client,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
-- +goose Up
-- +goose StatementBegin
ALTER TABLE payment_requests
ADD COLUMN modified_at timestamptz;

ALTER TABLE payment_requests
ADD COLUMN status TEXT;

ALTER TABLE payment_requests
ADD COLUMN paid_nonce numeric NULL;

UPDATE payment_requests set modified_at = created_at where modified_at is null;
UPDATE payment_requests set status = 'not-verified' where status is null;

ALTER TABLE payment_requests
ALTER COLUMN modified_at SET NOT NULL;

ALTER TABLE payment_requests
ALTER COLUMN status SET NOT NULL;
-- +goose StatementEnd

-- +goose Down
-- +goose StatementBegin
ALTER TABLE payment_requests
DROP COLUMN modified_at;

ALTER TABLE payment_requests
DROP COLUMN status;

ALTER TABLE payment_requests
DROP COLUMN paid_nonce;
-- +goose StatementEnd
Loading

0 comments on commit 644dc09

Please sign in to comment.