123 lines
4.6 KiB
TypeScript
123 lines
4.6 KiB
TypeScript
import { Checker } from 'oak-domain/lib/types/Auth';
|
||
import { EntityDict } from '../oak-app-domain';
|
||
import { RuntimeCxt } from '../types/RuntimeCxt';
|
||
import assert from 'assert';
|
||
import { pipeline } from 'oak-domain/lib/utils/executor';
|
||
import { OakAttrNotNullException, OakInputIllegalException } from 'oak-domain/lib/types';
|
||
|
||
const checkers: Checker<EntityDict, 'order', RuntimeCxt>[] = [
|
||
{
|
||
type: 'logical',
|
||
entity: 'order',
|
||
action: 'create',
|
||
checker: (operation, context) => {
|
||
const { data } = operation as EntityDict['order']['CreateSingle'];
|
||
if (!data.creatorId) {
|
||
data.creatorId = context.getCurrentUserId()!;
|
||
}
|
||
data.paid = 0;
|
||
data.refunded = 0;
|
||
data.settled = false;
|
||
if (!data.systemId) {
|
||
const contextSystemId = context.getApplication()?.systemId;
|
||
assert(contextSystemId);
|
||
data.systemId = contextSystemId;
|
||
}
|
||
}
|
||
},
|
||
{
|
||
type: 'logicalData',
|
||
entity: 'order',
|
||
action: 'startPaying',
|
||
checker: (operation, context) => {
|
||
const { data, filter } = operation as EntityDict['order']['Update'];
|
||
|
||
assert(typeof filter!.id === 'string');
|
||
|
||
return pipeline(
|
||
() => context.select('order', {
|
||
data: {
|
||
id: 1,
|
||
price: 1,
|
||
paid: 1,
|
||
refunded: 1,
|
||
iState: 1,
|
||
},
|
||
filter: {
|
||
id: filter!.id!,
|
||
},
|
||
}, {}),
|
||
(orders: EntityDict['order']['OpSchema'][]) => {
|
||
const [order] = orders;
|
||
const { price, paid, iState, allowPartialPay } = order;
|
||
assert(['unpaid', 'partiallyRefunded'].includes(iState!) && paid === 0);
|
||
|
||
const { pay$order: pays } = data;
|
||
if (!(pays instanceof Array) || !pays.length) {
|
||
throw new OakInputIllegalException('order', ['pay$order'], 'error::order.nonePay');
|
||
}
|
||
let amount = 0;
|
||
pays!.forEach(
|
||
({ action, data }) => {
|
||
assert(action === 'create');
|
||
const { price } = data as EntityDict['pay']['CreateSingle']['data'];
|
||
amount += price!;
|
||
}
|
||
);
|
||
if (!allowPartialPay && amount !== price) {
|
||
throw new OakInputIllegalException('order', ['pay$order'], 'error::order.payAmountNotEnough');
|
||
}
|
||
}
|
||
);
|
||
}
|
||
},
|
||
{
|
||
// 订单结算,将收入分帐到相关的Account中
|
||
type: 'logicalData',
|
||
entity: 'order',
|
||
action: 'settle',
|
||
checker: (operation, context) => {
|
||
const { data, filter } = operation as EntityDict['order']['Update'];
|
||
|
||
assert(typeof filter!.id === 'string');
|
||
|
||
data.settled = true;
|
||
return pipeline(
|
||
() => context.select('order', {
|
||
data: {
|
||
id: 1,
|
||
price: 1,
|
||
paid: 1,
|
||
refunded: 1,
|
||
iState: 1,
|
||
},
|
||
filter: {
|
||
id: filter!.id!,
|
||
},
|
||
}, {}),
|
||
(orders: EntityDict['order']['OpSchema'][]) => {
|
||
const [order] = orders;
|
||
const { price, paid, refunded, iState } = order;
|
||
assert(['paid', 'partiallyRefunded'].includes(iState!));
|
||
|
||
const { accountOper$entity: opers } = data;
|
||
assert(opers instanceof Array);
|
||
let amount = 0;
|
||
opers.forEach(
|
||
({ action, data }) => {
|
||
assert(action === 'create');
|
||
const { type, totalPlus, availPlus, refundablePlus } = data as EntityDict['accountOper']['CreateSingle']['data'];
|
||
assert(type === 'earn');
|
||
// assert(totalPlus === availPlus);
|
||
amount += totalPlus!;
|
||
}
|
||
);
|
||
assert(amount === paid - refunded);
|
||
}
|
||
);
|
||
}
|
||
}
|
||
];
|
||
|
||
export default checkers;
|