支付和退款中的各种小问题

This commit is contained in:
Xu Chang 2024-07-12 20:13:55 +08:00
parent 87b21b9f1a
commit 2f9e65b38a
29 changed files with 55 additions and 30 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

@ -1,7 +1,7 @@
import { generateNewIdAsync } from 'oak-domain/lib/utils/uuid';
import assert from 'assert';
import { getPayClazz } from '../utils/payClazz';
import { fullPayProjection, refreshPayState } from '../utils/pay';
import { fullPayProjection } from '../utils/pay';
import { DATA_SUBSCRIBER_KEYS } from '../config/constants';
import { getRelevantIds } from 'oak-domain/lib/store/filter';
async function changeOrderStateByPay(filter, context, option) {
@ -622,6 +622,7 @@ const triggers = [
}
}
},
/*
{
entity: 'pay',
name: '当选择pay并发现pay的状态是paying时尝试刷新其状态',
@ -629,10 +630,10 @@ const triggers = [
when: 'after',
fn: async ({ result }, context) => {
if (result.length === 1 && result[0].iState === 'paying') {
await refreshPayState(result[0], context);
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,

View File

@ -155,7 +155,7 @@ export async function refreshPayState(pay, context) {
filter: {
id: pay.id,
}
}, {});
}, { blockTrigger: true });
pay2 = pays[0];
}
const { entity, entityId, timeoutAt, price } = pay2;

View File

@ -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

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

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

@ -625,6 +625,7 @@ const triggers = [
}
}
},
/*
{
entity: 'pay',
name: '当选择pay并发现pay的状态是paying时尝试刷新其状态',
@ -632,10 +633,10 @@ const triggers = [
when: 'after',
fn: async ({ result }, context) => {
if (result.length === 1 && result[0].iState === 'paying') {
await (0, pay_1.refreshPayState)(result[0], context);
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

@ -161,7 +161,7 @@ async function refreshPayState(pay, context) {
filter: {
id: pay.id,
}
}, {});
}, { blockTrigger: true });
pay2 = pays[0];
}
const { entity, entityId, timeoutAt, price } = pay2;

View File

@ -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

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

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

@ -676,6 +676,7 @@ const triggers: Trigger<EntityDict, 'pay', BRC>[] = [
}
}
} as UpdateTriggerInTxn<EntityDict, 'pay', BRC>,
/*
{
entity: 'pay',
name: '当选择pay并发现pay的状态是paying时尝试刷新其状态',
@ -687,7 +688,7 @@ const triggers: Trigger<EntityDict, 'pay', BRC>[] = [
}
return 0;
}
} as SelectTriggerAfter<EntityDict, 'pay', BRC>,
} 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

@ -180,7 +180,7 @@ export async function refreshPayState(
filter: {
id: pay.id,
}
}, {});
}, { blockTrigger: true });
pay2 = pays[0] as typeof pay;
}
const { entity, entityId, timeoutAt, price } = pay2;

View File

@ -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

@ -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>[];