| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350 |
- #!/usr/bin/env node
- import { randomBytes } from 'node:crypto';
- const APP_ID = process.env.XIAOSHU_PARSE_APP_ID || '7pIbDBJmKx_main';
- const MASTER_KEY = process.env.XIAOSHU_MASTER_KEY || '';
- const PARSE_URL = (process.env.XIAOSHU_PARSE_URL || 'https://server.xiaoshu.pro/parse').replace(/\/$/, '');
- const FUNCTION_URL = (process.env.XIAOSHU_FUNCTION_URL || 'https://server.xiaoshu.pro/api/functions').replace(/\/$/, '');
- const COMPANY_ID = '7pIbDBJmKx';
- if (!MASTER_KEY) throw new Error('缺少 XIAOSHU_MASTER_KEY');
- const appHeaders = { 'X-Parse-Application-Id': APP_ID, 'Content-Type': 'application/json' };
- const masterHeaders = { ...appHeaders, 'X-Parse-Master-Key': MASTER_KEY };
- const username = `codex_member_resource_${Date.now()}`;
- const password = randomBytes(24).toString('base64url');
- const legacyUserId = 970000000 + Math.floor(Date.now() / 1000) % 20000000;
- let userObjectId = '';
- let membershipTargetUserId = '';
- let commerceProductId = 0;
- const created = [];
- async function request(url, init = {}, expected = 200) {
- const response = await fetch(url, init);
- const payload = await response.json().catch(() => ({}));
- if (response.status !== expected) throw new Error(`${url} 期望 ${expected},实际 ${response.status}: ${payload.retmsg || payload.error || ''}`);
- return payload;
- }
- async function master(path, init = {}, expected = 200) {
- return request(`${PARSE_URL}${path}`, { ...init, headers: { ...masterHeaders, ...(init.headers || {}) } }, expected);
- }
- async function cloud(token, action, params = {}, expected = 200) {
- return request(`${FUNCTION_URL}/xiaoshu/app/gateway`, {
- method: 'POST', headers: appHeaders, body: JSON.stringify({ token, params: { action, uid: legacyUserId, ...params } }),
- }, expected);
- }
- async function hardDelete(className, objectId) {
- if (!objectId) return;
- await master(`/classes/${className}/${objectId}`, { method: 'DELETE' }).catch(() => undefined);
- }
- try {
- const company = { __type: 'Pointer', className: 'Company', objectId: COMPANY_ID };
- const createdUser = await master('/users', {
- method: 'POST',
- body: JSON.stringify({ username, password, company, legacyUserId, legacyGroupId: 1, nickname: '会员资料云函数冒烟', legacyUserData: { UserID: legacyUserId, GroupID: 1, HoneyName: '会员资料云函数冒烟' } }),
- }, 201);
- userObjectId = createdUser.objectId;
- const login = await request(`${PARSE_URL}/login`, { method: 'POST', headers: appHeaders, body: JSON.stringify({ username, password }) });
- const token = login.sessionToken;
- await master(`/users/${userObjectId}`, {
- method: 'PUT',
- body: JSON.stringify({ legacyUserData: { UserID: legacyUserId, GroupID: 1, HoneyName: '会员资料云函数冒烟', SilverCoin: 200 } }),
- });
- const completedReviewStats = await cloud(token, 'e_get_21list_tj');
- if (!Array.isArray(completedReviewStats.result) || Number(completedReviewStats.result[0]?.num) !== 0) throw new Error('本人已完成复习任务统计异常');
- const address = await cloud(token, 'receaddr_add', { provinceName: '江西省', cityName: '南昌市', countyName: '青山湖区', userName: '测试收货人', telNumber: '13800138000', detailInfo: '测试路 1 号', postalCode: '330000' });
- const addressId = String(address.result?.ID || ''); created.push(['ReceivingAddress', addressId]);
- if (!addressId || address.result?.ReceivName !== '测试收货人') throw new Error('收货地址新增响应异常');
- const addressList = await cloud(token, 'receaddr_list', { cpage: 1, psize: 20 });
- if (addressList.page?.itemCount !== 1 || addressList.result?.[0]?.ID !== addressId) throw new Error('收货地址列表异常');
- const addressUpdated = await cloud(token, 'receaddr_upd', { id: addressId, provinceName: '江西省', cityName: '南昌市', countyName: '青山湖区', userName: '更新收货人', telNumber: '13800138000', detailInfo: '测试路 2 号', postalCode: '330000' });
- if (addressUpdated.result?.ReceivName !== '更新收货人') throw new Error('收货地址更新异常');
- const addressGet = await cloud(token, 'receaddr_get', { id: addressId });
- if (addressGet.result?.Street !== '测试路 2 号') throw new Error('收货地址详情异常');
- const invoice = await cloud(token, 'invoice_add', { aud: 1, name: '测试企业', idnum: '91360100TEST000001', mobile: '13800138000', email: 'billing@example.test', address: '测试注册地址', bankname: '测试银行', bankusr: '6222020000000000000' });
- const invoiceId = String(invoice.result?.ID || ''); created.push(['InvoiceProfile', invoiceId]);
- if (!invoiceId || invoice.result?.InvHead !== '测试企业') throw new Error('发票资料新增响应异常');
- const invoiceUpdated = await cloud(token, 'invoice_upd', { id: invoiceId, aud: 1, name: '更新测试企业', idnum: '91360100TEST000001', mobile: '13800138000', email: 'billing@example.test', address: '测试注册地址', bankname: '测试银行', bankusr: '6222020000000000000' });
- if (invoiceUpdated.result?.InvHead !== '更新测试企业') throw new Error('发票资料更新异常');
- const invoiceList = await cloud(token, 'invoice_list', { cpage: 1, psize: 20 });
- if (invoiceList.page?.itemCount !== 1 || invoiceList.result?.[0]?.ID !== invoiceId) throw new Error('发票资料列表异常');
- const bank = await cloud(token, 'user_bank_add', { CardType: '银行卡', BankName: '测试银行', PeopleName: '测试开户人', CardNum: '6222020000000000000', Remark: '首次创建' });
- const bankId = String(bank.result?.ID || ''); created.push(['UserBankAccount', bankId]);
- if (!bankId || bank.result?.PeopleName !== '测试开户人') throw new Error('提现账户新增响应异常');
- const bankUpdated = await cloud(token, 'user_bank_add', { id: bankId, CardType: '银行卡', BankName: '测试银行', PeopleName: '更新开户人', CardNum: '6222020000000000000', Remark: '已更新' });
- if (bankUpdated.result?.PeopleName !== '更新开户人') throw new Error('提现账户更新异常');
- const bankGet = await cloud(token, 'user_bank_get', { id: bankId });
- if (bankGet.result?.Remark !== '已更新') throw new Error('提现账户详情异常');
- const bankList = await cloud(token, 'user_bank_list', { cpage: 1, psize: 20 });
- if (bankList.page?.itemCount !== 1 || bankList.result?.[0]?.ID !== bankId) throw new Error('提现账户列表异常');
- const ask = await cloud('', 'vote_ask', { id: 1 });
- const questions = await cloud('', 'vote_question', { askid: 1 });
- if (ask.result?.[0]?.Title !== '第一组问题' || Number(questions.result?.length) !== 48 || !questions.result?.[0]?.QOption) throw new Error('测评问卷或题目读取异常');
- const examStamp = `2099-01-01 00:${String(Date.now() % 60).padStart(2, '0')}:${String(Date.now() % 60).padStart(2, '0')}`;
- const examAnswers = questions.result.slice(0, 2).map((item) => ({ qid: item.ID, qtype: item.QType, answer: '', result: 2 }));
- const answer = await cloud(token, 'vote_add', { mu: JSON.stringify({ AskID: 1, Answer: JSON.stringify(examAnswers), UserID: legacyUserId, CDate: examStamp }) });
- if (!Number(answer.result)) throw new Error('测评答题记录新增异常');
- const answerSourceKey = `app:vote:${legacyUserId}:1:${examStamp}`;
- const answerRows = await master(`/classes/DesignAnswer?where=${encodeURIComponent(JSON.stringify({ sourceKey: answerSourceKey }))}&limit=2`);
- if (answerRows.results?.length !== 1 || Number(answerRows.results[0].id) !== Number(answer.result)) throw new Error('测评答题记录写后读或幂等键异常');
- created.push(['DesignAnswer', answerRows.results[0].objectId]);
- const repeatedAnswer = await cloud(token, 'vote_add', { mu: JSON.stringify({ AskID: 1, Answer: JSON.stringify(examAnswers), UserID: legacyUserId, CDate: examStamp }) });
- if (Number(repeatedAnswer.result) !== Number(answer.result)) throw new Error('测评答题记录重复提交未保持幂等');
- const unit = await cloud(token, 'unit_record_update', { userId: legacyUserId, bookId: 16, nids: '40', wordIds: JSON.stringify({ 40: '2505,2506' }) });
- if (unit.result?.updated !== 1 || unit.result?.items?.[0]?.learnedCount !== 2) throw new Error('单元学习进度保存异常');
- created.push(['UnitLearningRecord', unit.result.items[0].objectId]);
- const unitRepeat = await cloud(token, 'unit_record_update', { userId: legacyUserId, bookId: 16, nids: '40', wordIds: JSON.stringify({ 40: '2505' }) });
- if (unitRepeat.result?.items?.[0]?.objectId !== unit.result.items[0].objectId || unitRepeat.result?.items?.[0]?.learnedCount !== 1) throw new Error('单元学习进度幂等更新异常');
- const favoriteMissing = await cloud(token, 'user_star_is', { id: 'future-product-1', type: 2 });
- if (String(favoriteMissing.result) !== '0') throw new Error('收藏初始状态异常');
- await cloud(token, 'user_star_add', { id: 'future-product-1', type: 2, title: '未来商品', url: '/Shop/future-product-1' });
- const favoriteAdded = await cloud(token, 'user_star_is', { id: 'future-product-1', type: 2 });
- if (String(favoriteAdded.result) !== '1') throw new Error('收藏新增后状态异常');
- const favoriteRows = await master(`/classes/UserFavorite?where=${encodeURIComponent(JSON.stringify({ sourceKey: `app:favorite:${legacyUserId}:2:future-product-1` }))}&limit=2`);
- if (favoriteRows.results?.length !== 1) throw new Error('收藏关系未写入规范类');
- created.push(['UserFavorite', favoriteRows.results[0].objectId]);
- await cloud(token, 'user_star_del', { id: 'future-product-1', type: 2 });
- const favoriteDeleted = await cloud(token, 'user_star_is', { id: 'future-product-1', type: 2 });
- if (String(favoriteDeleted.result) !== '0') throw new Error('取消收藏后状态异常');
- const supplierRequest = await cloud(token, 'pub_add', { pubid: 8, model: JSON.stringify({ PubTitle: '冒烟供应商', PubContent: '申请入驻', BankAccount: 'TEST-ONLY', PubIsTrue: 1 }) });
- const supplierRequestId = String(supplierRequest.result?.ID || '');
- if (!supplierRequestId || supplierRequest.result?.Category !== 'supplier-application') throw new Error('供应商服务申请新增异常');
- created.push(['ServiceRequest', supplierRequestId]);
- const supplierRequests = await cloud(token, 'pub_list', { pubid: 8, cpage: 1, psize: 20 });
- if (supplierRequests.page?.itemCount !== 1 || supplierRequests.result?.[0]?.ID !== supplierRequestId || supplierRequests.result?.[0]?.BankAccount !== 'TEST-ONLY') throw new Error('供应商服务申请列表异常');
- const returnRequest = await cloud(token, 'pub_add', { pubid: 10, model: JSON.stringify({ PubTitle: '冒烟退货', PubContent: '商品异常', PubContentid: 'order-smoke', PubIsTrue: 1 }) });
- const returnRequestId = String(returnRequest.result?.ID || '');
- if (!returnRequestId) throw new Error('售后服务申请新增异常');
- created.push(['ServiceRequest', returnRequestId]);
- const returnRequests = await cloud(token, 'pub_list', { pubid: 10, cid: 'order-smoke', cpage: 1, psize: 20 });
- if (returnRequests.page?.itemCount !== 1 || returnRequests.result?.[0]?.ID !== returnRequestId) throw new Error('售后服务申请按订单筛选异常');
- await cloud(token, 'pub_add', { pubid: 6, model: JSON.stringify({ PubTitle: '无效申请' }) }, 400);
- const productName = `冒烟商品-${Date.now()}`;
- const product = await cloud(token, 'product_add', {
- model: JSON.stringify({ Proname: productName, Nodeid: 7, LinPrice: 12.5, ShiPrice: 20, ProUnit: '件', Stock: 10, Thumbnails: 'https://example.test/product.png', Proinfo: '初始简介', Procontent: '<p>商品正文</p>' }),
- addon: JSON.stringify({ pics: JSON.stringify([{ url: 'https://example.test/product-1.png' }]) }),
- });
- const productId = Number(product.result);
- commerceProductId = productId;
- if (!productId) throw new Error('商品新增未返回规范编号');
- const productRows = await master(`/classes/CommerceProduct?where=${encodeURIComponent(JSON.stringify({ productId }))}&limit=2`);
- if (productRows.results?.length !== 1) throw new Error('商品主记录未写入规范类');
- const productObjectId = productRows.results[0].objectId;
- created.push(['CommerceProduct', productObjectId]);
- const draftProducts = await cloud(token, 'product_list', { uids: legacyUserId, mode: 'unaudit', skey: productName, cpage: 1, psize: 20 });
- if (draftProducts.page?.itemCount !== 1 || Number(draftProducts.result?.[0]?.ID) !== productId) throw new Error('待审核商品列表异常');
- const ownProduct = await cloud(token, 'product_get', { id: productId });
- if (ownProduct.result?.[0]?.Proname !== productName || Number(ownProduct.result?.[0]?.Stock) !== 10) throw new Error('商品详情投影异常');
- await cloud(token, 'product_upd', { id: productId, model: JSON.stringify({ ID: productId, Proinfo: '更新简介' }), addon: JSON.stringify({}) });
- const updatedProduct = await cloud(token, 'product_get', { id: productId });
- if (updatedProduct.result?.[0]?.Proinfo !== '更新简介') throw new Error('商品更新异常');
- await master(`/classes/CommerceProduct/${productObjectId}`, { method: 'PUT', body: JSON.stringify({ status: 'published' }) });
- const publicProducts = await cloud('', 'product_list', { uid: '', skey: productName, cpage: 1, psize: 20 });
- if (publicProducts.page?.itemCount !== 1 || Number(publicProducts.result?.[0]?.ID) !== productId) throw new Error('已发布商品公共列表异常');
- const publicProduct = await cloud('', 'product_get', { uid: '', id: productId });
- if (publicProduct.result?.[0]?.Proname !== productName) throw new Error('已发布商品公共详情异常');
- const stockIn = await cloud(token, 'product_stock_change', { proid: productId, num: 5, remark: '冒烟入库' });
- if (Number(stockIn.result?.Stock) !== 15) throw new Error('商品入库原子更新异常');
- const stockOut = await cloud(token, 'product_stock_change', { proid: productId, num: -2, remark: '冒烟出库' });
- if (Number(stockOut.result?.Stock) !== 13) throw new Error('商品出库原子更新异常');
- await cloud(token, 'product_stock_change', { proid: productId, num: -999, remark: '禁止负库存' }, 409);
- const stockLogs = await cloud(token, 'product_stock_list', { proid: productId, cpage: 1, psize: 20 });
- if (stockLogs.page?.itemCount !== 2 || !stockLogs.result?.some((item) => Number(item.StockNow) === 13)) throw new Error(`库存流水异常:${JSON.stringify(stockLogs)}`);
- for (const row of (await master(`/classes/ProductStockLedger?where=${encodeURIComponent(JSON.stringify({ productId }))}&limit=100`)).results || []) created.push(['ProductStockLedger', row.objectId]);
- await cloud(token, 'cart_add', { proID: productId, proNum: 1 });
- await cloud(token, 'cart_add', { proID: productId, proNum: 2 });
- const cart = await cloud(token, 'cart_list', { ids: '0' });
- if (cart.result?.CartDT?.length !== 1 || Number(cart.result.CartDT[0]?.Pronum) !== 3 || Number(cart.result.TotalMoney) !== 37.5) throw new Error('购物车合并或金额投影异常');
- const cartId = String(cart.result.CartDT[0]?.objectId || '');
- if (!cartId) throw new Error('购物车记录 ID 缺失');
- created.push(['ShoppingCartItem', cartId]);
- const selectedCart = await cloud(token, 'cart_list', { ids: cartId });
- if (selectedCart.result?.CartDT?.length !== 1) throw new Error('购物车按 ID 筛选异常');
- const couponId = 910000000 + Math.floor(Date.now() / 1000) % 80000000;
- const couponDefinition = await master('/classes/CouponDefinition', {
- method: 'POST',
- body: JSON.stringify({
- company,
- couponId,
- name: '冒烟满减券',
- amount: 5,
- minAmount: 20,
- maxAmount: 100,
- status: 'active',
- totalQuantity: 10,
- claimedQuantity: 0,
- sourceKey: `app:coupon-smoke:${couponId}`,
- }),
- }, 201);
- created.push(['CouponDefinition', couponDefinition.objectId]);
- const coupons = await cloud(token, 'coupon_list', { cpage: 1, psize: 100 });
- if (!coupons.result?.some((item) => Number(item.Flow) === couponId)) throw new Error('可领取优惠券列表异常');
- const claimedCoupon = await cloud(token, 'coupon_usrgot_add', { flowid: couponId });
- const userCouponId = String(claimedCoupon.result?.ID || '');
- if (!userCouponId || Number(claimedCoupon.result?.Flow) !== couponId) throw new Error('优惠券领取异常');
- created.push(['UserCoupon', userCouponId]);
- const claimedAgain = await cloud(token, 'coupon_usrgot_add', { flowid: couponId });
- if (String(claimedAgain.result?.ID) !== userCouponId) throw new Error('重复领取优惠券未保持幂等');
- const idleCoupons = await cloud(token, 'coupon_usrgot_list', { fast: 'idle', cpage: 1, psize: 20 });
- if (!idleCoupons.result?.some((item) => String(item.ID) === userCouponId)) throw new Error('用户未使用优惠券列表异常');
- const checkout = await cloud(token, 'payment_cart', {
- cartIds: cartId,
- use_sicon: 1,
- rece: JSON.stringify({ userName: '测试收货人', telNumber: '13800138000', provinceName: '江西省', cityName: '南昌市', countyName: '青山湖区', detailInfo: '测试路 1 号', postalCode: '330000' }),
- fareDT: '[]',
- invoice: '',
- couponid: userCouponId,
- });
- const orderId = Number(checkout.addon?.orderIds);
- if (!orderId || String(checkout.addon?.cartIds) !== cartId) throw new Error('学习豆订单结算响应异常');
- const repeatedCheckout = await cloud(token, 'payment_cart', {
- cartIds: cartId,
- use_sicon: 1,
- rece: JSON.stringify({ detailInfo: '幂等重试' }),
- fareDT: '[]',
- couponid: userCouponId,
- });
- if (Number(repeatedCheckout.addon?.orderIds) !== orderId) throw new Error('订单重复提交未保持幂等');
- await cloud(token, 'payment_success', { orderIds: orderId });
- await cloud(token, 'payment_success', { orderIds: orderId });
- await cloud(token, 'payment_cart_again', { orderId, mode: 1 });
- await cloud(token, 'payment_cart_again', { orderId, mode: 2 }, 501);
- const paidMember = await cloud(token, 'user_get');
- if (Number(paidMember.addon?.SilverCoin) !== 167.5) throw new Error(`学习豆扣减异常:${paidMember.addon?.SilverCoin}`);
- const emptyCartAfterCheckout = await cloud(token, 'cart_list', { ids: '0' });
- if (emptyCartAfterCheckout.result?.CartDT?.length) throw new Error('已结算购物车仍可见');
- const usedCoupons = await cloud(token, 'coupon_usrgot_list', { fast: 'used', cpage: 1, psize: 20 });
- if (!usedCoupons.result?.some((item) => String(item.ID) === userCouponId)) throw new Error('已使用优惠券状态异常');
- const order = await cloud(token, 'order_get', { id: orderId });
- if (Number(order.result?.ID) !== orderId || Number(order.result?.Ordersamount) !== 32.5 || order.addon?.cart?.length !== 1) throw new Error(`订单详情投影异常:${JSON.stringify(order)}`);
- const buyerOrders = await cloud(token, 'order_list', { fast: 'all', cpage: 1, psize: 20 });
- if (!buyerOrders.result?.some((item) => Number(item.ID) === orderId)) throw new Error('买家订单列表异常');
- const sellerOrders = await cloud(token, 'user_shop_order', { fast: 'paid', cpage: 1, psize: 20 });
- if (!sellerOrders.result?.some((item) => Number(item.ID) === orderId)) throw new Error('商户待发货订单列表异常');
- const sales = await cloud(token, 'user_shop_sales', { fast: 'month', cpage: 1, psize: 5 });
- if (!sales.result?.some((item) => Number(item.ID) === productId) || Number(sales.addon) !== 37.5) throw new Error('商户销售汇总异常');
- await cloud(token, 'order_delivery', { id: orderId, expComp: '顺丰快递', expNo: 'SF-TEST-0001', expRemind: '冒烟测试' });
- const shipped = await cloud(token, 'order_get', { id: orderId });
- if (Number(shipped.result?.StateLogistics) !== 1 || shipped.addon?.express?.ExpNo !== 'SF-TEST-0001') throw new Error('订单发货状态异常');
- await cloud(token, 'order_signfor', { id: orderId });
- const signed = await cloud(token, 'order_get', { id: orderId });
- if (Number(signed.result?.Signed) !== 1 || Number(signed.result?.StateLogistics) !== 2) throw new Error('订单签收状态异常');
- await cloud(token, 'order_comment_add', { orderId, proId: productId, score: 5, title: '冒烟好评', content: '订单链路验证通过', images: JSON.stringify([{ url: 'https://example.test/comment.png' }]) });
- await cloud(token, 'order_comment_add', { orderId, proId: productId, score: 5, title: '重复评价' }, 409);
- const publicComments = await cloud('', 'order_comment_list', { uid: '', proId: productId, rate: 'good', hasImgOnly: 1, cpage: 1, psize: 20 });
- if (publicComments.page?.itemCount !== 1 || publicComments.result?.[0]?.Title !== '冒烟好评') throw new Error('商品评价公共列表异常');
- const afterOrderProduct = await cloud(token, 'product_get', { id: productId });
- if (Number(afterOrderProduct.result?.[0]?.Stock) !== 10) throw new Error('订单库存扣减异常');
- for (const className of ['CommerceOrder', 'CommerceOrderItem', 'CommercePayment', 'ProductComment']) {
- const orderRows = await master(`/classes/${className}?where=${encodeURIComponent(JSON.stringify(className === 'ProductComment' ? { productId } : { orderId }))}&limit=100`);
- for (const row of orderRows.results || []) created.push([className, row.objectId]);
- }
- const membershipTargetLegacyId = legacyUserId + 1;
- const membershipTarget = await master('/users', {
- method: 'POST',
- body: JSON.stringify({
- username: `${username}_agent_target`,
- password: randomBytes(24).toString('base64url'),
- company,
- legacyUserId: membershipTargetLegacyId,
- legacyGroupId: 1,
- nickname: '代理库存目标会员',
- legacyUserData: { UserID: membershipTargetLegacyId, GroupID: 1, ParentUserID: legacyUserId, HoneyName: '代理库存目标会员', boffExp: 0 },
- }),
- }, 201);
- membershipTargetUserId = membershipTarget.objectId;
- await master(`/users/${userObjectId}`, {
- method: 'PUT',
- body: JSON.stringify({ legacyGroupId: 4, legacyUserData: { UserID: legacyUserId, GroupID: 4, HoneyName: '会员资料云函数冒烟', SilverCoin: 167.5, boffExp: 5000 } }),
- });
- const upgradeKey = `smoke-upgrade-${Date.now()}`;
- await cloud(token, 'user_group_usr_upgrade', { upusr: membershipTargetLegacyId, gid: 2, idempotencyKey: upgradeKey });
- await cloud(token, 'user_group_usr_upgrade', { upusr: membershipTargetLegacyId, gid: 2, idempotencyKey: upgradeKey });
- const supplyKey = `smoke-supply-${Date.now()}`;
- await cloud(token, 'user_group_usr_supply', { upusr: membershipTargetLegacyId, munber: 250, idempotencyKey: supplyKey });
- const operatorAfterStock = await master(`/users/${userObjectId}`);
- const targetAfterStock = await master(`/users/${membershipTargetUserId}`);
- if (Number(operatorAfterStock.legacyUserData?.boffExp) !== 3750 || Number(targetAfterStock.legacyGroupId) !== 2 || Number(targetAfterStock.legacyUserData?.boffExp) !== 1250) throw new Error('代理招募或库存批发原子余额异常');
- const membershipLedgers = await master(`/classes/MembershipStockLedger?where=${encodeURIComponent(JSON.stringify({ operatorLegacyId: legacyUserId }))}&limit=20`);
- if (membershipLedgers.results?.length !== 2) throw new Error('代理库存流水数量或幂等异常');
- for (const row of membershipLedgers.results || []) created.push(['MembershipStockLedger', row.objectId]);
- await cloud(token, 'product_sale_change', { id: productId, status: 0 });
- await cloud('', 'product_get', { uid: '', id: productId }, 404);
- await cloud(token, 'product_sale_change', { id: productId, status: 1 });
- await cloud(token, 'product_del', { id: productId });
- const emptyCartAfterRecycle = await cloud(token, 'cart_list', { ids: '0' });
- if (emptyCartAfterRecycle.result?.CartDT?.length) throw new Error('已回收商品仍出现在购物车');
- await cloud(token, 'receaddr_del', { id: addressId });
- await cloud(token, 'invoice_del', { id: invoiceId });
- await cloud(token, 'user_bank_del', { id: bankId });
- const emptyAddress = await cloud(token, 'receaddr_list', { cpage: 1, psize: 20 });
- const emptyInvoice = await cloud(token, 'invoice_list', { cpage: 1, psize: 20 });
- const emptyBank = await cloud(token, 'user_bank_list', { cpage: 1, psize: 20 });
- if (emptyAddress.page?.itemCount || emptyInvoice.page?.itemCount || emptyBank.page?.itemCount) throw new Error('软删除后的会员资料仍出现在列表');
- const auditWhere = encodeURIComponent(JSON.stringify({ legacyUserId }));
- const audits = await master(`/classes/AppAuditLog?where=${auditWhere}&count=1&limit=0`);
- if (Number(audits.count) < 30) throw new Error(`会员资料、商城与学习操作审计数量不足:${audits.count || 0}`);
- const direct = await fetch(`${PARSE_URL}/classes/ReceivingAddress?limit=1`, { headers: { 'X-Parse-Application-Id': APP_ID } });
- if (direct.ok) throw new Error('会员敏感资料类未关闭浏览器直接读取权限');
- const directServiceRequest = await fetch(`${PARSE_URL}/classes/ServiceRequest?limit=1`, { headers: { 'X-Parse-Application-Id': APP_ID } });
- if (directServiceRequest.ok) throw new Error('服务申请类未关闭浏览器直接读取权限');
- for (const className of ['CommerceProduct', 'ShoppingCartItem', 'ProductStockLedger', 'ProductComment', 'CommerceOrder', 'CommerceOrderItem', 'CommercePayment', 'CouponDefinition', 'UserCoupon', 'MembershipStockLedger']) {
- const directCommerce = await fetch(`${PARSE_URL}/classes/${className}?limit=1`, { headers: { 'X-Parse-Application-Id': APP_ID } });
- if (directCommerce.ok) throw new Error(`${className} 未关闭浏览器直接读取权限`);
- }
- console.log(JSON.stringify({ passed: true, reviewStats: true, address: true, invoice: true, bank: true, vote: true, unitProgress: true, favorite: true, serviceRequests: true, commerceProducts: true, stockLedger: true, cart: true, coupons: true, orders: true, internalPayment: true, comments: true, sellerSales: true, membershipStock: true, audit: Number(audits.count), directClassAccessDenied: true }, null, 2));
- } finally {
- for (const [className, objectId] of created.reverse()) await hardDelete(className, objectId);
- if (commerceProductId) {
- const productWhere = encodeURIComponent(JSON.stringify({ productId: commerceProductId }));
- for (const className of ['ShoppingCartItem', 'ProductStockLedger', 'ProductComment', 'CommerceOrderItem', 'CommerceProduct']) {
- const rows = await master(`/classes/${className}?where=${productWhere}&limit=1000`).catch(() => ({ results: [] }));
- for (const row of rows.results || []) await hardDelete(className, row.objectId);
- }
- }
- if (legacyUserId) {
- const where = encodeURIComponent(JSON.stringify({ legacyUserId }));
- for (const className of ['CommerceOrder', 'CommercePayment', 'UserCoupon']) {
- const rows = await master(`/classes/${className}?where=${where}&limit=1000`).catch(() => ({ results: [] }));
- for (const row of rows.results || []) await hardDelete(className, row.objectId);
- }
- const logs = await master(`/classes/AppAuditLog?where=${where}&limit=1000`).catch(() => ({ results: [] }));
- for (const row of logs.results || []) await hardDelete('AppAuditLog', row.objectId);
- const membershipWhere = encodeURIComponent(JSON.stringify({ operatorLegacyId: legacyUserId }));
- const membershipRows = await master(`/classes/MembershipStockLedger?where=${membershipWhere}&limit=1000`).catch(() => ({ results: [] }));
- for (const row of membershipRows.results || []) await hardDelete('MembershipStockLedger', row.objectId);
- }
- if (userObjectId) {
- const pointer = { __type: 'Pointer', className: '_User', objectId: userObjectId };
- const where = encodeURIComponent(JSON.stringify({ user: pointer }));
- const sessions = await master(`/sessions?where=${where}&limit=1000`).catch(() => ({ results: [] }));
- for (const row of sessions.results || []) await master(`/sessions/${row.objectId}`, { method: 'DELETE' }).catch(() => undefined);
- await master(`/users/${userObjectId}`, { method: 'DELETE' }).catch(() => undefined);
- }
- if (membershipTargetUserId) await master(`/users/${membershipTargetUserId}`, { method: 'DELETE' }).catch(() => undefined);
- }
|