Merge branch 'dev' into release

This commit is contained in:
Xu Chang 2024-07-12 20:15:52 +08:00
commit c06e3352d0
39 changed files with 330 additions and 182 deletions

View File

@ -12,6 +12,7 @@ const checkers = [
data.paid = 0;
data.applicationId = context.getApplicationId();
data.creatorId = context.getCurrentUserId();
data.refundable = false;
if (!data.meta) {
data.meta = {};
}

View File

@ -24,7 +24,7 @@ const checkers = [
checker(operation, context) {
const { data, filter } = operation;
const { externalId } = data;
// 必须有ExternalId除非是account类型的支付
// 当offline退款成功时必须有ExternalId
if (!externalId) {
return pipeline(() => context.select('refund', {
data: {
@ -39,7 +39,7 @@ const checkers = [
}
}, { dontCollect: true }), (refunds) => {
const [refund] = refunds;
if (refund.pay.entity !== 'account') {
if (refund.pay.entity === 'offlineAcount') {
throw new OakAttrNotNullException('refund', ['externalId']);
}
});

View File

@ -55,7 +55,7 @@ export default OakComponent({
}
}
],
formData({ data }) {
formData({ data, features }) {
return {
refunds: data?.map((ele) => {
const { creator, withdrawId, pay, ...rest } = ele;
@ -70,6 +70,7 @@ export default OakComponent({
creatorMobile: creator?.mobile$user?.[0]?.mobile || '-',
};
}),
amIRoot: features.token.isRoot(),
};
}
});

View File

@ -8,4 +8,5 @@ export default function Render(props: WebComponentProps<EntityDict, 'pay', false
isWithdraw: boolean;
payChannel: string;
})[];
amIRoot?: boolean;
}>): React.JSX.Element | null;

View File

@ -6,7 +6,7 @@ import { FilterPanel } from '../../../components/AbstractComponents';
import { ToYuan, ThousandCont } from 'oak-domain/lib/utils/money';
import assert from 'assert';
export default function Render(props) {
const { refunds, oakFullpath, oakExecutable } = props.data;
const { refunds, oakFullpath, oakExecutable, amIRoot } = props.data;
const { t, updateItem, execute, clean, setMessage } = props.methods;
const [upsertId, setUpsertId] = useState('');
const [updateAction, setUpdateAction] = useState('');
@ -100,7 +100,7 @@ export default function Render(props) {
]} onAction={(row, action) => {
const { entity } = row.pay;
assert(entity !== 'account');
if (entity !== 'offlineAccount') {
if (entity !== 'offlineAccount' || !amIRoot) {
setMessage({
type: 'error',
title: t('cantOperateOnline'),

View File

@ -84,6 +84,9 @@ const attrUpdateMatrix = {
},
reason: {
actions: ['fail'],
},
successAt: {
actions: ['succeed'],
}
},
withdraw: {

View File

@ -622,5 +622,18 @@ const triggers = [
}
}
},
/*
{
entity: 'pay',
name: '当选择pay并发现pay的状态是paying时尝试刷新其状态',
action: 'select',
when: 'after',
fn: async ({ result }, context) => {
if (result.length === 1 && result[0].iState === 'paying') {
await refreshPayState(result[0] as EntityDict['pay']['OpSchema'], context);
}
return 0;
}
} as SelectTriggerAfter<EntityDict, 'pay', BRC>, */
];
export default triggers;

View File

@ -115,6 +115,7 @@ async function succeedRefunding(context, refundId) {
action,
data: {
refunded: refunded2,
refundable: refunded2 < paid,
},
filter: {
id: pay.id,

8
es/utils/pay.d.ts vendored
View File

@ -3,6 +3,14 @@ import { EntityDict } from '../oak-app-domain';
import { EntityDict as BaseEntityDict } from 'oak-domain/lib/types/Entity';
import BackendRuntimeContext from '../context/BackendRuntimeContext';
import { IncomingHttpHeaders } from 'http';
import { BRC } from '../types/RuntimeCxt';
export declare const fullPayProjection: EntityDict['pay']['Selection']['data'];
export declare function payNotify<ED extends EntityDict & BaseEntityDict>(context: BackendRuntimeContext<ED>, body: any, payId: string, headers: IncomingHttpHeaders): Promise<void>;
export declare function refundNotify<ED extends EntityDict & BaseEntityDict>(context: BackendRuntimeContext<ED>, body: any, refundId: string, headers: IncomingHttpHeaders): Promise<void>;
/**
* paying状态的pay的真实支付状态
* @param pay
* @param context
* @returns
*/
export declare function refreshPayState(pay: EntityDict['pay']['OpSchema'], context: BRC): Promise<import("oak-domain/lib/types/Entity").OperationResult<EntityDict> | undefined>;

View File

@ -41,7 +41,7 @@ export async function payNotify(context, body, payId, headers) {
filter: {
id: payId,
}
}, {});
}, { blockTrigger: true });
if (!pay) {
console.error('接受到无效的payId', payId);
return;
@ -135,3 +135,67 @@ export async function refundNotify(context, body, refundId, headers) {
}, {});
}
}
/**
* 刷新paying状态的pay的真实支付状态
* @param pay
* @param context
* @returns
*/
export async function refreshPayState(pay, context) {
let pay2 = pay;
if (!pay2.entity || !pay2.entityId || !pay2.timeoutAt || !pay2.price || !pay2.iState) {
const pays = await context.select('pay', {
data: {
id: 1,
entity: 1,
entityId: 1,
price: 1,
iState: 1,
},
filter: {
id: pay.id,
}
}, { blockTrigger: true });
pay2 = pays[0];
}
const { entity, entityId, timeoutAt, price } = pay2;
const clazz = await getPayClazz(entity, entityId, context);
const [iState, updateData] = await clazz.getState(pay);
if (iState !== pay.iState) {
let action = 'close';
switch (iState) {
case 'closed': {
// action = 'close';
break;
}
case 'paid': {
action = 'succeedPaying';
updateData.paid = price;
break;
}
default: {
assert(false);
}
}
return await context.operate('pay', {
id: await generateNewIdAsync(),
action,
data: updateData,
filter: {
id: pay.id,
}
}, {});
}
else if (iState === 'paying' && timeoutAt < Date.now()) {
// 尝试关闭订单
// 理论上用户可能在上一个getState和这个close之间支付完成此时关闭失败下一个Watcher到来时就能处理成功了
return await context.operate('pay', {
id: await generateNewIdAsync(),
action: 'close',
data: updateData,
filter: {
id: pay.id,
}
}, {});
}
}

View File

@ -83,7 +83,7 @@ export default class WechatPay extends WechatPayDebug {
ABNORMAL: 退款异常
*/
const iState = REFUND_STATE_MATRIX[status];
return [iState, success_time ? { successAt: dayJs(success_time).millisecond() } : undefined];
return [iState, success_time ? { successAt: dayJs(success_time).valueOf() } : undefined];
}
analyzeResult(result) {
const { success, data, } = result;
@ -189,10 +189,10 @@ export default class WechatPay extends WechatPayDebug {
const updateData = {
meta: {
getState: omit(result, ['mchid', 'appid', 'out_trade_no']),
}
},
};
if (iState === 'paid') {
updateData.forbidRefundAt = dayJs(success_time).millisecond();
updateData.successAt = dayJs(success_time).valueOf();
}
return [iState, updateData];
}
@ -308,7 +308,7 @@ export default class WechatPay extends WechatPayDebug {
meta: omit(result, ['mchid',]),
};
if (iState === 'paid') {
extra.successAt = success_time;
extra.successAt = dayJs(success_time).valueOf();
}
return {
payId,
@ -361,7 +361,7 @@ export default class WechatPay extends WechatPayDebug {
meta: omit(result, ['mchid',]),
};
if (iState === 'successful') {
extra.successAt = success_time;
extra.successAt = dayJs(success_time).valueOf();
}
return {
refundId,

View File

@ -1,7 +1,4 @@
import { fullPayProjection } from '../utils/pay';
import { getPayClazz } from '../utils/payClazz';
import assert from 'assert';
import { generateNewIdAsync } from 'oak-domain/lib/utils/uuid';
import { fullPayProjection, refreshPayState } from '../utils/pay';
import { mergeOperationResult } from 'oak-domain/lib/utils/operationResult';
const QUERY_PAYING_STATE_GAP = process.env.NODE_ENV === 'production' ? 3600 * 1000 : 60 * 1000;
const watchers = [
@ -24,46 +21,8 @@ const watchers = [
fn: async (context, data) => {
const results = [];
for (const pay of data) {
const { applicationId, entity, entityId, timeoutAt, price } = pay;
const clazz = await getPayClazz(entity, entityId, context);
const [iState, updateData] = await clazz.getState(pay);
if (iState !== pay.iState) {
let action = 'close';
switch (iState) {
case 'closed': {
// action = 'close';
break;
}
case 'paid': {
action = 'succeedPaying';
updateData.paid = price;
break;
}
default: {
assert(false);
}
}
const result = await context.operate('pay', {
id: await generateNewIdAsync(),
action,
data: updateData,
filter: {
id: pay.id,
}
}, {});
results.push(result);
}
else if (iState === 'paying' && timeoutAt < Date.now()) {
// 尝试关闭订单
// 理论上用户可能在上一个getState和这个close之间支付完成此时关闭失败下一个Watcher到来时就能处理成功了
const result = await context.operate('pay', {
id: await generateNewIdAsync(),
action: 'close',
data: updateData,
filter: {
id: pay.id,
}
}, {});
const result = await refreshPayState(pay, context);
if (result) {
results.push(result);
}
}

View File

@ -29,7 +29,8 @@ const watchers = [
entity: 1,
entityId: 1,
applicationId: 1,
}
},
externalId: 1,
},
fn: async (context, data) => {
const results = [];

View File

@ -12,8 +12,8 @@ export declare function getWithdrawCreateData(params: {
creatorId: string;
creator?: import("../oak-app-domain/User/Schema").UpdateOperation | undefined;
} & {
refund$withdraw?: import("oak-domain/lib/types").Operation<string, Omit<import("../oak-app-domain/Refund/Schema").UpdateOperationData, "withdraw" | "withdrawId">, Omit<import("../oak-app-domain/Refund/Schema").Filter, "withdraw" | "withdrawId">> | import("oak-domain/lib/types").Operation<"create", Omit<import("../oak-app-domain/Refund/Schema").CreateOperationData, "withdraw" | "withdrawId">[]> | (import("oak-domain/lib/types").Operation<string, Omit<import("../oak-app-domain/Refund/Schema").UpdateOperationData, "withdraw" | "withdrawId">, Omit<import("../oak-app-domain/Refund/Schema").Filter, "withdraw" | "withdrawId">> | import("oak-domain/lib/types").Operation<"create", Omit<import("../oak-app-domain/Refund/Schema").CreateOperationData, "withdraw" | "withdrawId">>)[] | undefined;
withdrawTransfer$withdraw?: import("oak-domain/lib/types").Operation<string, Omit<import("../oak-app-domain/WithdrawTransfer/Schema").UpdateOperationData, "withdraw" | "withdrawId">, Omit<import("../oak-app-domain/WithdrawTransfer/Schema").Filter, "withdraw" | "withdrawId">> | import("oak-domain/lib/types").Operation<"create", Omit<import("../oak-app-domain/WithdrawTransfer/Schema").CreateOperationData, "withdraw" | "withdrawId">[]> | (import("oak-domain/lib/types").Operation<string, Omit<import("../oak-app-domain/WithdrawTransfer/Schema").UpdateOperationData, "withdraw" | "withdrawId">, Omit<import("../oak-app-domain/WithdrawTransfer/Schema").Filter, "withdraw" | "withdrawId">> | import("oak-domain/lib/types").Operation<"create", Omit<import("../oak-app-domain/WithdrawTransfer/Schema").CreateOperationData, "withdraw" | "withdrawId">>)[] | undefined;
refund$withdraw?: import("oak-domain/lib/types").Operation<string, Omit<import("../oak-app-domain/Refund/Schema").UpdateOperationData, "withdrawId" | "withdraw">, Omit<import("../oak-app-domain/Refund/Schema").Filter, "withdrawId" | "withdraw">> | import("oak-domain/lib/types").Operation<"create", Omit<import("../oak-app-domain/Refund/Schema").CreateOperationData, "withdrawId" | "withdraw">[]> | (import("oak-domain/lib/types").Operation<string, Omit<import("../oak-app-domain/Refund/Schema").UpdateOperationData, "withdrawId" | "withdraw">, Omit<import("../oak-app-domain/Refund/Schema").Filter, "withdrawId" | "withdraw">> | import("oak-domain/lib/types").Operation<"create", Omit<import("../oak-app-domain/Refund/Schema").CreateOperationData, "withdrawId" | "withdraw">>)[] | undefined;
withdrawTransfer$withdraw?: import("oak-domain/lib/types").Operation<string, Omit<import("../oak-app-domain/WithdrawTransfer/Schema").UpdateOperationData, "withdrawId" | "withdraw">, Omit<import("../oak-app-domain/WithdrawTransfer/Schema").Filter, "withdrawId" | "withdraw">> | import("oak-domain/lib/types").Operation<"create", Omit<import("../oak-app-domain/WithdrawTransfer/Schema").CreateOperationData, "withdrawId" | "withdraw">[]> | (import("oak-domain/lib/types").Operation<string, Omit<import("../oak-app-domain/WithdrawTransfer/Schema").UpdateOperationData, "withdrawId" | "withdraw">, Omit<import("../oak-app-domain/WithdrawTransfer/Schema").Filter, "withdrawId" | "withdraw">> | import("oak-domain/lib/types").Operation<"create", Omit<import("../oak-app-domain/WithdrawTransfer/Schema").CreateOperationData, "withdrawId" | "withdraw">>)[] | undefined;
modiEntity$entity?: import("oak-domain/lib/types").Operation<"create", Omit<import("../oak-app-domain/ModiEntity/Schema").CreateOperationData, "entity" | "entityId">[]> | import("oak-domain/lib/types").Operation<"create", Omit<import("../oak-app-domain/ModiEntity/Schema").CreateOperationData, "entity" | "entityId">>[] | undefined;
operEntity$entity?: import("oak-domain/lib/types").Operation<"create", Omit<import("../oak-app-domain/OperEntity/Schema").CreateOperationData, "entity" | "entityId">[]> | import("oak-domain/lib/types").Operation<"create", Omit<import("../oak-app-domain/OperEntity/Schema").CreateOperationData, "entity" | "entityId">>[] | undefined;
accountOper$entity?: import("oak-domain/lib/types").Operation<"create", Omit<import("../oak-app-domain/AccountOper/Schema").CreateOperationData, "entity" | "entityId">[]> | import("oak-domain/lib/types").Operation<"create", Omit<import("../oak-app-domain/AccountOper/Schema").CreateOperationData, "entity" | "entityId">>[] | undefined;
@ -26,8 +26,8 @@ export declare function getWithdrawCreateData(params: {
creator?: undefined;
creatorId: string;
} & {
refund$withdraw?: import("oak-domain/lib/types").Operation<string, Omit<import("../oak-app-domain/Refund/Schema").UpdateOperationData, "withdraw" | "withdrawId">, Omit<import("../oak-app-domain/Refund/Schema").Filter, "withdraw" | "withdrawId">> | import("oak-domain/lib/types").Operation<"create", Omit<import("../oak-app-domain/Refund/Schema").CreateOperationData, "withdraw" | "withdrawId">[]> | (import("oak-domain/lib/types").Operation<string, Omit<import("../oak-app-domain/Refund/Schema").UpdateOperationData, "withdraw" | "withdrawId">, Omit<import("../oak-app-domain/Refund/Schema").Filter, "withdraw" | "withdrawId">> | import("oak-domain/lib/types").Operation<"create", Omit<import("../oak-app-domain/Refund/Schema").CreateOperationData, "withdraw" | "withdrawId">>)[] | undefined;
withdrawTransfer$withdraw?: import("oak-domain/lib/types").Operation<string, Omit<import("../oak-app-domain/WithdrawTransfer/Schema").UpdateOperationData, "withdraw" | "withdrawId">, Omit<import("../oak-app-domain/WithdrawTransfer/Schema").Filter, "withdraw" | "withdrawId">> | import("oak-domain/lib/types").Operation<"create", Omit<import("../oak-app-domain/WithdrawTransfer/Schema").CreateOperationData, "withdraw" | "withdrawId">[]> | (import("oak-domain/lib/types").Operation<string, Omit<import("../oak-app-domain/WithdrawTransfer/Schema").UpdateOperationData, "withdraw" | "withdrawId">, Omit<import("../oak-app-domain/WithdrawTransfer/Schema").Filter, "withdraw" | "withdrawId">> | import("oak-domain/lib/types").Operation<"create", Omit<import("../oak-app-domain/WithdrawTransfer/Schema").CreateOperationData, "withdraw" | "withdrawId">>)[] | undefined;
refund$withdraw?: import("oak-domain/lib/types").Operation<string, Omit<import("../oak-app-domain/Refund/Schema").UpdateOperationData, "withdrawId" | "withdraw">, Omit<import("../oak-app-domain/Refund/Schema").Filter, "withdrawId" | "withdraw">> | import("oak-domain/lib/types").Operation<"create", Omit<import("../oak-app-domain/Refund/Schema").CreateOperationData, "withdrawId" | "withdraw">[]> | (import("oak-domain/lib/types").Operation<string, Omit<import("../oak-app-domain/Refund/Schema").UpdateOperationData, "withdrawId" | "withdraw">, Omit<import("../oak-app-domain/Refund/Schema").Filter, "withdrawId" | "withdraw">> | import("oak-domain/lib/types").Operation<"create", Omit<import("../oak-app-domain/Refund/Schema").CreateOperationData, "withdrawId" | "withdraw">>)[] | undefined;
withdrawTransfer$withdraw?: import("oak-domain/lib/types").Operation<string, Omit<import("../oak-app-domain/WithdrawTransfer/Schema").UpdateOperationData, "withdrawId" | "withdraw">, Omit<import("../oak-app-domain/WithdrawTransfer/Schema").Filter, "withdrawId" | "withdraw">> | import("oak-domain/lib/types").Operation<"create", Omit<import("../oak-app-domain/WithdrawTransfer/Schema").CreateOperationData, "withdrawId" | "withdraw">[]> | (import("oak-domain/lib/types").Operation<string, Omit<import("../oak-app-domain/WithdrawTransfer/Schema").UpdateOperationData, "withdrawId" | "withdraw">, Omit<import("../oak-app-domain/WithdrawTransfer/Schema").Filter, "withdrawId" | "withdraw">> | import("oak-domain/lib/types").Operation<"create", Omit<import("../oak-app-domain/WithdrawTransfer/Schema").CreateOperationData, "withdrawId" | "withdraw">>)[] | undefined;
modiEntity$entity?: import("oak-domain/lib/types").Operation<"create", Omit<import("../oak-app-domain/ModiEntity/Schema").CreateOperationData, "entity" | "entityId">[]> | import("oak-domain/lib/types").Operation<"create", Omit<import("../oak-app-domain/ModiEntity/Schema").CreateOperationData, "entity" | "entityId">>[] | undefined;
operEntity$entity?: import("oak-domain/lib/types").Operation<"create", Omit<import("../oak-app-domain/OperEntity/Schema").CreateOperationData, "entity" | "entityId">[]> | import("oak-domain/lib/types").Operation<"create", Omit<import("../oak-app-domain/OperEntity/Schema").CreateOperationData, "entity" | "entityId">>[] | undefined;
accountOper$entity?: import("oak-domain/lib/types").Operation<"create", Omit<import("../oak-app-domain/AccountOper/Schema").CreateOperationData, "entity" | "entityId">[]> | import("oak-domain/lib/types").Operation<"create", Omit<import("../oak-app-domain/AccountOper/Schema").CreateOperationData, "entity" | "entityId">>[] | undefined;
@ -40,8 +40,8 @@ export declare function getWithdrawCreateData(params: {
creatorId: string;
creator?: import("../oak-app-domain/User/Schema").UpdateOperation | undefined;
} & {
refund$withdraw?: import("oak-domain/lib/types").Operation<string, Omit<import("../oak-app-domain/Refund/Schema").UpdateOperationData, "withdraw" | "withdrawId">, Omit<import("../oak-app-domain/Refund/Schema").Filter, "withdraw" | "withdrawId">> | import("oak-domain/lib/types").Operation<"create", Omit<import("../oak-app-domain/Refund/Schema").CreateOperationData, "withdraw" | "withdrawId">[]> | (import("oak-domain/lib/types").Operation<string, Omit<import("../oak-app-domain/Refund/Schema").UpdateOperationData, "withdraw" | "withdrawId">, Omit<import("../oak-app-domain/Refund/Schema").Filter, "withdraw" | "withdrawId">> | import("oak-domain/lib/types").Operation<"create", Omit<import("../oak-app-domain/Refund/Schema").CreateOperationData, "withdraw" | "withdrawId">>)[] | undefined;
withdrawTransfer$withdraw?: import("oak-domain/lib/types").Operation<string, Omit<import("../oak-app-domain/WithdrawTransfer/Schema").UpdateOperationData, "withdraw" | "withdrawId">, Omit<import("../oak-app-domain/WithdrawTransfer/Schema").Filter, "withdraw" | "withdrawId">> | import("oak-domain/lib/types").Operation<"create", Omit<import("../oak-app-domain/WithdrawTransfer/Schema").CreateOperationData, "withdraw" | "withdrawId">[]> | (import("oak-domain/lib/types").Operation<string, Omit<import("../oak-app-domain/WithdrawTransfer/Schema").UpdateOperationData, "withdraw" | "withdrawId">, Omit<import("../oak-app-domain/WithdrawTransfer/Schema").Filter, "withdraw" | "withdrawId">> | import("oak-domain/lib/types").Operation<"create", Omit<import("../oak-app-domain/WithdrawTransfer/Schema").CreateOperationData, "withdraw" | "withdrawId">>)[] | undefined;
refund$withdraw?: import("oak-domain/lib/types").Operation<string, Omit<import("../oak-app-domain/Refund/Schema").UpdateOperationData, "withdrawId" | "withdraw">, Omit<import("../oak-app-domain/Refund/Schema").Filter, "withdrawId" | "withdraw">> | import("oak-domain/lib/types").Operation<"create", Omit<import("../oak-app-domain/Refund/Schema").CreateOperationData, "withdrawId" | "withdraw">[]> | (import("oak-domain/lib/types").Operation<string, Omit<import("../oak-app-domain/Refund/Schema").UpdateOperationData, "withdrawId" | "withdraw">, Omit<import("../oak-app-domain/Refund/Schema").Filter, "withdrawId" | "withdraw">> | import("oak-domain/lib/types").Operation<"create", Omit<import("../oak-app-domain/Refund/Schema").CreateOperationData, "withdrawId" | "withdraw">>)[] | undefined;
withdrawTransfer$withdraw?: import("oak-domain/lib/types").Operation<string, Omit<import("../oak-app-domain/WithdrawTransfer/Schema").UpdateOperationData, "withdrawId" | "withdraw">, Omit<import("../oak-app-domain/WithdrawTransfer/Schema").Filter, "withdrawId" | "withdraw">> | import("oak-domain/lib/types").Operation<"create", Omit<import("../oak-app-domain/WithdrawTransfer/Schema").CreateOperationData, "withdrawId" | "withdraw">[]> | (import("oak-domain/lib/types").Operation<string, Omit<import("../oak-app-domain/WithdrawTransfer/Schema").UpdateOperationData, "withdrawId" | "withdraw">, Omit<import("../oak-app-domain/WithdrawTransfer/Schema").Filter, "withdrawId" | "withdraw">> | import("oak-domain/lib/types").Operation<"create", Omit<import("../oak-app-domain/WithdrawTransfer/Schema").CreateOperationData, "withdrawId" | "withdraw">>)[] | undefined;
modiEntity$entity?: import("oak-domain/lib/types").Operation<"create", Omit<import("../oak-app-domain/ModiEntity/Schema").CreateOperationData, "entity" | "entityId">[]> | import("oak-domain/lib/types").Operation<"create", Omit<import("../oak-app-domain/ModiEntity/Schema").CreateOperationData, "entity" | "entityId">>[] | undefined;
operEntity$entity?: import("oak-domain/lib/types").Operation<"create", Omit<import("../oak-app-domain/OperEntity/Schema").CreateOperationData, "entity" | "entityId">[]> | import("oak-domain/lib/types").Operation<"create", Omit<import("../oak-app-domain/OperEntity/Schema").CreateOperationData, "entity" | "entityId">>[] | undefined;
accountOper$entity?: import("oak-domain/lib/types").Operation<"create", Omit<import("../oak-app-domain/AccountOper/Schema").CreateOperationData, "entity" | "entityId">[]> | import("oak-domain/lib/types").Operation<"create", Omit<import("../oak-app-domain/AccountOper/Schema").CreateOperationData, "entity" | "entityId">>[] | undefined;
@ -54,8 +54,8 @@ export declare function getWithdrawCreateData(params: {
creator?: undefined;
creatorId: string;
} & {
refund$withdraw?: import("oak-domain/lib/types").Operation<string, Omit<import("../oak-app-domain/Refund/Schema").UpdateOperationData, "withdraw" | "withdrawId">, Omit<import("../oak-app-domain/Refund/Schema").Filter, "withdraw" | "withdrawId">> | import("oak-domain/lib/types").Operation<"create", Omit<import("../oak-app-domain/Refund/Schema").CreateOperationData, "withdraw" | "withdrawId">[]> | (import("oak-domain/lib/types").Operation<string, Omit<import("../oak-app-domain/Refund/Schema").UpdateOperationData, "withdraw" | "withdrawId">, Omit<import("../oak-app-domain/Refund/Schema").Filter, "withdraw" | "withdrawId">> | import("oak-domain/lib/types").Operation<"create", Omit<import("../oak-app-domain/Refund/Schema").CreateOperationData, "withdraw" | "withdrawId">>)[] | undefined;
withdrawTransfer$withdraw?: import("oak-domain/lib/types").Operation<string, Omit<import("../oak-app-domain/WithdrawTransfer/Schema").UpdateOperationData, "withdraw" | "withdrawId">, Omit<import("../oak-app-domain/WithdrawTransfer/Schema").Filter, "withdraw" | "withdrawId">> | import("oak-domain/lib/types").Operation<"create", Omit<import("../oak-app-domain/WithdrawTransfer/Schema").CreateOperationData, "withdraw" | "withdrawId">[]> | (import("oak-domain/lib/types").Operation<string, Omit<import("../oak-app-domain/WithdrawTransfer/Schema").UpdateOperationData, "withdraw" | "withdrawId">, Omit<import("../oak-app-domain/WithdrawTransfer/Schema").Filter, "withdraw" | "withdrawId">> | import("oak-domain/lib/types").Operation<"create", Omit<import("../oak-app-domain/WithdrawTransfer/Schema").CreateOperationData, "withdraw" | "withdrawId">>)[] | undefined;
refund$withdraw?: import("oak-domain/lib/types").Operation<string, Omit<import("../oak-app-domain/Refund/Schema").UpdateOperationData, "withdrawId" | "withdraw">, Omit<import("../oak-app-domain/Refund/Schema").Filter, "withdrawId" | "withdraw">> | import("oak-domain/lib/types").Operation<"create", Omit<import("../oak-app-domain/Refund/Schema").CreateOperationData, "withdrawId" | "withdraw">[]> | (import("oak-domain/lib/types").Operation<string, Omit<import("../oak-app-domain/Refund/Schema").UpdateOperationData, "withdrawId" | "withdraw">, Omit<import("../oak-app-domain/Refund/Schema").Filter, "withdrawId" | "withdraw">> | import("oak-domain/lib/types").Operation<"create", Omit<import("../oak-app-domain/Refund/Schema").CreateOperationData, "withdrawId" | "withdraw">>)[] | undefined;
withdrawTransfer$withdraw?: import("oak-domain/lib/types").Operation<string, Omit<import("../oak-app-domain/WithdrawTransfer/Schema").UpdateOperationData, "withdrawId" | "withdraw">, Omit<import("../oak-app-domain/WithdrawTransfer/Schema").Filter, "withdrawId" | "withdraw">> | import("oak-domain/lib/types").Operation<"create", Omit<import("../oak-app-domain/WithdrawTransfer/Schema").CreateOperationData, "withdrawId" | "withdraw">[]> | (import("oak-domain/lib/types").Operation<string, Omit<import("../oak-app-domain/WithdrawTransfer/Schema").UpdateOperationData, "withdrawId" | "withdraw">, Omit<import("../oak-app-domain/WithdrawTransfer/Schema").Filter, "withdrawId" | "withdraw">> | import("oak-domain/lib/types").Operation<"create", Omit<import("../oak-app-domain/WithdrawTransfer/Schema").CreateOperationData, "withdrawId" | "withdraw">>)[] | undefined;
modiEntity$entity?: import("oak-domain/lib/types").Operation<"create", Omit<import("../oak-app-domain/ModiEntity/Schema").CreateOperationData, "entity" | "entityId">[]> | import("oak-domain/lib/types").Operation<"create", Omit<import("../oak-app-domain/ModiEntity/Schema").CreateOperationData, "entity" | "entityId">>[] | undefined;
operEntity$entity?: import("oak-domain/lib/types").Operation<"create", Omit<import("../oak-app-domain/OperEntity/Schema").CreateOperationData, "entity" | "entityId">[]> | import("oak-domain/lib/types").Operation<"create", Omit<import("../oak-app-domain/OperEntity/Schema").CreateOperationData, "entity" | "entityId">>[] | undefined;
accountOper$entity?: import("oak-domain/lib/types").Operation<"create", Omit<import("../oak-app-domain/AccountOper/Schema").CreateOperationData, "entity" | "entityId">[]> | import("oak-domain/lib/types").Operation<"create", Omit<import("../oak-app-domain/AccountOper/Schema").CreateOperationData, "entity" | "entityId">>[] | undefined;

View File

@ -15,6 +15,7 @@ const checkers = [
data.paid = 0;
data.applicationId = context.getApplicationId();
data.creatorId = context.getCurrentUserId();
data.refundable = false;
if (!data.meta) {
data.meta = {};
}

View File

@ -26,7 +26,7 @@ const checkers = [
checker(operation, context) {
const { data, filter } = operation;
const { externalId } = data;
// 必须有ExternalId除非是account类型的支付
// 当offline退款成功时必须有ExternalId
if (!externalId) {
return (0, executor_1.pipeline)(() => context.select('refund', {
data: {
@ -41,7 +41,7 @@ const checkers = [
}
}, { dontCollect: true }), (refunds) => {
const [refund] = refunds;
if (refund.pay.entity !== 'account') {
if (refund.pay.entity === 'offlineAcount') {
throw new types_1.OakAttrNotNullException('refund', ['externalId']);
}
});

View File

@ -86,6 +86,9 @@ const attrUpdateMatrix = {
},
reason: {
actions: ['fail'],
},
successAt: {
actions: ['succeed'],
}
},
withdraw: {

View File

@ -15,7 +15,7 @@ export declare class BackendRuntimeContext<ED extends EntityDict & BaseEntityDic
type?: number | undefined;
systemId?: number | undefined;
system?: import("../oak-app-domain/System/Schema").Projection | undefined;
config?: number | import("oak-domain/lib/types").JsonProjection<import("../oak-app-domain/Application/Schema").WechatMpConfig | import("../oak-app-domain/Application/Schema").WebConfig | import("../oak-app-domain/Application/Schema").WechatPublicConfig | import("../oak-app-domain/Application/Schema").NativeConfig> | undefined;
config?: number | import("oak-domain/lib/types").JsonProjection<import("../oak-app-domain/Application/Schema").WebConfig | import("../oak-app-domain/Application/Schema").WechatMpConfig | import("../oak-app-domain/Application/Schema").WechatPublicConfig | import("../oak-app-domain/Application/Schema").NativeConfig> | undefined;
style?: number | import("oak-domain/lib/types").JsonProjection<import("oak-general-business/lib/types/Style").Style> | undefined;
domainId?: number | undefined;
domain?: import("../oak-app-domain/Domain/Schema").Projection | undefined;

View File

@ -625,5 +625,18 @@ const triggers = [
}
}
},
/*
{
entity: 'pay',
name: '当选择pay并发现pay的状态是paying时尝试刷新其状态',
action: 'select',
when: 'after',
fn: async ({ result }, context) => {
if (result.length === 1 && result[0].iState === 'paying') {
await refreshPayState(result[0] as EntityDict['pay']['OpSchema'], context);
}
return 0;
}
} as SelectTriggerAfter<EntityDict, 'pay', BRC>, */
];
exports.default = triggers;

View File

@ -118,6 +118,7 @@ async function succeedRefunding(context, refundId) {
action,
data: {
refunded: refunded2,
refundable: refunded2 < paid,
},
filter: {
id: pay.id,

View File

@ -14,7 +14,7 @@ export declare const mergedProjection: {
type?: number | undefined;
systemId?: number | undefined;
system?: import("../oak-app-domain/System/Schema").Projection | undefined;
config?: number | import("oak-domain/lib/types").JsonProjection<import("../oak-app-domain/Application/Schema").WechatMpConfig | import("../oak-app-domain/Application/Schema").WebConfig | import("../oak-app-domain/Application/Schema").WechatPublicConfig | import("../oak-app-domain/Application/Schema").NativeConfig> | undefined;
config?: number | import("oak-domain/lib/types").JsonProjection<import("../oak-app-domain/Application/Schema").WebConfig | import("../oak-app-domain/Application/Schema").WechatMpConfig | import("../oak-app-domain/Application/Schema").WechatPublicConfig | import("../oak-app-domain/Application/Schema").NativeConfig> | undefined;
style?: number | import("oak-domain/lib/types").JsonProjection<import("oak-general-business/lib/types/Style").Style> | undefined;
domainId?: number | undefined;
domain?: import("../oak-app-domain/Domain/Schema").Projection | undefined;

8
lib/utils/pay.d.ts vendored
View File

@ -3,6 +3,14 @@ import { EntityDict } from '../oak-app-domain';
import { EntityDict as BaseEntityDict } from 'oak-domain/lib/types/Entity';
import BackendRuntimeContext from '../context/BackendRuntimeContext';
import { IncomingHttpHeaders } from 'http';
import { BRC } from '../types/RuntimeCxt';
export declare const fullPayProjection: EntityDict['pay']['Selection']['data'];
export declare function payNotify<ED extends EntityDict & BaseEntityDict>(context: BackendRuntimeContext<ED>, body: any, payId: string, headers: IncomingHttpHeaders): Promise<void>;
export declare function refundNotify<ED extends EntityDict & BaseEntityDict>(context: BackendRuntimeContext<ED>, body: any, refundId: string, headers: IncomingHttpHeaders): Promise<void>;
/**
* paying状态的pay的真实支付状态
* @param pay
* @param context
* @returns
*/
export declare function refreshPayState(pay: EntityDict['pay']['OpSchema'], context: BRC): Promise<import("oak-domain/lib/types/Entity").OperationResult<EntityDict> | undefined>;

View File

@ -1,6 +1,6 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.refundNotify = exports.payNotify = exports.fullPayProjection = void 0;
exports.refreshPayState = exports.refundNotify = exports.payNotify = exports.fullPayProjection = void 0;
const tslib_1 = require("tslib");
const payClazz_1 = require("./payClazz");
const assert_1 = tslib_1.__importDefault(require("assert"));
@ -45,7 +45,7 @@ async function payNotify(context, body, payId, headers) {
filter: {
id: payId,
}
}, {});
}, { blockTrigger: true });
if (!pay) {
console.error('接受到无效的payId', payId);
return;
@ -141,3 +141,68 @@ async function refundNotify(context, body, refundId, headers) {
}
}
exports.refundNotify = refundNotify;
/**
* 刷新paying状态的pay的真实支付状态
* @param pay
* @param context
* @returns
*/
async function refreshPayState(pay, context) {
let pay2 = pay;
if (!pay2.entity || !pay2.entityId || !pay2.timeoutAt || !pay2.price || !pay2.iState) {
const pays = await context.select('pay', {
data: {
id: 1,
entity: 1,
entityId: 1,
price: 1,
iState: 1,
},
filter: {
id: pay.id,
}
}, { blockTrigger: true });
pay2 = pays[0];
}
const { entity, entityId, timeoutAt, price } = pay2;
const clazz = await (0, payClazz_1.getPayClazz)(entity, entityId, context);
const [iState, updateData] = await clazz.getState(pay);
if (iState !== pay.iState) {
let action = 'close';
switch (iState) {
case 'closed': {
// action = 'close';
break;
}
case 'paid': {
action = 'succeedPaying';
updateData.paid = price;
break;
}
default: {
(0, assert_1.default)(false);
}
}
return await context.operate('pay', {
id: await (0, uuid_1.generateNewIdAsync)(),
action,
data: updateData,
filter: {
id: pay.id,
}
}, {});
}
else if (iState === 'paying' && timeoutAt < Date.now()) {
// 尝试关闭订单
// 理论上用户可能在上一个getState和这个close之间支付完成此时关闭失败下一个Watcher到来时就能处理成功了
return await context.operate('pay', {
id: await (0, uuid_1.generateNewIdAsync)(),
action: 'close',
data: updateData,
filter: {
id: pay.id,
}
}, {});
}
}
exports.refreshPayState = refreshPayState;

View File

@ -86,7 +86,7 @@ class WechatPay extends WechatPay_debug_1.default {
ABNORMAL: 退款异常
*/
const iState = REFUND_STATE_MATRIX[status];
return [iState, success_time ? { successAt: (0, dayjs_1.default)(success_time).millisecond() } : undefined];
return [iState, success_time ? { successAt: (0, dayjs_1.default)(success_time).valueOf() } : undefined];
}
analyzeResult(result) {
const { success, data, } = result;
@ -192,10 +192,10 @@ class WechatPay extends WechatPay_debug_1.default {
const updateData = {
meta: {
getState: (0, lodash_1.omit)(result, ['mchid', 'appid', 'out_trade_no']),
}
},
};
if (iState === 'paid') {
updateData.forbidRefundAt = (0, dayjs_1.default)(success_time).millisecond();
updateData.successAt = (0, dayjs_1.default)(success_time).valueOf();
}
return [iState, updateData];
}
@ -311,7 +311,7 @@ class WechatPay extends WechatPay_debug_1.default {
meta: (0, lodash_1.omit)(result, ['mchid',]),
};
if (iState === 'paid') {
extra.successAt = success_time;
extra.successAt = (0, dayjs_1.default)(success_time).valueOf();
}
return {
payId,
@ -364,7 +364,7 @@ class WechatPay extends WechatPay_debug_1.default {
meta: (0, lodash_1.omit)(result, ['mchid',]),
};
if (iState === 'successful') {
extra.successAt = success_time;
extra.successAt = (0, dayjs_1.default)(success_time).valueOf();
}
return {
refundId,

View File

@ -1,4 +1,4 @@
import WechatPay from './WechatPay';
import WechatPayDebug from './WechatPay.debug';
declare const _default: typeof WechatPayDebug | typeof WechatPay;
declare const _default: typeof WechatPay | typeof WechatPayDebug;
export default _default;

View File

@ -1,10 +1,6 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const pay_1 = require("../utils/pay");
const payClazz_1 = require("../utils/payClazz");
const assert_1 = tslib_1.__importDefault(require("assert"));
const uuid_1 = require("oak-domain/lib/utils/uuid");
const operationResult_1 = require("oak-domain/lib/utils/operationResult");
const QUERY_PAYING_STATE_GAP = process.env.NODE_ENV === 'production' ? 3600 * 1000 : 60 * 1000;
const watchers = [
@ -27,46 +23,8 @@ const watchers = [
fn: async (context, data) => {
const results = [];
for (const pay of data) {
const { applicationId, entity, entityId, timeoutAt, price } = pay;
const clazz = await (0, payClazz_1.getPayClazz)(entity, entityId, context);
const [iState, updateData] = await clazz.getState(pay);
if (iState !== pay.iState) {
let action = 'close';
switch (iState) {
case 'closed': {
// action = 'close';
break;
}
case 'paid': {
action = 'succeedPaying';
updateData.paid = price;
break;
}
default: {
(0, assert_1.default)(false);
}
}
const result = await context.operate('pay', {
id: await (0, uuid_1.generateNewIdAsync)(),
action,
data: updateData,
filter: {
id: pay.id,
}
}, {});
results.push(result);
}
else if (iState === 'paying' && timeoutAt < Date.now()) {
// 尝试关闭订单
// 理论上用户可能在上一个getState和这个close之间支付完成此时关闭失败下一个Watcher到来时就能处理成功了
const result = await context.operate('pay', {
id: await (0, uuid_1.generateNewIdAsync)(),
action: 'close',
data: updateData,
filter: {
id: pay.id,
}
}, {});
const result = await (0, pay_1.refreshPayState)(pay, context);
if (result) {
results.push(result);
}
}

View File

@ -32,7 +32,8 @@ const watchers = [
entity: 1,
entityId: 1,
applicationId: 1,
}
},
externalId: 1,
},
fn: async (context, data) => {
const results = [];

View File

@ -1,6 +1,6 @@
{
"name": "oak-pay-business",
"version": "2.2.7",
"version": "2.2.8",
"description": "",
"files": [
"lib/**/*",
@ -30,7 +30,7 @@
"classnames": "^2.3.1",
"dayjs": "^1.11.5",
"oak-domain": "~5.0.15",
"oak-frontend-base": "5.2.10",
"oak-frontend-base": "~5.2.10",
"oak-general-business": "~5.2.5",
"wechat-pay-nodejs": "^0.2.3"
},

View File

@ -19,6 +19,7 @@ const checkers: Checker<EntityDict, 'pay', RuntimeCxt>[] = [
data.paid = 0;
data.applicationId = context.getApplicationId()!;
data.creatorId = context.getCurrentUserId()!;
data.refundable = false;
if (!data.meta) {
data.meta = {};
}

View File

@ -31,7 +31,7 @@ const checkers: Checker<EntityDict, 'refund', RuntimeCxt>[] = [
const { data, filter } = operation as EntityDict['refund']['Update'];
const { externalId } = data;
// 必须有ExternalId除非是account类型的支付
// 当offline退款成功时必须有ExternalId
if (!externalId) {
return pipeline(
() => context.select('refund', {
@ -48,7 +48,7 @@ const checkers: Checker<EntityDict, 'refund', RuntimeCxt>[] = [
}, { dontCollect: true }),
(refunds: EntityDict['refund']['Schema'][]) => {
const [ refund ] = refunds;
if (refund!.pay!.entity !== 'account') {
if (refund!.pay!.entity === 'offlineAcount') {
throw new OakAttrNotNullException('refund', ['externalId']);
}
}

View File

@ -57,7 +57,7 @@ export default OakComponent({
}
}
],
formData({ data }) {
formData({ data, features }) {
return {
refunds: data?.map(
(ele) => {
@ -76,6 +76,7 @@ export default OakComponent({
};
}
),
amIRoot: features.token.isRoot(),
};
}
})

View File

@ -17,8 +17,9 @@ export default function Render(props: WebComponentProps<EntityDict, 'pay', false
isWithdraw: boolean;
payChannel: string;
})[];
amIRoot?: boolean;
}>) {
const { refunds, oakFullpath, oakExecutable } = props.data;
const { refunds, oakFullpath, oakExecutable, amIRoot } = props.data;
const { t, updateItem, execute, clean, setMessage } = props.methods;
const [upsertId, setUpsertId] = useState('');
@ -126,7 +127,7 @@ export default function Render(props: WebComponentProps<EntityDict, 'pay', false
onAction={(row, action) => {
const { entity } = row.pay;
assert(entity !== 'account');
if (entity !== 'offlineAccount') {
if (entity !== 'offlineAccount' || !amIRoot) {
setMessage({
type: 'error',
title: t('cantOperateOnline'),

View File

@ -89,6 +89,9 @@ const attrUpdateMatrix: AttrUpdateMatrix<EntityDict> = {
},
reason: {
actions: ['fail'],
},
successAt: {
actions: ['succeed'],
}
},
withdraw: {

View File

@ -1,4 +1,4 @@
import { CreateTriggerInTxn, Trigger, UpdateTriggerInTxn, UpdateTriggerCrossTxn } from 'oak-domain/lib/types/Trigger';
import { CreateTriggerInTxn, Trigger, UpdateTriggerInTxn, SelectTriggerAfter } from 'oak-domain/lib/types/Trigger';
import { generateNewIdAsync } from 'oak-domain/lib/utils/uuid';
import { EntityDict } from '../oak-app-domain';
import { EntityDict as BaseEntityDict } from 'oak-domain/lib/types/Entity';
@ -6,7 +6,7 @@ import { BRC } from '../types/RuntimeCxt';
import assert from 'assert';
import { OperateOption } from 'oak-domain/lib/types';
import { getPayClazz } from '../utils/payClazz';
import { fullPayProjection } from '../utils/pay';
import { fullPayProjection, refreshPayState } from '../utils/pay';
import { DATA_SUBSCRIBER_KEYS } from '../config/constants';
import { UpdateOperation } from '../oak-app-domain/Pay/Schema';
import { getRelevantIds } from 'oak-domain/lib/store/filter';
@ -676,6 +676,19 @@ const triggers: Trigger<EntityDict, 'pay', BRC>[] = [
}
}
} as UpdateTriggerInTxn<EntityDict, 'pay', BRC>,
/*
{
entity: 'pay',
name: '当选择pay并发现pay的状态是paying时尝试刷新其状态',
action: 'select',
when: 'after',
fn: async ({ result }, context) => {
if (result.length === 1 && result[0].iState === 'paying') {
await refreshPayState(result[0] as EntityDict['pay']['OpSchema'], context);
}
return 0;
}
} as SelectTriggerAfter<EntityDict, 'pay', BRC>, */
];
export default triggers;

View File

@ -131,6 +131,7 @@ async function succeedRefunding(context: BRC, refundId: string) {
action,
data: {
refunded: refunded2,
refundable: refunded2 < paid!,
},
filter: {
id: pay!.id!,

View File

@ -48,7 +48,7 @@ export async function payNotify<ED extends EntityDict & BaseEntityDict>(context:
filter: {
id: payId,
}
}, {});
}, { blockTrigger: true });
if (!pay) {
console.error('接受到无效的payId', payId);
return;
@ -157,5 +157,72 @@ export async function refundNotify<ED extends EntityDict & BaseEntityDict>(conte
}
}
/**
* paying状态的pay的真实支付状态
* @param pay
* @param context
* @returns
*/
export async function refreshPayState(
pay: EntityDict['pay']['OpSchema'],
context: BRC,
) {
let pay2 = pay;
if (!pay2.entity || !pay2.entityId || !pay2.timeoutAt || !pay2.price || !pay2.iState ) {
const pays = await context.select('pay', {
data: {
id: 1,
entity: 1,
entityId: 1,
price: 1,
iState: 1,
},
filter: {
id: pay.id,
}
}, { blockTrigger: true });
pay2 = pays[0] as typeof pay;
}
const { entity, entityId, timeoutAt, price } = pay2;
const clazz = await getPayClazz(entity!, entityId!, context);
const [iState, updateData] = await clazz.getState(pay as EntityDict['pay']['OpSchema']);
if (iState !== pay.iState!) {
let action: EntityDict['pay']['Action'] = 'close';
switch (iState) {
case 'closed': {
// action = 'close';
break;
}
case 'paid': {
action = 'succeedPaying';
updateData.paid = price!;
break;
}
default: {
assert(false);
}
}
return await context.operate('pay', {
id: await generateNewIdAsync(),
action,
data: updateData,
filter: {
id: pay.id!,
}
}, {});
}
else if (iState === 'paying' && timeoutAt as number < Date.now()) {
// 尝试关闭订单
// 理论上用户可能在上一个getState和这个close之间支付完成此时关闭失败下一个Watcher到来时就能处理成功了
return await context.operate('pay', {
id: await generateNewIdAsync(),
action: 'close',
data: updateData,
filter: {
id: pay.id!,
}
}, {});
}
}

View File

@ -102,7 +102,7 @@ export default class WechatPay extends WechatPayDebug implements PayClazz {
*/
const iState = REFUND_STATE_MATRIX[status];
return [iState, success_time ? { successAt: dayJs(success_time).millisecond() } : undefined];
return [iState, success_time ? { successAt: dayJs(success_time).valueOf() } : undefined];
}
private analyzeResult<R extends any>(result: ApiResult<R>) {
@ -218,10 +218,10 @@ export default class WechatPay extends WechatPayDebug implements PayClazz {
const updateData: PayUpdateData = {
meta: {
getState: omit(result, ['mchid', 'appid', 'out_trade_no']),
}
},
};
if (iState === 'paid') {
updateData.forbidRefundAt = dayJs(success_time).millisecond();
updateData.successAt = dayJs(success_time).valueOf();
}
return [iState!, updateData];
}
@ -363,7 +363,7 @@ export default class WechatPay extends WechatPayDebug implements PayClazz {
};
if (iState === 'paid') {
extra.successAt = success_time;
extra.successAt = dayJs(success_time).valueOf();
}
return {
@ -439,7 +439,7 @@ export default class WechatPay extends WechatPayDebug implements PayClazz {
};
if (iState === 'successful') {
extra.successAt = success_time;
extra.successAt = dayJs(success_time).valueOf();
}
return {

View File

@ -1,10 +1,7 @@
import { BBWatcher, WBWatcher, Watcher } from 'oak-domain/lib/types/Watcher';
import { EntityDict } from '../oak-app-domain';
import { BRC } from '../types/RuntimeCxt';
import { fullPayProjection } from '../utils/pay';
import { getPayClazz } from '../utils/payClazz';
import assert from 'assert';
import { generateNewIdAsync } from 'oak-domain/lib/utils/uuid';
import { fullPayProjection, refreshPayState } from '../utils/pay';
import { OperationResult } from 'oak-domain/lib/types';
import { mergeOperationResult } from 'oak-domain/lib/utils/operationResult';
@ -30,47 +27,8 @@ const watchers: Watcher<EntityDict, 'pay', BRC>[] = [
fn: async (context, data) => {
const results = [] as OperationResult<EntityDict>[];
for (const pay of data) {
const { applicationId, entity, entityId, timeoutAt, price } = pay;
const clazz = await getPayClazz(entity!, entityId!, context);
const [iState, updateData] = await clazz.getState(pay as EntityDict['pay']['OpSchema']);
if (iState !== pay.iState!) {
let action: EntityDict['pay']['Action'] = 'close';
switch (iState) {
case 'closed': {
// action = 'close';
break;
}
case 'paid': {
action = 'succeedPaying';
updateData.paid = price!;
break;
}
default: {
assert(false);
}
}
const result = await context.operate('pay', {
id: await generateNewIdAsync(),
action,
data: updateData,
filter: {
id: pay.id!,
}
}, {});
results.push(result);
}
else if (iState === 'paying' && timeoutAt as number < Date.now()) {
// 尝试关闭订单
// 理论上用户可能在上一个getState和这个close之间支付完成此时关闭失败下一个Watcher到来时就能处理成功了
const result = await context.operate('pay', {
id: await generateNewIdAsync(),
action: 'close',
data: updateData,
filter: {
id: pay.id!,
}
}, {});
const result = await refreshPayState(pay as EntityDict['pay']['OpSchema'], context);
if (result) {
results.push(result);
}
}

View File

@ -36,7 +36,8 @@ const watchers: Watcher<EntityDict, 'refund', BRC>[] = [
entity: 1,
entityId: 1,
applicationId: 1,
}
},
externalId: 1,
},
fn: async (context, data) => {
const results = [] as OperationResult<EntityDict>[];