diff --git a/es/oak-app-domain/ArticleMenu/Storage.js b/es/oak-app-domain/ArticleMenu/Storage.js index d327c44c..fe939439 100644 --- a/es/oak-app-domain/ArticleMenu/Storage.js +++ b/es/oak-app-domain/ArticleMenu/Storage.js @@ -32,6 +32,9 @@ export const desc = { params: { length: 64 } + }, + latestAt: { + type: "datetime" } }, actionType: "crud", diff --git a/es/oak-app-domain/ArticleMenu/_baseSchema.d.ts b/es/oak-app-domain/ArticleMenu/_baseSchema.d.ts index 8a040876..18b3f8b1 100644 --- a/es/oak-app-domain/ArticleMenu/_baseSchema.d.ts +++ b/es/oak-app-domain/ArticleMenu/_baseSchema.d.ts @@ -2,7 +2,7 @@ import { ForeignKey } from "oak-domain/lib/types/DataType"; import { Q_DateValue, Q_BooleanValue, Q_NumberValue, Q_StringValue, NodeId, ExprOp, ExpressionKey } from "oak-domain/lib/types/Demand"; import { MakeAction as OakMakeAction, EntityShape } from "oak-domain/lib/types/Entity"; import { GenericAction } from "oak-domain/lib/actions/action"; -import { String, Boolean } from "oak-domain/lib/types/DataType"; +import { String, Boolean, Datetime } from "oak-domain/lib/types/DataType"; export type OpSchema = EntityShape & { name: String<32>; isArticle: Boolean; @@ -10,6 +10,7 @@ export type OpSchema = EntityShape & { isLeaf?: Boolean | null; entity: String<32>; entityId: String<64>; + latestAt?: Datetime | null; } & { [A in ExpressionKey]?: any; }; @@ -25,6 +26,7 @@ export type OpFilter = { isLeaf: Q_BooleanValue; entity: Q_StringValue; entityId: Q_StringValue; + latestAt: Q_DateValue; } & ExprOp; export type OpProjection = { "#id"?: NodeId; @@ -39,6 +41,7 @@ export type OpProjection = { isLeaf?: number; entity?: number; entityId?: number; + latestAt?: number; } & Partial>; export type OpSortAttr = Partial<{ id: number; @@ -51,6 +54,7 @@ export type OpSortAttr = Partial<{ isLeaf: number; entity: number; entityId: number; + latestAt: number; [k: string]: any; } | ExprOp>; export type OpAction = OakMakeAction; diff --git a/es/oak-app-domain/ArticleMenu/locales/zh_CN.json b/es/oak-app-domain/ArticleMenu/locales/zh_CN.json index 8bff47d0..29a7a495 100644 --- a/es/oak-app-domain/ArticleMenu/locales/zh_CN.json +++ b/es/oak-app-domain/ArticleMenu/locales/zh_CN.json @@ -7,6 +7,7 @@ "entity": "对象", "entityId": "对象Id", "isLeaf": "结点下是否存在叶子结点", - "files": "文件" + "files": "文件", + "latestAt": "最近编辑" } } diff --git a/es/triggers/refund.js b/es/triggers/refund.js index 8f2a3e1f..09efd0fd 100644 --- a/es/triggers/refund.js +++ b/es/triggers/refund.js @@ -25,6 +25,7 @@ async function startRefunding(context, data) { }, order: { id: 1, + price: 1, paid: 1, refunded: 1, settled: 1, @@ -112,50 +113,14 @@ async function startRefunding(context, data) { } }, { forUpdate: true }); const { accountOper$entity: opers, } = data; - // 对opers检查 - if (order.settled === (order.paid - order.refunded)) { - // 已全部结算 - // 已全部结算的订单由refund传入的opers决定退款,检查opers的金额总和等于refund的金额 - let amount = 0; - // 有明确的来源account - assert(opers && opers instanceof Array, '已结算的订单退款一定要有相应的account来源'); - opers.forEach(({ action, data }) => { - assert(action === 'create'); - const { type, totalPlus, availPlus, accountId } = data; - assert(type === 'refund'); - assert(totalPlus === availPlus); - const settlement = settledSettlements?.find((ele) => ele?.accountId === accountId); - assert(!!settlement, '请从订单分账的相关账户中选择订单退款的account来源'); - amount += -totalPlus; - }); - assert(amount === data.price); - //将order的settled更新 - const newSettled = order.settled - data.price; - await context.operate('order', { - id: await generateNewIdAsync(), - action: 'update', - data: { - settled: newSettled, - }, - filter: { - id: order.id, - } - }, {}); - } - else if (order.settled === 0) { - //未结算 - //未结算的订单无opers - assert(!(opers && opers.length > 0)); - } - else { - //部分结算 - /** - * 部分结算的订单: - * 1. opers的金额总和 <= 订单已结算金额 - * 2. opers的金额总和 + unsettled的金额 >= 退款金额 - */ - let opersPrice = 0; - if (opers && opers.length > 0) { + // 对opers检查 退款0元无需检查 + if (!(data.price === 0 && order.price === 0 && pay.paid === 0)) { + if (order.settled === (order.paid - order.refunded)) { + // 已全部结算 + // 已全部结算的订单由refund传入的opers决定退款,检查opers的金额总和等于refund的金额 + let amount = 0; + // 有明确的来源account + assert(opers && opers instanceof Array, '已结算的订单退款一定要有相应的account来源'); opers.forEach(({ action, data }) => { assert(action === 'create'); const { type, totalPlus, availPlus, accountId } = data; @@ -163,29 +128,70 @@ async function startRefunding(context, data) { assert(totalPlus === availPlus); const settlement = settledSettlements?.find((ele) => ele?.accountId === accountId); assert(!!settlement, '请从订单分账的相关账户中选择订单退款的account来源'); - opersPrice += -totalPlus; + amount += -totalPlus; }); + assert(amount === data.price); + //将order的settled更新 + const newSettled = order.settled - data.price; + await context.operate('order', { + id: await generateNewIdAsync(), + action: 'update', + data: { + settled: newSettled, + }, + filter: { + id: order.id, + } + }, {}); } - const { paid, refunded, settled, settlePlan$order: settlePlans } = order; - const orderUnsettledPrice = paid - refunded - settled; - if (opersPrice > settled) { - throw new refundOpersExceed(opersPrice - settled); + else if (order.settled === 0) { + //未结算 + //未结算的订单无opers + assert(!(opers && opers.length > 0)); } - if (opersPrice < data.price - orderUnsettledPrice) { - throw new refundOpersNotEnough(opersPrice - (data.price - orderUnsettledPrice)); - } - //将order的settled更新 - const newSettled = order.settled - opersPrice; - await context.operate('order', { - id: await generateNewIdAsync(), - action: 'update', - data: { - settled: newSettled, - }, - filter: { - id: order.id, + else { + //部分结算 + /** + * 部分结算的订单: + * 1. opers的金额总和 <= 订单已结算金额 + * 2. opers的金额总和 + unsettled的金额 >= 退款金额 + */ + let opersPrice = 0; + if (opers && opers.length > 0) { + opers.forEach(({ action, data }) => { + assert(action === 'create'); + const { type, totalPlus, availPlus, accountId } = data; + assert(type === 'refund'); + assert(totalPlus === availPlus); + const settlement = settledSettlements?.find((ele) => ele?.accountId === accountId); + assert(!!settlement, '请从订单分账的相关账户中选择订单退款的account来源'); + opersPrice += -totalPlus; + }); } - }, {}); + const { paid, refunded, settled, settlePlan$order: settlePlans } = order; + const orderUnsettledPrice = paid - refunded - settled; + if (opersPrice > settled) { + throw new refundOpersExceed(opersPrice - settled); + } + if (opersPrice < data.price - orderUnsettledPrice) { + throw new refundOpersNotEnough(opersPrice - (data.price - orderUnsettledPrice)); + } + //将order的settled更新 + const newSettled = order.settled - opersPrice; + await context.operate('order', { + id: await generateNewIdAsync(), + action: 'update', + data: { + settled: newSettled, + }, + filter: { + id: order.id, + } + }, {}); + } + } + else { + assert(order.price === 0 && data.price === 0, '0元订单,退款金额不可大于订单金额'); } } data.pay = { diff --git a/lib/oak-app-domain/ArticleMenu/Storage.js b/lib/oak-app-domain/ArticleMenu/Storage.js index 2ef5f1cc..eb9d81d0 100644 --- a/lib/oak-app-domain/ArticleMenu/Storage.js +++ b/lib/oak-app-domain/ArticleMenu/Storage.js @@ -35,6 +35,9 @@ exports.desc = { params: { length: 64 } + }, + latestAt: { + type: "datetime" } }, actionType: "crud", diff --git a/lib/oak-app-domain/ArticleMenu/_baseSchema.d.ts b/lib/oak-app-domain/ArticleMenu/_baseSchema.d.ts index 8a040876..18b3f8b1 100644 --- a/lib/oak-app-domain/ArticleMenu/_baseSchema.d.ts +++ b/lib/oak-app-domain/ArticleMenu/_baseSchema.d.ts @@ -2,7 +2,7 @@ import { ForeignKey } from "oak-domain/lib/types/DataType"; import { Q_DateValue, Q_BooleanValue, Q_NumberValue, Q_StringValue, NodeId, ExprOp, ExpressionKey } from "oak-domain/lib/types/Demand"; import { MakeAction as OakMakeAction, EntityShape } from "oak-domain/lib/types/Entity"; import { GenericAction } from "oak-domain/lib/actions/action"; -import { String, Boolean } from "oak-domain/lib/types/DataType"; +import { String, Boolean, Datetime } from "oak-domain/lib/types/DataType"; export type OpSchema = EntityShape & { name: String<32>; isArticle: Boolean; @@ -10,6 +10,7 @@ export type OpSchema = EntityShape & { isLeaf?: Boolean | null; entity: String<32>; entityId: String<64>; + latestAt?: Datetime | null; } & { [A in ExpressionKey]?: any; }; @@ -25,6 +26,7 @@ export type OpFilter = { isLeaf: Q_BooleanValue; entity: Q_StringValue; entityId: Q_StringValue; + latestAt: Q_DateValue; } & ExprOp; export type OpProjection = { "#id"?: NodeId; @@ -39,6 +41,7 @@ export type OpProjection = { isLeaf?: number; entity?: number; entityId?: number; + latestAt?: number; } & Partial>; export type OpSortAttr = Partial<{ id: number; @@ -51,6 +54,7 @@ export type OpSortAttr = Partial<{ isLeaf: number; entity: number; entityId: number; + latestAt: number; [k: string]: any; } | ExprOp>; export type OpAction = OakMakeAction; diff --git a/lib/oak-app-domain/ArticleMenu/locales/zh_CN.json b/lib/oak-app-domain/ArticleMenu/locales/zh_CN.json index 8bff47d0..29a7a495 100644 --- a/lib/oak-app-domain/ArticleMenu/locales/zh_CN.json +++ b/lib/oak-app-domain/ArticleMenu/locales/zh_CN.json @@ -7,6 +7,7 @@ "entity": "对象", "entityId": "对象Id", "isLeaf": "结点下是否存在叶子结点", - "files": "文件" + "files": "文件", + "latestAt": "最近编辑" } } diff --git a/lib/triggers/refund.js b/lib/triggers/refund.js index e5fe9ab3..7c168dd1 100644 --- a/lib/triggers/refund.js +++ b/lib/triggers/refund.js @@ -28,6 +28,7 @@ async function startRefunding(context, data) { }, order: { id: 1, + price: 1, paid: 1, refunded: 1, settled: 1, @@ -115,50 +116,14 @@ async function startRefunding(context, data) { } }, { forUpdate: true }); const { accountOper$entity: opers, } = data; - // 对opers检查 - if (order.settled === (order.paid - order.refunded)) { - // 已全部结算 - // 已全部结算的订单由refund传入的opers决定退款,检查opers的金额总和等于refund的金额 - let amount = 0; - // 有明确的来源account - (0, assert_1.default)(opers && opers instanceof Array, '已结算的订单退款一定要有相应的account来源'); - opers.forEach(({ action, data }) => { - (0, assert_1.default)(action === 'create'); - const { type, totalPlus, availPlus, accountId } = data; - (0, assert_1.default)(type === 'refund'); - (0, assert_1.default)(totalPlus === availPlus); - const settlement = settledSettlements?.find((ele) => ele?.accountId === accountId); - (0, assert_1.default)(!!settlement, '请从订单分账的相关账户中选择订单退款的account来源'); - amount += -totalPlus; - }); - (0, assert_1.default)(amount === data.price); - //将order的settled更新 - const newSettled = order.settled - data.price; - await context.operate('order', { - id: await (0, uuid_1.generateNewIdAsync)(), - action: 'update', - data: { - settled: newSettled, - }, - filter: { - id: order.id, - } - }, {}); - } - else if (order.settled === 0) { - //未结算 - //未结算的订单无opers - (0, assert_1.default)(!(opers && opers.length > 0)); - } - else { - //部分结算 - /** - * 部分结算的订单: - * 1. opers的金额总和 <= 订单已结算金额 - * 2. opers的金额总和 + unsettled的金额 >= 退款金额 - */ - let opersPrice = 0; - if (opers && opers.length > 0) { + // 对opers检查 退款0元无需检查 + if (!(data.price === 0 && order.price === 0 && pay.paid === 0)) { + if (order.settled === (order.paid - order.refunded)) { + // 已全部结算 + // 已全部结算的订单由refund传入的opers决定退款,检查opers的金额总和等于refund的金额 + let amount = 0; + // 有明确的来源account + (0, assert_1.default)(opers && opers instanceof Array, '已结算的订单退款一定要有相应的account来源'); opers.forEach(({ action, data }) => { (0, assert_1.default)(action === 'create'); const { type, totalPlus, availPlus, accountId } = data; @@ -166,29 +131,70 @@ async function startRefunding(context, data) { (0, assert_1.default)(totalPlus === availPlus); const settlement = settledSettlements?.find((ele) => ele?.accountId === accountId); (0, assert_1.default)(!!settlement, '请从订单分账的相关账户中选择订单退款的account来源'); - opersPrice += -totalPlus; + amount += -totalPlus; }); + (0, assert_1.default)(amount === data.price); + //将order的settled更新 + const newSettled = order.settled - data.price; + await context.operate('order', { + id: await (0, uuid_1.generateNewIdAsync)(), + action: 'update', + data: { + settled: newSettled, + }, + filter: { + id: order.id, + } + }, {}); } - const { paid, refunded, settled, settlePlan$order: settlePlans } = order; - const orderUnsettledPrice = paid - refunded - settled; - if (opersPrice > settled) { - throw new Exception_1.refundOpersExceed(opersPrice - settled); + else if (order.settled === 0) { + //未结算 + //未结算的订单无opers + (0, assert_1.default)(!(opers && opers.length > 0)); } - if (opersPrice < data.price - orderUnsettledPrice) { - throw new Exception_1.refundOpersNotEnough(opersPrice - (data.price - orderUnsettledPrice)); - } - //将order的settled更新 - const newSettled = order.settled - opersPrice; - await context.operate('order', { - id: await (0, uuid_1.generateNewIdAsync)(), - action: 'update', - data: { - settled: newSettled, - }, - filter: { - id: order.id, + else { + //部分结算 + /** + * 部分结算的订单: + * 1. opers的金额总和 <= 订单已结算金额 + * 2. opers的金额总和 + unsettled的金额 >= 退款金额 + */ + let opersPrice = 0; + if (opers && opers.length > 0) { + opers.forEach(({ action, data }) => { + (0, assert_1.default)(action === 'create'); + const { type, totalPlus, availPlus, accountId } = data; + (0, assert_1.default)(type === 'refund'); + (0, assert_1.default)(totalPlus === availPlus); + const settlement = settledSettlements?.find((ele) => ele?.accountId === accountId); + (0, assert_1.default)(!!settlement, '请从订单分账的相关账户中选择订单退款的account来源'); + opersPrice += -totalPlus; + }); } - }, {}); + const { paid, refunded, settled, settlePlan$order: settlePlans } = order; + const orderUnsettledPrice = paid - refunded - settled; + if (opersPrice > settled) { + throw new Exception_1.refundOpersExceed(opersPrice - settled); + } + if (opersPrice < data.price - orderUnsettledPrice) { + throw new Exception_1.refundOpersNotEnough(opersPrice - (data.price - orderUnsettledPrice)); + } + //将order的settled更新 + const newSettled = order.settled - opersPrice; + await context.operate('order', { + id: await (0, uuid_1.generateNewIdAsync)(), + action: 'update', + data: { + settled: newSettled, + }, + filter: { + id: order.id, + } + }, {}); + } + } + else { + (0, assert_1.default)(order.price === 0 && data.price === 0, '0元订单,退款金额不可大于订单金额'); } } data.pay = { diff --git a/src/triggers/refund.ts b/src/triggers/refund.ts index f47bc160..fd4a0e61 100644 --- a/src/triggers/refund.ts +++ b/src/triggers/refund.ts @@ -30,6 +30,7 @@ async function startRefunding(context: BRC, data: EntityDict['refund']['CreateOp }, order: { id: 1, + price: 1, paid: 1, refunded: 1, settled: 1, @@ -121,53 +122,14 @@ async function startRefunding(context: BRC, data: EntityDict['refund']['CreateOp }, { forUpdate: true }); const { accountOper$entity: opers, } = data; - // 对opers检查 - if (order.settled === (order.paid - order.refunded)) { - // 已全部结算 - // 已全部结算的订单由refund传入的opers决定退款,检查opers的金额总和等于refund的金额 - let amount = 0; - // 有明确的来源account - assert(opers && opers instanceof Array, '已结算的订单退款一定要有相应的account来源'); - opers.forEach( - ({ action, data }) => { - assert(action === 'create'); - const { type, totalPlus, availPlus, accountId } = data as EntityDict['accountOper']['CreateOperationData']; - assert(type === 'refund'); - assert(totalPlus === availPlus); - - const settlement = settledSettlements?.find((ele) => ele?.accountId === accountId); - assert(!!settlement, '请从订单分账的相关账户中选择订单退款的account来源'); - - amount += -totalPlus!; - } - ); - assert(amount === data.price); - //将order的settled更新 - const newSettled = order.settled - data.price!; - await context.operate('order', { - id: await generateNewIdAsync(), - action: 'update', - data: { - settled: newSettled, - }, - filter: { - id: order.id, - } - }, {}); - } - else if (order.settled === 0) { - //未结算 - //未结算的订单无opers - assert(!(opers && opers.length > 0)); - } else { - //部分结算 - /** - * 部分结算的订单: - * 1. opers的金额总和 <= 订单已结算金额 - * 2. opers的金额总和 + unsettled的金额 >= 退款金额 - */ - let opersPrice = 0; - if (opers && opers.length > 0) { + // 对opers检查 退款0元无需检查 + if (!(data.price === 0 && order.price === 0 && pay.paid === 0)) { + if (order.settled === (order.paid - order.refunded)) { + // 已全部结算 + // 已全部结算的订单由refund传入的opers决定退款,检查opers的金额总和等于refund的金额 + let amount = 0; + // 有明确的来源account + assert(opers && opers instanceof Array, '已结算的订单退款一定要有相应的account来源'); opers.forEach( ({ action, data }) => { assert(action === 'create'); @@ -178,32 +140,75 @@ async function startRefunding(context: BRC, data: EntityDict['refund']['CreateOp const settlement = settledSettlements?.find((ele) => ele?.accountId === accountId); assert(!!settlement, '请从订单分账的相关账户中选择订单退款的account来源'); - opersPrice += -totalPlus!; + amount += -totalPlus!; } ); + assert(amount === data.price); + //将order的settled更新 + const newSettled = order.settled - data.price!; + await context.operate('order', { + id: await generateNewIdAsync(), + action: 'update', + data: { + settled: newSettled, + }, + filter: { + id: order.id, + } + }, {}); } - const { paid, refunded, settled, settlePlan$order: settlePlans } = order; - const orderUnsettledPrice = paid - refunded - settled; - if (opersPrice > settled) { - throw new refundOpersExceed(opersPrice - settled); - } + else if (order.settled === 0) { + //未结算 + //未结算的订单无opers + assert(!(opers && opers.length > 0)); + } else { + //部分结算 + /** + * 部分结算的订单: + * 1. opers的金额总和 <= 订单已结算金额 + * 2. opers的金额总和 + unsettled的金额 >= 退款金额 + */ + let opersPrice = 0; + if (opers && opers.length > 0) { + opers.forEach( + ({ action, data }) => { + assert(action === 'create'); + const { type, totalPlus, availPlus, accountId } = data as EntityDict['accountOper']['CreateOperationData']; + assert(type === 'refund'); + assert(totalPlus === availPlus); - if (opersPrice < data.price! - orderUnsettledPrice) { - throw new refundOpersNotEnough(opersPrice - (data.price! - orderUnsettledPrice)); - } + const settlement = settledSettlements?.find((ele) => ele?.accountId === accountId); + assert(!!settlement, '请从订单分账的相关账户中选择订单退款的account来源'); - //将order的settled更新 - const newSettled = order.settled - opersPrice; - await context.operate('order', { - id: await generateNewIdAsync(), - action: 'update', - data: { - settled: newSettled, - }, - filter: { - id: order.id, + opersPrice += -totalPlus!; + } + ); } - }, {}); + const { paid, refunded, settled, settlePlan$order: settlePlans } = order; + const orderUnsettledPrice = paid - refunded - settled; + if (opersPrice > settled) { + throw new refundOpersExceed(opersPrice - settled); + } + + if (opersPrice < data.price! - orderUnsettledPrice) { + throw new refundOpersNotEnough(opersPrice - (data.price! - orderUnsettledPrice)); + } + + //将order的settled更新 + const newSettled = order.settled - opersPrice; + await context.operate('order', { + id: await generateNewIdAsync(), + action: 'update', + data: { + settled: newSettled, + }, + filter: { + id: order.id, + } + }, {}); + } + } else { + assert(order.price === 0 && data.price === 0, '0元订单,退款金额不可大于订单金额') } }