From b835f6414a3f66f7e3373fee4e3446b010beec83 Mon Sep 17 00:00:00 2001 From: lxy Date: Thu, 17 Jul 2025 17:04:22 +0800 Subject: [PATCH] =?UTF-8?q?refund=E7=9B=B8=E5=85=B3trigger=E8=B0=83?= =?UTF-8?q?=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/sysAccount/survey/index.ts | 16 +- src/components/withdraw/display/index.ts | 2 +- src/triggers/refund.ts | 235 ++++++++++++---------- 3 files changed, 140 insertions(+), 113 deletions(-) diff --git a/src/components/sysAccount/survey/index.ts b/src/components/sysAccount/survey/index.ts index 557c90e1..764d80ef 100644 --- a/src/components/sysAccount/survey/index.ts +++ b/src/components/sysAccount/survey/index.ts @@ -27,7 +27,7 @@ export default OakComponent({ try { promises.push(...(ref as string[]).map( - (entity) => { + (entity) => { const projection: EntityDict['offlineAccount']['Projection'] = { id: 1, $$createAt$$: 1, @@ -48,7 +48,7 @@ export default OakComponent({ }); } )); - + promises.push((async () => { const result = await this.features.cache.aggregate('account', { data: { @@ -66,7 +66,7 @@ export default OakComponent({ ofSystemId: systemId, } }); - + const { '#count-1': accountNum, '#sum-1': accountTotalSum, '#sum-2': accountAvailSum } = result[0]; this.setState({ accountNum, @@ -152,7 +152,7 @@ export default OakComponent({ transferCnt, transferPriceSum, }); - })()); + })()); promises.push((async () => { const result = await this.features.cache.aggregate('order', { data: { @@ -167,7 +167,7 @@ export default OakComponent({ }, }, filter: { - settled: false, + settled: 0, //todo 部分settle的order是否需要统计在内 price: { $gt: 0, }, @@ -181,12 +181,12 @@ export default OakComponent({ orderRefundedSum, }); })()); - + await Promise.all(promises); this.setState({ refreshing: false }); this.reRender(); } - catch(e: any) { + catch (e: any) { this.setState({ refreshing: false }); throw e; } @@ -201,7 +201,7 @@ export default OakComponent({ const { ref } = schema.sysAccountOper.attributes.entity; let total = 0; const accounts = (ref as string[]).map( - (entity) => { + (entity) => { const projection: EntityDict['offlineAccount']['Projection'] = { id: 1, $$createAt$$: 1, diff --git a/src/components/withdraw/display/index.ts b/src/components/withdraw/display/index.ts index 1afd41cc..cf689389 100644 --- a/src/components/withdraw/display/index.ts +++ b/src/components/withdraw/display/index.ts @@ -31,7 +31,7 @@ export default OakComponent({ } ) || []; const transferData2 = transferData?.map( - (transfer: EntityDict['withdrawTransfer']['Schema']) => { + (transfer: any) => { const { price, loss, iState, meta, withdrawAccountId, withdrawAccount, $$updateAt$$, reason } = transfer; let withdrawChannel = withdrawAccount?.channel; if (!withdrawChannel && withdrawAccountId) { diff --git a/src/triggers/refund.ts b/src/triggers/refund.ts index 75734312..d40e2e70 100644 --- a/src/triggers/refund.ts +++ b/src/triggers/refund.ts @@ -33,18 +33,30 @@ async function startRefunding(context: BRC, data: EntityDict['refund']['CreateOp paid: 1, refunded: 1, settled: 1, - // settlement$order: { - // $entity: 'settlement', - // data: { - // id: 1, - // accountId: 1, - // price: 1, - // iState: 1, - // }, - // filter: { - // iState: 'unsettled', - // } - // } + settlePlanned: 1, + settlePlan$order: { + $entity: 'settlePlan', + data: { + id: 1, + price: 1, + iState: 1, + settlement$plan: { + $entity: 'settlement', + data: { + id: 1, + accountId: 1, + price: 1, + iState: 1, + }, + filter: { + iState: 'unsettled' + } + } + }, + filter: { + iState: 'unsettled' + } + } } }, filter: { @@ -82,12 +94,14 @@ async function startRefunding(context: BRC, data: EntityDict['refund']['CreateOp } else { assert(order); - //订单退款的钱要有明确的来源account - const { accountOper$entity: opers } = data; - assert(opers && opers instanceof Array, '订单退款一定要有相应的account来源'); + if (order.settled === (order.paid - order.refunded)) { - // 已经分账 + // 已全部分账 + // 已全部分账的订单由refund传入的opers决定退款,检查opers的金额总和等于refund的金额 let amount = 0; + // 有明确的来源account + const { accountOper$entity: opers } = data; + assert(opers && opers instanceof Array, '订单退款一定要有相应的account来源'); opers.forEach( ({ action, data }) => { assert(action === 'create'); @@ -98,37 +112,77 @@ async function startRefunding(context: BRC, data: EntityDict['refund']['CreateOp } ); assert(amount === data.price); + + //todo 将order的settled更新 + const newSettled = order.settled - data.price!; + await context.operate('order', { + id: await generateNewIdAsync(), + action: 'update', + data: { + settled: newSettled, + }, + filter: { + id: order.id, + } + }, {}); } - else { - //未完成分账的订单退款,关联的AccountOper的totalPlus总和等于refund的price - //同时更新对应的settlement的price - /** todo - let amount = 0; - const { settlement$order: settlements } = order; - for (const oper of opers) { - const { action, data } = oper; - assert(action === 'create'); - const { type, totalPlus, accountId } = data as EntityDict['accountOper']['CreateOperationData']; - assert(type === 'refund'); - amount += -totalPlus!; - - const settlement = settlements?.find((ele) => ele.accountId === accountId); - assert(!!settlement, '请从订单分账的相关账户中选择订单退款的account来源'); - - const settlementNewPrice = settlement.price + totalPlus!; //可能为负值 - await context.operate('settlement', { - id: await generateNewIdAsync(), - action: 'refund', - data: { - price: settlementNewPrice, - }, - filter: { - id: settlement.id, - } - }, {}); - } - assert(amount === data.price); - */ + else if (order.settled === 0) { + //未分账 + //未分帐的订单需更新相应的settlePlan,检查unsettled的settlePlan的金额是否小于等于订单可分账金额 + const { settlePlan$order: settlePlans, paid, refunded, } = order; + let amount = 0; + settlePlans!.forEach( + (settlePlan) => amount += settlePlan.price + ); + const allowPlanPrice = paid - refunded - data.price! + //todo 改为特定error + assert(amount <= allowPlanPrice); + } else { + //部分分账 + /** + * 部分分账的订单: + * 1. opers的金额 + unsettled的金额 >= 退款金额 + * 2. unsettled的settlePlan的金额是否 < 订单可分账金额 + */ + const { accountOper$entity: opers } = data; + let opersPrice = 0; + if (opers && opers.length > 0) { + opers.forEach( + ({ action, data }) => { + assert(action === 'create'); + const { type, totalPlus, availPlus, refundablePlus } = data as EntityDict['accountOper']['CreateOperationData']; + assert(type === 'refund'); + assert(totalPlus === availPlus); + opersPrice += -totalPlus!; + } + ); + } + const { paid, refunded, settled, settlePlan$order: settlePlans } = order; + const orderUnsettledPrice = paid - refunded - settled; + //todo 改为特定error + assert(opersPrice <= settled); + assert(opersPrice + orderUnsettledPrice >= data.price!); + + let amount = 0; + settlePlans!.forEach( + (settlePlan) => amount += settlePlan.price + ); + const allowPlanPrice = paid - refunded - data.price! - settled; + //todo 改为特定error + assert(amount <= allowPlanPrice); + + //todo 将order的settled更新 + const newSettled = order.settled - opersPrice; + await context.operate('order', { + id: await generateNewIdAsync(), + action: 'update', + data: { + settled: newSettled, + }, + filter: { + id: order.id, + } + }, {}); } } @@ -334,18 +388,6 @@ async function failRefunding(context: BRC, refundId: string) { order: { id: 1, settled: 1, - // settlement$order: { - // $entity: 'settlement', - // data: { - // id: 1, - // accountId: 1, - // price: 1, - // iState: 1, - // }, - // filter: { - // iState: 'unsettled', - // } - // } } }, filter: { @@ -397,56 +439,41 @@ async function failRefunding(context: BRC, refundId: string) { }, }, { dontCollect: true }); - /** todo - if (order.settled) { - // 已经分账 - let amount = 0; - for (const oper of accountOpers) { - const { totalPlus, availPlus, accountId } = oper; - assert(totalPlus! < 0 && totalPlus === availPlus); - await context.operate('accountOper', { + let opersPrice = 0; + for (const oper of accountOpers) { + const { totalPlus, availPlus, accountId } = oper; + assert(totalPlus! < 0 && totalPlus === availPlus); + await context.operate('accountOper', { + id: await generateNewIdAsync(), + action: 'create', + data: { id: await generateNewIdAsync(), - action: 'create', - data: { - id: await generateNewIdAsync(), - totalPlus: -totalPlus!, - availPlus: -availPlus!, - type: 'refundFailure', - entity: 'refund', - entityId: refundId, - accountId, - } - }, {}); - amount += -availPlus!; - } - assert(amount === refund!.price!); + totalPlus: -totalPlus!, + availPlus: -availPlus!, + type: 'refundFailure', + entity: 'refund', + entityId: refundId, + accountId, + } + }, {}); + opersPrice += -availPlus!; } - else { - //未完成分账的订单,需要修改settlement - let amount = 0; - const { settlement$order: settlements } = order; - for (const oper of accountOpers) { - const { totalPlus, availPlus, accountId } = oper; - amount += -totalPlus!; - const settlement = settlements?.find((ele) => ele.accountId === accountId); - assert(!!settlement); - - const settlementNewPrice = settlement.price - totalPlus!; - await context.operate('settlement', { - id: await generateNewIdAsync(), - action: 'refundFailure', - data: { - price: settlementNewPrice, - }, - filter: { - id: settlement.id, - } - }, {}); - } - assert(amount === refund!.price!); + //如果refund有accountOper回退order.settled变化 + if (opersPrice > 0) { + const newSettled = order.settled + opersPrice; + await context.operate('order', { + id: await generateNewIdAsync(), + action: 'update', + data: { + settled: newSettled + }, + filter: { + id: order.id, + } + }, {}); } - */ + return 1 + accountOpers.length; } }