diff --git a/es/configuration/attrUpdateMatrix.js b/es/configuration/attrUpdateMatrix.js index 1fd74699..13a2f6ea 100644 --- a/es/configuration/attrUpdateMatrix.js +++ b/es/configuration/attrUpdateMatrix.js @@ -44,7 +44,7 @@ const attrUpdateMatrix = { actions: ['refundPartially', 'refundAll'], }, refundable: { - actions: ['succeedPaying', 'closeRefund'], + actions: ['succeedPaying', 'closeRefund', 'stopRefunding', 'refundPartially'], }, forbidRefundAt: { actions: ['succeedPaying'], diff --git a/es/data/i18n.js b/es/data/i18n.js index 03d6ad64..de9f43e7 100644 --- a/es/data/i18n.js +++ b/es/data/i18n.js @@ -798,7 +798,9 @@ const i18ns = [ }, "refund": { "create": { - "hasAnotherRefunding": "您有一笔退款正在进行中" + "hasAnotherRefunding": "您有一笔退款正在进行中", + "exceedMax": "退款额度大于可用值", + "payUnrefundable": "支付已经不可退款" } } } diff --git a/es/locales/error/zh-CN.json b/es/locales/error/zh-CN.json index e4205661..d086d9a4 100644 --- a/es/locales/error/zh-CN.json +++ b/es/locales/error/zh-CN.json @@ -19,7 +19,9 @@ }, "refund": { "create": { - "hasAnotherRefunding": "您有一笔退款正在进行中" + "hasAnotherRefunding": "您有一笔退款正在进行中", + "exceedMax": "退款额度大于可用值", + "payUnrefundable": "支付已经不可退款" } } } diff --git a/es/triggers/pay.js b/es/triggers/pay.js index 6fdbac16..d2ddff77 100644 --- a/es/triggers/pay.js +++ b/es/triggers/pay.js @@ -44,8 +44,7 @@ async function changeOrderStateByPay(filter, context, option) { break; } } - if (paid && iState === 'paid') { - //已支付完成的订单的paid + if (paid) { //对iState是否为paid的判断会影响退款,先去掉 payPaid += paid; } if (refunded) { @@ -72,7 +71,7 @@ async function changeOrderStateByPay(filter, context, option) { } } else if (hasRefunding) { - assert(!hasPaying && payPaid === orderPrice && payPaid === orderPaid && payRefunded < orderPrice); + assert(!hasPaying && payPaid === orderPrice && payRefunded < orderPrice); if (orderIState !== 'refunding' || orderRefunded !== payRefunded) { await context.operate('order', { id: await generateNewIdAsync(), @@ -504,17 +503,6 @@ const triggers = [ action: 'create', } ]; - await context.operate('deposit', { - id: await generateNewIdAsync(), - action: 'succeed', - data: { - accountOper$entity: accountOpers, - }, - filter: { - id: depositId, - }, - }, {}); - cnt++; if (loss > 0) { // 如果有loss就充入system的account账户 const [account] = await context.select('account', { @@ -539,6 +527,17 @@ const triggers = [ }); cnt++; } + await context.operate('deposit', { + id: await generateNewIdAsync(), + action: 'succeed', + data: { + accountOper$entity: accountOpers, + }, + filter: { + id: depositId, + }, + }, {}); + cnt++; } return cnt; }, diff --git a/es/triggers/refund.js b/es/triggers/refund.js index b81b5edc..44338510 100644 --- a/es/triggers/refund.js +++ b/es/triggers/refund.js @@ -2,6 +2,7 @@ import { generateNewId, generateNewIdAsync } from 'oak-domain/lib/utils/uuid'; import { getAccountEntity, getPayClazz } from '../utils/payClazz'; import assert from 'assert'; import { updateWithdrawState } from './withdraw'; +import { RefundExceedMax, PayUnRefundable } from '../types/Exception'; /** * 开始退款的逻辑 * @param context @@ -15,6 +16,9 @@ async function startRefunding(context, data) { paid: 1, refunded: 1, iState: 1, + entity: 1, + entityId: 1, + refundable: 1, deposit: { id: 1, accountId: 1, @@ -29,10 +33,32 @@ async function startRefunding(context, data) { } }, { dontCollect: true }); const { paid, refunded, deposit, order } = pay; - assert(paid - refunded >= data.price); + if (paid - refunded < data.price) { + throw new RefundExceedMax(); + } + if (!pay.refundable) { + throw new PayUnRefundable(); + } if (deposit) { - // 是提现,其Account相应的计算在withdraw进行 - assert(data.withdrawId); + // 充值不可能从account渠道支付 + assert(pay.entity !== 'account'); + if (!data.withdrawId && !order?.id) { + //充值退款需创建关联的accountOper,若为提现则在withdraw中创建 + data.accountOper$entity = [ + { + id: await generateNewIdAsync(), + action: 'create', + data: { + id: await generateNewIdAsync(), + accountId: deposit.accountId, + type: 'refund', + totalPlus: -data.price, + availPlus: -data.price, + refundablePlus: -data.price, + }, + } + ]; + } } else { assert(order); @@ -121,24 +147,45 @@ async function succeedRefunding(context, refundId) { id: pay.id, } }, {}); - const payClazz = await getPayClazz(entity, entityId, context); - // 实际执行的退款的额度应该是price - loss - const [delta, sysAccountEntity, sysAccountEntityId] = payClazz.calcRefundTax(refundPrice - refundLoss); - // sysAccount上减掉实际退款的额度-税费 - await context.operate('sysAccountOper', { - id: await generateNewIdAsync(), - action: 'create', - data: { + let d = undefined; //退回至account的退款无渠道退款补偿 + if (entity === 'account') { + //退回至account中的退款,创建accountOper,更新account余额 + await context.operate('accountOper', { id: await generateNewIdAsync(), - delta: refundLoss - refundPrice - delta, - entity: sysAccountEntity, - entityId: sysAccountEntityId, - refundId: refund.id, - type: 'refund', - } - }, {}); + action: 'create', + data: { + id: await generateNewIdAsync(), + accountId: pay.entityId, + entity: 'refund', + entityId: refund.id, + type: 'consumeBack', + totalPlus: refundPrice - refundLoss, + availPlus: refundPrice - refundLoss, + } + }, {}); + } + else { + //订单退回至非account的退款会使得系统对应账户的资金发生流出 + const payClazz = await getPayClazz(entity, entityId, context); + // 实际执行的退款的额度应该是price - loss + const [delta, sysAccountEntity, sysAccountEntityId] = payClazz.calcRefundTax(refundPrice - refundLoss); + // sysAccount上减掉实际退款的额度-税费 + await context.operate('sysAccountOper', { + id: await generateNewIdAsync(), + action: 'create', + data: { + id: await generateNewIdAsync(), + delta: refundLoss - refundPrice - delta, + entity: sysAccountEntity, + entityId: sysAccountEntityId, + refundId: refund.id, + type: 'refund', + } + }, {}); + d = delta; + } let cnt = 2; - if (refundLoss || delta) { + if (refundLoss || d) { // 如果有退回或者要缴纳的税费,进入system相关联的account账户 const [account] = await context.select('account', { data: { @@ -149,16 +196,16 @@ async function succeedRefunding(context, refundId) { entityId: application.systemId, }, }, { dontCollect: true }); - if (delta) { + if (d) { await context.operate('accountOper', { id: await generateNewIdAsync(), action: 'create', data: { id: await generateNewIdAsync(), accountId: account.id, - type: delta < 0 ? 'taxRefund' : 'tax', - totalPlus: -delta, - availPlus: -delta, + type: d < 0 ? 'taxRefund' : 'tax', + totalPlus: -d, + availPlus: -d, entity: 'refund', entityId: refund.id, }, diff --git a/es/types/Exception.d.ts b/es/types/Exception.d.ts index 67b988a8..c3155226 100644 --- a/es/types/Exception.d.ts +++ b/es/types/Exception.d.ts @@ -16,6 +16,9 @@ export declare class ExternalPayUtilException extends Oak export declare class RefundExceedMax extends OakException { constructor(message?: string); } +export declare class PayUnRefundable extends OakException { + constructor(message?: string); +} export declare class StartPayFailure extends OakException { constructor(message: string); } diff --git a/es/types/Exception.js b/es/types/Exception.js index 589829d6..9b92732b 100644 --- a/es/types/Exception.js +++ b/es/types/Exception.js @@ -16,7 +16,12 @@ export class ExternalPayUtilException extends OakException { } export class RefundExceedMax extends OakException { constructor(message) { - super(message || '可退款的总额不足'); + super(message || 'error::refund.create.exceedMax'); + } +} +export class PayUnRefundable extends OakException { + constructor(message) { + super(message || 'error::refund.create.payUnrefundable'); } } export class StartPayFailure extends OakException { diff --git a/lib/configuration/attrUpdateMatrix.js b/lib/configuration/attrUpdateMatrix.js index 51c8f7d7..de981cc1 100644 --- a/lib/configuration/attrUpdateMatrix.js +++ b/lib/configuration/attrUpdateMatrix.js @@ -46,7 +46,7 @@ const attrUpdateMatrix = { actions: ['refundPartially', 'refundAll'], }, refundable: { - actions: ['succeedPaying', 'closeRefund'], + actions: ['succeedPaying', 'closeRefund', 'stopRefunding', 'refundPartially'], }, forbidRefundAt: { actions: ['succeedPaying'], diff --git a/lib/data/i18n.js b/lib/data/i18n.js index 4db7bdca..a5ebb1c3 100644 --- a/lib/data/i18n.js +++ b/lib/data/i18n.js @@ -800,7 +800,9 @@ const i18ns = [ }, "refund": { "create": { - "hasAnotherRefunding": "您有一笔退款正在进行中" + "hasAnotherRefunding": "您有一笔退款正在进行中", + "exceedMax": "退款额度大于可用值", + "payUnrefundable": "支付已经不可退款" } } } diff --git a/lib/locales/error/zh-CN.json b/lib/locales/error/zh-CN.json index e4205661..d086d9a4 100644 --- a/lib/locales/error/zh-CN.json +++ b/lib/locales/error/zh-CN.json @@ -19,7 +19,9 @@ }, "refund": { "create": { - "hasAnotherRefunding": "您有一笔退款正在进行中" + "hasAnotherRefunding": "您有一笔退款正在进行中", + "exceedMax": "退款额度大于可用值", + "payUnrefundable": "支付已经不可退款" } } } diff --git a/lib/triggers/pay.js b/lib/triggers/pay.js index 63b1e420..5f564ff5 100644 --- a/lib/triggers/pay.js +++ b/lib/triggers/pay.js @@ -47,8 +47,7 @@ async function changeOrderStateByPay(filter, context, option) { break; } } - if (paid && iState === 'paid') { - //已支付完成的订单的paid + if (paid) { //对iState是否为paid的判断会影响退款,先去掉 payPaid += paid; } if (refunded) { @@ -75,7 +74,7 @@ async function changeOrderStateByPay(filter, context, option) { } } else if (hasRefunding) { - (0, assert_1.default)(!hasPaying && payPaid === orderPrice && payPaid === orderPaid && payRefunded < orderPrice); + (0, assert_1.default)(!hasPaying && payPaid === orderPrice && payRefunded < orderPrice); if (orderIState !== 'refunding' || orderRefunded !== payRefunded) { await context.operate('order', { id: await (0, uuid_1.generateNewIdAsync)(), @@ -507,17 +506,6 @@ const triggers = [ action: 'create', } ]; - await context.operate('deposit', { - id: await (0, uuid_1.generateNewIdAsync)(), - action: 'succeed', - data: { - accountOper$entity: accountOpers, - }, - filter: { - id: depositId, - }, - }, {}); - cnt++; if (loss > 0) { // 如果有loss就充入system的account账户 const [account] = await context.select('account', { @@ -542,6 +530,17 @@ const triggers = [ }); cnt++; } + await context.operate('deposit', { + id: await (0, uuid_1.generateNewIdAsync)(), + action: 'succeed', + data: { + accountOper$entity: accountOpers, + }, + filter: { + id: depositId, + }, + }, {}); + cnt++; } return cnt; }, diff --git a/lib/triggers/refund.js b/lib/triggers/refund.js index 1bb27cf1..ef1df591 100644 --- a/lib/triggers/refund.js +++ b/lib/triggers/refund.js @@ -5,6 +5,7 @@ const uuid_1 = require("oak-domain/lib/utils/uuid"); const payClazz_1 = require("../utils/payClazz"); const assert_1 = tslib_1.__importDefault(require("assert")); const withdraw_1 = require("./withdraw"); +const Exception_1 = require("../types/Exception"); /** * 开始退款的逻辑 * @param context @@ -18,6 +19,9 @@ async function startRefunding(context, data) { paid: 1, refunded: 1, iState: 1, + entity: 1, + entityId: 1, + refundable: 1, deposit: { id: 1, accountId: 1, @@ -32,10 +36,32 @@ async function startRefunding(context, data) { } }, { dontCollect: true }); const { paid, refunded, deposit, order } = pay; - (0, assert_1.default)(paid - refunded >= data.price); + if (paid - refunded < data.price) { + throw new Exception_1.RefundExceedMax(); + } + if (!pay.refundable) { + throw new Exception_1.PayUnRefundable(); + } if (deposit) { - // 是提现,其Account相应的计算在withdraw进行 - (0, assert_1.default)(data.withdrawId); + // 充值不可能从account渠道支付 + (0, assert_1.default)(pay.entity !== 'account'); + if (!data.withdrawId && !order?.id) { + //充值退款需创建关联的accountOper,若为提现则在withdraw中创建 + data.accountOper$entity = [ + { + id: await (0, uuid_1.generateNewIdAsync)(), + action: 'create', + data: { + id: await (0, uuid_1.generateNewIdAsync)(), + accountId: deposit.accountId, + type: 'refund', + totalPlus: -data.price, + availPlus: -data.price, + refundablePlus: -data.price, + }, + } + ]; + } } else { (0, assert_1.default)(order); @@ -124,24 +150,45 @@ async function succeedRefunding(context, refundId) { id: pay.id, } }, {}); - const payClazz = await (0, payClazz_1.getPayClazz)(entity, entityId, context); - // 实际执行的退款的额度应该是price - loss - const [delta, sysAccountEntity, sysAccountEntityId] = payClazz.calcRefundTax(refundPrice - refundLoss); - // sysAccount上减掉实际退款的额度-税费 - await context.operate('sysAccountOper', { - id: await (0, uuid_1.generateNewIdAsync)(), - action: 'create', - data: { + let d = undefined; //退回至account的退款无渠道退款补偿 + if (entity === 'account') { + //退回至account中的退款,创建accountOper,更新account余额 + await context.operate('accountOper', { id: await (0, uuid_1.generateNewIdAsync)(), - delta: refundLoss - refundPrice - delta, - entity: sysAccountEntity, - entityId: sysAccountEntityId, - refundId: refund.id, - type: 'refund', - } - }, {}); + action: 'create', + data: { + id: await (0, uuid_1.generateNewIdAsync)(), + accountId: pay.entityId, + entity: 'refund', + entityId: refund.id, + type: 'consumeBack', + totalPlus: refundPrice - refundLoss, + availPlus: refundPrice - refundLoss, + } + }, {}); + } + else { + //订单退回至非account的退款会使得系统对应账户的资金发生流出 + const payClazz = await (0, payClazz_1.getPayClazz)(entity, entityId, context); + // 实际执行的退款的额度应该是price - loss + const [delta, sysAccountEntity, sysAccountEntityId] = payClazz.calcRefundTax(refundPrice - refundLoss); + // sysAccount上减掉实际退款的额度-税费 + await context.operate('sysAccountOper', { + id: await (0, uuid_1.generateNewIdAsync)(), + action: 'create', + data: { + id: await (0, uuid_1.generateNewIdAsync)(), + delta: refundLoss - refundPrice - delta, + entity: sysAccountEntity, + entityId: sysAccountEntityId, + refundId: refund.id, + type: 'refund', + } + }, {}); + d = delta; + } let cnt = 2; - if (refundLoss || delta) { + if (refundLoss || d) { // 如果有退回或者要缴纳的税费,进入system相关联的account账户 const [account] = await context.select('account', { data: { @@ -152,16 +199,16 @@ async function succeedRefunding(context, refundId) { entityId: application.systemId, }, }, { dontCollect: true }); - if (delta) { + if (d) { await context.operate('accountOper', { id: await (0, uuid_1.generateNewIdAsync)(), action: 'create', data: { id: await (0, uuid_1.generateNewIdAsync)(), accountId: account.id, - type: delta < 0 ? 'taxRefund' : 'tax', - totalPlus: -delta, - availPlus: -delta, + type: d < 0 ? 'taxRefund' : 'tax', + totalPlus: -d, + availPlus: -d, entity: 'refund', entityId: refund.id, }, diff --git a/lib/types/Exception.d.ts b/lib/types/Exception.d.ts index 67b988a8..c3155226 100644 --- a/lib/types/Exception.d.ts +++ b/lib/types/Exception.d.ts @@ -16,6 +16,9 @@ export declare class ExternalPayUtilException extends Oak export declare class RefundExceedMax extends OakException { constructor(message?: string); } +export declare class PayUnRefundable extends OakException { + constructor(message?: string); +} export declare class StartPayFailure extends OakException { constructor(message: string); } diff --git a/lib/types/Exception.js b/lib/types/Exception.js index e5a3bbbb..ce90bbc1 100644 --- a/lib/types/Exception.js +++ b/lib/types/Exception.js @@ -1,6 +1,6 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -exports.makeException = exports.StartPayFailure = exports.RefundExceedMax = exports.ExternalPayUtilException = void 0; +exports.makeException = exports.StartPayFailure = exports.PayUnRefundable = exports.RefundExceedMax = exports.ExternalPayUtilException = void 0; const tslib_1 = require("tslib"); const types_1 = require("oak-domain/lib/types"); const DependentExceptions_1 = tslib_1.__importDefault(require("./DependentExceptions")); @@ -21,10 +21,16 @@ class ExternalPayUtilException extends types_1.OakException { exports.ExternalPayUtilException = ExternalPayUtilException; class RefundExceedMax extends types_1.OakException { constructor(message) { - super(message || '可退款的总额不足'); + super(message || 'error::refund.create.exceedMax'); } } exports.RefundExceedMax = RefundExceedMax; +class PayUnRefundable extends types_1.OakException { + constructor(message) { + super(message || 'error::refund.create.payUnrefundable'); + } +} +exports.PayUnRefundable = PayUnRefundable; class StartPayFailure extends types_1.OakException { constructor(message) { super(message); diff --git a/package.json b/package.json index 0f25a5e0..5e3ccfb3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "oak-pay-business", - "version": "2.5.1", + "version": "2.5.2", "description": "", "files": [ "lib/**/*", @@ -29,9 +29,9 @@ "dependencies": { "classnames": "^2.3.1", "dayjs": "^1.11.5", - "oak-domain": "^5.1.2", - "oak-frontend-base": "^5.3.10", - "oak-general-business": "~5.5.1", + "oak-domain": "^5.1.5", + "oak-frontend-base": "^5.3.13", + "oak-general-business": "~5.5.3", "wechat-pay-nodejs": "^0.2.3" }, "peerDependencies": { diff --git a/src/configuration/attrUpdateMatrix.ts b/src/configuration/attrUpdateMatrix.ts index a8f041c9..854ef114 100644 --- a/src/configuration/attrUpdateMatrix.ts +++ b/src/configuration/attrUpdateMatrix.ts @@ -49,7 +49,7 @@ const attrUpdateMatrix: AttrUpdateMatrix = { actions: ['refundPartially', 'refundAll'], }, refundable: { - actions: ['succeedPaying', 'closeRefund'], + actions: ['succeedPaying', 'closeRefund', 'stopRefunding', 'refundPartially'], }, forbidRefundAt: { actions: ['succeedPaying'], diff --git a/src/data/i18n.ts b/src/data/i18n.ts index 60229a5c..da1bde0c 100644 --- a/src/data/i18n.ts +++ b/src/data/i18n.ts @@ -800,7 +800,9 @@ const i18ns: I18n[] = [ }, "refund": { "create": { - "hasAnotherRefunding": "您有一笔退款正在进行中" + "hasAnotherRefunding": "您有一笔退款正在进行中", + "exceedMax": "退款额度大于可用值", + "payUnrefundable": "支付已经不可退款" } } } diff --git a/src/locales/error/zh-CN.json b/src/locales/error/zh-CN.json index 6598a357..cc5f0874 100644 --- a/src/locales/error/zh-CN.json +++ b/src/locales/error/zh-CN.json @@ -19,7 +19,9 @@ }, "refund": { "create": { - "hasAnotherRefunding": "您有一笔退款正在进行中" + "hasAnotherRefunding": "您有一笔退款正在进行中", + "exceedMax": "退款额度大于可用值", + "payUnrefundable": "支付已经不可退款" } } } \ No newline at end of file diff --git a/src/triggers/pay.ts b/src/triggers/pay.ts index 8d97bac3..3178394b 100644 --- a/src/triggers/pay.ts +++ b/src/triggers/pay.ts @@ -56,8 +56,7 @@ async function changeOrderStateByPay( break; } } - if (paid && iState === 'paid') { - //已支付完成的订单的paid + if (paid) { //对iState是否为paid的判断会影响退款,先去掉 payPaid += paid; } if (refunded) { @@ -85,7 +84,7 @@ async function changeOrderStateByPay( } } else if (hasRefunding) { - assert(!hasPaying && payPaid === orderPrice && payPaid === orderPaid && payRefunded < orderPrice); + assert(!hasPaying && payPaid === orderPrice && payRefunded < orderPrice); if (orderIState !== 'refunding' || orderRefunded !== payRefunded) { await context.operate('order', { id: await generateNewIdAsync(), @@ -292,7 +291,7 @@ const triggers: Trigger[] = [ priority: 99, fn: async ({ operation }, context, option) => { const { data, filter, action, id } = operation as EntityDict['pay']['Update']; - + const pays = await context.select('pay', { data: { id: 1, @@ -313,10 +312,10 @@ const triggers: Trigger[] = [ }, filter, }, { dontCollect: true }); - + for (const pay of pays) { const { orderId, depositId, iState, deposit, application } = pay; - + context.saveOperationToEvent(id, `${DATA_SUBSCRIBER_KEYS.payStateChanged}-${filter!.id!}`); if (orderId) { await changeOrderStateByPay({ id: orderId }, context, option); @@ -366,11 +365,11 @@ const triggers: Trigger[] = [ for (const pay of pays) { const { applicationId, entity, entityId, iState, depositId } = pay; assert(iState === 'unpaid' || iState === 'paying'); - + if (iState === 'paying') { const payClazz = await getPayClazz(entity!, entityId!, context); await payClazz.close(pay as EntityDict['pay']['OpSchema']); - + cnt++; } if (depositId) { @@ -552,18 +551,7 @@ const triggers: Trigger[] = [ action: 'create', } ]; - await context.operate('deposit', { - id: await generateNewIdAsync(), - action: 'succeed', - data: { - accountOper$entity: accountOpers, - }, - filter: { - id: depositId, - }, - }, {}); - cnt++; if (loss > 0) { // 如果有loss就充入system的account账户 const [account] = await context.select('account', { @@ -589,6 +577,20 @@ const triggers: Trigger[] = [ cnt++; } + + await context.operate('deposit', { + id: await generateNewIdAsync(), + action: 'succeed', + data: { + accountOper$entity: accountOpers, + }, + filter: { + id: depositId, + }, + }, {}); + + cnt++; + } return cnt; @@ -673,7 +675,7 @@ const triggers: Trigger[] = [ availPlus: pay.paid!, }, }, {}); - cnt ++; + cnt++; } else { cnt += await tryCompleteAccountPay(pay.id!, context); diff --git a/src/triggers/refund.ts b/src/triggers/refund.ts index 4c0f2f45..1387868a 100644 --- a/src/triggers/refund.ts +++ b/src/triggers/refund.ts @@ -6,7 +6,7 @@ import { BRC } from '../types/RuntimeCxt'; import { getAccountEntity, getPayClazz } from '../utils/payClazz'; import assert from 'assert'; import { updateWithdrawState } from './withdraw'; - +import { RefundExceedMax, PayUnRefundable } from '@project/types/Exception'; /** * 开始退款的逻辑 * @param context @@ -21,6 +21,9 @@ async function startRefunding(context: BRC, data: EntityDict['refund']['CreateSi paid: 1, refunded: 1, iState: 1, + entity: 1, + entityId: 1, + refundable: 1, deposit: { id: 1, accountId: 1, @@ -36,10 +39,32 @@ async function startRefunding(context: BRC, data: EntityDict['refund']['CreateSi }, { dontCollect: true }); const { paid, refunded, deposit, order } = pay; - assert(paid! - refunded! >= data.price!); + if (paid! - refunded! < data.price!) { + throw new RefundExceedMax(); + } + if (!pay.refundable) { + throw new PayUnRefundable(); + } if (deposit) { - // 是提现,其Account相应的计算在withdraw进行 - assert(data.withdrawId!); + // 充值不可能从account渠道支付 + assert(pay.entity !== 'account'); + if (!data.withdrawId && !order?.id) { + //充值退款需创建关联的accountOper,若为提现则在withdraw中创建 + data.accountOper$entity = [ + { + id: await generateNewIdAsync(), + action: 'create', + data: { + id: await generateNewIdAsync(), + accountId: deposit.accountId, + type: 'refund', + totalPlus: -data.price!, + availPlus: -data.price!, + refundablePlus: -data.price!, + }, + } + ] + } } else { assert(order); @@ -138,26 +163,46 @@ async function succeedRefunding(context: BRC, refundId: string) { } }, {}); - const payClazz = await getPayClazz(entity!, entityId!, context); - // 实际执行的退款的额度应该是price - loss - const [delta, sysAccountEntity, sysAccountEntityId] = payClazz.calcRefundTax(refundPrice - refundLoss!); - // sysAccount上减掉实际退款的额度-税费 - await context.operate('sysAccountOper', { - id: await generateNewIdAsync(), - action: 'create', - data: { + let d = undefined; //退回至account的退款无渠道退款补偿 + if (entity === 'account') { + //退回至account中的退款,创建accountOper,更新account余额 + await context.operate('accountOper', { id: await generateNewIdAsync(), - delta: refundLoss! - refundPrice! - delta!, - entity: sysAccountEntity, - entityId: sysAccountEntityId, - refundId: refund.id, - type: 'refund', - } - }, {}); + action: 'create', + data: { + id: await generateNewIdAsync(), + accountId: pay!.entityId!, + entity: 'refund', + entityId: refund.id, + type: 'consumeBack', + totalPlus: refundPrice! - refundLoss!, + availPlus: refundPrice! - refundLoss!, + } + }, {}); + } else { + //订单退回至非account的退款会使得系统对应账户的资金发生流出 + const payClazz = await getPayClazz(entity!, entityId!, context); + // 实际执行的退款的额度应该是price - loss + const [delta, sysAccountEntity, sysAccountEntityId] = payClazz.calcRefundTax(refundPrice - refundLoss!); + // sysAccount上减掉实际退款的额度-税费 + await context.operate('sysAccountOper', { + id: await generateNewIdAsync(), + action: 'create', + data: { + id: await generateNewIdAsync(), + delta: refundLoss! - refundPrice! - delta!, + entity: sysAccountEntity, + entityId: sysAccountEntityId, + refundId: refund.id, + type: 'refund', + } + }, {}); + d = delta; + } let cnt = 2; - if (refundLoss || delta) { + if (refundLoss || d) { // 如果有退回或者要缴纳的税费,进入system相关联的account账户 const [account] = await context.select('account', { data: { @@ -168,16 +213,16 @@ async function succeedRefunding(context: BRC, refundId: string) { entityId: application!.systemId!, }, }, { dontCollect: true }); - if (delta) { + if (d) { await context.operate('accountOper', { id: await generateNewIdAsync(), action: 'create', data: { id: await generateNewIdAsync(), accountId: account!.id, - type: delta < 0 ? 'taxRefund' : 'tax', - totalPlus: -delta, - availPlus: -delta, + type: d < 0 ? 'taxRefund' : 'tax', + totalPlus: -d, + availPlus: -d, entity: 'refund', entityId: refund.id!, }, diff --git a/src/types/Exception.ts b/src/types/Exception.ts index 43310960..5acd3b1e 100644 --- a/src/types/Exception.ts +++ b/src/types/Exception.ts @@ -20,7 +20,13 @@ export class ExternalPayUtilException extends OakExceptio export class RefundExceedMax extends OakException { constructor(message?: string) { - super(message || '可退款的总额不足'); + super(message || 'error::refund.create.exceedMax'); + } +} + +export class PayUnRefundable extends OakException { + constructor(message?: string) { + super(message || 'error::refund.create.payUnrefundable'); } }