Codex/alipay official payment - #5285
Conversation
WalkthroughThis PR implements Alipay official payment top-ups, adds ZLHub Video channel support with configurable task adapter paths, updates Docker build configuration for registry/mirror support, improves user language persistence, and provides multilingual UI translations. The changes span backend payment processing (RSA2 signing/verification, webhook handling), relay task adapter enhancements (envelope response parsing, configurable paths), frontend payment flow integration, comprehensive system settings UI, and Docker build flexibility. ChangesAlipay Official Payment Integration
ZLHub Video Channel Support
Build Infrastructure and UI Polish
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 7
🧹 Nitpick comments (2)
web/default/src/main.tsx (1)
115-142: ⚡ Quick winDuplicated
user.settingparsing logic.
getUserSavedLanguagere-implements the same string/objectsettingparsing thatparseUserSettingdoes inweb/default/src/components/language-switcher.tsx. Consider extracting a shared helper (e.g., insrc/lib/) so the two stay in sync, especially given the field-priority coupling noted on theLanguageSwitchersetUsercall.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@web/default/src/main.tsx` around lines 115 - 142, getUserSavedLanguage duplicates the string/object parsing logic that's already in parseUserSetting (used by LanguageSwitcher.setUser); extract the shared parsing into a single helper (e.g., src/lib/parseUserSettingOrLanguage.ts) and have both getUserSavedLanguage and parseUserSetting call that helper so the field-priority coupling and parsing behavior remain consistent across getUserSavedLanguage, parseUserSetting, and LanguageSwitcher.setUser.controller/topup.go (1)
108-113: 💤 Low valueConsider using a distinct color for Alipay Official.
The current color
rgba(var(--semi-blue-5), 1)is already used by Waffo (line 91). Using a different color would improve visual distinction between payment methods in the UI.🎨 Suggested alternative colors
payMethods = append(payMethods, map[string]string{ "name": "Alipay Official", "type": model.PaymentMethodAlipayOfficial, - "color": "rgba(var(--semi-blue-5), 1)", + "color": "rgba(var(--semi-cyan-5), 1)", "min_topup": strconv.Itoa(operation_setting.MinTopUp), })Alternative suggestions:
--semi-teal-5,--semi-indigo-5, or--semi-light-blue-5🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@controller/topup.go` around lines 108 - 113, The Alipay Official entry appended to payMethods currently reuses the blue color ("rgba(var(--semi-blue-5), 1)") used by Waffo; update the color value for the map added where payMethods is appended (look for the block that constructs the map with "name":"Alipay Official" and "type": model.PaymentMethodAlipayOfficial) to a distinct CSS variable such as "rgba(var(--semi-teal-5), 1)" (or "--semi-indigo-5"/"--semi-light-blue-5") so Alipay is visually distinct; keep the rest of the map (including "min_topup": strconv.Itoa(operation_setting.MinTopUp)) unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@controller/topup_alipay.go`:
- Line 138: The warning currently logs the full Alipay callback params
(logger.LogWarn call in topup_alipay.go) which may contain sensitive data;
update the LogWarn invocations (the one at signature verification and the
similar calls around the other occurrences) to extract and log only minimal
identifiers such as params["trade_no"] and params["trade_status"] and, if
necessary, a short masked summary (e.g., mask all other fields or replace with
"[REDACTED]") instead of using common.GetJsonString(params); ensure you still
include context like request URI and client IP but remove or redact full payload
content when constructing the log message.
- Around line 171-187: The code persists topUp.Status = TopUpStatusSuccess via
topUp.Update() before calling model.IncreaseUserQuota, which can leave the order
marked success if quota credit fails; instead perform both the conditional
pending→success update and the quota increment inside a single DB transaction:
open a transaction, run an UPDATE on the topup row (or call a transactional
method) that sets Status and CompleteTime only where Status ==
TopUpStatusPending and check affected rows > 0, then call
model.IncreaseUserQuota (or a new IncreaseUserQuotaTx) using the same
transaction; if any step fails rollback and return "fail", otherwise commit and
return success. Ensure to reference topUp.Update, topUp.Status/CompleteTime, and
model.IncreaseUserQuota (or implement a transactional variant) so the transition
+ quota credit are atomic.
In `@docker-compose.dev.yml`:
- Line 26: The docker-compose port change exposes the backend on host port 3004
but the dev proxy (web/default/rsbuild.config.ts) and the comment still assume
http://localhost:3000, breaking the dev proxy flow; fix by either reverting the
docker-compose mapping back to "3000:3000" so the container publishes to host
3000, or update the default serverUrl in rsbuild.config.ts (and the comment on
Line 6) to use http://localhost:3004 so the dev server proxies to the new host
port consistently; ensure the chosen option updates both the docker-compose port
mapping ("3000:3000" vs "3004:3000") or the serverUrl/default comment in
rsbuild.config.ts accordingly.
In `@relay/channel/task/doubao/adaptor.go`:
- Around line 366-393: The current parseResponsePayload and parseResponseTask
can mask real deserialization errors because they unmarshal twice without
validating which shape the raw JSON actually is; change the logic to first
inspect the raw JSON for a discriminator (e.g., check for the presence of keys
like "data" or "code" by unmarshaling into map[string]json.RawMessage or a small
struct) and only then unmarshal into responsePayload/responseTask or
responsePayloadEnvelope/responseTaskEnvelope accordingly, and if the first
unmarshal returned an error return it immediately instead of falling through;
specifically update parseResponsePayload, parseResponseTask to detect envelope
vs direct object before attempting the second Unmarshal so errors from the
appropriate attempt are propagated and not masked.
In
`@web/default/src/features/system-settings/integrations/payment-settings-section.tsx`:
- Around line 410-420: The sanitized object literal in
payment-settings-section.tsx has inconsistent indentation (some properties use 4
spaces vs. the file's 6-space style) which breaks formatting; update the
properties inside the sanitized object (keys like PayAddress, EpayId, EpayKey,
AlipayAppId, AlipayGateway, AlipayPrivateKey, AlipayPublicKey, Price, MinTopUp,
CustomCallbackAddress) to use the same 6-space indentation as the surrounding
code so the object aligns consistently with the rest of the file.
In `@web/default/src/i18n/locales/fr.json`:
- Around line 255-257: Several French localization entries for Alipay are
missing accents/apostrophes; update the value strings for keys "Alipay private
key", "Alipay public key", and "Alipay public key used to verify callbacks" to
proper French spelling/diacritics (e.g., "Clé privée Alipay", "Clé publique
Alipay", "Clé publique Alipay utilisée pour vérifier les callbacks") and review
the other similar keys mentioned in the comment to apply consistent corrections
(fix accents, apostrophes, and common words like "attribué", "intégration", "par
défaut").
In `@web/default/src/i18n/locales/vi.json`:
- Around line 251-257: The new Alipay entries use ASCII-only transliterations;
update the JSON values for the keys "Alipay App ID", "Alipay gateway", "Alipay
Gateway", "Alipay Open Platform", "Alipay private key", "Alipay public key", and
"Alipay public key used to verify callbacks" to proper Vietnamese with
diacritics (e.g., "Alipay App ID" → "ID ứng dụng Alipay", "Alipay gateway" /
"Alipay Gateway" → "Cổng Alipay" or "Cổng thanh toán Alipay", "Alipay Open
Platform" → "Nền tảng mở Alipay", "Alipay private key" → "Khóa riêng Alipay",
"Alipay public key" → "Khóa công khai Alipay", "Alipay public key used to verify
callbacks" → "Khóa công khai Alipay dùng để xác minh callback"); apply the same
diacritic corrections to the other keyed entries noted in the comment (those at
the other indices) so all Vietnamese translations use proper accents and match
the locale's style.
---
Nitpick comments:
In `@controller/topup.go`:
- Around line 108-113: The Alipay Official entry appended to payMethods
currently reuses the blue color ("rgba(var(--semi-blue-5), 1)") used by Waffo;
update the color value for the map added where payMethods is appended (look for
the block that constructs the map with "name":"Alipay Official" and "type":
model.PaymentMethodAlipayOfficial) to a distinct CSS variable such as
"rgba(var(--semi-teal-5), 1)" (or "--semi-indigo-5"/"--semi-light-blue-5") so
Alipay is visually distinct; keep the rest of the map (including "min_topup":
strconv.Itoa(operation_setting.MinTopUp)) unchanged.
In `@web/default/src/main.tsx`:
- Around line 115-142: getUserSavedLanguage duplicates the string/object parsing
logic that's already in parseUserSetting (used by LanguageSwitcher.setUser);
extract the shared parsing into a single helper (e.g.,
src/lib/parseUserSettingOrLanguage.ts) and have both getUserSavedLanguage and
parseUserSetting call that helper so the field-priority coupling and parsing
behavior remain consistent across getUserSavedLanguage, parseUserSetting, and
LanguageSwitcher.setUser.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 5cdbadc1-6c95-4941-a33f-41bba55a77bd
📒 Files selected for processing (47)
DockerfileDockerfile.devconstant/channel.gocontroller/channel-test.gocontroller/payment_webhook_availability.gocontroller/payment_webhook_availability_test.gocontroller/topup.gocontroller/topup_alipay.godocker-compose.dev.ymldocker-compose.ymlmodel/option.gomodel/topup.gorelay/channel/task/doubao/adaptor.gorelay/channel/task/doubao/adaptor_test.gorelay/channel/task/doubao/constants.gorelay/relay_adaptor.gorouter/api-router.goservice/alipay.gosetting/payment_alipay.gosetting/system_setting/theme.goweb/classic/src/constants/channel.constants.jsweb/classic/src/helpers/render.jsxweb/default/scripts/sync-i18n.mjsweb/default/src/components/language-switcher.tsxweb/default/src/features/channels/constants.tsweb/default/src/features/channels/lib/channel-type-config.tsweb/default/src/features/channels/lib/channel-utils.tsweb/default/src/features/system-settings/billing/index.tsxweb/default/src/features/system-settings/billing/section-registry.tsxweb/default/src/features/system-settings/integrations/payment-settings-section.tsxweb/default/src/features/system-settings/types.tsweb/default/src/features/wallet/api.tsweb/default/src/features/wallet/components/recharge-form-card.tsxweb/default/src/features/wallet/components/subscription-plans-card.tsxweb/default/src/features/wallet/constants.tsweb/default/src/features/wallet/hooks/use-payment.tsweb/default/src/features/wallet/lib/billing.tsweb/default/src/features/wallet/lib/payment.tsweb/default/src/features/wallet/lib/ui.tsxweb/default/src/features/wallet/types.tsweb/default/src/i18n/locales/en.jsonweb/default/src/i18n/locales/fr.jsonweb/default/src/i18n/locales/ja.jsonweb/default/src/i18n/locales/ru.jsonweb/default/src/i18n/locales/vi.jsonweb/default/src/i18n/locales/zh.jsonweb/default/src/main.tsx
| } | ||
|
|
||
| if err := service.VerifyAlipayParams(params); err != nil { | ||
| logger.LogWarn(c.Request.Context(), fmt.Sprintf("Alipay webhook signature verification failed path=%q client_ip=%s error=%q params=%q", c.Request.RequestURI, c.ClientIP(), err.Error(), common.GetJsonString(params))) |
There was a problem hiding this comment.
Avoid logging full Alipay callback params.
These logs serialize the entire webhook payload, which can include sensitive user/payment metadata. Log only minimal identifiers (e.g., trade_no, trade_status) and redact/mask the rest.
Minimal redaction example
- logger.LogWarn(..., common.GetJsonString(params)))
+ safe := map[string]string{
+ "out_trade_no": strings.TrimSpace(params["out_trade_no"]),
+ "trade_status": strings.TrimSpace(params["trade_status"]),
+ }
+ logger.LogWarn(..., common.GetJsonString(safe)))Also applies to: 151-151, 161-161
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@controller/topup_alipay.go` at line 138, The warning currently logs the full
Alipay callback params (logger.LogWarn call in topup_alipay.go) which may
contain sensitive data; update the LogWarn invocations (the one at signature
verification and the similar calls around the other occurrences) to extract and
log only minimal identifiers such as params["trade_no"] and
params["trade_status"] and, if necessary, a short masked summary (e.g., mask all
other fields or replace with "[REDACTED]") instead of using
common.GetJsonString(params); ensure you still include context like request URI
and client IP but remove or redact full payload content when constructing the
log message.
| if topUp.Status == common.TopUpStatusPending { | ||
| topUp.Status = common.TopUpStatusSuccess | ||
| topUp.CompleteTime = common.GetTimestamp() | ||
| if err := topUp.Update(); err != nil { | ||
| logger.LogError(c.Request.Context(), fmt.Sprintf("Alipay update topup order failed trade_no=%s user_id=%d client_ip=%s error=%q topup=%q", topUp.TradeNo, topUp.UserId, c.ClientIP(), err.Error(), common.GetJsonString(topUp))) | ||
| _, _ = c.Writer.Write([]byte("fail")) | ||
| return | ||
| } | ||
|
|
||
| dAmount := decimal.NewFromInt(int64(topUp.Amount)) | ||
| dQuotaPerUnit := decimal.NewFromFloat(common.QuotaPerUnit) | ||
| quotaToAdd := int(dAmount.Mul(dQuotaPerUnit).IntPart()) | ||
| if err := model.IncreaseUserQuota(topUp.UserId, quotaToAdd, true); err != nil { | ||
| logger.LogError(c.Request.Context(), fmt.Sprintf("Alipay increase user quota failed trade_no=%s user_id=%d client_ip=%s quota_to_add=%d error=%q topup=%q", topUp.TradeNo, topUp.UserId, c.ClientIP(), quotaToAdd, err.Error(), common.GetJsonString(topUp))) | ||
| _, _ = c.Writer.Write([]byte("fail")) | ||
| return | ||
| } |
There was a problem hiding this comment.
Make order state transition and quota credit atomic.
topUp.Status is persisted before quota credit. If quota update fails, the order remains success and later retries won’t credit the user. This can permanently lose funds/credits. Use a single DB transaction with a conditional pending→success update and quota increment in the same transaction.
Suggested direction
- if topUp.Status == common.TopUpStatusPending {
- topUp.Status = common.TopUpStatusSuccess
- topUp.CompleteTime = common.GetTimestamp()
- if err := topUp.Update(); err != nil { ... }
- ...
- if err := model.IncreaseUserQuota(topUp.UserId, quotaToAdd, true); err != nil { ... }
- }
+ // Use a transactional model method that:
+ // 1) locks/conditionally updates pending->success
+ // 2) increments user quota
+ // 3) commits or rolls back as one unit
+ // 4) returns idempotent success when already completed🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@controller/topup_alipay.go` around lines 171 - 187, The code persists
topUp.Status = TopUpStatusSuccess via topUp.Update() before calling
model.IncreaseUserQuota, which can leave the order marked success if quota
credit fails; instead perform both the conditional pending→success update and
the quota increment inside a single DB transaction: open a transaction, run an
UPDATE on the topup row (or call a transactional method) that sets Status and
CompleteTime only where Status == TopUpStatusPending and check affected rows >
0, then call model.IncreaseUserQuota (or a new IncreaseUserQuotaTx) using the
same transaction; if any step fails rollback and return "fail", otherwise commit
and return success. Ensure to reference topUp.Update, topUp.Status/CompleteTime,
and model.IncreaseUserQuota (or implement a transactional variant) so the
transition + quota credit are atomic.
| restart: unless-stopped | ||
| ports: | ||
| - "3000:3000" | ||
| - "3004:3000" |
There was a problem hiding this comment.
Port change breaks the documented dev proxy flow.
The backend container is now published on host port 3004, but the Rsbuild dev server proxies /api, /mj, /pg to serverUrl which defaults to http://localhost:3000 (web/default/rsbuild.config.ts), and the comment on Line 6 still states "API auto-proxied to :3000". After this change, API requests from the dev server (run on host via bun run dev) will hit localhost:3000 where nothing is listening, so the dev workflow breaks unless the user manually sets VITE_REACT_APP_SERVER_URL=http://localhost:3004.
Either keep the dev mapping at "3000:3000", or update the proxy default and the Line 6 comment to :3004 consistently.
Proposed fix (keep dev backend on :3000)
ports:
- - "3004:3000"
+ - "3000:3000"🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docker-compose.dev.yml` at line 26, The docker-compose port change exposes
the backend on host port 3004 but the dev proxy (web/default/rsbuild.config.ts)
and the comment still assume http://localhost:3000, breaking the dev proxy flow;
fix by either reverting the docker-compose mapping back to "3000:3000" so the
container publishes to host 3000, or update the default serverUrl in
rsbuild.config.ts (and the comment on Line 6) to use http://localhost:3004 so
the dev server proxies to the new host port consistently; ensure the chosen
option updates both the docker-compose port mapping ("3000:3000" vs "3004:3000")
or the serverUrl/default comment in rsbuild.config.ts accordingly.
| func parseResponsePayload(respBody []byte) (responsePayload, error) { | ||
| var payload responsePayload | ||
| if err := common.Unmarshal(respBody, &payload); err != nil { | ||
| return responsePayload{}, err | ||
| } | ||
| if payload.ID != "" { | ||
| return payload, nil | ||
| } | ||
|
|
||
| var envelope responsePayloadEnvelope | ||
| if err := common.Unmarshal(respBody, &envelope); err != nil { | ||
| return responsePayload{}, err | ||
| } | ||
| return envelope.Data, nil | ||
| } | ||
|
|
||
| func parseResponseTask(respBody []byte) (responseTask, error) { | ||
| var envelope responseTaskEnvelope | ||
| if err := common.Unmarshal(respBody, &envelope); err == nil && envelope.Data.ID != "" { | ||
| return envelope.Data, nil | ||
| } | ||
|
|
||
| var task responseTask | ||
| if err := common.Unmarshal(respBody, &task); err != nil { | ||
| return responseTask{}, err | ||
| } | ||
| return task, nil | ||
| } |
There was a problem hiding this comment.
Envelope parsing may mask deserialization errors.
The parsing functions try multiple response formats but might mask actual errors. For example, in parseResponsePayload, if the first Unmarshal succeeds but returns an empty ID due to a malformed response (not because it's an envelope), the second unmarshal is attempted and might incorrectly succeed or fail with a misleading error.
Consider checking the error from the first unmarshal more carefully, or adding a discriminator field check (e.g., presence of "code" or "data" keys in envelope) to determine format before unmarshaling.
🛡️ Proposed improvement with discriminator check
func parseResponsePayload(respBody []byte) (responsePayload, error) {
+ // Quick check for envelope format by looking for "data" field
+ if bytes.Contains(respBody, []byte(`"data"`)) {
+ var envelope responsePayloadEnvelope
+ if err := common.Unmarshal(respBody, &envelope); err == nil && envelope.Data.ID != "" {
+ return envelope.Data, nil
+ }
+ }
+
var payload responsePayload
if err := common.Unmarshal(respBody, &payload); err != nil {
return responsePayload{}, err
}
- if payload.ID != "" {
- return payload, nil
- }
-
- var envelope responsePayloadEnvelope
- if err := common.Unmarshal(respBody, &envelope); err != nil {
- return responsePayload{}, err
- }
- return envelope.Data, nil
+ return payload, nil
}🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@relay/channel/task/doubao/adaptor.go` around lines 366 - 393, The current
parseResponsePayload and parseResponseTask can mask real deserialization errors
because they unmarshal twice without validating which shape the raw JSON
actually is; change the logic to first inspect the raw JSON for a discriminator
(e.g., check for the presence of keys like "data" or "code" by unmarshaling into
map[string]json.RawMessage or a small struct) and only then unmarshal into
responsePayload/responseTask or responsePayloadEnvelope/responseTaskEnvelope
accordingly, and if the first unmarshal returned an error return it immediately
instead of falling through; specifically update parseResponsePayload,
parseResponseTask to detect envelope vs direct object before attempting the
second Unmarshal so errors from the appropriate attempt are propagated and not
masked.
| const sanitized = { | ||
| PayAddress: removeTrailingSlash(values.PayAddress), | ||
| EpayId: values.EpayId.trim(), | ||
| EpayKey: values.EpayKey.trim(), | ||
| Price: values.Price, | ||
| MinTopUp: values.MinTopUp, | ||
| CustomCallbackAddress: removeTrailingSlash(values.CustomCallbackAddress), | ||
| EpayId: values.EpayId.trim(), | ||
| EpayKey: values.EpayKey.trim(), | ||
| AlipayAppId: values.AlipayAppId.trim(), | ||
| AlipayGateway: removeTrailingSlash(values.AlipayGateway.trim()), | ||
| AlipayPrivateKey: values.AlipayPrivateKey.trim(), | ||
| AlipayPublicKey: values.AlipayPublicKey.trim(), | ||
| Price: values.Price, | ||
| MinTopUp: values.MinTopUp, | ||
| CustomCallbackAddress: removeTrailingSlash(values.CustomCallbackAddress), |
There was a problem hiding this comment.
Inconsistent indentation in sanitized object.
Lines 411-420 use 4-space indentation while the rest of the object (line 410 and lines 421+) uses 6 spaces. This appears to be a formatting error that breaks code consistency.
🔧 Suggested fix
const sanitized = {
PayAddress: removeTrailingSlash(values.PayAddress),
- EpayId: values.EpayId.trim(),
- EpayKey: values.EpayKey.trim(),
- AlipayAppId: values.AlipayAppId.trim(),
- AlipayGateway: removeTrailingSlash(values.AlipayGateway.trim()),
- AlipayPrivateKey: values.AlipayPrivateKey.trim(),
- AlipayPublicKey: values.AlipayPublicKey.trim(),
- Price: values.Price,
- MinTopUp: values.MinTopUp,
- CustomCallbackAddress: removeTrailingSlash(values.CustomCallbackAddress),
+ EpayId: values.EpayId.trim(),
+ EpayKey: values.EpayKey.trim(),
+ AlipayAppId: values.AlipayAppId.trim(),
+ AlipayGateway: removeTrailingSlash(values.AlipayGateway.trim()),
+ AlipayPrivateKey: values.AlipayPrivateKey.trim(),
+ AlipayPublicKey: values.AlipayPublicKey.trim(),
+ Price: values.Price,
+ MinTopUp: values.MinTopUp,
+ CustomCallbackAddress: removeTrailingSlash(values.CustomCallbackAddress),
PayMethods: values.PayMethods.trim(),📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const sanitized = { | |
| PayAddress: removeTrailingSlash(values.PayAddress), | |
| EpayId: values.EpayId.trim(), | |
| EpayKey: values.EpayKey.trim(), | |
| Price: values.Price, | |
| MinTopUp: values.MinTopUp, | |
| CustomCallbackAddress: removeTrailingSlash(values.CustomCallbackAddress), | |
| EpayId: values.EpayId.trim(), | |
| EpayKey: values.EpayKey.trim(), | |
| AlipayAppId: values.AlipayAppId.trim(), | |
| AlipayGateway: removeTrailingSlash(values.AlipayGateway.trim()), | |
| AlipayPrivateKey: values.AlipayPrivateKey.trim(), | |
| AlipayPublicKey: values.AlipayPublicKey.trim(), | |
| Price: values.Price, | |
| MinTopUp: values.MinTopUp, | |
| CustomCallbackAddress: removeTrailingSlash(values.CustomCallbackAddress), | |
| const sanitized = { | |
| PayAddress: removeTrailingSlash(values.PayAddress), | |
| EpayId: values.EpayId.trim(), | |
| EpayKey: values.EpayKey.trim(), | |
| AlipayAppId: values.AlipayAppId.trim(), | |
| AlipayGateway: removeTrailingSlash(values.AlipayGateway.trim()), | |
| AlipayPrivateKey: values.AlipayPrivateKey.trim(), | |
| AlipayPublicKey: values.AlipayPublicKey.trim(), | |
| Price: values.Price, | |
| MinTopUp: values.MinTopUp, | |
| CustomCallbackAddress: removeTrailingSlash(values.CustomCallbackAddress), |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In
`@web/default/src/features/system-settings/integrations/payment-settings-section.tsx`
around lines 410 - 420, The sanitized object literal in
payment-settings-section.tsx has inconsistent indentation (some properties use 4
spaces vs. the file's 6-space style) which breaks formatting; update the
properties inside the sanitized object (keys like PayAddress, EpayId, EpayKey,
AlipayAppId, AlipayGateway, AlipayPrivateKey, AlipayPublicKey, Price, MinTopUp,
CustomCallbackAddress) to use the same 6-space indentation as the surrounding
code so the object aligns consistently with the rest of the file.
| "Alipay private key": "Cle privee Alipay", | ||
| "Alipay public key": "Cle publique Alipay", | ||
| "Alipay public key used to verify callbacks": "Cle publique Alipay utilisee pour verifier les callbacks", |
There was a problem hiding this comment.
Fix French localization quality in new Alipay strings (missing accents/apostrophes).
Several new French entries look machine-transliterated (e.g., Cle privee, attribue, integration, defaut), which degrades UX consistency in a user-facing payment flow. Please switch these to proper French spelling/accents.
Suggested patch
- "Alipay private key": "Cle privee Alipay",
- "Alipay public key": "Cle publique Alipay",
- "Alipay public key used to verify callbacks": "Cle publique Alipay utilisee pour verifier les callbacks",
+ "Alipay private key": "Clé privée Alipay",
+ "Alipay public key": "Clé publique Alipay",
+ "Alipay public key used to verify callbacks": "Clé publique Alipay utilisée pour vérifier les callbacks",
@@
- "App ID assigned by Alipay Open Platform": "ID d'application attribue par Alipay Open Platform",
+ "App ID assigned by Alipay Open Platform": "ID d'application attribué par Alipay Open Platform",
@@
- "Configuration for Alipay official payment integration": "Configuration de l'integration du paiement officiel Alipay",
+ "Configuration for Alipay official payment integration": "Configuration de l'intégration du paiement officiel Alipay",
@@
- "Leave the default gateway unless you are using a custom endpoint": "Conservez la passerelle par defaut sauf si vous utilisez un endpoint personnalise",
+ "Leave the default gateway unless you are using a custom endpoint": "Conservez la passerelle par défaut sauf si vous utilisez un endpoint personnalisé",
@@
- "Paste Alipay public key here": "Collez la cle publique Alipay ici",
+ "Paste Alipay public key here": "Collez la clé publique Alipay ici",
@@
- "Paste your private key here": "Collez votre cle privee ici",
+ "Paste your private key here": "Collez votre clé privée ici",
@@
- "RSA2 private key used to sign payment requests": "Cle privee RSA2 utilisee pour signer les demandes de paiement",
+ "RSA2 private key used to sign payment requests": "Clé privée RSA2 utilisée pour signer les demandes de paiement",Also applies to: 370-370, 834-834, 2174-2174, 2861-2861, 2863-2863, 3413-3413
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@web/default/src/i18n/locales/fr.json` around lines 255 - 257, Several French
localization entries for Alipay are missing accents/apostrophes; update the
value strings for keys "Alipay private key", "Alipay public key", and "Alipay
public key used to verify callbacks" to proper French spelling/diacritics (e.g.,
"Clé privée Alipay", "Clé publique Alipay", "Clé publique Alipay utilisée pour
vérifier les callbacks") and review the other similar keys mentioned in the
comment to apply consistent corrections (fix accents, apostrophes, and common
words like "attribué", "intégration", "par défaut").
| "Alipay App ID": "ID ung dung Alipay", | ||
| "Alipay gateway": "Cong Alipay", | ||
| "Alipay Gateway": "Cong thanh toan Alipay", | ||
| "Alipay Open Platform": "Nen tang mo Alipay", | ||
| "Alipay private key": "Khoa rieng Alipay", | ||
| "Alipay public key": "Khoa cong khai Alipay", | ||
| "Alipay public key used to verify callbacks": "Khoa cong khai Alipay dung de xac minh callback", |
There was a problem hiding this comment.
Fix Vietnamese diacritics in new Alipay translations (readability regression).
Several newly added values are ASCII-only transliterations (e.g., at Line 251, Line 370, Line 834), which is inconsistent with the rest of this locale file and degrades UX for Vietnamese users.
Suggested translation fixes
- "Alipay App ID": "ID ung dung Alipay",
- "Alipay gateway": "Cong Alipay",
- "Alipay Gateway": "Cong thanh toan Alipay",
- "Alipay Open Platform": "Nen tang mo Alipay",
- "Alipay private key": "Khoa rieng Alipay",
- "Alipay public key": "Khoa cong khai Alipay",
- "Alipay public key used to verify callbacks": "Khoa cong khai Alipay dung de xac minh callback",
+ "Alipay App ID": "ID ứng dụng Alipay",
+ "Alipay gateway": "Cổng Alipay",
+ "Alipay Gateway": "Cổng thanh toán Alipay",
+ "Alipay Open Platform": "Nền tảng Mở Alipay",
+ "Alipay private key": "Khóa riêng Alipay",
+ "Alipay public key": "Khóa công khai Alipay",
+ "Alipay public key used to verify callbacks": "Khóa công khai Alipay dùng để xác minh callback",
- "App ID assigned by Alipay Open Platform": "ID ung dung do Alipay Open Platform cap",
+ "App ID assigned by Alipay Open Platform": "ID ứng dụng do Nền tảng Mở Alipay cấp",
- "Configuration for Alipay official payment integration": "Cau hinh tich hop thanh toan chinh thuc Alipay",
+ "Configuration for Alipay official payment integration": "Cấu hình tích hợp thanh toán chính thức Alipay",
- "Leave the default gateway unless you are using a custom endpoint": "Giu cong mac dinh neu ban khong dung endpoint tuy chinh",
+ "Leave the default gateway unless you are using a custom endpoint": "Giữ cổng mặc định nếu bạn không dùng endpoint tùy chỉnh",
- "Paste Alipay public key here": "Dan khoa cong khai Alipay vao day",
+ "Paste Alipay public key here": "Dán khóa công khai Alipay vào đây",
- "Paste your private key here": "Dan khoa rieng cua ban vao day",
+ "Paste your private key here": "Dán khóa riêng của bạn vào đây",
- "RSA2 private key used to sign payment requests": "Khoa rieng RSA2 dung de ky yeu cau thanh toan",
+ "RSA2 private key used to sign payment requests": "Khóa riêng RSA2 dùng để ký yêu cầu thanh toán",Also applies to: 370-370, 834-834, 2174-2174, 2861-2861, 2863-2863, 3413-3413
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@web/default/src/i18n/locales/vi.json` around lines 251 - 257, The new Alipay
entries use ASCII-only transliterations; update the JSON values for the keys
"Alipay App ID", "Alipay gateway", "Alipay Gateway", "Alipay Open Platform",
"Alipay private key", "Alipay public key", and "Alipay public key used to verify
callbacks" to proper Vietnamese with diacritics (e.g., "Alipay App ID" → "ID ứng
dụng Alipay", "Alipay gateway" / "Alipay Gateway" → "Cổng Alipay" or "Cổng thanh
toán Alipay", "Alipay Open Platform" → "Nền tảng mở Alipay", "Alipay private
key" → "Khóa riêng Alipay", "Alipay public key" → "Khóa công khai Alipay",
"Alipay public key used to verify callbacks" → "Khóa công khai Alipay dùng để
xác minh callback"); apply the same diacritic corrections to the other keyed
entries noted in the comment (those at the other indices) so all Vietnamese
translations use proper accents and match the locale's style.
Important
📝 变更描述 / Description
(简述:做了什么?为什么这样改能生效?请基于你对代码逻辑的理解来写,避免粘贴未经整理的内容)
🚀 变更类型 / Type of change
🔗 关联任务 / Related Issue
✅ 提交前检查项 / Checklist
Bug fix,我已提交或关联对应 Issue,且不会将设计取舍、预期不一致或理解偏差直接归类为 bug。📸 运行证明 / Proof of Work
(请在此粘贴截图、关键日志或测试报告,以证明变更生效)
Summary by CodeRabbit
Release Notes
New Features
Chores