diff --git a/es/aspects/AspectDict.d.ts b/es/aspects/AspectDict.d.ts index 5e759d15..09393ca8 100644 --- a/es/aspects/AspectDict.d.ts +++ b/es/aspects/AspectDict.d.ts @@ -15,4 +15,7 @@ export type AspectDict = { type: "html"; data: string; }>; + shipConfirmSuccess: (params: { + shipId: string; + }, context: BackendRuntimeContext) => Promise; }; diff --git a/es/aspects/index.js b/es/aspects/index.js index ac402c76..54293b0d 100644 --- a/es/aspects/index.js +++ b/es/aspects/index.js @@ -1,8 +1,9 @@ import { getWithdrawCreateData } from './withdraw'; -import { getExpressPrintInfo, getMpShipState } from './ship'; +import { getExpressPrintInfo, getMpShipState, shipConfirmSuccess } from './ship'; const aspectDict = { getMpShipState, getWithdrawCreateData, getExpressPrintInfo, + shipConfirmSuccess, }; export default aspectDict; diff --git a/es/aspects/ship.d.ts b/es/aspects/ship.d.ts index 2fbf3f4c..3959410f 100644 --- a/es/aspects/ship.d.ts +++ b/es/aspects/ship.d.ts @@ -16,3 +16,9 @@ export declare function getExpressPrintInfo(params: { type: "html"; data: string; }>; +/** + * 小程序确认收货组件成功后更新ship状态 + */ +export declare function shipConfirmSuccess(params: { + shipId: string; +}, context: BRC): Promise; diff --git a/es/aspects/ship.js b/es/aspects/ship.js index 57bc2f2e..0ccd1736 100644 --- a/es/aspects/ship.js +++ b/es/aspects/ship.js @@ -1,6 +1,7 @@ import { OakPreConditionUnsetException } from 'oak-domain/lib/types'; import { getOrderShipState } from '../utils/ship'; import { getShipClazz } from '../utils/shipClazz'; +import { generateNewIdAsync } from 'oak-domain/lib/utils/uuid'; /** * 获取小程序订单发货状态 * @param params @@ -39,3 +40,42 @@ export async function getExpressPrintInfo(params, context) { const clazz = await getShipClazz(entity, entityId, context); return await clazz.getPrintInfo(shipId, context); } +/** + * 小程序确认收货组件成功后更新ship状态 + */ +export async function shipConfirmSuccess(params, context) { + const application = context.getApplication(); + const { type, } = application; + if (type === 'wechatMp') { + try { + const { shipId } = params; + const shipState = await getOrderShipState(context, shipId); + if (shipState === 'received') { + //微信端已确认收货 + const [ship] = await context.select('ship', { + data: { + id: 1, + iState: 1, + }, filter: { + id: shipId, + } + }, { forUpdate: true }); + if (ship.iState === 'receiving') { + await context.operate('ship', { + id: await generateNewIdAsync(), + action: 'succeedReceiving', + data: {}, + filter: { + id: shipId, + }, + }, {}); + return true; + } + } + } + catch (err) { + return false; + } + } + return false; +} diff --git a/es/components/AbstractComponents.d.ts b/es/components/AbstractComponents.d.ts index 0c48143a..f19453d9 100644 --- a/es/components/AbstractComponents.d.ts +++ b/es/components/AbstractComponents.d.ts @@ -21,13 +21,8 @@ declare const List: (props: ReactComponentProps(props: { tablePagination?: any; rowSelection?: any; disableSerialNumber?: boolean | undefined; - size?: "small" | "middle" | "large" | undefined; + size?: "small" | "large" | "middle" | undefined; scroll?: any; empty?: any; opWidth?: number | undefined; diff --git a/es/components/account/detail/index.js b/es/components/account/detail/index.js index 78ba9b92..d96618b1 100644 --- a/es/components/account/detail/index.js +++ b/es/components/account/detail/index.js @@ -347,30 +347,43 @@ export default OakComponent({ }, success: async () => { console.log('success'); - const { result: mpShipState } = await this.features.cache.exec('getMpShipState', { + // const { result: mpShipState } = await this.features.cache.exec('getMpShipState', { + // shipId: ship.id, + // }) + // if (mpShipState === 'received') { + // await this.features.cache.operate('ship', + // [{ + // id: await generateNewIdAsync(), + // action: 'succeedReceiving', + // data: {}, + // filter: { + // id: ship.id, + // }, + // }] + // ); + // this.setMessage({ + // type: 'success', + // content: this.t('ship.success') + // }); + // } else { + // console.log(mpShipState); + // this.reRender(); + // // this.setMessage({ + // // type: 'warning', + // // content: this.t('ship.wait'), + // // }) + // } + const { result } = await this.features.cache.exec('shipConfirmSuccess', { shipId: ship.id, }); - if (mpShipState === 'received') { - await this.features.cache.operate('ship', [{ - id: await generateNewIdAsync(), - action: 'succeedReceiving', - data: {}, - filter: { - id: ship.id, - }, - }]); + if (result) { this.setMessage({ type: 'success', content: this.t('ship.success') }); } else { - console.log(mpShipState); this.reRender(); - // this.setMessage({ - // type: 'warning', - // content: this.t('ship.wait'), - // }) } }, fail: () => { diff --git a/es/components/pay/detail/index.js b/es/components/pay/detail/index.js index 3ac6d3c4..74465426 100644 --- a/es/components/pay/detail/index.js +++ b/es/components/pay/detail/index.js @@ -360,30 +360,43 @@ export default OakComponent({ }, success: async () => { console.log('success'); - const { result: mpShipState } = await this.features.cache.exec('getMpShipState', { + // const { result: mpShipState } = await this.features.cache.exec('getMpShipState', { + // shipId, + // }) + // if (mpShipState === 'received') { + // await this.features.cache.operate('ship', + // [{ + // id: await generateNewIdAsync(), + // action: 'succeedReceiving', + // data: {}, + // filter: { + // id: shipId, + // }, + // }] + // ); + // this.reRender(); + // this.setMessage({ + // type: 'success', + // content: this.t('ship.success') + // }); + // } else { + // console.log(mpShipState); + // // this.setMessage({ + // // type: 'warning', + // // content: this.t('ship.wait'), + // // }) + // this.reRender(); + // } + const { result } = await this.features.cache.exec('shipConfirmSuccess', { shipId, }); - if (mpShipState === 'received') { - await this.features.cache.operate('ship', [{ - id: await generateNewIdAsync(), - action: 'succeedReceiving', - data: {}, - filter: { - id: shipId, - }, - }]); - this.reRender(); + if (result) { this.setMessage({ type: 'success', content: this.t('ship.success') }); } else { - console.log(mpShipState); - // this.setMessage({ - // type: 'warning', - // content: this.t('ship.wait'), - // }) this.reRender(); } }, @@ -422,16 +435,27 @@ export default OakComponent({ const unsub = await this.subDataEvents([ `${DATA_SUBSCRIBER_KEYS.payStateChanged}-${oakId}`, `${DATA_SUBSCRIBER_KEYS.depositStateChanged}-${oakId}` - ]); + ], async (event, opRecords) => { + for (const record of opRecords) { + console.log(record); + if (record.e === 'pay' || record.e === 'deposit') { + const { f } = record; + const [pay] = this.features.cache.get('pay', { + data: baseProjection, + filter: f, + }); + console.log(JSON.stringify(pay)); + } + } + }); + let depositUnsub = undefined; const { depositId } = this.state; if (depositId) { - const depositUnsub = await this.subDataEvents([`${DATA_SUBSCRIBER_KEYS.shipStateChanged}-${depositId}`]); - this.setState({ - depositUnsub, - }); + depositUnsub = await this.subDataEvents([`${DATA_SUBSCRIBER_KEYS.shipStateChanged}-${depositId}`]); } this.setState({ unsub, + depositUnsub, }); }, async mature() { diff --git a/es/timers/ship.js b/es/timers/ship.js index ea9793c6..19d83358 100644 --- a/es/timers/ship.js +++ b/es/timers/ship.js @@ -8,7 +8,7 @@ const timers = [ filter: { type: 'express', iState: { - $nin: ['received', 'cancelled', 'rejected', 'receiving'], + $nin: ['received', 'cancelled', 'rejected', 'receiving', 'unshipped'], }, entity: { $exists: true @@ -41,7 +41,7 @@ const timers = [ }, { name: '同步微信小程序虚拟、自提ship状态', - cron: '0 0/2 * * * ?', + cron: '0 * * * * ?', entity: 'ship', filter: { type: { @@ -53,6 +53,7 @@ const timers = [ }, projection: { id: 1, + iState: 1, }, fn: async (context, data) => { const results = []; @@ -68,21 +69,21 @@ const timers = [ return results.reduce((prev, cur) => mergeOperationResult(prev, cur)); }, }, - { - name: '对虚拟或自提类型的ship自动发货', - cron: '0 * * * * ?', - entity: 'ship', - filter: { - type: { - $in: ['virtual', 'pickup'], - }, - iState: 'unshipped', - }, - projection: { - id: 1, - }, - action: 'ship', - actionData: {}, - }, + // { + // name: '对虚拟或自提类型的ship自动发货', + // cron: '0 * * * * ?', + // entity: 'ship', + // filter: { + // type: { + // $in: ['virtual', 'pickup'], + // }, + // iState: 'unshipped', + // }, + // projection: { + // id: 1, + // }, + // action: 'ship', + // actionData: {}, + // }, ]; export default timers; diff --git a/es/triggers/ship.js b/es/triggers/ship.js index 9d384c4e..ba8045d6 100644 --- a/es/triggers/ship.js +++ b/es/triggers/ship.js @@ -3,6 +3,7 @@ import { DATA_SUBSCRIBER_KEYS } from '../config/constants'; import assert from 'assert'; import { getShipClazz, getShipEntity } from '../utils/shipClazz'; import { notifyConfirmReceive, uploadShippingInfo } from '../utils/ship'; +import { promisify } from 'util'; const triggers = [ { name: '当虚拟或自提类型的ship创建后自动发货', @@ -14,14 +15,27 @@ const triggers = [ check: (operation) => ['virtual', 'pickup'].includes(operation.data.type), fn: async ({ ids }, context, option) => { for (const id of ids) { - await context.operate('ship', { - id: await generateNewIdAsync(), - action: 'ship', - data: {}, + const [ship] = await context.select('ship', { + data: { + id: 1, + iState: 1, + type: 1, + }, filter: { - id, + id } - }, option); + }, { dontCollect: true, forUpdate: true }); + const { iState, type } = ship; + if (iState && ['unshipped', 'unknown'].includes(iState) && type && ['virtual', 'pickup'].includes(type)) { + await context.operate('ship', { + id: await generateNewIdAsync(), + action: 'ship', + data: {}, + filter: { + id, + } + }, option); + } } return; }, @@ -48,7 +62,7 @@ const triggers = [ id } }, { dontCollect: true, forUpdate: true }); - const { entity, entityId } = ship; + const { entity, entityId } = ship || {}; if (entity && entityId) { const shipClazz = await getShipClazz(entity, entityId, context); const extraShipId = await shipClazz.eOrder(id, context); @@ -116,6 +130,9 @@ const triggers = [ const { id: shipId, type, deposit$ship: deposits, shipOrder$ship, shipServiceId, entity, entityId, wechatMpShip } = ship || {}; if (deposits && deposits.length > 0) { //充值 (此时该充值必定为受发货限制的小程序上的充值) + //等待5秒以避免小程序订单号查询不到 + const sleep = promisify(setTimeout); + await sleep(5 * 1000); await uploadShippingInfo(shipId, context); cnt++; } @@ -448,49 +465,5 @@ const triggers = [ return count; }, }, - { - name: '当虚拟ship自动确认收货后更新deposit状态', - entity: 'ship', - action: 'update', - when: 'after', - asRoot: true, - fn: async ({ operation }, context, option) => { - const { filter, id, data } = operation; - const ships = await context.select('ship', { - data: { - id: 1, - iState: 1, - type: 1, - deposit$ship: { - $entity: 'deposit', - data: { - id: 1, - iState: 1, - } - } - }, - filter, - }, { forUpdate: true }); - let count = 0; - const virtualShips = ships?.filter((ele) => ele.type === 'virtual'); - if (virtualShips && virtualShips.length > 0) { - for (const ship of virtualShips) { - const deposit = ship.deposit$ship?.[0]; - if (deposit && deposit.iState === 'shipped') { - await context.operate('deposit', { - id: await generateNewIdAsync(), - action: 'succeed', - data: {}, - filter: { - id: deposit.id, - } - }, option); - count++; - } - } - } - return count; - } - }, ]; export default triggers; diff --git a/es/triggers/withdraw.d.ts b/es/triggers/withdraw.d.ts index e69f8d6e..979a44c8 100644 --- a/es/triggers/withdraw.d.ts +++ b/es/triggers/withdraw.d.ts @@ -6,6 +6,6 @@ import { BRC } from '../types/RuntimeCxt'; * @param context * @param refunds */ -export declare function updateWithdrawState(context: BRC, id: string): Promise<0 | 1>; +export declare function updateWithdrawState(context: BRC, id: string): Promise<1 | 0>; declare const triggers: Trigger[]; export default triggers; diff --git a/es/watchers/ship.js b/es/watchers/ship.js index f472a642..6738b20b 100644 --- a/es/watchers/ship.js +++ b/es/watchers/ship.js @@ -1,34 +1,34 @@ -import { mergeOperationResult } from 'oak-domain/lib/utils/operationResult'; -import { shipProjection, refreshShipState } from '../utils/ship'; const QUERY_PAYING_STATE_GAP = process.env.NODE_ENV === 'production' ? 3600 * 1000 : 60 * 1000; const watchers = [ - { - name: '对shipping状态的物流,同步其真实状态', - entity: 'ship', - filter: async () => { - const now = Date.now(); - return { - type: 'express', - iState: 'shipping', - $$updateAt$$: { - $lte: now - QUERY_PAYING_STATE_GAP, - }, - }; - }, - projection: shipProjection, - fn: async (context, data) => { - const results = []; - for (const ship of data) { - const result = await refreshShipState(ship.id, context); - if (result) { - results.push(result); - } - } - if (results.length === 0) { - return {}; - } - return results.reduce((prev, cur) => mergeOperationResult(prev, cur)); - } - } +// { +// name: '对shipping状态的物流,同步其真实状态', +// entity: 'ship', +// filter: async () => { +// const now = Date.now(); +// return { +// type: 'express', +// iState: 'shipping', +// $$updateAt$$: { +// $lte: now - QUERY_PAYING_STATE_GAP, +// }, +// }; +// }, +// projection: shipProjection, +// fn: async (context, data) => { +// const results = [] as OperationResult[]; +// for (const ship of data) { +// const result = await refreshShipState(ship.id!, context); +// if (result) { +// results.push(result); +// } +// } +// if (results.length === 0) { +// return {}; +// } +// return results.reduce( +// (prev, cur) => mergeOperationResult(prev, cur) +// ); +// } +// } ]; export default watchers; diff --git a/lib/aspects/AspectDict.d.ts b/lib/aspects/AspectDict.d.ts index 5e759d15..09393ca8 100644 --- a/lib/aspects/AspectDict.d.ts +++ b/lib/aspects/AspectDict.d.ts @@ -15,4 +15,7 @@ export type AspectDict = { type: "html"; data: string; }>; + shipConfirmSuccess: (params: { + shipId: string; + }, context: BackendRuntimeContext) => Promise; }; diff --git a/lib/aspects/index.js b/lib/aspects/index.js index 80124c34..457b1758 100644 --- a/lib/aspects/index.js +++ b/lib/aspects/index.js @@ -6,5 +6,6 @@ const aspectDict = { getMpShipState: ship_1.getMpShipState, getWithdrawCreateData: withdraw_1.getWithdrawCreateData, getExpressPrintInfo: ship_1.getExpressPrintInfo, + shipConfirmSuccess: ship_1.shipConfirmSuccess, }; exports.default = aspectDict; diff --git a/lib/aspects/ship.d.ts b/lib/aspects/ship.d.ts index 2fbf3f4c..3959410f 100644 --- a/lib/aspects/ship.d.ts +++ b/lib/aspects/ship.d.ts @@ -16,3 +16,9 @@ export declare function getExpressPrintInfo(params: { type: "html"; data: string; }>; +/** + * 小程序确认收货组件成功后更新ship状态 + */ +export declare function shipConfirmSuccess(params: { + shipId: string; +}, context: BRC): Promise; diff --git a/lib/aspects/ship.js b/lib/aspects/ship.js index 1db56038..58c7963f 100644 --- a/lib/aspects/ship.js +++ b/lib/aspects/ship.js @@ -1,9 +1,10 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -exports.getExpressPrintInfo = exports.getMpShipState = void 0; +exports.shipConfirmSuccess = exports.getExpressPrintInfo = exports.getMpShipState = void 0; const types_1 = require("oak-domain/lib/types"); const ship_1 = require("../utils/ship"); const shipClazz_1 = require("../utils/shipClazz"); +const uuid_1 = require("oak-domain/lib/utils/uuid"); /** * 获取小程序订单发货状态 * @param params @@ -44,3 +45,43 @@ async function getExpressPrintInfo(params, context) { return await clazz.getPrintInfo(shipId, context); } exports.getExpressPrintInfo = getExpressPrintInfo; +/** + * 小程序确认收货组件成功后更新ship状态 + */ +async function shipConfirmSuccess(params, context) { + const application = context.getApplication(); + const { type, } = application; + if (type === 'wechatMp') { + try { + const { shipId } = params; + const shipState = await (0, ship_1.getOrderShipState)(context, shipId); + if (shipState === 'received') { + //微信端已确认收货 + const [ship] = await context.select('ship', { + data: { + id: 1, + iState: 1, + }, filter: { + id: shipId, + } + }, { forUpdate: true }); + if (ship.iState === 'receiving') { + await context.operate('ship', { + id: await (0, uuid_1.generateNewIdAsync)(), + action: 'succeedReceiving', + data: {}, + filter: { + id: shipId, + }, + }, {}); + return true; + } + } + } + catch (err) { + return false; + } + } + return false; +} +exports.shipConfirmSuccess = shipConfirmSuccess; diff --git a/lib/timers/ship.js b/lib/timers/ship.js index 890868d3..d5c151e8 100644 --- a/lib/timers/ship.js +++ b/lib/timers/ship.js @@ -10,7 +10,7 @@ const timers = [ filter: { type: 'express', iState: { - $nin: ['received', 'cancelled', 'rejected', 'receiving'], + $nin: ['received', 'cancelled', 'rejected', 'receiving', 'unshipped'], }, entity: { $exists: true @@ -43,7 +43,7 @@ const timers = [ }, { name: '同步微信小程序虚拟、自提ship状态', - cron: '0 0/2 * * * ?', + cron: '0 * * * * ?', entity: 'ship', filter: { type: { @@ -55,6 +55,7 @@ const timers = [ }, projection: { id: 1, + iState: 1, }, fn: async (context, data) => { const results = []; @@ -70,21 +71,21 @@ const timers = [ return results.reduce((prev, cur) => (0, operationResult_1.mergeOperationResult)(prev, cur)); }, }, - { - name: '对虚拟或自提类型的ship自动发货', - cron: '0 * * * * ?', - entity: 'ship', - filter: { - type: { - $in: ['virtual', 'pickup'], - }, - iState: 'unshipped', - }, - projection: { - id: 1, - }, - action: 'ship', - actionData: {}, - }, + // { + // name: '对虚拟或自提类型的ship自动发货', + // cron: '0 * * * * ?', + // entity: 'ship', + // filter: { + // type: { + // $in: ['virtual', 'pickup'], + // }, + // iState: 'unshipped', + // }, + // projection: { + // id: 1, + // }, + // action: 'ship', + // actionData: {}, + // }, ]; exports.default = timers; diff --git a/lib/triggers/ship.js b/lib/triggers/ship.js index 6bfa9c00..34e69655 100644 --- a/lib/triggers/ship.js +++ b/lib/triggers/ship.js @@ -6,6 +6,7 @@ const constants_1 = require("../config/constants"); const assert_1 = tslib_1.__importDefault(require("assert")); const shipClazz_1 = require("../utils/shipClazz"); const ship_1 = require("../utils/ship"); +const util_1 = require("util"); const triggers = [ { name: '当虚拟或自提类型的ship创建后自动发货', @@ -17,14 +18,27 @@ const triggers = [ check: (operation) => ['virtual', 'pickup'].includes(operation.data.type), fn: async ({ ids }, context, option) => { for (const id of ids) { - await context.operate('ship', { - id: await (0, uuid_1.generateNewIdAsync)(), - action: 'ship', - data: {}, + const [ship] = await context.select('ship', { + data: { + id: 1, + iState: 1, + type: 1, + }, filter: { - id, + id } - }, option); + }, { dontCollect: true, forUpdate: true }); + const { iState, type } = ship; + if (iState && ['unshipped', 'unknown'].includes(iState) && type && ['virtual', 'pickup'].includes(type)) { + await context.operate('ship', { + id: await (0, uuid_1.generateNewIdAsync)(), + action: 'ship', + data: {}, + filter: { + id, + } + }, option); + } } return; }, @@ -51,7 +65,7 @@ const triggers = [ id } }, { dontCollect: true, forUpdate: true }); - const { entity, entityId } = ship; + const { entity, entityId } = ship || {}; if (entity && entityId) { const shipClazz = await (0, shipClazz_1.getShipClazz)(entity, entityId, context); const extraShipId = await shipClazz.eOrder(id, context); @@ -119,6 +133,9 @@ const triggers = [ const { id: shipId, type, deposit$ship: deposits, shipOrder$ship, shipServiceId, entity, entityId, wechatMpShip } = ship || {}; if (deposits && deposits.length > 0) { //充值 (此时该充值必定为受发货限制的小程序上的充值) + //等待5秒以避免小程序订单号查询不到 + const sleep = (0, util_1.promisify)(setTimeout); + await sleep(5 * 1000); await (0, ship_1.uploadShippingInfo)(shipId, context); cnt++; } @@ -451,49 +468,5 @@ const triggers = [ return count; }, }, - { - name: '当虚拟ship自动确认收货后更新deposit状态', - entity: 'ship', - action: 'update', - when: 'after', - asRoot: true, - fn: async ({ operation }, context, option) => { - const { filter, id, data } = operation; - const ships = await context.select('ship', { - data: { - id: 1, - iState: 1, - type: 1, - deposit$ship: { - $entity: 'deposit', - data: { - id: 1, - iState: 1, - } - } - }, - filter, - }, { forUpdate: true }); - let count = 0; - const virtualShips = ships?.filter((ele) => ele.type === 'virtual'); - if (virtualShips && virtualShips.length > 0) { - for (const ship of virtualShips) { - const deposit = ship.deposit$ship?.[0]; - if (deposit && deposit.iState === 'shipped') { - await context.operate('deposit', { - id: await (0, uuid_1.generateNewIdAsync)(), - action: 'succeed', - data: {}, - filter: { - id: deposit.id, - } - }, option); - count++; - } - } - } - return count; - } - }, ]; exports.default = triggers; diff --git a/lib/triggers/withdraw.d.ts b/lib/triggers/withdraw.d.ts index e69f8d6e..979a44c8 100644 --- a/lib/triggers/withdraw.d.ts +++ b/lib/triggers/withdraw.d.ts @@ -6,6 +6,6 @@ import { BRC } from '../types/RuntimeCxt'; * @param context * @param refunds */ -export declare function updateWithdrawState(context: BRC, id: string): Promise<0 | 1>; +export declare function updateWithdrawState(context: BRC, id: string): Promise<1 | 0>; declare const triggers: Trigger[]; export default triggers; diff --git a/lib/watchers/ship.js b/lib/watchers/ship.js index b3a587b8..d2d1294f 100644 --- a/lib/watchers/ship.js +++ b/lib/watchers/ship.js @@ -1,36 +1,36 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const operationResult_1 = require("oak-domain/lib/utils/operationResult"); -const ship_1 = require("../utils/ship"); const QUERY_PAYING_STATE_GAP = process.env.NODE_ENV === 'production' ? 3600 * 1000 : 60 * 1000; const watchers = [ - { - name: '对shipping状态的物流,同步其真实状态', - entity: 'ship', - filter: async () => { - const now = Date.now(); - return { - type: 'express', - iState: 'shipping', - $$updateAt$$: { - $lte: now - QUERY_PAYING_STATE_GAP, - }, - }; - }, - projection: ship_1.shipProjection, - fn: async (context, data) => { - const results = []; - for (const ship of data) { - const result = await (0, ship_1.refreshShipState)(ship.id, context); - if (result) { - results.push(result); - } - } - if (results.length === 0) { - return {}; - } - return results.reduce((prev, cur) => (0, operationResult_1.mergeOperationResult)(prev, cur)); - } - } +// { +// name: '对shipping状态的物流,同步其真实状态', +// entity: 'ship', +// filter: async () => { +// const now = Date.now(); +// return { +// type: 'express', +// iState: 'shipping', +// $$updateAt$$: { +// $lte: now - QUERY_PAYING_STATE_GAP, +// }, +// }; +// }, +// projection: shipProjection, +// fn: async (context, data) => { +// const results = [] as OperationResult[]; +// for (const ship of data) { +// const result = await refreshShipState(ship.id!, context); +// if (result) { +// results.push(result); +// } +// } +// if (results.length === 0) { +// return {}; +// } +// return results.reduce( +// (prev, cur) => mergeOperationResult(prev, cur) +// ); +// } +// } ]; exports.default = watchers; diff --git a/src/aspects/AspectDict.ts b/src/aspects/AspectDict.ts index 7b5aefd7..00dd7e18 100644 --- a/src/aspects/AspectDict.ts +++ b/src/aspects/AspectDict.ts @@ -13,4 +13,7 @@ export type AspectDict = { getExpressPrintInfo: (params: { shipId: string; }, context: BackendRuntimeContext) => Promise<{ type: "html", data: string }>; + shipConfirmSuccess: (params: { + shipId: string; + }, context: BackendRuntimeContext) => Promise; }; diff --git a/src/aspects/index.ts b/src/aspects/index.ts index 5c9a0739..15d73094 100644 --- a/src/aspects/index.ts +++ b/src/aspects/index.ts @@ -1,12 +1,13 @@ import { EntityDict } from '../oak-app-domain'; import { AspectDict } from './AspectDict'; import { getWithdrawCreateData } from './withdraw'; -import { getExpressPrintInfo, getMpShipState } from './ship'; +import { getExpressPrintInfo, getMpShipState, shipConfirmSuccess } from './ship'; const aspectDict = { getMpShipState, getWithdrawCreateData, getExpressPrintInfo, + shipConfirmSuccess, } as AspectDict; export default aspectDict; diff --git a/src/aspects/ship.ts b/src/aspects/ship.ts index 5c6e5da9..8fabb19d 100644 --- a/src/aspects/ship.ts +++ b/src/aspects/ship.ts @@ -4,6 +4,7 @@ import { BRC } from '../types/RuntimeCxt'; import assert from 'assert'; import { getOrderShipState } from '../utils/ship'; import { getShipClazz } from '../utils/shipClazz'; +import { generateNewIdAsync } from 'oak-domain/lib/utils/uuid'; /** * 获取小程序订单发货状态 @@ -61,4 +62,54 @@ export async function getExpressPrintInfo( } const clazz = await getShipClazz(entity, entityId, context); return await clazz.getPrintInfo(shipId, context); +} + +/** + * 小程序确认收货组件成功后更新ship状态 + */ +export async function shipConfirmSuccess( + params: { + shipId: string, + }, + context: BRC, +) { + const application = context.getApplication(); + const { type, } = application!; + if (type === 'wechatMp') { + try { + + const { shipId } = params; + const shipState = await getOrderShipState( + context, + shipId, + ) as EntityDict['ship']['Schema']['iState']; + if (shipState === 'received') { + //微信端已确认收货 + const [ship] = await context.select('ship', { + data: { + id: 1, + iState: 1, + + }, filter: { + id: shipId, + } + }, { forUpdate: true }); + if (ship.iState === 'receiving') { + await context.operate('ship', { + id: await generateNewIdAsync(), + action: 'succeedReceiving', + data: {}, + filter: { + id: shipId, + }, + }, {}); + return true; + } + } + } + catch (err) { + return false; + } + } + return false; } \ No newline at end of file diff --git a/src/components/account/detail/index.ts b/src/components/account/detail/index.ts index 70a02c5b..0ca7a1e0 100644 --- a/src/components/account/detail/index.ts +++ b/src/components/account/detail/index.ts @@ -356,31 +356,42 @@ export default OakComponent({ }, success: async () => { console.log('success'); - const { result: mpShipState } = await this.features.cache.exec('getMpShipState', { + // const { result: mpShipState } = await this.features.cache.exec('getMpShipState', { + // shipId: ship.id, + // }) + // if (mpShipState === 'received') { + // await this.features.cache.operate('ship', + // [{ + // id: await generateNewIdAsync(), + // action: 'succeedReceiving', + // data: {}, + // filter: { + // id: ship.id, + // }, + // }] + // ); + // this.setMessage({ + // type: 'success', + // content: this.t('ship.success') + // }); + // } else { + // console.log(mpShipState); + // this.reRender(); + // // this.setMessage({ + // // type: 'warning', + // // content: this.t('ship.wait'), + // // }) + // } + const { result } = await this.features.cache.exec('shipConfirmSuccess', { shipId: ship.id, }) - if (mpShipState === 'received') { - await this.features.cache.operate('ship', - [{ - id: await generateNewIdAsync(), - action: 'succeedReceiving', - data: {}, - filter: { - id: ship.id, - }, - }] - ); + if (result) { this.setMessage({ type: 'success', content: this.t('ship.success') }); } else { - console.log(mpShipState); this.reRender(); - // this.setMessage({ - // type: 'warning', - // content: this.t('ship.wait'), - // }) } }, fail: () => { diff --git a/src/components/pay/detail/index.ts b/src/components/pay/detail/index.ts index 4180a864..1beb9900 100644 --- a/src/components/pay/detail/index.ts +++ b/src/components/pay/detail/index.ts @@ -393,31 +393,42 @@ export default OakComponent({ }, success: async () => { console.log('success'); - const { result: mpShipState } = await this.features.cache.exec('getMpShipState', { + // const { result: mpShipState } = await this.features.cache.exec('getMpShipState', { + // shipId, + // }) + // if (mpShipState === 'received') { + // await this.features.cache.operate('ship', + // [{ + // id: await generateNewIdAsync(), + // action: 'succeedReceiving', + // data: {}, + // filter: { + // id: shipId, + // }, + // }] + // ); + // this.reRender(); + // this.setMessage({ + // type: 'success', + // content: this.t('ship.success') + // }); + // } else { + // console.log(mpShipState); + // // this.setMessage({ + // // type: 'warning', + // // content: this.t('ship.wait'), + // // }) + // this.reRender(); + // } + const { result } = await this.features.cache.exec('shipConfirmSuccess', { shipId, }) - if (mpShipState === 'received') { - await this.features.cache.operate('ship', - [{ - id: await generateNewIdAsync(), - action: 'succeedReceiving', - data: {}, - filter: { - id: shipId, - }, - }] - ); - this.reRender(); + if (result) { this.setMessage({ type: 'success', content: this.t('ship.success') }); } else { - console.log(mpShipState); - // this.setMessage({ - // type: 'warning', - // content: this.t('ship.wait'), - // }) this.reRender(); } }, @@ -454,17 +465,28 @@ export default OakComponent({ const unsub = await this.subDataEvents([ `${DATA_SUBSCRIBER_KEYS.payStateChanged}-${oakId}`, `${DATA_SUBSCRIBER_KEYS.depositStateChanged}-${oakId}` - ]); + ], async (event: string, opRecords: OpRecord[]) => { + for (const record of opRecords) { + console.log(record); + if ((record as any).e === 'pay' || (record as any).e === 'deposit') { + const { f } = record as any; + const [pay] = this.features.cache.get('pay', { + data: baseProjection, + filter: f, + }) + console.log(JSON.stringify(pay)); + } + } + }); + let depositUnsub = undefined; const { depositId } = this.state; if (depositId) { - const depositUnsub = await this.subDataEvents([`${DATA_SUBSCRIBER_KEYS.shipStateChanged}-${depositId}`]); - this.setState({ - depositUnsub, - }) + depositUnsub = await this.subDataEvents([`${DATA_SUBSCRIBER_KEYS.shipStateChanged}-${depositId}`]); } this.setState({ unsub, + depositUnsub, }) }, async mature() { diff --git a/src/timers/ship.ts b/src/timers/ship.ts index ca57322c..27f77dbe 100644 --- a/src/timers/ship.ts +++ b/src/timers/ship.ts @@ -13,7 +13,7 @@ const timers: Array> = [ filter: { type: 'express', iState: { - $nin: ['received', 'cancelled', 'rejected', 'receiving'], + $nin: ['received', 'cancelled', 'rejected', 'receiving', 'unshipped'], }, entity: { $exists: true @@ -48,7 +48,7 @@ const timers: Array> = [ }, { name: '同步微信小程序虚拟、自提ship状态', - cron: '0 0/2 * * * ?', + cron: '0 * * * * ?', entity: 'ship', filter: { type: { @@ -60,6 +60,7 @@ const timers: Array> = [ }, projection: { id: 1, + iState: 1, }, fn: async (context, data) => { const results = [] as OperationResult[]; @@ -77,22 +78,22 @@ const timers: Array> = [ ); }, }, - { - name: '对虚拟或自提类型的ship自动发货', - cron: '0 * * * * ?', - entity: 'ship', - filter: { - type: { - $in: ['virtual', 'pickup'], - }, - iState: 'unshipped', - }, - projection: { - id: 1, - }, - action: 'ship', - actionData: {}, - }, + // { + // name: '对虚拟或自提类型的ship自动发货', + // cron: '0 * * * * ?', + // entity: 'ship', + // filter: { + // type: { + // $in: ['virtual', 'pickup'], + // }, + // iState: 'unshipped', + // }, + // projection: { + // id: 1, + // }, + // action: 'ship', + // actionData: {}, + // }, ]; export default timers; diff --git a/src/triggers/ship.ts b/src/triggers/ship.ts index 4e4b1e8d..4b0c218b 100644 --- a/src/triggers/ship.ts +++ b/src/triggers/ship.ts @@ -6,6 +6,7 @@ import { DATA_SUBSCRIBER_KEYS } from '../config/constants'; import assert from 'assert'; import { getShipClazz, getShipEntity } from '../utils/shipClazz'; import { notifyConfirmReceive, uploadShippingInfo } from '../utils/ship'; +import { promisify } from 'util'; const triggers: Trigger[] = [ { @@ -18,15 +19,28 @@ const triggers: Trigger[] = [ check: (operation: EntityDict['ship']['CreateSingle']) => ['virtual', 'pickup'].includes(operation.data.type!), fn: async ({ ids }, context, option) => { for (const id of ids) { - await context.operate('ship', { - id: await generateNewIdAsync(), - action: 'ship', + const [ship] = await context.select('ship', { data: { + id: 1, + iState: 1, + type: 1, }, filter: { - id, + id } - }, option); + }, { dontCollect: true, forUpdate: true }); + const { iState, type } = ship; + if (iState && ['unshipped', 'unknown'].includes(iState) && type && ['virtual', 'pickup'].includes(type)) { + await context.operate('ship', { + id: await generateNewIdAsync(), + action: 'ship', + data: { + }, + filter: { + id, + } + }, option); + } } return; }, @@ -55,7 +69,7 @@ const triggers: Trigger[] = [ }, { dontCollect: true, forUpdate: true }); - const { entity, entityId } = ship; + const { entity, entityId } = ship || {}; if (entity && entityId) { const shipClazz = await getShipClazz(entity, entityId, context); const extraShipId = await shipClazz.eOrder(id!, context); @@ -125,6 +139,9 @@ const triggers: Trigger[] = [ const { id: shipId, type, deposit$ship: deposits, shipOrder$ship, shipServiceId, entity, entityId, wechatMpShip } = ship || {}; if (deposits && deposits.length > 0) { //充值 (此时该充值必定为受发货限制的小程序上的充值) + //等待5秒以避免小程序订单号查询不到 + const sleep = promisify(setTimeout); + await sleep(5 * 1000); await uploadShippingInfo(shipId!, context); cnt++; } else if (shipOrder$ship && shipOrder$ship.length > 0) { @@ -465,51 +482,6 @@ const triggers: Trigger[] = [ return count; }, }, - { - name: '当虚拟ship自动确认收货后更新deposit状态', - entity: 'ship', - action: 'update', - when: 'after', - asRoot: true, - fn: async ({ operation }, context, option) => { - const { filter, id, data } = operation as EntityDict['ship']['Update']; - const ships = await context.select('ship', { - data: { - id: 1, - iState: 1, - type: 1, - deposit$ship: { - $entity: 'deposit', - data: { - id: 1, - iState: 1, - } - } - }, - filter, - }, { forUpdate: true }); - let count = 0; - const virtualShips = ships?.filter((ele) => ele.type === 'virtual'); - if (virtualShips && virtualShips.length > 0) { - for (const ship of virtualShips) { - const deposit = ship.deposit$ship?.[0]; - if (deposit && deposit.iState === 'shipped') { - await context.operate('deposit', { - id: await generateNewIdAsync(), - action: 'succeed', - data: { - }, - filter: { - id: deposit.id, - } - }, option); - count++; - } - } - } - return count; - } - }, ]; export default triggers; \ No newline at end of file diff --git a/src/watchers/ship.ts b/src/watchers/ship.ts index e361f41d..f105a2e4 100644 --- a/src/watchers/ship.ts +++ b/src/watchers/ship.ts @@ -8,37 +8,37 @@ import { shipProjection, refreshShipState } from '../utils/ship'; const QUERY_PAYING_STATE_GAP = process.env.NODE_ENV === 'production' ? 3600 * 1000 : 60 * 1000; const watchers: Watcher[] = [ - { - name: '对shipping状态的物流,同步其真实状态', - entity: 'ship', - filter: async () => { - const now = Date.now(); - return { - type: 'express', - iState: 'shipping', - $$updateAt$$: { - $lte: now - QUERY_PAYING_STATE_GAP, - }, - }; - }, - projection: shipProjection, - fn: async (context, data) => { - const results = [] as OperationResult[]; - for (const ship of data) { - const result = await refreshShipState(ship.id!, context); - if (result) { - results.push(result); - } - } + // { + // name: '对shipping状态的物流,同步其真实状态', + // entity: 'ship', + // filter: async () => { + // const now = Date.now(); + // return { + // type: 'express', + // iState: 'shipping', + // $$updateAt$$: { + // $lte: now - QUERY_PAYING_STATE_GAP, + // }, + // }; + // }, + // projection: shipProjection, + // fn: async (context, data) => { + // const results = [] as OperationResult[]; + // for (const ship of data) { + // const result = await refreshShipState(ship.id!, context); + // if (result) { + // results.push(result); + // } + // } - if (results.length === 0) { - return {}; - } - return results.reduce( - (prev, cur) => mergeOperationResult(prev, cur) - ); - } - } + // if (results.length === 0) { + // return {}; + // } + // return results.reduce( + // (prev, cur) => mergeOperationResult(prev, cur) + // ); + // } + // } ]; export default watchers; \ No newline at end of file