feat(ops): 下单与核销纳入接口访问百分比

总部可按成功百分比拦截现场提货、配送下单,以及扫码、手机号和弱网核销,规则写入 v4 文档。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-09-26 14:00:55 +08:00
parent 550697c346
commit d306ffaea8
12 changed files with 60 additions and 11 deletions
+22
View File
@@ -137,6 +137,17 @@ describe('classifyApiAccessRoute', () => {
expect(classifyApiAccessRoute('GET', '/api/v1/stores')).toEqual({ feature: 'store_load' });
expect(classifyApiAccessRoute('GET', '/api/v1/stores/9')).toEqual({ feature: 'store_load' });
expect(classifyApiAccessRoute('POST', '/api/v1/partner/stores')).toEqual({ feature: 'store_submit' });
expect(classifyApiAccessRoute('POST', '/api/v1/trade/orders')).toEqual({ feature: 'order_create' });
expect(classifyApiAccessRoute('POST', '/trade/orders')).toEqual({ feature: 'order_create' });
expect(classifyApiAccessRoute('POST', '/api/v1/shop/redeem/confirm')).toEqual({
feature: 'redeem_confirm',
});
expect(classifyApiAccessRoute('POST', '/shop/redeem/phone/confirm')).toEqual({
feature: 'redeem_confirm',
});
expect(classifyApiAccessRoute('POST', '/api/v1/shop/redeem/pending')).toEqual({
feature: 'redeem_confirm',
});
});
it('skips headquarters login, admin reads, and nested store routes', () => {
@@ -146,6 +157,17 @@ describe('classifyApiAccessRoute', () => {
expect(classifyApiAccessRoute('GET', '/api/v1/catalog/cities')).toBeNull();
expect(classifyApiAccessRoute('GET', '/api/v1/stores/9/recent-redeems')).toBeNull();
expect(classifyApiAccessRoute('POST', '/api/v1/partner/stores/send-phone-sms')).toBeNull();
expect(classifyApiAccessRoute('POST', '/api/v1/trade/orders/preview')).toBeNull();
expect(classifyApiAccessRoute('POST', '/api/v1/trade/orders/12/pay')).toBeNull();
expect(classifyApiAccessRoute('POST', '/api/v1/admin/proxy-orders')).toBeNull();
expect(classifyApiAccessRoute('POST', '/api/v1/partner/proxy-orders')).toBeNull();
expect(classifyApiAccessRoute('POST', '/api/v1/shop/redeem/preview')).toBeNull();
expect(classifyApiAccessRoute('POST', '/api/v1/shop/redeem/phone/prepare')).toBeNull();
expect(classifyApiAccessRoute('POST', '/api/v1/shop/redeem/phone/prepare-direct')).toBeNull();
expect(classifyApiAccessRoute('POST', '/api/v1/shop/redeem/failures')).toBeNull();
expect(classifyApiAccessRoute('POST', '/api/v1/redeem/tokens')).toBeNull();
expect(classifyApiAccessRoute('POST', '/api/v1/admin/redeem/debug/confirm')).toBeNull();
expect(classifyApiAccessRoute('POST', '/api/v1/admin/redeem/pending/1/complete')).toBeNull();
});
});
+11 -1
View File
@@ -3,6 +3,8 @@ export const API_ACCESS_PERCENT_FEATURE_KEYS = [
'product_load',
'store_load',
'store_submit',
'order_create',
'redeem_confirm',
'audit_notify',
] as const;
@@ -102,7 +104,7 @@ export function allowBySuccessPercent(successPercent: number, roll: number): boo
}
export type ApiAccessRouteHit = {
feature: 'login' | 'product_load' | 'store_load' | 'store_submit';
feature: 'login' | 'product_load' | 'store_load' | 'store_submit' | 'order_create' | 'redeem_confirm';
loginChannel?: 'user' | 'store' | 'partner';
};
@@ -123,6 +125,14 @@ export function classifyApiAccessRoute(method: string, url: string): ApiAccessRo
return { feature: 'login', loginChannel: 'partner' };
}
if (path === '/partner/stores') return { feature: 'store_submit' };
if (path === '/trade/orders') return { feature: 'order_create' };
if (
path === '/shop/redeem/confirm' ||
path === '/shop/redeem/phone/confirm' ||
path === '/shop/redeem/pending'
) {
return { feature: 'redeem_confirm' };
}
return null;
}
+4
View File
@@ -4,6 +4,8 @@ export const API_ACCESS_PERCENT_FEATURES = [
'product_load',
'store_load',
'store_submit',
'order_create',
'redeem_confirm',
'audit_notify',
] as const;
@@ -14,6 +16,8 @@ export const API_ACCESS_PERCENT_FEATURE_LABELS: Record<ApiAccessPercentFeature,
product_load: '商品加载',
store_load: '门店加载',
store_submit: '门店提交',
order_create: '下单',
redeem_confirm: '核销',
audit_notify: '审核通知',
};