Merge branch 'dev' into release
This commit is contained in:
commit
c06e3352d0
|
|
@ -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 = {};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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']);
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
};
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -8,4 +8,5 @@ export default function Render(props: WebComponentProps<EntityDict, 'pay', false
|
|||
isWithdraw: boolean;
|
||||
payChannel: string;
|
||||
})[];
|
||||
amIRoot?: boolean;
|
||||
}>): React.JSX.Element | null;
|
||||
|
|
|
|||
|
|
@ -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'),
|
||||
|
|
|
|||
|
|
@ -84,6 +84,9 @@ const attrUpdateMatrix = {
|
|||
},
|
||||
reason: {
|
||||
actions: ['fail'],
|
||||
},
|
||||
successAt: {
|
||||
actions: ['succeed'],
|
||||
}
|
||||
},
|
||||
withdraw: {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -115,6 +115,7 @@ async function succeedRefunding(context, refundId) {
|
|||
action,
|
||||
data: {
|
||||
refunded: refunded2,
|
||||
refundable: refunded2 < paid,
|
||||
},
|
||||
filter: {
|
||||
id: pay.id,
|
||||
|
|
|
|||
|
|
@ -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>;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
}, {});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,8 @@ const watchers = [
|
|||
entity: 1,
|
||||
entityId: 1,
|
||||
applicationId: 1,
|
||||
}
|
||||
},
|
||||
externalId: 1,
|
||||
},
|
||||
fn: async (context, data) => {
|
||||
const results = [];
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 = {};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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']);
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -86,6 +86,9 @@ const attrUpdateMatrix = {
|
|||
},
|
||||
reason: {
|
||||
actions: ['fail'],
|
||||
},
|
||||
successAt: {
|
||||
actions: ['succeed'],
|
||||
}
|
||||
},
|
||||
withdraw: {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -118,6 +118,7 @@ async function succeedRefunding(context, refundId) {
|
|||
action,
|
||||
data: {
|
||||
refunded: refunded2,
|
||||
refundable: refunded2 < paid,
|
||||
},
|
||||
filter: {
|
||||
id: pay.id,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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>;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,7 +32,8 @@ const watchers = [
|
|||
entity: 1,
|
||||
entityId: 1,
|
||||
applicationId: 1,
|
||||
}
|
||||
},
|
||||
externalId: 1,
|
||||
},
|
||||
fn: async (context, data) => {
|
||||
const results = [];
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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 = {};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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']);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
};
|
||||
}
|
||||
})
|
||||
|
|
@ -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'),
|
||||
|
|
|
|||
|
|
@ -89,6 +89,9 @@ const attrUpdateMatrix: AttrUpdateMatrix<EntityDict> = {
|
|||
},
|
||||
reason: {
|
||||
actions: ['fail'],
|
||||
},
|
||||
successAt: {
|
||||
actions: ['succeed'],
|
||||
}
|
||||
},
|
||||
withdraw: {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -131,6 +131,7 @@ async function succeedRefunding(context: BRC, refundId: string) {
|
|||
action,
|
||||
data: {
|
||||
refunded: refunded2,
|
||||
refundable: refunded2 < paid!,
|
||||
},
|
||||
filter: {
|
||||
id: pay!.id!,
|
||||
|
|
|
|||
|
|
@ -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!,
|
||||
}
|
||||
}, {});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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,49 +27,10 @@ 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!,
|
||||
}
|
||||
}, {});
|
||||
const result = await refreshPayState(pay as EntityDict['pay']['OpSchema'], context);
|
||||
if (result) {
|
||||
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!,
|
||||
}
|
||||
}, {});
|
||||
results.push(result);
|
||||
}
|
||||
}
|
||||
|
||||
if (results.length === 0) {
|
||||
|
|
|
|||
|
|
@ -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>[];
|
||||
|
|
|
|||
Loading…
Reference in New Issue