import { generateNewId, generateNewIdAsync } from 'oak-domain/lib/utils/uuid'; import { getPayClazz } from '../utils/payClazz'; import assert from 'assert'; /** * 当refund完成或失败时,如果关联有提现,去更新提现的状态 * @param context * @param refunds */ async function changeWithdrawStateByRefunds(context, refunds) { const withdraws = await context.select('withdraw', { data: { id: 1, iState: 1, price: 1, refund$entity: { $entity: 'refund', data: { id: 1, price: 1, iState: 1, loss: 1, }, }, }, filter: { id: { $in: refunds.filter(ele => ele.entity === 'withdraw').map(ele => ele.entityId), } } }, {}); let count = 0; for (const withdraw of withdraws) { const { price, iState, refund$entity: relatedRefunds } = withdraw; assert(iState === 'withdrawing'); let dealPrice = 0; let dealLoss = 0; let allRefundsOver = true; for (const refund2 of relatedRefunds) { if (refund2.iState === 'refunding') { allRefundsOver = false; break; } if (refund2.iState === 'refunded') { dealPrice += refund2.price; dealLoss += refund2.loss; } } if (!allRefundsOver) { continue; } const action = dealPrice === 0 ? 'fail' : (dealPrice === price ? 'succeed' : 'succeedPartially'); await context.operate('withdraw', { id: await generateNewIdAsync(), action, data: { dealPrice, dealLoss, }, filter: { id: withdraw.id, } }, {}); count++; } return count; } const triggers = [ { entity: 'refund', action: 'create', when: 'commit', name: '当refund建立时,触发外部退款操作', strict: 'makeSure', fn: async ({ ids }, context) => { const refunds = await context.select('refund', { data: { id: 1, price: 1, loss: 1, pay: { id: 1, price: 1, iState: 1, refunded: 1, channel: 1, applicationId: 1, }, }, filter: { id: { $in: ids, }, }, }, {}); for (const refund of refunds) { const { id, price, pay } = refund; const { price: payPrice, refunded, channel, applicationId } = pay; const payClazz = await getPayClazz(applicationId, channel, context); const data = await payClazz.refund(refund); if (data) { const closeFn = context.openRootMode(); await context.operate('refund', { id: await generateNewIdAsync(), data, action: 'update', filter: { id, } }, { dontCollect: true }); closeFn(); } } }, }, { entity: 'refund', action: 'succeedRefunding', when: 'after', name: '退款成功时,更新对应的pay状态以及对应的withdraw状态', fn: async ({ operation }, context) => { const { filter } = operation; const refunds = await context.select('refund', { data: { id: 1, price: 1, iState: 1, entity: 1, entityId: 1, pay: { id: 1, price: 1, iState: 1, refunded: 1, channel: 1, applicationId: 1, orderId: 1, accountId: 1, }, }, filter, }, {}); for (const refund of refunds) { const { id, price, iState, pay } = refund; assert(iState === 'refunded' && pay.iState === 'refunding'); const { price: payPrice, refunded } = pay; const refunded2 = refunded + price; assert(refunded2 <= payPrice, '退款金额不应高于pay的总金额'); const action = refunded2 === payPrice ? 'refundAll' : 'refundPartially'; await context.operate('pay', { id: await generateNewIdAsync(), action, data: { refunded: refunded2, }, filter: { id: pay.id, } }, {}); } return refunds.length + await changeWithdrawStateByRefunds(context, refunds); } }, { entity: 'refund', action: 'failRefunding', when: 'after', name: '退款失败时,更新对应的pay状态以及对应的withdraw状态', fn: async ({ operation }, context) => { const { filter } = operation; const refunds = await context.select('refund', { data: { id: 1, price: 1, iState: 1, entity: 1, entityId: 1, pay: { id: 1, price: 1, iState: 1, refunded: 1, channel: 1, applicationId: 1, orderId: 1, accountId: 1, }, }, filter, }, {}); for (const refund of refunds) { const { id, iState, pay } = refund; assert(iState === 'failed' && pay.iState === 'refunding'); const { refunded } = pay; const action = refunded === 0 ? 'stopRefunding' : 'refundPartially'; await context.operate('pay', { id: await generateNewIdAsync(), action, data: {}, filter: { id: pay.id, } }, {}); } return refunds.length + await changeWithdrawStateByRefunds(context, refunds); } }, { entity: 'refund', name: '当发起退款时,将对应的pay置退款中状态', action: 'create', when: 'before', fn: async ({ operation }, context) => { const { data } = operation; if (data instanceof Array) { data.forEach((refund) => { assert(!refund.pay && refund.payId); refund.pay = { id: generateNewId(), action: 'startRefunding', data: {}, }; }); } else { data.pay = { id: generateNewId(), action: 'startRefunding', data: {}, }; } return 1; } }, ]; export default triggers;