币种汇率改变
This commit is contained in:
parent
c6ec9fe6aa
commit
9e46ce0b02
@ -688,8 +688,13 @@ func applyThirdPartyPaymentRateMarkup(rateText string, markupPercent float64) (s
|
|||||||
if err != nil || rawRate <= 0 || !validThirdPartyPaymentRateMarkup(markupPercent) {
|
if err != nil || rawRate <= 0 || !validThirdPartyPaymentRateMarkup(markupPercent) {
|
||||||
return "", false
|
return "", false
|
||||||
}
|
}
|
||||||
// 汇率源返回的是实时 USD->本币原值;写库前统一叠加运营设置的上浮比例,再按 1 位小数向上取,保证 H5 下单看到的支付汇率不低于实时汇率。
|
// 汇率源返回的是实时 USD->本币原值;写库前先叠加运营上浮比例,再按金额量级向上取整,保证 H5 下单汇率不低于实时汇率。
|
||||||
markedRate := rawRate * (1 + markupPercent/100)
|
markedRate := rawRate * (1 + markupPercent/100)
|
||||||
|
if markedRate > 50 {
|
||||||
|
// 高汇率币种(例如 IDR)展示和支付金额都不应出现小数;减去极小量只抵消 float 乘法毛刺,真实 18510.1 仍会进到 18511。
|
||||||
|
return strconv.FormatFloat(math.Ceil(markedRate-1e-9), 'f', 0, 64), true
|
||||||
|
}
|
||||||
|
// 低汇率币种仍保留原有“最多 1 位小数且向上取”的策略,避免 SAR/BHD 这类币种因强行整数化放大支付金额。
|
||||||
roundedRate := math.Ceil(markedRate*10-1e-9) / 10
|
roundedRate := math.Ceil(markedRate*10-1e-9) / 10
|
||||||
return trimOneDecimalRate(strconv.FormatFloat(roundedRate, 'f', 1, 64)), true
|
return trimOneDecimalRate(strconv.FormatFloat(roundedRate, 'f', 1, 64)), true
|
||||||
}
|
}
|
||||||
|
|||||||
@ -482,7 +482,7 @@ func TestSyncThirdPartyPaymentMethodsDefaultsToV5Pay(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSyncThirdPartyPaymentRatesAppliesMarkupAndCeilsToOneDecimal(t *testing.T) {
|
func TestSyncThirdPartyPaymentRatesAppliesMarkupAndCeilRules(t *testing.T) {
|
||||||
wallet := &mockPaymentWallet{thirdPartyChannelsResp: &walletv1.ListThirdPartyPaymentChannelsResponse{
|
wallet := &mockPaymentWallet{thirdPartyChannelsResp: &walletv1.ListThirdPartyPaymentChannelsResponse{
|
||||||
Channels: []*walletv1.ThirdPartyPaymentChannel{{
|
Channels: []*walletv1.ThirdPartyPaymentChannel{{
|
||||||
AppCode: "lalu",
|
AppCode: "lalu",
|
||||||
@ -500,12 +500,13 @@ func TestSyncThirdPartyPaymentRatesAppliesMarkupAndCeilsToOneDecimal(t *testing.
|
|||||||
Status: "active",
|
Status: "active",
|
||||||
Methods: []*walletv1.ThirdPartyPaymentMethod{
|
Methods: []*walletv1.ThirdPartyPaymentMethod{
|
||||||
{MethodId: 2310, CurrencyCode: "SAR", Status: "active"},
|
{MethodId: 2310, CurrencyCode: "SAR", Status: "active"},
|
||||||
|
{MethodId: 2311, CurrencyCode: "IDR", Status: "active"},
|
||||||
},
|
},
|
||||||
}},
|
}},
|
||||||
}}
|
}}
|
||||||
handler := New(wallet, nil, nil, nil, nil)
|
handler := New(wallet, nil, nil, nil, nil)
|
||||||
handler.exchangeRates = fakeExchangeRateClient{result: exchangeRateResult{
|
handler.exchangeRates = fakeExchangeRateClient{result: exchangeRateResult{
|
||||||
Rates: map[string]string{"SAR": "3.75000000", "BHD": "0.37600000"},
|
Rates: map[string]string{"SAR": "3.75000000", "BHD": "0.37600000", "IDR": "18510.10000000"},
|
||||||
SourceNames: []string{"open.er-api.com"},
|
SourceNames: []string{"open.er-api.com"},
|
||||||
}}
|
}}
|
||||||
router := newPaymentHandlerTestRouter(handler)
|
router := newPaymentHandlerTestRouter(handler)
|
||||||
@ -521,7 +522,7 @@ func TestSyncThirdPartyPaymentRatesAppliesMarkupAndCeilsToOneDecimal(t *testing.
|
|||||||
if wallet.lastThirdPartyChannels == nil || !wallet.lastThirdPartyChannels.GetIncludeDisabledMethods() {
|
if wallet.lastThirdPartyChannels == nil || !wallet.lastThirdPartyChannels.GetIncludeDisabledMethods() {
|
||||||
t.Fatalf("sync must read active and disabled methods: %+v", wallet.lastThirdPartyChannels)
|
t.Fatalf("sync must read active and disabled methods: %+v", wallet.lastThirdPartyChannels)
|
||||||
}
|
}
|
||||||
if len(wallet.updateRateRequests) != 3 {
|
if len(wallet.updateRateRequests) != 4 {
|
||||||
t.Fatalf("sync should update every method with a fetched currency rate: %+v", wallet.updateRateRequests)
|
t.Fatalf("sync should update every method with a fetched currency rate: %+v", wallet.updateRateRequests)
|
||||||
}
|
}
|
||||||
got := map[int64]string{}
|
got := map[int64]string{}
|
||||||
@ -531,18 +532,26 @@ func TestSyncThirdPartyPaymentRatesAppliesMarkupAndCeilsToOneDecimal(t *testing.
|
|||||||
}
|
}
|
||||||
got[req.GetMethodId()] = req.GetUsdToCurrencyRate()
|
got[req.GetMethodId()] = req.GetUsdToCurrencyRate()
|
||||||
}
|
}
|
||||||
if got[810] != "3.9" || got[811] != "0.4" || got[2310] != "3.9" {
|
if got[810] != "3.9" || got[811] != "0.4" || got[2310] != "3.9" || got[2311] != "19066" {
|
||||||
t.Fatalf("synced rates mismatch: %+v", got)
|
t.Fatalf("synced rates mismatch: %+v", got)
|
||||||
}
|
}
|
||||||
var response adminPaymentTestResponse
|
var response adminPaymentTestResponse
|
||||||
if err := json.NewDecoder(recorder.Body).Decode(&response); err != nil {
|
if err := json.NewDecoder(recorder.Body).Decode(&response); err != nil {
|
||||||
t.Fatalf("decode response failed: %v", err)
|
t.Fatalf("decode response failed: %v", err)
|
||||||
}
|
}
|
||||||
if response.Code != 0 || response.Data["updatedCount"].(float64) != 3 {
|
if response.Code != 0 || response.Data["updatedCount"].(float64) != 4 {
|
||||||
t.Fatalf("sync response mismatch: %+v", response)
|
t.Fatalf("sync response mismatch: %+v", response)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestApplyThirdPartyPaymentRateMarkupCeilsHighRateToInteger(t *testing.T) {
|
||||||
|
rate, ok := applyThirdPartyPaymentRateMarkup("18510.10000000", 0)
|
||||||
|
|
||||||
|
if !ok || rate != "18511" {
|
||||||
|
t.Fatalf("IDR high rate must ceil to integer: rate=%q ok=%v", rate, ok)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestSyncThirdPartyPaymentRatesRejectsInvalidMarkupPercent(t *testing.T) {
|
func TestSyncThirdPartyPaymentRatesRejectsInvalidMarkupPercent(t *testing.T) {
|
||||||
wallet := &mockPaymentWallet{}
|
wallet := &mockPaymentWallet{}
|
||||||
router := newPaymentHandlerTestRouter(New(wallet, nil, nil, nil, nil))
|
router := newPaymentHandlerTestRouter(New(wallet, nil, nil, nil, nil))
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user