521 lines
17 KiB
JavaScript
521 lines
17 KiB
JavaScript
"use strict";
|
||
Object.defineProperty(exports, "__esModule", { value: true });
|
||
exports.shipProjection = void 0;
|
||
exports.maskPhone = maskPhone;
|
||
exports.uploadShippingInfo = uploadShippingInfo;
|
||
exports.getOrderShipState = getOrderShipState;
|
||
exports.refreshMpOrderShipState = refreshMpOrderShipState;
|
||
exports.refreshShipState = refreshShipState;
|
||
exports.notifyConfirmReceive = notifyConfirmReceive;
|
||
const oak_app_domain_1 = require("../oak-app-domain");
|
||
const oak_external_sdk_1 = require("oak-external-sdk");
|
||
const assert_1 = require("oak-domain/lib/utils/assert");
|
||
const uuid_1 = require("oak-domain/lib/utils/uuid");
|
||
const Exception_1 = require("../types/Exception");
|
||
const validator_1 = require("oak-domain/lib/utils/validator");
|
||
const shipClazz_1 = require("./shipClazz");
|
||
exports.shipProjection = {
|
||
id: 1,
|
||
type: 1,
|
||
iState: 1,
|
||
entity: 1,
|
||
entityId: 1,
|
||
extraShipId: 1,
|
||
shipService: {
|
||
id: 1,
|
||
name: 1,
|
||
shipCompany: {
|
||
id: 1,
|
||
name: 1,
|
||
abbr: 1,
|
||
wechatMpName: 1,
|
||
}
|
||
},
|
||
deposit$ship: {
|
||
$entity: 'deposit',
|
||
data: {
|
||
id: 1,
|
||
iState: 1,
|
||
accountId: 1,
|
||
pay$deposit: {
|
||
$entity: 'pay',
|
||
data: {
|
||
id: 1,
|
||
applicationId: 1,
|
||
application: {
|
||
id: 1,
|
||
type: 1,
|
||
config: 1,
|
||
},
|
||
price: 1,
|
||
meta: 1,
|
||
iState: 1,
|
||
entity: 1,
|
||
entityId: 1,
|
||
},
|
||
filter: {
|
||
iState: 'paid'
|
||
}
|
||
}
|
||
}
|
||
},
|
||
shipOrder$ship: {
|
||
$entity: 'shipOrder',
|
||
data: {
|
||
id: 1,
|
||
orderId: 1,
|
||
order: {
|
||
id: 1,
|
||
iState: 1,
|
||
desc: 1,
|
||
pay$order: {
|
||
$entity: 'pay',
|
||
data: {
|
||
id: 1,
|
||
applicationId: 1,
|
||
application: {
|
||
id: 1,
|
||
type: 1,
|
||
config: 1,
|
||
},
|
||
price: 1,
|
||
meta: 1,
|
||
iState: 1,
|
||
entity: 1,
|
||
entityId: 1,
|
||
},
|
||
filter: {
|
||
iState: 'paid'
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
from: {
|
||
id: 1,
|
||
detail: 1,
|
||
name: 1,
|
||
phone: 1,
|
||
area: {
|
||
id: 1,
|
||
name: 1,
|
||
parent: {
|
||
id: 1,
|
||
name: 1,
|
||
parent: {
|
||
id: 1,
|
||
name: 1,
|
||
},
|
||
},
|
||
},
|
||
},
|
||
to: {
|
||
id: 1,
|
||
detail: 1,
|
||
name: 1,
|
||
phone: 1,
|
||
area: {
|
||
id: 1,
|
||
name: 1,
|
||
parent: {
|
||
id: 1,
|
||
name: 1,
|
||
parent: {
|
||
id: 1,
|
||
name: 1,
|
||
},
|
||
},
|
||
},
|
||
},
|
||
};
|
||
/**
|
||
* 手机号掩码(130****0000)
|
||
* @param phone
|
||
*/
|
||
function maskPhone(phone) {
|
||
(0, assert_1.assert)((0, validator_1.isMobile)(phone));
|
||
const start = phone.slice(3);
|
||
const end = phone.slice(-4);
|
||
return start + '****' + end;
|
||
}
|
||
/**
|
||
* 小程序发货信息录入
|
||
* @param shipInfo
|
||
* @param context
|
||
* @returns
|
||
*/
|
||
async function uploadShippingInfo(shipId, context) {
|
||
const [ship] = await context.select('ship', {
|
||
data: exports.shipProjection,
|
||
filter: {
|
||
id: shipId,
|
||
}
|
||
}, { forUpdate: true });
|
||
const { deposit$ship: deposits, shipOrder$ship, type: shipType, extraShipId, shipService, from, to } = ship;
|
||
// assert(iState === 'unshipped'); //可更改一次发货信息
|
||
//发货信息录入前检查小程序订单发货状态
|
||
const shipState = await getOrderShipState(context, shipId);
|
||
const date = new Date();
|
||
const isoString = date.toISOString().replace('Z', ''); // 移除UTC的'Z'
|
||
// 手动添加时区偏移(例如 +08:00)
|
||
const finalFormat = `${isoString}+08:00`;
|
||
// const application = context.getApplication();
|
||
// const { type, config } = application!;
|
||
// assert(type === 'wechatMp');
|
||
// const { appId, appSecret } = config as WechatMpConfig;
|
||
// const wechatInstance = WechatSDK.getInstance(
|
||
// appId,
|
||
// 'wechatMp',
|
||
// appSecret,
|
||
// ) as WechatMpInstance;
|
||
if (deposits && deposits.length > 0 && shipState === 'unshipped') {
|
||
//充值
|
||
(0, assert_1.assert)(deposits.length === 1);
|
||
const [deposit] = deposits;
|
||
const { pay$deposit: pays, } = deposit;
|
||
const pay = pays?.[0];
|
||
const meta = pay?.meta;
|
||
const shipInfo = {
|
||
order_key: {
|
||
order_number_type: 2,
|
||
transaction_id: meta?.transaction_id,
|
||
},
|
||
logistics_type: 3,
|
||
delivery_mode: 1,
|
||
shipping_list: [
|
||
{
|
||
item_desc: '账户充值',
|
||
}
|
||
],
|
||
upload_time: finalFormat,
|
||
payer: {
|
||
openid: meta?.payer?.openid,
|
||
},
|
||
};
|
||
const { type, config } = pay?.application;
|
||
if (type === 'wechatMp') {
|
||
const { appId, appSecret } = config;
|
||
const wechatInstance = oak_external_sdk_1.WechatSDK.getInstance(appId, 'wechatMp', appSecret);
|
||
const result = await wechatInstance.uploadShippingInfo(shipInfo);
|
||
if (result?.errcode !== 0) {
|
||
console.error(JSON.stringify(result));
|
||
throw new Exception_1.UploadShipException(result);
|
||
}
|
||
}
|
||
}
|
||
else if (shipOrder$ship && shipOrder$ship.length > 0 && shipState && ['unshipped', 'shipping'].includes(shipState)) {
|
||
//订单 每笔微信支付调用一次接口
|
||
//当已发货的订单再次调用小程序发货信息录入接口视为重新发货(仅可重新发货一次)
|
||
const orders = shipOrder$ship.map((ele) => ele.order);
|
||
for (const order of orders) {
|
||
const { pay$order, desc } = order;
|
||
const wechatPay = pay$order.find((ele) => ele.entity === 'wpProduct');
|
||
const meta = wechatPay?.meta;
|
||
let shippingList = [];
|
||
if (shipType === 'express') {
|
||
const fromPhoneStr = maskPhone(from.phone);
|
||
const toPhoneStr = maskPhone(to.phone);
|
||
shippingList = [
|
||
{
|
||
tracking_no: extraShipId,
|
||
express_company: shipService?.shipCompany?.wechatMpName,
|
||
item_desc: desc,
|
||
contact: {
|
||
consignor_contact: fromPhoneStr,
|
||
receiver_contact: toPhoneStr,
|
||
}
|
||
}
|
||
];
|
||
}
|
||
else if (shipType === 'pickup') {
|
||
shippingList = [{
|
||
item_desc: desc,
|
||
}];
|
||
}
|
||
const shipInfo = {
|
||
order_key: {
|
||
order_number_type: 2,
|
||
transaction_id: meta?.transaction_id,
|
||
},
|
||
logistics_type: shipType === 'express' ? 1 : 4,
|
||
delivery_mode: 1,
|
||
shipping_list: shippingList,
|
||
upload_time: finalFormat,
|
||
payer: {
|
||
openid: meta?.payer?.openid,
|
||
},
|
||
};
|
||
const { type, config } = wechatPay?.application;
|
||
if (type === 'wechatMp') {
|
||
const { appId, appSecret } = config;
|
||
const wechatInstance = oak_external_sdk_1.WechatSDK.getInstance(appId, 'wechatMp', appSecret);
|
||
const result = await wechatInstance.uploadShippingInfo(shipInfo);
|
||
if (result?.errcode !== 0) {
|
||
console.error(JSON.stringify(result));
|
||
throw new Exception_1.UploadShipException(result);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
/**
|
||
* 获取小程序订单状态
|
||
* @param context
|
||
* @param shipId
|
||
* @returns
|
||
*/
|
||
async function getOrderShipState(context, shipId) {
|
||
const [ship] = await context.select('ship', {
|
||
data: exports.shipProjection,
|
||
filter: {
|
||
id: shipId,
|
||
}
|
||
}, {
|
||
blockTrigger: true,
|
||
forUpdate: true
|
||
});
|
||
(0, assert_1.assert)(ship);
|
||
const { deposit$ship: deposits, shipOrder$ship, type } = ship;
|
||
let info = undefined, wechatInstance = undefined;
|
||
if (deposits && deposits.length > 0) {
|
||
//充值
|
||
const [deposit] = deposits;
|
||
const { pay$deposit: pays, } = deposit;
|
||
const pay = pays?.[0];
|
||
if (shipId && pay) {
|
||
const { config } = pay.application;
|
||
const { appId, appSecret } = config;
|
||
wechatInstance = oak_external_sdk_1.WechatSDK.getInstance(appId, 'wechatMp', appSecret);
|
||
info = {
|
||
transaction_id: pay?.meta?.transaction_id
|
||
};
|
||
}
|
||
}
|
||
else if (shipOrder$ship && shipOrder$ship.length > 0) {
|
||
const order = shipOrder$ship[0].order;
|
||
const { pay$order: pays, } = order;
|
||
const pay = pays?.find((ele) => ele.entity === 'wpProduct');
|
||
if (shipId && pay) {
|
||
const { config } = pay.application;
|
||
const { appId, appSecret } = config;
|
||
wechatInstance = oak_external_sdk_1.WechatSDK.getInstance(appId, 'wechatMp', appSecret);
|
||
info = {
|
||
transaction_id: pay?.meta?.transaction_id
|
||
};
|
||
}
|
||
}
|
||
if (info && wechatInstance) {
|
||
const result = await wechatInstance.getOrderState(info);
|
||
const { orderState, inComplaint } = result;
|
||
if (!inComplaint) {
|
||
//未处于纠纷中
|
||
let state = 'unknow';
|
||
// let action = undefined;
|
||
switch (orderState) {
|
||
case 1: //待发货
|
||
state = 'unshipped';
|
||
break;
|
||
case 2: //已发货
|
||
if (['pickup', 'virtual'].includes(type)) {
|
||
state = 'receiving';
|
||
}
|
||
else {
|
||
state = 'shipping';
|
||
}
|
||
// action = 'ship';
|
||
break;
|
||
case 3: //确认收货
|
||
if (type === 'express') {
|
||
state = 'receiving';
|
||
}
|
||
break;
|
||
case 4: //交易完成
|
||
state = 'received';
|
||
// action = 'receive';
|
||
break;
|
||
}
|
||
return state;
|
||
}
|
||
}
|
||
}
|
||
/**
|
||
* 刷新小程序订单状态(自动确认收货)
|
||
* @param context
|
||
* @param shipId
|
||
* @returns
|
||
*/
|
||
async function refreshMpOrderShipState(shipId, context) {
|
||
const [ship] = await context.select('ship', {
|
||
data: {
|
||
id: 1,
|
||
iState: 1,
|
||
},
|
||
filter: {
|
||
id: shipId,
|
||
}
|
||
}, {
|
||
blockTrigger: true,
|
||
forUpdate: true
|
||
});
|
||
const currentState = ship.iState;
|
||
const mpState = await getOrderShipState(context, shipId);
|
||
if (currentState !== mpState) {
|
||
let action = undefined;
|
||
const shipActionDef = oak_app_domain_1.actionDefDict.ship.iState.stm;
|
||
for (const a of Object.keys(shipActionDef)) {
|
||
const pState = shipActionDef[a][0];
|
||
const nState = shipActionDef[a][1];
|
||
if (mpState === nState && pState.includes(currentState)) {
|
||
action = a;
|
||
break;
|
||
}
|
||
}
|
||
if (action) {
|
||
return await context.operate('ship', {
|
||
id: await (0, uuid_1.generateNewIdAsync)(),
|
||
action,
|
||
data: {},
|
||
filter: {
|
||
id: ship.id,
|
||
}
|
||
}, {});
|
||
}
|
||
}
|
||
}
|
||
/**
|
||
* 刷新ship的物流状态
|
||
* @param ship
|
||
* @param context
|
||
* @returns
|
||
*/
|
||
async function refreshShipState(shipId, context) {
|
||
const ships = await context.select('ship', {
|
||
data: exports.shipProjection,
|
||
filter: {
|
||
id: shipId,
|
||
}
|
||
}, {
|
||
blockTrigger: true,
|
||
forUpdate: true,
|
||
});
|
||
const ship = ships[0];
|
||
const { entity, entityId } = ship;
|
||
if (entity && entityId) {
|
||
const clazz = await (0, shipClazz_1.getShipClazz)(entity, entityId, context);
|
||
const { state, time } = await clazz.syncState(ship.id, context);
|
||
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 needReceiving = 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) {
|
||
needReceiving = true;
|
||
}
|
||
}
|
||
let action = undefined, updateData = {};
|
||
switch (state) {
|
||
case 'shipping': //已发货
|
||
action = 'ship';
|
||
break;
|
||
case 'received': //已收货
|
||
action = needReceiving ? 'startReceiving' : 'receive';
|
||
updateData = {
|
||
receiveAt: time
|
||
};
|
||
break;
|
||
case 'unknow': //不明
|
||
action = 'unknow';
|
||
break;
|
||
default:
|
||
action = undefined;
|
||
}
|
||
if (action && ship.iState !== state) {
|
||
return await context.operate('ship', {
|
||
id: await (0, uuid_1.generateNewIdAsync)(),
|
||
action,
|
||
data: updateData,
|
||
filter: {
|
||
id: ship.id,
|
||
}
|
||
}, {});
|
||
}
|
||
}
|
||
}
|
||
/**
|
||
* 小程序确认收货提醒
|
||
*/
|
||
async function notifyConfirmReceive(shipId, context) {
|
||
const [ship] = await context.select('ship', {
|
||
data: {
|
||
id: 1,
|
||
receiveAt: 1,
|
||
shipOrder$ship: {
|
||
$entity: 'shipOrder',
|
||
data: {
|
||
id: 1,
|
||
orderId: 1,
|
||
order: {
|
||
id: 1,
|
||
iState: 1,
|
||
pay$order: {
|
||
$entity: 'pay',
|
||
data: {
|
||
id: 1,
|
||
applicationId: 1,
|
||
application: {
|
||
id: 1,
|
||
type: 1,
|
||
config: 1,
|
||
},
|
||
price: 1,
|
||
meta: 1,
|
||
iState: 1,
|
||
entity: 1,
|
||
entityId: 1,
|
||
},
|
||
filter: {
|
||
iState: 'paid'
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
},
|
||
filter: {
|
||
id: shipId,
|
||
}
|
||
}, {
|
||
blockTrigger: true,
|
||
forUpdate: true
|
||
});
|
||
(0, assert_1.assert)(ship);
|
||
const { shipOrder$ship, receiveAt } = ship;
|
||
(0, assert_1.assert)(!!receiveAt && shipOrder$ship && shipOrder$ship.length > 0);
|
||
const orders = shipOrder$ship.map((ele) => ele.order);
|
||
for (const order of orders) {
|
||
const wechatPay = order.pay$order.find((ele) => ele.entity === 'wpProduct');
|
||
const meta = wechatPay?.meta;
|
||
const notifyInfo = {
|
||
transaction_id: meta.transaction_id,
|
||
received_time: receiveAt.valueOf(),
|
||
};
|
||
const { type, config } = wechatPay?.application;
|
||
if (type === 'wechatMp') {
|
||
const { appId, appSecret } = config;
|
||
const wechatInstance = oak_external_sdk_1.WechatSDK.getInstance(appId, 'wechatMp', appSecret);
|
||
await wechatInstance.notifyConfirmReceive(notifyInfo);
|
||
}
|
||
}
|
||
}
|