Feature: 对接uniuni物流,补充物流管理和物流信息 #1
|
|
@ -3,24 +3,24 @@ export default {
|
||||||
koa: {
|
koa: {
|
||||||
port: 7001,
|
port: 7001,
|
||||||
},
|
},
|
||||||
typeorm: {
|
|
||||||
dataSource: {
|
|
||||||
default: {
|
|
||||||
host: '13.212.62.127',
|
|
||||||
username: 'root',
|
|
||||||
password: 'Yoone!@.2025',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
// typeorm: {
|
// typeorm: {
|
||||||
// dataSource: {
|
// dataSource: {
|
||||||
// default: {
|
// default: {
|
||||||
// host: '127.0.0.1',
|
// host: '13.212.62.127',
|
||||||
// username: 'root',
|
// username: 'root',
|
||||||
// password: '123456',
|
// password: 'Yoone!@.2025',
|
||||||
// },
|
// },
|
||||||
// },
|
// },
|
||||||
// },
|
// },
|
||||||
|
typeorm: {
|
||||||
|
dataSource: {
|
||||||
|
default: {
|
||||||
|
host: 'localhost',
|
||||||
|
username: 'root',
|
||||||
|
password: '12345678',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
cors: {
|
cors: {
|
||||||
origin: '*', // 允许所有来源跨域请求
|
origin: '*', // 允许所有来源跨域请求
|
||||||
allowMethods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'], // 允许的 HTTP 方法
|
allowMethods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'], // 允许的 HTTP 方法
|
||||||
|
|
@ -35,17 +35,26 @@ export default {
|
||||||
{
|
{
|
||||||
id: '-1',
|
id: '-1',
|
||||||
siteName: 'Admin',
|
siteName: 'Admin',
|
||||||
email: 'tom@yoonevape.com',
|
email: '444693295@qq.com',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: '2',
|
id: '2',
|
||||||
wpApiUrl: 'http://localhost:10004',
|
wpApiUrl: 'http://t1-shop.local/',
|
||||||
consumerKey: 'ck_dc9e151e9048c8ed3e27f35ac79d2bf7d6840652',
|
consumerKey: 'ck_a369473a6451dbaec63d19cbfd74a074b2c5f742',
|
||||||
consumerSecret: 'cs_d05d625d7b0ac05c6d765671d8417f41d9477e38',
|
consumerSecret: 'cs_0946bbbeea1bfefff08a69e817ac62a48412df8c',
|
||||||
siteName: 'Local',
|
siteName: 'Local',
|
||||||
email: 'tom@yoonevape.com',
|
email: '444693295@qq.com',
|
||||||
emailPswd: 'lulin91.',
|
emailPswd: 'lulin91.',
|
||||||
},
|
},
|
||||||
|
// {
|
||||||
|
// id: '2',
|
||||||
|
// wpApiUrl: 'http://localhost:10004',
|
||||||
|
// consumerKey: 'ck_dc9e151e9048c8ed3e27f35ac79d2bf7d6840652',
|
||||||
|
// consumerSecret: 'cs_d05d625d7b0ac05c6d765671d8417f41d9477e38',
|
||||||
|
// siteName: 'Local',
|
||||||
|
// email: 'tom@yoonevape.com',
|
||||||
|
// emailPswd: 'lulin91.',
|
||||||
|
// },
|
||||||
],
|
],
|
||||||
freightcom: {
|
freightcom: {
|
||||||
url: 'https://customer-external-api.ssd-test.freightcom.com',
|
url: 'https://customer-external-api.ssd-test.freightcom.com',
|
||||||
|
|
@ -58,4 +67,11 @@ export default {
|
||||||
customerNumber: '0006122480',
|
customerNumber: '0006122480',
|
||||||
contractId: '0044168528',
|
contractId: '0044168528',
|
||||||
},
|
},
|
||||||
|
uniExpress: {
|
||||||
|
url: 'https://sjqa.uniexpress.org', // 测试环境url
|
||||||
|
// url: 'https://sj.uniexpress.ca', //正式环境url
|
||||||
|
clientId: '101018',
|
||||||
|
clientSecret: 'cbcb51bea204f3f69c47b5280064408e',
|
||||||
|
customerNo: 2067,
|
||||||
|
}
|
||||||
} as MidwayConfig;
|
} as MidwayConfig;
|
||||||
|
|
|
||||||
|
|
@ -155,8 +155,8 @@ export class LogisticsController {
|
||||||
@User() user
|
@User() user
|
||||||
) {
|
) {
|
||||||
try {
|
try {
|
||||||
await this.logisticsService.createShipment(orderId, data, user.id);
|
const res: any = await this.logisticsService.createShipment(orderId, data, user.id);
|
||||||
return successResponse(true);
|
return successResponse(res.data);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return errorResponse(error?.message || '创建失败');
|
return errorResponse(error?.message || '创建失败');
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,25 +2,12 @@ import { ApiProperty } from '@midwayjs/swagger';
|
||||||
import { ShippingDetailsDTO } from './freightcom.dto';
|
import { ShippingDetailsDTO } from './freightcom.dto';
|
||||||
import { Rule, RuleType } from '@midwayjs/validate';
|
import { Rule, RuleType } from '@midwayjs/validate';
|
||||||
import { OrderSale } from '../entity/order_sale.entity';
|
import { OrderSale } from '../entity/order_sale.entity';
|
||||||
import { ShipmentType } from '../enums/base.enum';
|
|
||||||
|
|
||||||
export class ShipmentBookDTO {
|
export class ShipmentBookDTO {
|
||||||
@ApiProperty({ type: OrderSale, isArray: true })
|
@ApiProperty({ type: OrderSale, isArray: true })
|
||||||
@Rule(RuleType.array<OrderSale>())
|
@Rule(RuleType.array<OrderSale>())
|
||||||
sales: OrderSale[];
|
sales: OrderSale[];
|
||||||
|
|
||||||
@ApiProperty()
|
|
||||||
@Rule(RuleType.string())
|
|
||||||
payment_method_id: string;
|
|
||||||
|
|
||||||
@ApiProperty()
|
|
||||||
@Rule(RuleType.string())
|
|
||||||
service_id: string;
|
|
||||||
|
|
||||||
@ApiProperty()
|
|
||||||
@Rule(RuleType.string())
|
|
||||||
service_type: ShipmentType;
|
|
||||||
|
|
||||||
@ApiProperty({ type: ShippingDetailsDTO })
|
@ApiProperty({ type: ShippingDetailsDTO })
|
||||||
@Rule(RuleType.object<ShippingDetailsDTO>())
|
@Rule(RuleType.object<ShippingDetailsDTO>())
|
||||||
details: ShippingDetailsDTO;
|
details: ShippingDetailsDTO;
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
import { ApiProperty } from '@midwayjs/swagger';
|
import { ApiProperty } from '@midwayjs/swagger';
|
||||||
import { ErpOrderStatus } from '../enums/base.enum';
|
import { ErpOrderStatus } from '../enums/base.enum';
|
||||||
import { Rule, RuleType } from '@midwayjs/validate';
|
import { Rule, RuleType } from '@midwayjs/validate';
|
||||||
import { Shipment } from '../entity/shipment.entity';
|
// import { Shipment } from '../entity/shipment.entity';
|
||||||
import { ShipmentItem } from '../entity/shipment_item.entity';
|
// import { ShipmentItem } from '../entity/shipment_item.entity';
|
||||||
|
|
||||||
export class OrderAddress {
|
export class OrderAddress {
|
||||||
@ApiProperty()
|
@ApiProperty()
|
||||||
|
|
@ -115,10 +115,10 @@ export class QueryOrderSalesDTO {
|
||||||
endDate: Date;
|
endDate: Date;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Tracking extends Shipment {
|
// export class Tracking extends Shipment {
|
||||||
@ApiProperty({ type: ShipmentItem, isArray: true })
|
// @ApiProperty({ type: ShipmentItem, isArray: true })
|
||||||
products?: ShipmentItem[];
|
// products?: ShipmentItem[];
|
||||||
}
|
// }
|
||||||
|
|
||||||
export class CreateOrderNoteDTO {
|
export class CreateOrderNoteDTO {
|
||||||
@ApiProperty()
|
@ApiProperty()
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ import {
|
||||||
SuccessArrayWrapper,
|
SuccessArrayWrapper,
|
||||||
SuccessWrapper,
|
SuccessWrapper,
|
||||||
} from '../utils/response-wrapper.util';
|
} from '../utils/response-wrapper.util';
|
||||||
import { OrderStatusCountDTO, Tracking } from './order.dto';
|
import { OrderStatusCountDTO } from './order.dto';
|
||||||
import { SiteConfig } from './site.dto';
|
import { SiteConfig } from './site.dto';
|
||||||
import { PurchaseOrderDTO, StockDTO, StockRecordDTO } from './stock.dto';
|
import { PurchaseOrderDTO, StockDTO, StockRecordDTO } from './stock.dto';
|
||||||
import { LoginResDTO } from './user.dto';
|
import { LoginResDTO } from './user.dto';
|
||||||
|
|
@ -107,8 +107,8 @@ export class OrderDetail extends Order {
|
||||||
@ApiProperty({ type: OrderRefundItem, isArray: true })
|
@ApiProperty({ type: OrderRefundItem, isArray: true })
|
||||||
refundItems: OrderRefundItem[];
|
refundItems: OrderRefundItem[];
|
||||||
|
|
||||||
@ApiProperty({ type: Tracking, isArray: true })
|
// @ApiProperty({ type: Tracking, isArray: true })
|
||||||
trackings: Tracking[];
|
// trackings: Tracking[];
|
||||||
|
|
||||||
@ApiProperty({ type: OrderNote, isArray: true })
|
@ApiProperty({ type: OrderNote, isArray: true })
|
||||||
notes: OrderNote[];
|
notes: OrderNote[];
|
||||||
|
|
|
||||||
|
|
@ -7,10 +7,13 @@ import {
|
||||||
Entity,
|
Entity,
|
||||||
PrimaryGeneratedColumn,
|
PrimaryGeneratedColumn,
|
||||||
UpdateDateColumn,
|
UpdateDateColumn,
|
||||||
|
OneToOne,
|
||||||
|
JoinColumn
|
||||||
} from 'typeorm';
|
} from 'typeorm';
|
||||||
import { ErpOrderStatus, OrderStatus } from '../enums/base.enum';
|
import { ErpOrderStatus, OrderStatus } from '../enums/base.enum';
|
||||||
import { OrderAddress } from '../dto/order.dto';
|
import { OrderAddress } from '../dto/order.dto';
|
||||||
import { Exclude, Expose } from 'class-transformer';
|
import { Exclude, Expose } from 'class-transformer';
|
||||||
|
import { Shipment } from './shipment.entity';
|
||||||
|
|
||||||
@Entity('order')
|
@Entity('order')
|
||||||
@Exclude()
|
@Exclude()
|
||||||
|
|
@ -44,6 +47,15 @@ export class Order {
|
||||||
@Expose()
|
@Expose()
|
||||||
orderStatus: ErpOrderStatus; // 订单状态
|
orderStatus: ErpOrderStatus; // 订单状态
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column({ name: 'shipment_id', nullable: true })
|
||||||
|
@Expose()
|
||||||
|
shipmentId: string;
|
||||||
|
|
||||||
|
@OneToOne(() => Shipment)
|
||||||
|
@JoinColumn({ name: 'shipment_id' })
|
||||||
|
shipment: Shipment;
|
||||||
|
|
||||||
@ApiProperty()
|
@ApiProperty()
|
||||||
@Column()
|
@Column()
|
||||||
@Expose()
|
@Expose()
|
||||||
|
|
|
||||||
|
|
@ -4,18 +4,41 @@ import {
|
||||||
Column,
|
Column,
|
||||||
CreateDateColumn,
|
CreateDateColumn,
|
||||||
Entity,
|
Entity,
|
||||||
PrimaryColumn,
|
PrimaryGeneratedColumn,
|
||||||
UpdateDateColumn,
|
UpdateDateColumn,
|
||||||
|
ManyToOne,
|
||||||
|
OneToOne,
|
||||||
|
JoinColumn
|
||||||
} from 'typeorm';
|
} from 'typeorm';
|
||||||
|
import { StockPoint } from './stock_point.entity';
|
||||||
|
import { Order } from './order.entity';
|
||||||
|
|
||||||
@Entity('shipment')
|
@Entity('shipment')
|
||||||
@Exclude()
|
@Exclude()
|
||||||
export class Shipment {
|
export class Shipment {
|
||||||
@ApiProperty()
|
@ApiProperty()
|
||||||
@PrimaryColumn()
|
@PrimaryGeneratedColumn()
|
||||||
@Expose()
|
@Expose()
|
||||||
id: string;
|
id: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column({ name: 'order_id', nullable: true })
|
||||||
|
@Expose()
|
||||||
|
orderId: string;
|
||||||
|
|
||||||
|
@OneToOne(() => Order)
|
||||||
|
@JoinColumn({ name: 'order_id' })
|
||||||
|
order: Order;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column({ name: 'stock_point_id' })
|
||||||
|
@Expose()
|
||||||
|
stockPointId: string;
|
||||||
|
|
||||||
|
@ManyToOne(() => StockPoint)
|
||||||
|
@JoinColumn({ name: 'stock_point_id' })
|
||||||
|
stockPoint: StockPoint;
|
||||||
|
|
||||||
@ApiProperty()
|
@ApiProperty()
|
||||||
@Column({ nullable: true })
|
@Column({ nullable: true })
|
||||||
@Expose()
|
@Expose()
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,9 @@ import {
|
||||||
Entity,
|
Entity,
|
||||||
PrimaryGeneratedColumn,
|
PrimaryGeneratedColumn,
|
||||||
UpdateDateColumn,
|
UpdateDateColumn,
|
||||||
|
OneToMany,
|
||||||
} from 'typeorm';
|
} from 'typeorm';
|
||||||
|
import { Shipment } from './shipment.entity';
|
||||||
|
|
||||||
@Entity('stock_point')
|
@Entity('stock_point')
|
||||||
export class StockPoint extends BaseEntity {
|
export class StockPoint extends BaseEntity {
|
||||||
|
|
@ -15,6 +17,9 @@ export class StockPoint extends BaseEntity {
|
||||||
@PrimaryGeneratedColumn()
|
@PrimaryGeneratedColumn()
|
||||||
id: number;
|
id: number;
|
||||||
|
|
||||||
|
@OneToMany(() => Shipment, shipment => shipment.stockPoint)
|
||||||
|
shipments: Shipment[];
|
||||||
|
|
||||||
@ApiProperty({ type: 'string' })
|
@ApiProperty({ type: 'string' })
|
||||||
@Column()
|
@Column()
|
||||||
name: string;
|
name: string;
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ import { InjectEntityModel, TypeORMDataSourceManager } from '@midwayjs/typeorm';
|
||||||
import { Service } from '../entity/service.entity';
|
import { Service } from '../entity/service.entity';
|
||||||
import { In, IsNull, Like, Repository } from 'typeorm';
|
import { In, IsNull, Like, Repository } from 'typeorm';
|
||||||
import { ShippingAddress } from '../entity/shipping_address.entity';
|
import { ShippingAddress } from '../entity/shipping_address.entity';
|
||||||
// import { ShipmentBookDTO } from '../dto/logistics.dto';
|
|
||||||
import { Order } from '../entity/order.entity';
|
import { Order } from '../entity/order.entity';
|
||||||
import { Shipment } from '../entity/shipment.entity';
|
import { Shipment } from '../entity/shipment.entity';
|
||||||
import { ShipmentItem } from '../entity/shipment_item.entity';
|
import { ShipmentItem } from '../entity/shipment_item.entity';
|
||||||
|
|
@ -15,18 +15,19 @@ import {
|
||||||
ShipmentType,
|
ShipmentType,
|
||||||
StockRecordOperationType,
|
StockRecordOperationType,
|
||||||
} from '../enums/base.enum';
|
} from '../enums/base.enum';
|
||||||
import { generateUniqueId } from '../utils/helper.util';
|
// import { generateUniqueId } from '../utils/helper.util';
|
||||||
import { FreightcomService } from './freightcom.service';
|
import { FreightcomService } from './freightcom.service';
|
||||||
import { StockRecord } from '../entity/stock_record.entity';
|
import { StockRecord } from '../entity/stock_record.entity';
|
||||||
import { Stock } from '../entity/stock.entity';
|
import { Stock } from '../entity/stock.entity';
|
||||||
import { plainToClass } from 'class-transformer';
|
import { plainToClass } from 'class-transformer';
|
||||||
import { WPService } from './wp.service';
|
import { WPService } from './wp.service';
|
||||||
import { WpSite } from '../interface';
|
import { WpSite } from '../interface';
|
||||||
import { Product } from '../entity/product.entty';
|
// import { Product } from '../entity/product.entty';
|
||||||
import { ShippingDetailsDTO } from '../dto/freightcom.dto';
|
import { ShippingDetailsDTO } from '../dto/freightcom.dto';
|
||||||
import { CanadaPostService } from './canadaPost.service';
|
import { CanadaPostService } from './canadaPost.service';
|
||||||
import { OrderItem } from '../entity/order_item.entity';
|
import { OrderItem } from '../entity/order_item.entity';
|
||||||
import { OrderSale } from '../entity/order_sale.entity';
|
import { OrderSale } from '../entity/order_sale.entity';
|
||||||
|
import { UniExpressService } from './uni_express.service';
|
||||||
|
|
||||||
@Provide()
|
@Provide()
|
||||||
export class LogisticsService {
|
export class LogisticsService {
|
||||||
|
|
@ -63,6 +64,9 @@ export class LogisticsService {
|
||||||
@Inject()
|
@Inject()
|
||||||
canadaPostService: CanadaPostService;
|
canadaPostService: CanadaPostService;
|
||||||
|
|
||||||
|
@Inject()
|
||||||
|
uniExpressService: UniExpressService;
|
||||||
|
|
||||||
@Inject()
|
@Inject()
|
||||||
wpService: WPService;
|
wpService: WPService;
|
||||||
|
|
||||||
|
|
@ -195,147 +199,130 @@ export class LogisticsService {
|
||||||
) {
|
) {
|
||||||
throw new Error('订单状态不正确 ');
|
throw new Error('订单状态不正确 ');
|
||||||
}
|
}
|
||||||
// for (const item of data?.sales) {
|
try {
|
||||||
// const stock = await this.stockModel.findOne({
|
const reqBody = {
|
||||||
// where: {
|
sender: data.details.origin.contact_name,
|
||||||
|
start_phone: data.details.origin.phone_number,
|
||||||
|
start_postal_code: data.details.origin.address.postal_code.replace(/\s/g, ''),
|
||||||
|
pickup_address: data.details.origin.address.address_line_1,
|
||||||
|
pickup_warehouse: 1, // todo, 可能需要添加
|
||||||
|
shipper_country_code: data.details.origin.address.country,
|
||||||
|
receiver: data.details.destination.contact_name,
|
||||||
|
city: data.details.destination.address.city,
|
||||||
|
province: data.details.destination.address.region, // todo,待确认
|
||||||
|
country: data.details.destination.address.country,
|
||||||
|
postal_code: data.details.destination.address.postal_code.replace(/\s/g, ''),
|
||||||
|
delivery_address: data.details.destination.address.address_line_1,
|
||||||
|
receiver_phone: data.details.destination.phone_number.number,
|
||||||
|
receiver_email: data.details.destination.email_addresses,
|
||||||
|
// item_description: data.sales, // todo: 货品信息
|
||||||
|
length: data.details.packaging_properties.packages[0].measurements.cuboid.l, // todo, (只能一个包)
|
||||||
|
width: data.details.packaging_properties.packages[0].measurements.cuboid.w,
|
||||||
|
height: data.details.packaging_properties.packages[0].measurements.cuboid.h,
|
||||||
|
dimension_uom: data.details.packaging_properties.packages[0].measurements.cuboid.unit,
|
||||||
|
weight: data.details.packaging_properties.packages[0].measurements.weight.value,
|
||||||
|
weight_uom: `${data.details.packaging_properties.packages[0].measurements.weight.unit}S`, // todo,换成KGS和LBS
|
||||||
|
currency: 'CAD',
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo: 两个请求做异步 参考promise.all()方法
|
||||||
|
// 获取预估费率
|
||||||
|
const resShipmentFee = await this.uniExpressService.getRates(reqBody);
|
||||||
|
// 添加运单
|
||||||
|
const resShipmentOrder = await this.uniExpressService.createShipment(reqBody);
|
||||||
|
|
||||||
|
// 记录物流信息,并将订单状态转到完成
|
||||||
|
if (resShipmentOrder.status === 'SUCCESS') {
|
||||||
|
order.orderStatus = ErpOrderStatus.COMPLETED;
|
||||||
|
}
|
||||||
|
const dataSource = this.dataSourceManager.getDataSource('default');
|
||||||
|
dataSource.transaction(async manager => {
|
||||||
|
const orderRepo = manager.getRepository(Order);
|
||||||
|
const shipmentRepo = manager.getRepository(Shipment);
|
||||||
|
|
||||||
|
if (order.orderStatus === ErpOrderStatus.COMPLETED) {
|
||||||
|
const shipment = await shipmentRepo.save({
|
||||||
|
tracking_provider: 'uniuni-express', // todo: id未确定,后写进常数
|
||||||
|
unique_id: resShipmentOrder.data.uni_order_sn,
|
||||||
|
stockPointId: '1', // todo
|
||||||
|
state: resShipmentOrder.data.uni_status_code,
|
||||||
|
order_id: order.id
|
||||||
|
});
|
||||||
|
order.shipmentId = shipment.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
await orderRepo.save(order);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
return { data: {
|
||||||
|
resShipmentFee,
|
||||||
|
resShipmentOrder
|
||||||
|
} };
|
||||||
|
} catch(error) {
|
||||||
|
throw new Error(`上游请求错误:${error}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// const dataSource = this.dataSourceManager.getDataSource('default');
|
||||||
|
// return dataSource.transaction(async manager => {
|
||||||
|
// const productRepo = manager.getRepository(Product);
|
||||||
|
// const shipmentRepo = manager.getRepository(Shipment);
|
||||||
|
// const shipmentItemRepo = manager.getRepository(ShipmentItem);
|
||||||
|
// const orderShipmentRepo = manager.getRepository(OrderShipment);
|
||||||
|
// const stockRecordRepo = manager.getRepository(StockRecord);
|
||||||
|
// const stockRepo = manager.getRepository(Stock);
|
||||||
|
// const orderRepo = manager.getRepository(Order);
|
||||||
|
|
||||||
|
// await shipmentRepo.save(shipment);
|
||||||
|
// await this.getShipment(shipment.id);
|
||||||
|
// const shipmentItems = [];
|
||||||
|
// for (const item of data?.sales) {
|
||||||
|
// const product = await productRepo.findOne({ where: { sku: item.sku } });
|
||||||
|
// shipmentItems.push({
|
||||||
|
// shipment_id: shipment.id,
|
||||||
|
// productId: product.id,
|
||||||
|
// name: product.name,
|
||||||
|
// sku: item.sku,
|
||||||
|
// quantity: item.quantity,
|
||||||
|
// });
|
||||||
|
// const stock = await stockRepo.findOne({
|
||||||
|
// where: {
|
||||||
|
// stockPointId: data.stockPointId,
|
||||||
|
// productSku: item.sku,
|
||||||
|
// },
|
||||||
|
// });
|
||||||
|
// stock.quantity -= item.quantity;
|
||||||
|
// await stockRepo.save(stock);
|
||||||
|
// await stockRecordRepo.save({
|
||||||
// stockPointId: data.stockPointId,
|
// stockPointId: data.stockPointId,
|
||||||
// productSku: item.sku,
|
// productSku: item.sku,
|
||||||
// },
|
// operationType: StockRecordOperationType.OUT,
|
||||||
|
// quantityChange: item.quantity,
|
||||||
|
// operatorId: userId,
|
||||||
|
// note: `订单${[orderId, ...data.orderIds].join(',')} 发货`,
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
// await shipmentItemRepo.save(shipmentItems);
|
||||||
|
// await orderShipmentRepo.save({
|
||||||
|
// order_id: orderId,
|
||||||
|
// shipment_id: shipment.id,
|
||||||
|
// stockPointId: data.stockPointId,
|
||||||
// });
|
// });
|
||||||
// if (!stock || stock.quantity < item.quantity)
|
// for (const orderId of data?.orderIds) {
|
||||||
// throw new Error(item.name + '库存不足');
|
// await orderShipmentRepo.save({
|
||||||
// }
|
// order_id: orderId,
|
||||||
let shipment: Shipment;
|
// shipment_id: shipment.id,
|
||||||
|
// stockPointId: data.stockPointId,
|
||||||
if (data.service_type === ShipmentType.FREIGHTCOM) {
|
// });
|
||||||
const uuid = generateUniqueId();
|
// const order = await orderRepo.findOneBy({ id: orderId });
|
||||||
data.details.reference_codes = [String(orderId)];
|
// order.orderStatus = ErpOrderStatus.COMPLETED;
|
||||||
const { id } = await this.freightcomService.createShipment({
|
// order.status = OrderStatus.COMPLETED;
|
||||||
unique_id: uuid,
|
// await orderRepo.save(order);
|
||||||
payment_method_id: data.payment_method_id,
|
// }
|
||||||
service_id: data.service_id,
|
// order.orderStatus = ErpOrderStatus.COMPLETED;
|
||||||
details: data.details,
|
// order.status = OrderStatus.COMPLETED;
|
||||||
});
|
// await orderRepo.save(order);
|
||||||
|
// });
|
||||||
const service = await this.serviceModel.findOneBy({
|
|
||||||
id: data.service_id,
|
|
||||||
});
|
|
||||||
shipment = {
|
|
||||||
id,
|
|
||||||
unique_id: uuid,
|
|
||||||
tracking_provider: service?.carrier_name || '',
|
|
||||||
};
|
|
||||||
} else if (data.service_type === ShipmentType.CANADAPOST) {
|
|
||||||
const shipmentRequest = {
|
|
||||||
'transmit-shipment': true,
|
|
||||||
'requested-shipping-point':
|
|
||||||
data.details.origin.address.postal_code.replace(/\s/g, ''),
|
|
||||||
'delivery-spec': {
|
|
||||||
'service-code': data.service_id,
|
|
||||||
sender: {
|
|
||||||
name: data.details.origin.name,
|
|
||||||
company: data.details.origin.name,
|
|
||||||
'contact-phone': data.details.origin.phone_number.number,
|
|
||||||
'address-details': {
|
|
||||||
'address-line-1': data.details.origin.address.address_line_1,
|
|
||||||
city: data.details.origin.address.city,
|
|
||||||
'prov-state': data.details.origin.address.region,
|
|
||||||
'postal-zip-code':
|
|
||||||
data.details.origin.address.postal_code.replace(/\s/g, ''),
|
|
||||||
'country-code': data.details.origin.address.country,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
destination: {
|
|
||||||
name: data.details.destination.contact_name,
|
|
||||||
company: data.details.destination.name,
|
|
||||||
'address-details': {
|
|
||||||
'address-line-1': data.details.destination.address.address_line_1,
|
|
||||||
city: data.details.destination.address.city,
|
|
||||||
'prov-state': data.details.destination.address.region,
|
|
||||||
'postal-zip-code':
|
|
||||||
data.details.destination.address.postal_code.replace(/\s/g, ''),
|
|
||||||
'country-code': data.details.destination.address.country,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
'parcel-characteristics': {
|
|
||||||
weight: data.details.packaging_properties.packages?.reduce(
|
|
||||||
(cur, next) => cur + (next?.measurements?.weight?.value || 0),
|
|
||||||
0
|
|
||||||
),
|
|
||||||
},
|
|
||||||
preferences: {
|
|
||||||
'show-packing-instructions': true,
|
|
||||||
},
|
|
||||||
'settlement-info': {
|
|
||||||
'contract-id': this.canadaPostService.contractId,
|
|
||||||
'intended-method-of-payment': 'CreditCard',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
shipment = await this.canadaPostService.createShipment(shipmentRequest);
|
|
||||||
}
|
|
||||||
shipment.type = data.service_type;
|
|
||||||
|
|
||||||
const dataSource = this.dataSourceManager.getDataSource('default');
|
|
||||||
return dataSource.transaction(async manager => {
|
|
||||||
const productRepo = manager.getRepository(Product);
|
|
||||||
const shipmentRepo = manager.getRepository(Shipment);
|
|
||||||
const shipmentItemRepo = manager.getRepository(ShipmentItem);
|
|
||||||
const orderShipmentRepo = manager.getRepository(OrderShipment);
|
|
||||||
const stockRecordRepo = manager.getRepository(StockRecord);
|
|
||||||
const stockRepo = manager.getRepository(Stock);
|
|
||||||
const orderRepo = manager.getRepository(Order);
|
|
||||||
|
|
||||||
await shipmentRepo.save(shipment);
|
|
||||||
await this.getShipment(shipment.id);
|
|
||||||
const shipmentItems = [];
|
|
||||||
for (const item of data?.sales) {
|
|
||||||
const product = await productRepo.findOne({ where: { sku: item.sku } });
|
|
||||||
shipmentItems.push({
|
|
||||||
shipment_id: shipment.id,
|
|
||||||
productId: product.id,
|
|
||||||
name: product.name,
|
|
||||||
sku: item.sku,
|
|
||||||
quantity: item.quantity,
|
|
||||||
});
|
|
||||||
const stock = await stockRepo.findOne({
|
|
||||||
where: {
|
|
||||||
stockPointId: data.stockPointId,
|
|
||||||
productSku: item.sku,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
stock.quantity -= item.quantity;
|
|
||||||
await stockRepo.save(stock);
|
|
||||||
await stockRecordRepo.save({
|
|
||||||
stockPointId: data.stockPointId,
|
|
||||||
productSku: item.sku,
|
|
||||||
operationType: StockRecordOperationType.OUT,
|
|
||||||
quantityChange: item.quantity,
|
|
||||||
operatorId: userId,
|
|
||||||
note: `订单${[orderId, ...data.orderIds].join(',')} 发货`,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
await shipmentItemRepo.save(shipmentItems);
|
|
||||||
await orderShipmentRepo.save({
|
|
||||||
order_id: orderId,
|
|
||||||
shipment_id: shipment.id,
|
|
||||||
stockPointId: data.stockPointId,
|
|
||||||
});
|
|
||||||
for (const orderId of data?.orderIds) {
|
|
||||||
await orderShipmentRepo.save({
|
|
||||||
order_id: orderId,
|
|
||||||
shipment_id: shipment.id,
|
|
||||||
stockPointId: data.stockPointId,
|
|
||||||
});
|
|
||||||
const order = await orderRepo.findOneBy({ id: orderId });
|
|
||||||
order.orderStatus = ErpOrderStatus.COMPLETED;
|
|
||||||
order.status = OrderStatus.COMPLETED;
|
|
||||||
await orderRepo.save(order);
|
|
||||||
}
|
|
||||||
order.orderStatus = ErpOrderStatus.COMPLETED;
|
|
||||||
order.status = OrderStatus.COMPLETED;
|
|
||||||
await orderRepo.save(order);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async syncShipment() {
|
async syncShipment() {
|
||||||
|
|
@ -544,7 +531,6 @@ export class LogisticsService {
|
||||||
primary_tracking_number,
|
primary_tracking_number,
|
||||||
stockPointId,
|
stockPointId,
|
||||||
} = param;
|
} = param;
|
||||||
console.log(pageSize, current, primary_tracking_number, stockPointId);
|
|
||||||
|
|
||||||
const offset = pageSize * (current - 1);
|
const offset = pageSize * (current - 1);
|
||||||
const values: any[] = [];
|
const values: any[] = [];
|
||||||
|
|
@ -566,7 +552,6 @@ export class LogisticsService {
|
||||||
LEFT JOIN order_shipment os ON s.id = os.shipment_id
|
LEFT JOIN order_shipment os ON s.id = os.shipment_id
|
||||||
LEFT JOIN stock_point sp ON os.stockPointId = sp.id
|
LEFT JOIN stock_point sp ON os.stockPointId = sp.id
|
||||||
${whereClause}
|
${whereClause}
|
||||||
GROUP BY s.id
|
|
||||||
ORDER BY s.createdAt DESC
|
ORDER BY s.createdAt DESC
|
||||||
LIMIT ?, ?
|
LIMIT ?, ?
|
||||||
`;
|
`;
|
||||||
|
|
|
||||||
|
|
@ -113,7 +113,9 @@ export class OrderService {
|
||||||
const existingOrder = await this.orderModel.findOne({
|
const existingOrder = await this.orderModel.findOne({
|
||||||
where: { externalOrderId: order.id, siteId: siteId },
|
where: { externalOrderId: order.id, siteId: siteId },
|
||||||
});
|
});
|
||||||
|
console.log('before save', order);
|
||||||
const orderId = (await this.saveOrder(siteId, orderData)).id;
|
const orderId = (await this.saveOrder(siteId, orderData)).id;
|
||||||
|
console.log('order_id', orderId);
|
||||||
const externalOrderId = order.id;
|
const externalOrderId = order.id;
|
||||||
if (
|
if (
|
||||||
existingOrder &&
|
existingOrder &&
|
||||||
|
|
@ -202,7 +204,6 @@ export class OrderService {
|
||||||
el => el.key === '_wc_order_attribution_utm_source'
|
el => el.key === '_wc_order_attribution_utm_source'
|
||||||
)?.value || '';
|
)?.value || '';
|
||||||
order.customer_email = order?.billing?.email || order?.shipping?.email;
|
order.customer_email = order?.billing?.email || order?.shipping?.email;
|
||||||
|
|
||||||
const entity = plainToClass(Order, order);
|
const entity = plainToClass(Order, order);
|
||||||
const existingOrder = await this.orderModel.findOne({
|
const existingOrder = await this.orderModel.findOne({
|
||||||
where: { externalOrderId: order.externalOrderId, siteId: siteId },
|
where: { externalOrderId: order.externalOrderId, siteId: siteId },
|
||||||
|
|
@ -215,10 +216,12 @@ export class OrderService {
|
||||||
entity.id = existingOrder.id;
|
entity.id = existingOrder.id;
|
||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
|
console.log('/////////////');
|
||||||
entity.orderStatus = this.mapOrderStatus(entity.status);
|
entity.orderStatus = this.mapOrderStatus(entity.status);
|
||||||
const customer = await this.customerModel.findOne({
|
const customer = await this.customerModel.findOne({
|
||||||
where: { email: order.customer_email },
|
where: { email: order.customer_email },
|
||||||
});
|
});
|
||||||
|
console.log('error? ', this.customerModel);
|
||||||
if(!customer) {
|
if(!customer) {
|
||||||
await this.customerModel.save({
|
await this.customerModel.save({
|
||||||
email: order.customer_email,
|
email: order.customer_email,
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,106 @@
|
||||||
|
import { Provide } from "@midwayjs/core";
|
||||||
|
import { Config } from '@midwayjs/decorator';
|
||||||
|
import axios, { AxiosRequestConfig } from 'axios';
|
||||||
|
|
||||||
|
@Provide()
|
||||||
|
export class UniExpressService {
|
||||||
|
@Config('uniExpress.url')
|
||||||
|
url;
|
||||||
|
|
||||||
|
@Config('uniExpress.clientId')
|
||||||
|
clientId;
|
||||||
|
|
||||||
|
@Config('uniExpress.clientSecret')
|
||||||
|
cliientSecret;
|
||||||
|
|
||||||
|
@Config('uniExpress.customerNo')
|
||||||
|
customerNo;
|
||||||
|
|
||||||
|
async getToken() {
|
||||||
|
const config: AxiosRequestConfig = {
|
||||||
|
method: 'POST',
|
||||||
|
url: `${this.url}/storeauth/customertoken`,
|
||||||
|
data: {
|
||||||
|
'grant_type': 'client_credentials',
|
||||||
|
'client_id': this.clientId,
|
||||||
|
'client_secret': this.cliientSecret
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const tokenBody = await axios.request(config);
|
||||||
|
return tokenBody.data.data.access_token;
|
||||||
|
}
|
||||||
|
|
||||||
|
async getRates(data: any) {
|
||||||
|
try {
|
||||||
|
const requiredKeys = {
|
||||||
|
customer_no: this.customerNo,
|
||||||
|
pickup_warehouse: 1
|
||||||
|
};
|
||||||
|
const body = {
|
||||||
|
...requiredKeys,
|
||||||
|
...data
|
||||||
|
};
|
||||||
|
const token = await this.getToken();
|
||||||
|
const config: AxiosRequestConfig= {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Authorization': `Bearer ${token}`
|
||||||
|
},
|
||||||
|
url: `${this.url}/orders/estimateshipping`,
|
||||||
|
data: body
|
||||||
|
};
|
||||||
|
return (await axios.request(config)).data;
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async createShipment(
|
||||||
|
data: any
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
const requiredKeys = {
|
||||||
|
customer_no: this.customerNo,
|
||||||
|
pickup_warehouse: 1
|
||||||
|
};
|
||||||
|
const body = {
|
||||||
|
...requiredKeys,
|
||||||
|
...data
|
||||||
|
};
|
||||||
|
const token = await this.getToken();
|
||||||
|
const config: AxiosRequestConfig= {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Authorization': `Bearer ${token}`
|
||||||
|
},
|
||||||
|
url: `${this.url}/orders/createbusinessorder`,
|
||||||
|
data: body
|
||||||
|
};
|
||||||
|
const req = await axios.request(config);
|
||||||
|
const res = req.data;
|
||||||
|
return res;
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async getOrdersByDate(from: string, to: string, page: number = 1, perPage: number = 100) {
|
||||||
|
try {
|
||||||
|
const token = await this.getToken();
|
||||||
|
const config: AxiosRequestConfig= {
|
||||||
|
method: 'GET',
|
||||||
|
headers: {
|
||||||
|
'Authorization': `Bearer ${token}`
|
||||||
|
},
|
||||||
|
params: {
|
||||||
|
from, to, page, perPage
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const res = (await axios.request(config)).data;
|
||||||
|
return res;
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue