cashless2ecash

cashless2ecash: pay with cards for digital cash (experimental)
Log | Files | Refs | README

commit 23c15bc81deb564b0d2011a0590a3440ebf02461
parent f840c891ca0235637225bf5349348fe768aa048a
Author: Joel-Haeberli <haebu@rubigen.ch>
Date:   Mon,  3 Jun 2024 11:32:00 +0200

fix: refund

Diffstat:
Mc2ec/amount.go | 25++++++++++++++++---------
Mc2ec/amount_test.go | 66++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
Mc2ec/api-wire-gateway.go | 4++--
Mc2ec/http-util.go | 1+
Mc2ec/wallee-client.go | 21++++++++++++++++++++-
Mc2ec/wallee-client_test.go | 2+-
Mc2ec/wallee-models.go | 4++--
7 files changed, 106 insertions(+), 17 deletions(-)

diff --git a/c2ec/amount.go b/c2ec/amount.go @@ -197,12 +197,16 @@ func ParseAmount(s string, fractionDigits int) (*Amount, error) { if len(valueAndFraction[1]) > fractionDigits { return nil, fmt.Errorf("invalid amount: %s expected at max %d fractional digits", s, fractionDigits) } + k := 0 + if len(valueAndFraction[1]) < fractionDigits { + k = fractionDigits - len(valueAndFraction[1]) + } fractionInt, err := strconv.Atoi(valueAndFraction[1]) if err != nil { LogError("amount", err) return nil, fmt.Errorf("invalid fraction in amount %s", s) } - fraction = fractionInt + fraction = fractionInt * int(math.Pow10(k)) } a := NewAmount(currency, uint64(value), uint64(fraction)) @@ -216,12 +220,15 @@ func (a *Amount) IsZero() bool { // Returns the string representation of the amount: <currency>:<value>[.<fraction>] // Omits trailing zeroes. -func (a *Amount) String() string { - v := strconv.FormatUint(a.Value, 10) - if a.Fraction != 0 { - f := strconv.FormatUint(a.Fraction, 10) - f = strings.TrimRight(f, "0") - v = fmt.Sprintf("%s.%s", v, f) - } - return fmt.Sprintf("%s:%s", a.Currency, v) +func (a *Amount) String(fractionalDigits int) string { + + return FormatAmount(a, fractionalDigits) + + // v := strconv.FormatUint(a.Value, 10) + // if a.Fraction != 0 { + // f := strconv.FormatUint(a.Fraction, 10) + // f = strings.TrimRight(f, "0") + // v = fmt.Sprintf("%s.%s", v, f) + // } + // return fmt.Sprintf("%s:%s", a.Currency, v) } diff --git a/c2ec/amount_test.go b/c2ec/amount_test.go @@ -44,7 +44,7 @@ func TestAmountAdd(t *testing.T) { if err != nil { t.Errorf("Failed adding amount") } - if c.String() != d.String() { + if c.String(8) != d.String(8) { t.Errorf("Failed to add to correct amount") } } @@ -54,7 +54,7 @@ func TestAmountSub(t *testing.T) { if err != nil { t.Errorf("Failed substracting amount") } - if a.String() != d.String() { + if a.String(8) != d.String(8) { t.Errorf("Failed to substract to correct amount") } } @@ -72,6 +72,68 @@ func TestAmountLarge(t *testing.T) { } } +func TestAmountSub2(t *testing.T) { + + amnts := []string{ + "CHF:30", + "EUR:20.34", + "CHF:23.99", + "CHF:50.35", + "USD:109992332", + "CHF:0.0", + "EUR:00.0", + "USD:0.00", + "CHF:00.00", + } + + for _, a := range amnts { + am, err := ParseAmount(a, 2) + if err != nil { + fmt.Println("parsing failed!", a, err) + t.FailNow() + } + fmt.Println("subtracting", am.String(2)) + a2, err := am.Sub(*am) + if err != nil { + fmt.Println("subtracting failed!", a, err) + t.FailNow() + } + fmt.Println("subtraction result", a2.String(2)) + if !a2.IsZero() { + fmt.Println("subtracting failure... expected zero amount but was", a2.String(2)) + } + } +} + +func TestAmountSub3(t *testing.T) { + + amnts := []string{ + "CHF:30.0004", + "CHF:30.004", + "CHF:30.04", + "CHF:30.4", + "CHF:30", + } + + for _, a := range amnts { + am, err := ParseAmount(a, 4) + if err != nil { + fmt.Println("parsing failed!", a, err) + t.FailNow() + } + fmt.Println("subtracting", am.String(4)) + a2, err := am.Sub(*am) + if err != nil { + fmt.Println("subtracting failed!", a, err) + t.FailNow() + } + fmt.Println("subtraction result", a2.String(4)) + if !a2.IsZero() && a2.String(4) != am.Currency+":0" { + fmt.Println("subtracting failure... expected zero amount but was", a2.String(4)) + } + } +} + func TestParseValid(t *testing.T) { amnts := []string{ diff --git a/c2ec/api-wire-gateway.go b/c2ec/api-wire-gateway.go @@ -500,6 +500,6 @@ func historyOutgoing(res http.ResponseWriter, req *http.Request) { func adminAddIncoming(res http.ResponseWriter, req *http.Request) { // not implemented, because not used - setLastResponseCodeForLogger(HTTP_BAD_REQUEST) - res.WriteHeader(HTTP_BAD_REQUEST) + setLastResponseCodeForLogger(HTTP_NOT_IMPLEMENTED) + res.WriteHeader(HTTP_NOT_IMPLEMENTED) } diff --git a/c2ec/http-util.go b/c2ec/http-util.go @@ -20,6 +20,7 @@ const HTTP_NOT_FOUND = 404 const HTTP_METHOD_NOT_ALLOWED = 405 const HTTP_CONFLICT = 409 const HTTP_INTERNAL_SERVER_ERROR = 500 +const HTTP_NOT_IMPLEMENTED = 501 const CONTENT_TYPE_HEADER = "Content-Type" diff --git a/c2ec/wallee-client.go b/c2ec/wallee-client.go @@ -192,8 +192,27 @@ func (w *WalleeClient) Refund(transactionId string) error { return err } + amountWithFeesStr := fmt.Sprintf("%s:%s", CONFIG.Server.Currency, decodedWalleeTransaction.CompletedAmount) + amountWithFees, err := ParseAmount(amountWithFeesStr, CONFIG.Server.CurrencyFractionDigits) + if err != nil { + LogError("wallee-client", err) + return err + } + + fees, err := ParseAmount(CONFIG.Server.WithdrawalFees, CONFIG.Server.CurrencyFractionDigits) + if err != nil { + LogError("wallee-client", err) + return err + } + + refundAmount, err := amountWithFees.Sub(*fees) + if err != nil { + LogError("wallee-client", err) + return err + } + refund := &WalleeRefund{ - Amount: decodedWalleeTransaction.CompletedAmount, + Amount: refundAmount.String(CONFIG.Server.CurrencyFractionDigits), ExternalID: encodeCrock(withdrawal.Wopid), MerchantReference: decodedWalleeTransaction.MerchantReference, Transaction: WalleeRefundTransaction{ diff --git a/c2ec/wallee-client_test.go b/c2ec/wallee-client_test.go @@ -19,7 +19,7 @@ const INT_TEST_SPACE_ID = 0 const INT_TEST_USER_ID = 0 const INT_TEST_ACCESS_TOKEN = "" -const INT_TEST_REFUND_AMOUNT = 0 +const INT_TEST_REFUND_AMOUNT = "0" const INT_TEST_REFUND_EXT_ID = "" // can be anything -> idempotency const INT_TEST_REFUND_MERCHANT_REFERENCE = "" const INT_TEST_REFUND_TRANSACTION_ID = 0 diff --git a/c2ec/wallee-models.go b/c2ec/wallee-models.go @@ -76,7 +76,7 @@ type WalleeTransactionCompletion struct { } */ type WalleeRefund struct { - Amount float64 `json:"amount"` + Amount string `json:"amount"` ExternalID string `json:"externalId"` // idempotence support MerchantReference string `json:"merchantReference"` Transaction WalleeRefundTransaction `json:"transaction"` @@ -189,7 +189,7 @@ type WalleeTransaction struct { AutoConfirmationEnabled bool `json:"autoConfirmationEnabled"` BillingAddress interface{} `json:"billingAddress"` ChargeRetryEnabled bool `json:"chargeRetryEnabled"` - CompletedAmount float64 `json:"completedAmount"` + CompletedAmount string `json:"completedAmount"` CompletedOn interface{} `json:"completedOn"` CompletionBehavior string `json:"completionBehavior"` CompletionTimeoutOn interface{} `json:"completionTimeoutOn"`