283 lines
9.8 KiB
JavaScript
283 lines
9.8 KiB
JavaScript
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,
|
||
entity: 1,
|
||
entityId: 1,
|
||
applicationId: 1,
|
||
},
|
||
},
|
||
filter: {
|
||
id: {
|
||
$in: ids,
|
||
},
|
||
},
|
||
}, {});
|
||
for (const refund of refunds) {
|
||
const { id, price, pay } = refund;
|
||
const { price: payPrice, refunded, entity, entityId, applicationId } = pay;
|
||
const payClazz = await getPayClazz(applicationId, entity, entityId, 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',
|
||
asRoot: true,
|
||
name: '退款成功时,更新对应的pay状态以及对应的withdraw状态',
|
||
fn: async ({ operation }, context) => {
|
||
const { filter } = operation;
|
||
const payProj = {
|
||
id: 1,
|
||
price: 1,
|
||
refunded: 1,
|
||
entity: 1,
|
||
entityId: 1,
|
||
iState: 1,
|
||
applicationId: 1,
|
||
application: {
|
||
systemId: 1,
|
||
}
|
||
};
|
||
const refunds = await context.select('refund', {
|
||
data: {
|
||
id: 1,
|
||
price: 1,
|
||
iState: 1,
|
||
entity: 1,
|
||
entityId: 1,
|
||
pay: payProj,
|
||
loss: 1,
|
||
},
|
||
filter,
|
||
}, {});
|
||
for (const refund of refunds) {
|
||
const { price, iState, pay, loss } = refund;
|
||
assert(iState === 'refunded' && pay.iState === 'refunding');
|
||
const { price: payPrice, refunded, entity, entityId, applicationId, application } = 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,
|
||
}
|
||
}, {});
|
||
const payClazz = await getPayClazz(applicationId, entity, entityId, context);
|
||
// 实际执行的退款的额度应该是price - loss
|
||
const [delta, sysAccountEntity, sysAccountEntityId] = payClazz.calcRefundTax(price - loss);
|
||
// sysAccount上减掉实际退款的额度
|
||
await context.operate('sysAccountOper', {
|
||
id: await generateNewIdAsync(),
|
||
action: 'create',
|
||
data: {
|
||
id: await generateNewIdAsync(),
|
||
delta: loss - price,
|
||
entity: sysAccountEntity,
|
||
entityId: sysAccountEntityId,
|
||
refundId: refund.id,
|
||
type: 'refund',
|
||
}
|
||
}, {});
|
||
if (delta !== 0) {
|
||
// 如果有退回或者要缴纳的税费,进入system相关联的account账户
|
||
const [account] = await context.select('account', {
|
||
data: {
|
||
id: 1,
|
||
},
|
||
filter: {
|
||
entity: 'system',
|
||
entityId: application.systemId,
|
||
},
|
||
}, { dontCollect: true });
|
||
await context.operate('accountOper', {
|
||
id: await generateNewIdAsync(),
|
||
action: 'create',
|
||
data: {
|
||
id: await generateNewIdAsync(),
|
||
accountId: account.id,
|
||
type: delta < 0 ? 'taxRefund' : 'tax',
|
||
totalPlus: -delta,
|
||
availPlus: -delta,
|
||
entity: 'refund',
|
||
entityId: refund.id,
|
||
},
|
||
}, {});
|
||
}
|
||
}
|
||
return refunds.length + await changeWithdrawStateByRefunds(context, refunds);
|
||
}
|
||
},
|
||
{
|
||
entity: 'refund',
|
||
action: 'failRefunding',
|
||
when: 'after',
|
||
asRoot: true,
|
||
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,
|
||
applicationId: 1,
|
||
orderId: 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',
|
||
asRoot: true,
|
||
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;
|