sf-apple-sdk
Version:
Apple SF SDK for SF WMS
391 lines (390 loc) • 19.7 kB
JavaScript
// src/services/outbound.service.ts
import { LocationEnum } from "../types/location.js";
import { Scene } from "../types/index.js";
import { SERVICE_CODE } from "../constants/service.js";
import { TransactionCode, TransactionCodeSfOutOrderTypeMap, } from "../constants/transaction-code.js";
import { post } from "../utils/post.js";
/**
* 出库单接口 Service 3.5 ✅
* 下发出库单数据
*/
export class OutboundService {
constructor(options) {
this.options = options;
}
/**
* 通用下发到SF出库单
* 非必要,不建议调用
*/
async sendOutbound(data) {
if (!data.saleOrders?.length) {
throw new Error("SaleOrders 长度至少为1");
}
const res = await post({
url: this.options.baseURL,
checkword: this.options.checkword,
sysSource: this.options.sysSource,
serviceCode: SERVICE_CODE.SALE_ORDER_SERVICE,
specialStr: this.options.specialStr,
body: {
CompanyCode: this.options.sysSource,
Checkword: this.options.checkword,
AccessCode: this.options.accessCode,
ServiceCode: SERVICE_CODE.SALE_ORDER_SERVICE,
SaleOrders: data.saleOrders,
},
});
return res;
}
/**
* 统一场景出库
*/
async sceneOut(data) {
try {
let transactionCode = "";
let sfOrderType = "10"; // 默认: 销售订单
const location = {
from: {
location_code: "",
location_name: "",
},
to: {
location_code: "",
location_name: "",
location_type: "",
},
};
let ec_platform_code;
let ec_order_number;
if (data.scene === Scene.return_factory_out) {
// 采购退货出库 - 工厂退大仓
transactionCode = TransactionCode.return_factory;
sfOrderType = TransactionCodeSfOutOrderTypeMap.return_factory;
// 残次品仓 -> 工厂
location.from = {
location_code: `${this.options.hqid}-${this.options.defectiveWarehouseCode}`,
location_name: `${this.options.defectiveWarehouseName}`,
};
location.to = {
location_code: "Factory",
location_name: "Factory",
location_type: LocationEnum.factory,
};
}
// else if (data.scene === Scene.sales_2c_out) {
// // 销售出库 - 2C消费者
// transactionCode = TransactionCode.sale_out;
// sfOrderType = TransactionCodeSfOutOrderTypeMap.sale_out!;
// // 良品仓 -> 2C消费者
// location.from = {
// location_code: `${this.options.hqid}-${this.options.goodWarehouseCode}`,
// location_name: `${this.options.goodWarehouseName}`,
// };
// location.to = {
// location_code: "EDTC", // 2C消费者
// location_name: "EDTC",
// location_type: LocationEnum.edtc,
// };
// }
/** 企业订单 or 企业员工 都使用 sales_2b_out 场景 */
else if (data.scene === Scene.sales_2b_e_out) {
// 销售出库 - 企业员工
transactionCode = TransactionCode.sale_out;
sfOrderType = TransactionCodeSfOutOrderTypeMap.sale_out;
location.from = {
location_code: `${this.options.hqid}-${this.options.goodWarehouseCode}`,
location_name: `${this.options.goodWarehouseName}`,
};
// 良品仓 -> 企业员工
location.to = {
location_code: "EDTC", // 企业员工
location_name: "EDTC",
location_type: LocationEnum.edtc,
};
if (data?.ec_platform?.ec_order_number) {
ec_platform_code = this.options.ecPlatformCode;
ec_order_number = data.ec_platform?.ec_order_number;
}
}
else if (data.scene === Scene.sales_2b_out) {
// 销售出库 - 企业 无需报数 ✅
transactionCode = TransactionCode.sale_out;
sfOrderType = TransactionCodeSfOutOrderTypeMap.sale_out;
// 良品仓 -> 企业
location.from = {
location_code: `${this.options.hqid}-${this.options.goodWarehouseCode}`,
location_name: `${this.options.goodWarehouseName}`,
};
location.to = {
location_code: "EDTC", // 企业
location_name: "EDTC", // 企业
location_type: LocationEnum.edtc, // 企业
};
}
else if (data.scene === Scene.sales_2ro_out) {
// 销售出库 - 经销商办公室
transactionCode = TransactionCode.sale_out;
sfOrderType = TransactionCodeSfOutOrderTypeMap.sale_out;
// 良品仓 -> 经销商办公室
location.from = {
location_code: `${this.options.hqid}-${this.options.goodWarehouseCode}`,
location_name: `${this.options.goodWarehouseName}`,
};
location.to = {
location_code: this.options.officeCode,
location_name: this.options.officeName,
location_type: LocationEnum.reseller_office,
};
}
else if (data.scene === Scene.gift_out) {
// 礼品出库
transactionCode = TransactionCode.gift_out;
sfOrderType = TransactionCodeSfOutOrderTypeMap.gift_out;
// 礼品仓 -> 消费者
location.from = {
location_code: `${this.options.hqid}-${this.options.giftWarehouseCode}`,
location_name: `${this.options.giftWarehouseName}`,
};
location.to = {
location_code: `Expense`,
location_name: `Expense`,
location_type: LocationEnum.expense,
};
}
else if (data.scene === Scene.borrow_out) {
// 借机出库
transactionCode = TransactionCode.borrow_out;
sfOrderType = TransactionCodeSfOutOrderTypeMap.borrow_out;
// 借机仓 -> 消费者
location.from = {
location_code: `${this.options.hqid}-${this.options.borrowWarehouseCode}`,
location_name: `${this.options.borrowWarehouseName}`,
};
location.to = {
location_code: `Expense`,
location_name: `Expense`,
location_type: LocationEnum.expense,
};
}
else if (data.scene === Scene.seed_out) {
// Seed出库
transactionCode = TransactionCode.seed_out;
sfOrderType = TransactionCodeSfOutOrderTypeMap.seed_out;
// Seed仓 -> 消费者
location.from = {
location_code: `${this.options.hqid}-${this.options.seedWarehouseCode}`,
location_name: `${this.options.seedWarehouseName}`,
};
location.to = {
location_code: `Expense`,
location_name: `Expense`,
location_type: LocationEnum.expense,
};
}
else if (data.scene === Scene.quality_change_out) {
if (!data.transfer?.origin_bill_code) {
throw new Error("品质变更出库 transfer.origin_bill_code 是必填的");
}
// 品质变更出库 良品 -> 残次品
transactionCode = TransactionCode.quality_change_out;
sfOrderType = TransactionCodeSfOutOrderTypeMap.quality_change_out;
// 良品仓 -> 残次品仓
location.from = {
location_code: `${this.options.hqid}-${this.options.goodWarehouseCode}`,
location_name: `${this.options.goodWarehouseName}`,
};
location.to = {
location_code: `${this.options.hqid}-${this.options.defectiveWarehouseCode}`,
location_name: `${this.options.defectiveWarehouseName}`,
location_type: LocationEnum.sf_apple_warehouse,
};
}
else if (data.scene === Scene.defective_out) {
// 残次品处理 残次品出库 残次品出售
transactionCode = TransactionCode.defective_out;
sfOrderType = TransactionCodeSfOutOrderTypeMap.defective_out;
// 残次品仓 -> 消费者
location.from = {
location_code: `${this.options.hqid}-${this.options.defectiveWarehouseCode}`,
location_name: `${this.options.defectiveWarehouseName}`,
};
location.to = {
location_code: `Expense`,
location_name: `Expense`,
location_type: LocationEnum.expense,
};
}
else if (data.scene === Scene.difference_out) {
// 差异调拨出库
if (!data.transfer?.origin_bill_code) {
throw new Error("差异调拨出库 transfer.origin_bill_code 是必填的");
}
transactionCode = TransactionCode.difference_out;
sfOrderType = TransactionCodeSfOutOrderTypeMap.difference_out;
// 大仓 -> 大仓
location.from = {
location_code: data.transfer.from_location_code,
location_name: data.transfer.from_location_name,
};
location.to = {
location_code: data.transfer.to_location_code,
location_name: data.transfer.to_location_name,
location_type: LocationEnum.sf_apple_warehouse,
};
}
else if (data.scene === Scene.transfer_out) {
// 仓间调拨出库
if (!data.transfer?.origin_bill_code) {
throw new Error("仓间调拨出库 transfer.origin_bill_code 是必填的");
}
transactionCode = TransactionCode.transfer_out;
sfOrderType = TransactionCodeSfOutOrderTypeMap.transfer_out;
// 调拨出库 from to 都是大仓
location.from = {
location_code: data.transfer.from_location_code,
location_name: data.transfer.from_location_name,
};
location.to = {
location_code: data.transfer.to_location_code,
location_name: data.transfer.to_location_name,
location_type: LocationEnum.sf_apple_warehouse,
};
}
else if (data.scene === Scene.cycle_out) {
// 盘点出库 from to 都是大仓
if (!data.cycle) {
throw new Error("盘点出库 cycle 是必填的");
}
transactionCode = TransactionCode.cycle_out;
sfOrderType = TransactionCodeSfOutOrderTypeMap.cycle_out;
// 盘点出库 from to 都是大仓
location.from = {
location_code: `${this.options.hqid}-${data.cycle?.from_location_code}`,
location_name: `${data.cycle?.from_location_name}`,
};
location.to = {
location_code: `${this.options.hqid}-${data.cycle?.to_location_code}`,
location_name: `${data.cycle?.to_location_name}`,
location_type: LocationEnum.sf_apple_warehouse,
};
}
else if (data.scene === Scene.value_added_service_transfer_out) {
if (!data.transfer?.origin_bill_code) {
throw new Error("增值服务调拨出库 transfer.origin_bill_code 是必填的");
}
transactionCode = TransactionCode.value_added_service_transfer_out;
sfOrderType =
TransactionCodeSfOutOrderTypeMap.value_added_service_transfer_out;
location.from = {
location_code: `${this.options.hqid}-${this.options.goodWarehouseCode}`,
location_name: `${this.options.goodWarehouseName}`,
};
location.to = {
location_code: `${this.options.hqid}-${this.options.deployWarehouseCode}`,
location_name: `${this.options.deployWarehouseName}`,
location_type: LocationEnum.sf_apple_warehouse,
};
}
if (data?.jxqz && data.jxqz === "Y") {
if (!data?.jxqz_time) {
throw new Error("极校前置时间 jxqz_time 是必填的");
}
}
const items = data.skus.map((sku) => {
return {
SkuNo: sku.sku_code,
ItemQuantity: sku.qty,
LotAttr4: location.from.location_code, // FromLocationCode
UserDef2: sku.mpn,
ItemUom: sku?.unit,
SerialNumbers: sku?.sn_list,
InventoryStatus: sku.inventory_status,
};
});
const result = await this.sendOutbound({
saleOrders: [
{
WarehouseCode: this.options.warehouseCode,
ErpOrder: data.bill_code,
ErpOrderType: transactionCode, // 苹果要求的 TransactionCode
SfOrderType: data.jxqz === "Y" ? "JXQZ" : sfOrderType,
DestinationFacilityName: data.receiver.company_name, // 电子签收单 消费
SalesRepresentative: data.sender?.sales_name,
ExpeditedPrereleaseTime: data.jxqz === "Y" ? data?.jxqz_time : undefined,
TradePlatform: ec_platform_code,
TradeOrder: ec_order_number,
OrderCarrier: {
/** 顺丰速运、自提 */
Carrier: data.jxqz === "Y"
? "CP"
: data.scene === Scene.sales_2b_out ||
data.scene === Scene.sales_2b_e_out ||
data.scene === Scene.sales_2ro_out ||
data.scene === Scene.gift_out ||
data.scene === Scene.borrow_out ||
data.scene === Scene.seed_out
? "CP"
: "ZT",
/** 极校前置优先级最高,其次是销售出库(标准快递),最后是其他场景(自提) */
CarrierProduct: data.jxqz === "Y"
? "SE0129"
: data.scene === Scene.sales_2b_out ||
data.scene === Scene.sales_2b_e_out ||
data.scene === Scene.sales_2ro_out ||
data.scene === Scene.gift_out ||
data.scene === Scene.borrow_out ||
data.scene === Scene.seed_out
? data.carrier_product_code
: "ZT",
CarrierAddedServices: [
{
ServiceCode: data.need_electronic_receipt === "Y" ? "IN149" : undefined,
Attr01: data.need_electronic_receipt ? "3" : undefined, // 需要使用电子回单的,该字段传 3
},
],
},
OrderReceiverInfo: {
ReceiverCompany: location.to.location_name || undefined, // ToLocationName
ReceiverName: data.receiver.person_name, // 电子签收单 消费
ReceiverPhone: data.receiver.person_phone, // 电子签收单 消费
ReceiverProvince: data.receiver.province,
ReceiverCity: data.receiver.city,
ReceiverArea: data.receiver.area,
ReceiverAddress: data.receiver.address, // 电子签收单 消费
ReceiverIdCard: data.receiver?.person_id_card,
ReceiverCountry: "中国",
},
OrderSenderInfo: {
SenderCompany: data.sender?.company_name,
SenderName: data.sender?.person_name,
SenderPhone: data.sender?.person_phone,
},
OrderExtendAttribute: {
UserDef4: location.to.location_code || undefined, // ToLocationCode 两个字段都传
UserDef5: data.transfer?.origin_bill_code, // 存回传 Apple 厂商的调拨单原参考 erp单号
UserDef7: location.to.location_code || undefined, // ToLocationCode 两个字段都传
UserDef8: data.scene === Scene.sales_2ro_out
? this.options.officeName
: data.scene === Scene.sales_2b_e_out
? data.receiver.company_name
: undefined, // 经销商AccountName 或者 客户企业名称
UserDef9: data.scene === Scene.sales_2b_out ||
data.scene === Scene.sales_2b_e_out ||
data.scene === Scene.sales_2ro_out
? this.options.hqid
: undefined, // 经销商 ASAB hqid
UserDef11: location.to.location_type || undefined, // ToLocationType
UserDef12: `${data.receiver.province}|${data.receiver.city}|${data.receiver.area}|${data.receiver.address}`, // 使用 | 拼接省市区县详细地址,例如:广东|深圳市|南山区|中山路 1 号
UserDef15: location.from.location_name || undefined, // FromLocationName
},
OrderItems: items,
},
],
});
return result;
}
catch (error) {
throw error;
}
}
}