import { generateNewIdAsync } from 'oak-domain/lib/utils/uuid'; 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创建后自动发货', entity: 'ship', action: 'create', when: 'commit', strict: 'makeSure', asRoot: true, check: (operation) => ['virtual', 'pickup'].includes(operation.data.type), fn: async ({ ids }, context, option) => { for (const id of ids) { const [ship] = await context.select('ship', { data: { id: 1, iState: 1, type: 1, }, filter: { id } }, { 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; }, }, { name: '当物流类的ship创建后自动下单', entity: 'ship', action: 'create', when: 'commit', strict: 'makeSure', asRoot: true, check: (operation) => ['express'].includes(operation.data.type), fn: async ({ ids }, context, option) => { assert(ids.length === 1); const id = ids[0]; const [ship] = await context.select('ship', { data: { id: 1, entity: 1, entityId: 1, shipServiceId: 1, }, filter: { id } }, { dontCollect: true, forUpdate: true }); const { entity, entityId } = ship || {}; if (entity && entityId) { const shipClazz = await getShipClazz(entity, entityId, context); const extraShipId = await shipClazz.eOrder(id, context); return { extraShipId, }; } } }, { // deposit的ship和 shipClazz中有配置wechatShip且可获取openId的order的ship entity: 'ship', name: '当虚拟的ship变为shipping状态时,调用小程序发货信息录入接口', action: 'ship', when: 'before', asRoot: true, priority: 99, fn: async ({ operation }, context) => { const { data, filter } = operation; const ships = await context.select('ship', { data: { id: 1, type: 1, deposit$ship: { $entity: 'deposit', data: { id: 1, }, }, entity: 1, entityId: 1, shipServiceId: 1, shipOrder$ship: { $entity: 'shipOrder', data: { id: 1, orderId: 1, order: { id: 1, pay$order: { $entity: 'pay', data: { id: 1, meta: 1, iState: 1, entity: 1, entityId: 1, }, filter: { iState: 'paid' } } } } }, wechatMpShip: { id: 1, applicationId: 1, } }, filter, }, {}); let cnt = 0; for (const ship of ships) { 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) { //订单 const wpPayIds = ship.shipOrder$ship?.map((ele) => ele.order).map((order) => order.pay$order).flat().filter((pay) => pay?.entity === 'wpProduct').map((ele) => ele?.id); let needUpload = false; if (wpPayIds && wpPayIds.length > 0) { const cnt = await context.count('pay', { filter: { id: { $in: wpPayIds, }, iState: { $ne: 'closed', }, wpProduct: { needReceiving: true, } } }, {}); if (cnt > 0) { needUpload = true; } } if (needUpload) { await uploadShippingInfo(shipId, context); cnt++; } } } return cnt; } }, { entity: 'ship', name: '当ship状态发生变化时,尝试向订阅者推送', action: ['ship', 'receive', 'cancel', 'reject', 'unknow', 'startReceiving', 'succeedReceiving'], when: 'after', fn: async ({ operation }, context, option) => { const { filter, id } = operation; const { id: shipId } = filter; const [ship] = await context.select('ship', { data: { id: 1, deposit$ship: { $entity: 'deposit', data: { id: 1, } }, shipOrder$ship: { $entity: 'shipOrder', data: { id: 1, orderId: 1, } } }, filter, }, {}); const { deposit$ship: deposits, shipOrder$ship: shipOrders } = ship || {}; const depositIds = deposits?.map((ele) => ele.id); const orderIds = shipOrders?.map((ele) => ele.orderId); if (shipId) { context.saveOperationToEvent(id, `${DATA_SUBSCRIBER_KEYS.shipStateChanged}-${shipId}`); } const selectionId = await generateNewIdAsync(); await context.select('ship', { id: selectionId, data: { id: 1, iState: 1, deposit$ship: { $entity: 'deposit', data: { id: 1, iState: 1, } }, shipOrder$ship: { $entity: 'shipOrder', data: { id: 1, orderId: 1, order: { id: 1, iState: 1, } } } }, filter: { id: shipId, } }, {}); if (depositIds && depositIds.length > 0) { depositIds.forEach((depositId) => { context.saveOperationToEvent(selectionId, `${DATA_SUBSCRIBER_KEYS.shipStateChanged}-${depositId}`); }); } if (orderIds && orderIds.length > 0) { orderIds.forEach((orderId) => { context.saveOperationToEvent(selectionId, `${DATA_SUBSCRIBER_KEYS.shipStateChanged}-${orderId}`); }); } return 1; } }, { name: '当物流创建时,赋上对应的物流系统对象', entity: 'ship', action: 'create', when: 'before', priority: 75, check: (operation) => operation.data.shipOrder$ship && operation.data.shipOrder$ship.length > 0, fn: async ({ operation }, context) => { const { data } = operation; let count = 0; if (data instanceof Array) { for (const d of data) { const { shipServiceId, shipOrder$ship } = d; if (shipServiceId) { const result = await getShipEntity(shipServiceId, shipOrder$ship.map(ele => ele.data.orderId), context); if (result) { d.entity = result[0]; d.entityId = result[1]; count++; } } } } else { const { shipServiceId, shipOrder$ship } = data; if (shipServiceId) { const result = await getShipEntity(shipServiceId, shipOrder$ship.map(ele => ele.data.orderId), context); if (result) { data.entity = result[0]; data.entityId = result[1]; count++; } } } return count; } }, { name: '当物流类的ship取消后,调用外部接口取消下单', entity: 'ship', action: 'cancel', when: 'commit', strict: 'makeSure', asRoot: true, filter: { type: 'express', entity: { $exists: true, }, extraShipId: { $exists: true, }, }, fn: async ({ ids }, context, option) => { assert(ids.length === 1); const id = ids[0]; const [ship] = await context.select('ship', { data: { id: 1, entity: 1, entityId: 1, shipServiceId: 1, extraShipId: 1, }, filter: { id } }, { dontCollect: true, forUpdate: true }); const { entity, entityId, extraShipId } = ship; if (entity && entityId && extraShipId) { const shipClazz = await getShipClazz(entity, entityId, context); await shipClazz.cancelOrder(id, context); } } }, { name: '当物流类的ship签收后,调用小程序确认收货提醒', entity: 'ship', action: 'startReceiving', when: 'commit', asRoot: true, filter: { type: 'express', receiveAt: { $exists: true, } }, fn: async ({ ids }, context, option) => { assert(ids.length === 1); const id = ids[0]; const [ship] = await context.select('ship', { data: { id: 1, entity: 1, entityId: 1, shipServiceId: 1, extraShipId: 1, receiveAt: 1, shipOrder$ship: { $entity: 'shipOrder', data: { id: 1, orderId: 1, } }, wechatMpShip: { id: 1, applicationId: 1, } }, filter: { id } }, { dontCollect: true, forUpdate: true }); const { entity, entityId, extraShipId, shipOrder$ship, wechatMpShip } = ship; if (entity && entityId && extraShipId && shipOrder$ship) { const shipClazz = await getShipClazz(entity, entityId, context); const { openId } = await shipClazz.getReceiverInfo(shipOrder$ship.map((ele) => ele.orderId), wechatMpShip?.applicationId, context); if (openId) { //当存在openId时调用小程序发货信息录入 await notifyConfirmReceive(id, context); return 1; } } } }, { name: '当虚拟或受发货限制的自提ship发货后,自动开始确认收货流程', entity: 'ship', action: 'ship', when: 'commit', asRoot: true, fn: async ({ ids }, context, option) => { // assert(ids.length === 1); for (const id of ids) { const [ship] = await context.select('ship', { data: { id: 1, type: 1, receiveAt: 1, shipOrder$ship: { $entity: 'shipOrder', data: { id: 1, orderId: 1, order: { id: 1, pay$order: { $entity: 'pay', data: { id: 1, }, filter: { entity: 'wpProduct', wpProduct: { needReceiving: true } } } } } }, }, filter: { id } }, { forUpdate: true }); const { type, shipOrder$ship } = ship; const wpPay = shipOrder$ship?.map((shipOrder) => shipOrder?.order?.pay$order).flat(); if (type === 'virtual' || (type === 'pickup' && wpPay && wpPay.length > 0)) { await context.operate('ship', { id: await generateNewIdAsync(), action: 'startReceiving', data: {}, filter: { id, } }, option); } } }, }, { name: '当虚拟ship确认收货后更新deposit状态', entity: 'ship', action: 'succeedReceiving', when: 'after', asRoot: true, fn: async ({ operation }, context, option) => { const { filter, id, data } = operation; const ships = await context.select('ship', { data: { id: 1, type: 1, deposit$ship: { $entity: 'deposit', data: { id: 1, iState: 1, } } }, filter, }, { forUpdate: true }); let count = 0; for (const ship of ships) { const { type, deposit$ship: deposits } = ship; if (type === 'virtual' && deposits && deposits.length > 0) { const [deposit] = deposits; await context.operate('deposit', { id: await generateNewIdAsync(), action: 'succeed', data: {}, filter: { id: deposit.id, } }, option); count++; } } return count; }, }, ]; export default triggers;