0
# Express & Logistics
1
2
Express delivery integration and logistics management including shipping, tracking, delivery services, and same-city delivery for WeChat MiniApp e-commerce and service applications.
3
4
## Capabilities
5
6
### Express Service Interface
7
8
Core express delivery operations for package shipping and tracking.
9
10
```java { .api }
11
public interface WxMaExpressService {
12
// Delivery Company Management
13
List<WxMaExpressDeliveryCompany> getAllDelivery() throws WxErrorException;
14
WxMaExpressAccount getAccount(String type, String bindAccount) throws WxErrorException;
15
WxMaExpressAccountResult bindAccount(String type, String bizId, String deliveryId, String password) throws WxErrorException;
16
boolean unbindAccount(String type, String bizId, String deliveryId) throws WxErrorException;
17
18
// Order Management
19
WxMaExpressOrderResult addOrder(WxMaExpressOrder order) throws WxErrorException;
20
boolean cancelOrder(String orderId, String openid, String deliveryId, String waybillId) throws WxErrorException;
21
WxMaExpressOrderResult getOrder(String orderId, String openid, String deliveryId, String waybillId) throws WxErrorException;
22
WxMaExpressPathResult getPath(String orderId, String openid, String deliveryId, String waybillId) throws WxErrorException;
23
24
// Shipping Information
25
WxMaExpressQuotaResult getQuota(String deliveryId) throws WxErrorException;
26
WxMaExpressPrinterResult getPrinter() throws WxErrorException;
27
WxMaExpressPrinterResult updatePrinter(String openid, WxMaExpressPrinter printer) throws WxErrorException;
28
}
29
```
30
31
### Immediate Delivery Service Interface
32
33
Same-city instant delivery services for time-sensitive deliveries.
34
35
```java { .api }
36
public interface WxMaImmediateDeliveryService {
37
// Delivery Configuration
38
WxMaImmeDeliveryBindResult bindAccount(String shopAppId, String deliveryId, String shopAppKey) throws WxErrorException;
39
40
// Order Management
41
WxMaImmeDeliveryCreateResult createOrder(WxMaImmeDeliveryOrder order) throws WxErrorException;
42
boolean addOrderTip(String shopOrderId, String deliveryToken, Integer tips) throws WxErrorException;
43
boolean cancelOrder(String shopOrderId, String deliveryToken, Integer reasonCode) throws WxErrorException;
44
WxMaImmeDeliveryOrderResult getOrder(String shopOrderId, String openid) throws WxErrorException;
45
46
// Delivery Management
47
WxMaImmeDeliveryCarrier mockUpdateOrder(String shopOrderId, Integer actionType) throws WxErrorException;
48
boolean receiveOrder(String shopOrderId) throws WxErrorException;
49
50
// Service Information
51
WxMaImmeDeliveryResult getAllImmeDelivery() throws WxErrorException;
52
boolean onAddOrder(String shopOrderId) throws WxErrorException;
53
boolean onOrderStatus(String shopOrderId) throws WxErrorException;
54
}
55
```
56
57
### Express Delivery Return Service
58
59
Return and exchange logistics component for e-commerce order returns.
60
61
```java { .api }
62
public interface WxMaExpressDeliveryReturnService {
63
// Return Order Management
64
WxMaExpressDeliveryReturnResult addReturnOrder(WxMaExpressDeliveryReturnOrder order) throws WxErrorException;
65
boolean cancelReturnOrder(String orderId, String openid, String waybillId) throws WxErrorException;
66
WxMaExpressDeliveryReturnOrderResult getReturnOrder(String orderId, String openid, String waybillId) throws WxErrorException;
67
68
// Return Path Tracking
69
WxMaExpressDeliveryReturnPathResult getReturnPath(String orderId, String openid, String waybillId) throws WxErrorException;
70
}
71
```
72
73
### Same-City Delivery Service
74
75
Local delivery services for same-city fulfillment.
76
77
```java { .api }
78
public interface WxMaIntracityService {
79
// Service Management
80
WxMaIntracityServiceResult queryService(WxMaIntracityServiceQuery query) throws WxErrorException;
81
82
// Order Operations
83
WxMaIntracityOrderResult createOrder(WxMaIntracityOrder order) throws WxErrorException;
84
boolean cancelOrder(String orderId, Integer reasonCode, String reasonDesc) throws WxErrorException;
85
WxMaIntracityOrderDetailResult getOrder(String orderId) throws WxErrorException;
86
87
// Real-time Updates
88
WxMaIntracityRealtimeOrderResult realtimeQuery(String orderId) throws WxErrorException;
89
}
90
```
91
92
### Express Data Models
93
94
Comprehensive data models for express delivery operations.
95
96
```java { .api }
97
public class WxMaExpressOrder implements Serializable {
98
private String orderId; // Order ID
99
private String openid; // User OpenID
100
private String deliveryId; // Delivery company ID
101
private String bizId; // Business ID
102
private String customRemark; // Custom remark
103
private String tagid; // Template ID
104
private WxMaExpressSender sender; // Sender information
105
private WxMaExpressReceiver receiver; // Receiver information
106
private WxMaExpressShop shop; // Shop information
107
private WxMaExpressInsured insured; // Insurance information
108
private WxMaExpressService service; // Service information
109
110
// Getters and setters
111
public String getOrderId();
112
public void setOrderId(String orderId);
113
public String getOpenid();
114
public void setOpenid(String openid);
115
public String getDeliveryId();
116
public void setDeliveryId(String deliveryId);
117
public WxMaExpressSender getSender();
118
public void setSender(WxMaExpressSender sender);
119
public WxMaExpressReceiver getReceiver();
120
public void setReceiver(WxMaExpressReceiver receiver);
121
122
// Utility methods
123
public static WxMaExpressOrder fromJson(String json);
124
public String toJson();
125
}
126
127
public class WxMaExpressSender implements Serializable {
128
private String name; // Sender name
129
private String tel; // Phone number
130
private String mobile; // Mobile number
131
private String company; // Company name
132
private String postCode; // Postal code
133
private String country; // Country
134
private String province; // Province
135
private String city; // City
136
private String area; // District/Area
137
private String address; // Detailed address
138
139
// Getters and setters
140
public String getName();
141
public void setName(String name);
142
public String getTel();
143
public void setTel(String tel);
144
public String getAddress();
145
public void setAddress(String address);
146
public String getCity();
147
public void setCity(String city);
148
public String getProvince();
149
public void setProvince(String province);
150
}
151
152
public class WxMaExpressReceiver implements Serializable {
153
private String name; // Receiver name
154
private String tel; // Phone number
155
private String mobile; // Mobile number
156
private String company; // Company name
157
private String postCode; // Postal code
158
private String country; // Country
159
private String province; // Province
160
private String city; // City
161
private String area; // District/Area
162
private String address; // Detailed address
163
164
// Same structure as WxMaExpressSender
165
// Getters and setters omitted for brevity
166
}
167
168
public class WxMaExpressOrderResult implements Serializable {
169
private Integer resultCode; // Result code
170
private String resultMsg; // Result message
171
private String orderId; // Order ID
172
private String waybillId; // Waybill number
173
private String waybillData; // Waybill data for printing
174
175
// Getters and setters
176
public Integer getResultCode();
177
public void setResultCode(Integer resultCode);
178
public String getWaybillId();
179
public void setWaybillId(String waybillId);
180
181
// Convenience methods
182
public boolean isSuccess();
183
public String getWaybillData();
184
}
185
```
186
187
### Immediate Delivery Models
188
189
Data models for same-city instant delivery operations.
190
191
```java { .api }
192
public class WxMaImmeDeliveryOrder implements Serializable {
193
private String shopOrderId; // Shop order ID
194
private String shopNo; // Shop number
195
private Integer deliverySign; // Delivery signature requirement
196
private String shopOrderStatus; // Shop order status
197
private String deliveryId; // Delivery company ID
198
private String openid; // User OpenID
199
private String subtip; // Delivery note
200
private String tag; // Order tag
201
private WxMaImmeDeliverySender sender; // Sender info
202
private WxMaImmeDeliveryReceiver receiver; // Receiver info
203
private WxMaImmeDeliveryOrder cargo; // Cargo info
204
private WxMaImmeDeliveryOrderInfo orderInfo; // Order details
205
private WxMaImmeDeliveryShop shop; // Shop info
206
207
// Getters and setters
208
public String getShopOrderId();
209
public void setShopOrderId(String shopOrderId);
210
public String getDeliveryId();
211
public void setDeliveryId(String deliveryId);
212
213
// Nested classes for sender, receiver, cargo, etc.
214
public static class WxMaImmeDeliverySender {
215
private String name; // Sender name
216
private String city; // City
217
private String address; // Address
218
private Double lng; // Longitude
219
private Double lat; // Latitude
220
private String phone; // Phone number
221
222
// Getters and setters
223
public String getName();
224
public void setName(String name);
225
public String getPhone();
226
public void setPhone(String phone);
227
public Double getLng();
228
public void setLng(Double lng);
229
public Double getLat();
230
public void setLat(Double lat);
231
}
232
233
public static class WxMaImmeDeliveryReceiver {
234
private String name; // Receiver name
235
private String city; // City
236
private String address; // Address
237
private Double lng; // Longitude
238
private Double lat; // Latitude
239
private String phone; // Phone number
240
241
// Same structure as sender
242
}
243
}
244
245
public class WxMaImmeDeliveryCreateResult implements Serializable {
246
private Integer resultcode; // Result code
247
private String resultmsg; // Result message
248
private String fee; // Delivery fee
249
private String deliverfee; // Actual delivery fee
250
private String couponfee; // Coupon discount
251
private String tips; // Tips
252
private String insurancefee; // Insurance fee
253
private String distance; // Distance
254
private String waybillId; // Waybill ID
255
private String orderId; // Order ID
256
private String deliveryToken; // Delivery token
257
258
// Getters and setters
259
public boolean isSuccess();
260
public String getWaybillId();
261
public String getDeliveryToken();
262
}
263
```
264
265
## Usage Examples
266
267
### Express Delivery Management
268
269
#### Set Up Express Delivery
270
271
```java
272
@Service
273
public class ExpressDeliveryService {
274
275
@Autowired
276
private WxMaService wxMaService;
277
278
public List<DeliveryCompany> getAvailableDeliveryCompanies() {
279
try {
280
List<WxMaExpressDeliveryCompany> companies = wxMaService.getExpressService()
281
.getAllDelivery();
282
283
return companies.stream()
284
.map(this::convertToDeliveryCompany)
285
.collect(Collectors.toList());
286
287
} catch (WxErrorException e) {
288
logger.error("Failed to get delivery companies: {}", e.getMessage());
289
throw new ExpressServiceException("Failed to get delivery companies", e);
290
}
291
}
292
293
public void bindDeliveryAccount(String deliveryCompanyId, String accountId, String password) {
294
try {
295
WxMaExpressAccountResult result = wxMaService.getExpressService()
296
.bindAccount("bind", accountId, deliveryCompanyId, password);
297
298
if (result.getResultCode() == 0) {
299
logger.info("Successfully bound delivery account: {} to company: {}",
300
accountId, deliveryCompanyId);
301
} else {
302
throw new ExpressServiceException("Failed to bind account: " + result.getResultMsg());
303
}
304
305
} catch (WxErrorException e) {
306
logger.error("Delivery account binding failed: {}", e.getMessage());
307
throw new ExpressServiceException("Account binding failed", e);
308
}
309
}
310
}
311
```
312
313
#### Create Express Order
314
315
```java
316
public class ExpressOrderService {
317
318
public String createExpressOrder(ExpressOrderRequest request) {
319
try {
320
// Build express order
321
WxMaExpressOrder order = new WxMaExpressOrder();
322
order.setOrderId(request.getOrderId());
323
order.setOpenid(request.getOpenid());
324
order.setDeliveryId(request.getDeliveryCompanyId());
325
order.setBizId(request.getBizId());
326
order.setCustomRemark(request.getRemark());
327
328
// Set sender information
329
WxMaExpressSender sender = new WxMaExpressSender();
330
sender.setName(request.getSender().getName());
331
sender.setTel(request.getSender().getPhone());
332
sender.setProvince(request.getSender().getProvince());
333
sender.setCity(request.getSender().getCity());
334
sender.setArea(request.getSender().getArea());
335
sender.setAddress(request.getSender().getAddress());
336
sender.setPostCode(request.getSender().getPostCode());
337
order.setSender(sender);
338
339
// Set receiver information
340
WxMaExpressReceiver receiver = new WxMaExpressReceiver();
341
receiver.setName(request.getReceiver().getName());
342
receiver.setTel(request.getReceiver().getPhone());
343
receiver.setProvince(request.getReceiver().getProvince());
344
receiver.setCity(request.getReceiver().getCity());
345
receiver.setArea(request.getReceiver().getArea());
346
receiver.setAddress(request.getReceiver().getAddress());
347
receiver.setPostCode(request.getReceiver().getPostCode());
348
order.setReceiver(receiver);
349
350
// Set cargo information if needed
351
if (request.getCargo() != null) {
352
WxMaExpressCargo cargo = new WxMaExpressCargo();
353
cargo.setCount(request.getCargo().getCount());
354
cargo.setWeight(request.getCargo().getWeight());
355
cargo.setSpaceX(request.getCargo().getLength());
356
cargo.setSpaceY(request.getCargo().getWidth());
357
cargo.setSpaceZ(request.getCargo().getHeight());
358
cargo.setDetailList(request.getCargo().getItems().stream()
359
.map(item -> new WxMaExpressCargoDetail(item.getName(), item.getCount()))
360
.collect(Collectors.toList()));
361
order.setCargo(cargo);
362
}
363
364
// Create order with WeChat
365
WxMaExpressOrderResult result = wxMaService.getExpressService()
366
.addOrder(order);
367
368
if (result.isSuccess()) {
369
String waybillId = result.getWaybillId();
370
logger.info("Express order created: {} -> waybill: {}",
371
request.getOrderId(), waybillId);
372
373
// Store waybill information
374
storeWaybillInfo(request.getOrderId(), waybillId, result.getWaybillData());
375
376
return waybillId;
377
} else {
378
throw new ExpressOrderException("Order creation failed: " + result.getResultMsg());
379
}
380
381
} catch (WxErrorException e) {
382
logger.error("Express order creation failed: {}", e.getMessage());
383
throw new ExpressOrderException("Failed to create express order", e);
384
}
385
}
386
387
public ExpressOrderStatus getOrderStatus(String orderId, String openid,
388
String deliveryId, String waybillId) {
389
try {
390
WxMaExpressOrderResult result = wxMaService.getExpressService()
391
.getOrder(orderId, openid, deliveryId, waybillId);
392
393
return convertToOrderStatus(result);
394
395
} catch (WxErrorException e) {
396
logger.error("Failed to get express order status: {}", e.getMessage());
397
throw new ExpressOrderException("Failed to get order status", e);
398
}
399
}
400
401
public List<ExpressPathInfo> getDeliveryPath(String orderId, String openid,
402
String deliveryId, String waybillId) {
403
try {
404
WxMaExpressPathResult result = wxMaService.getExpressService()
405
.getPath(orderId, openid, deliveryId, waybillId);
406
407
return result.getPathItemList().stream()
408
.map(this::convertToPathInfo)
409
.collect(Collectors.toList());
410
411
} catch (WxErrorException e) {
412
logger.error("Failed to get delivery path: {}", e.getMessage());
413
return Collections.emptyList();
414
}
415
}
416
}
417
```
418
419
### Immediate Delivery Service
420
421
#### Same-City Instant Delivery
422
423
```java
424
@Service
425
public class ImmediateDeliveryService {
426
427
public String createImmediateDelivery(ImmediateDeliveryRequest request) {
428
try {
429
// Build immediate delivery order
430
WxMaImmeDeliveryOrder order = new WxMaImmeDeliveryOrder();
431
order.setShopOrderId(request.getOrderId());
432
order.setDeliveryId(request.getDeliveryCompanyId());
433
order.setOpenid(request.getOpenid());
434
order.setSubtip(request.getDeliveryNote());
435
order.setDeliverySign(request.getRequireSignature() ? 1 : 0);
436
437
// Set sender information
438
WxMaImmeDeliveryOrder.WxMaImmeDeliverySender sender =
439
new WxMaImmeDeliveryOrder.WxMaImmeDeliverySender();
440
sender.setName(request.getSender().getName());
441
sender.setPhone(request.getSender().getPhone());
442
sender.setAddress(request.getSender().getAddress());
443
sender.setLng(request.getSender().getLongitude());
444
sender.setLat(request.getSender().getLatitude());
445
order.setSender(sender);
446
447
// Set receiver information
448
WxMaImmeDeliveryOrder.WxMaImmeDeliveryReceiver receiver =
449
new WxMaImmeDeliveryOrder.WxMaImmeDeliveryReceiver();
450
receiver.setName(request.getReceiver().getName());
451
receiver.setPhone(request.getReceiver().getPhone());
452
receiver.setAddress(request.getReceiver().getAddress());
453
receiver.setLng(request.getReceiver().getLongitude());
454
receiver.setLat(request.getReceiver().getLatitude());
455
order.setReceiver(receiver);
456
457
// Create immediate delivery order
458
WxMaImmeDeliveryCreateResult result = wxMaService.getImmeDeliveryService()
459
.createOrder(order);
460
461
if (result.isSuccess()) {
462
String waybillId = result.getWaybillId();
463
String deliveryToken = result.getDeliveryToken();
464
465
logger.info("Immediate delivery created: {} -> waybill: {}",
466
request.getOrderId(), waybillId);
467
468
// Store delivery information
469
storeDeliveryInfo(request.getOrderId(), waybillId, deliveryToken, result);
470
471
return waybillId;
472
} else {
473
throw new ImmediateDeliveryException(
474
"Immediate delivery creation failed: " + result.getResultmsg());
475
}
476
477
} catch (WxErrorException e) {
478
logger.error("Immediate delivery creation failed: {}", e.getMessage());
479
throw new ImmediateDeliveryException("Failed to create immediate delivery", e);
480
}
481
}
482
483
public void addDeliveryTip(String orderId, String deliveryToken, double tipAmount) {
484
try {
485
int tipAmountCents = (int) (tipAmount * 100); // Convert to cents
486
487
boolean success = wxMaService.getImmeDeliveryService()
488
.addOrderTip(orderId, deliveryToken, tipAmountCents);
489
490
if (success) {
491
logger.info("Added tip of ¥{} to order: {}", tipAmount, orderId);
492
}
493
494
} catch (WxErrorException e) {
495
logger.error("Failed to add delivery tip: {}", e.getMessage());
496
}
497
}
498
499
public void cancelImmediateDelivery(String orderId, String deliveryToken,
500
CancellationReason reason) {
501
try {
502
Integer reasonCode = getCancellationReasonCode(reason);
503
504
boolean success = wxMaService.getImmeDeliveryService()
505
.cancelOrder(orderId, deliveryToken, reasonCode);
506
507
if (success) {
508
logger.info("Cancelled immediate delivery order: {} (reason: {})",
509
orderId, reason);
510
511
// Update order status in database
512
updateOrderStatus(orderId, "cancelled", reason.getDescription());
513
}
514
515
} catch (WxErrorException e) {
516
logger.error("Failed to cancel immediate delivery: {}", e.getMessage());
517
throw new ImmediateDeliveryException("Cancellation failed", e);
518
}
519
}
520
}
521
```
522
523
### Delivery Tracking and Monitoring
524
525
```java
526
@Service
527
public class DeliveryTrackingService {
528
529
@Scheduled(fixedRate = 300000) // Every 5 minutes
530
public void updateDeliveryStatuses() {
531
List<ActiveDelivery> activeDeliveries = deliveryRepository.findActiveDeliveries();
532
533
for (ActiveDelivery delivery : activeDeliveries) {
534
try {
535
updateDeliveryStatus(delivery);
536
Thread.sleep(100); // Rate limiting
537
538
} catch (Exception e) {
539
logger.error("Failed to update delivery status for order {}: {}",
540
delivery.getOrderId(), e.getMessage());
541
}
542
}
543
}
544
545
private void updateDeliveryStatus(ActiveDelivery delivery) {
546
try {
547
if (delivery.getDeliveryType() == DeliveryType.EXPRESS) {
548
updateExpressDeliveryStatus(delivery);
549
} else if (delivery.getDeliveryType() == DeliveryType.IMMEDIATE) {
550
updateImmediateDeliveryStatus(delivery);
551
}
552
553
} catch (WxErrorException e) {
554
logger.error("Delivery status update failed: {}", e.getMessage());
555
}
556
}
557
558
private void updateExpressDeliveryStatus(ActiveDelivery delivery) throws WxErrorException {
559
WxMaExpressPathResult pathResult = wxMaService.getExpressService()
560
.getPath(delivery.getOrderId(), delivery.getOpenid(),
561
delivery.getDeliveryId(), delivery.getWaybillId());
562
563
if (pathResult.isSuccess() && !pathResult.getPathItemList().isEmpty()) {
564
List<WxMaExpressPathItem> pathItems = pathResult.getPathItemList();
565
WxMaExpressPathItem latestStatus = pathItems.get(0); // Latest status first
566
567
// Check if status has changed
568
if (!latestStatus.getActionType().equals(delivery.getLastStatus())) {
569
// Update status in database
570
delivery.setLastStatus(latestStatus.getActionType());
571
delivery.setLastStatusTime(new Date(latestStatus.getActionTime() * 1000));
572
deliveryRepository.save(delivery);
573
574
// Send status notification to user
575
sendStatusNotification(delivery, latestStatus);
576
577
// Check if delivered
578
if (isDeliveredStatus(latestStatus.getActionType())) {
579
handleDeliveryCompleted(delivery);
580
}
581
}
582
}
583
}
584
585
private void updateImmediateDeliveryStatus(ActiveDelivery delivery) throws WxErrorException {
586
WxMaImmeDeliveryOrderResult orderResult = wxMaService.getImmeDeliveryService()
587
.getOrder(delivery.getOrderId(), delivery.getOpenid());
588
589
if (orderResult.isSuccess()) {
590
String currentStatus = orderResult.getOrderStatus();
591
592
if (!currentStatus.equals(delivery.getLastStatus())) {
593
delivery.setLastStatus(currentStatus);
594
delivery.setLastStatusTime(new Date());
595
deliveryRepository.save(delivery);
596
597
// Send notification
598
sendImmediateDeliveryNotification(delivery, currentStatus);
599
600
// Handle completion
601
if ("FINISHED_FINISH".equals(currentStatus)) {
602
handleDeliveryCompleted(delivery);
603
}
604
}
605
}
606
}
607
608
private void sendStatusNotification(ActiveDelivery delivery, WxMaExpressPathItem status) {
609
// Send WeChat subscription message
610
Map<String, WxMaSubscribeData> data = new HashMap<>();
611
data.put("thing1", new WxMaSubscribeData(delivery.getOrderId()));
612
data.put("thing2", new WxMaSubscribeData(status.getActionTypeDesc()));
613
data.put("time3", new WxMaSubscribeData(
614
new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
615
.format(new Date(status.getActionTime() * 1000))));
616
617
WxMaSubscribeMessage message = new WxMaSubscribeMessage();
618
message.setToUser(delivery.getOpenid());
619
message.setTemplateId("delivery_status_template_id");
620
message.setData(data);
621
622
try {
623
wxMaService.getMsgService().sendSubscribeMsg(message);
624
} catch (WxErrorException e) {
625
logger.error("Failed to send delivery notification: {}", e.getMessage());
626
}
627
}
628
}
629
```
630
631
### Return and Exchange Management
632
633
```java
634
@Service
635
public class ReturnDeliveryService {
636
637
public String createReturnOrder(ReturnOrderRequest request) {
638
try {
639
WxMaExpressDeliveryReturnOrder returnOrder = new WxMaExpressDeliveryReturnOrder();
640
returnOrder.setOrderId(request.getOriginalOrderId());
641
returnOrder.setOpenid(request.getOpenid());
642
returnOrder.setReturnInfo(request.getReturnReason());
643
644
// Set pickup information (customer)
645
WxMaExpressDeliveryReturnSender sender = new WxMaExpressDeliveryReturnSender();
646
sender.setName(request.getCustomer().getName());
647
sender.setTel(request.getCustomer().getPhone());
648
sender.setAddress(request.getCustomer().getAddress());
649
returnOrder.setSender(sender);
650
651
// Set delivery information (merchant)
652
WxMaExpressDeliveryReturnReceiver receiver = new WxMaExpressDeliveryReturnReceiver();
653
receiver.setName(request.getMerchant().getName());
654
receiver.setTel(request.getMerchant().getPhone());
655
receiver.setAddress(request.getMerchant().getAddress());
656
returnOrder.setReceiver(receiver);
657
658
WxMaExpressDeliveryReturnResult result = wxMaService.getExpressDeliveryReturnService()
659
.addReturnOrder(returnOrder);
660
661
if (result.isSuccess()) {
662
String waybillId = result.getWaybillId();
663
logger.info("Return order created: {} -> waybill: {}",
664
request.getOriginalOrderId(), waybillId);
665
666
// Store return order information
667
storeReturnOrderInfo(request, waybillId, result);
668
669
return waybillId;
670
} else {
671
throw new ReturnOrderException("Return order creation failed: " + result.getResultMsg());
672
}
673
674
} catch (WxErrorException e) {
675
logger.error("Return order creation failed: {}", e.getMessage());
676
throw new ReturnOrderException("Failed to create return order", e);
677
}
678
}
679
680
public List<ReturnPathInfo> getReturnPath(String orderId, String openid, String waybillId) {
681
try {
682
WxMaExpressDeliveryReturnPathResult result = wxMaService.getExpressDeliveryReturnService()
683
.getReturnPath(orderId, openid, waybillId);
684
685
return result.getPathItemList().stream()
686
.map(this::convertToReturnPathInfo)
687
.collect(Collectors.toList());
688
689
} catch (WxErrorException e) {
690
logger.error("Failed to get return path: {}", e.getMessage());
691
return Collections.emptyList();
692
}
693
}
694
}
695
```
696
697
### Logistics Analytics
698
699
```java
700
@Service
701
public class LogisticsAnalyticsService {
702
703
public DeliveryPerformanceReport generateDeliveryReport(Date startDate, Date endDate) {
704
List<DeliveryRecord> deliveries = deliveryRepository.findByDateRange(startDate, endDate);
705
706
DeliveryPerformanceReport report = new DeliveryPerformanceReport();
707
report.setTotalDeliveries(deliveries.size());
708
709
// Calculate average delivery time
710
double avgDeliveryHours = deliveries.stream()
711
.filter(d -> d.getDeliveredTime() != null)
712
.mapToLong(d -> d.getDeliveredTime().getTime() - d.getCreatedTime().getTime())
713
.average()
714
.orElse(0) / (1000 * 60 * 60); // Convert to hours
715
716
report.setAverageDeliveryHours(avgDeliveryHours);
717
718
// Success rate
719
long successfulDeliveries = deliveries.stream()
720
.filter(d -> "delivered".equals(d.getStatus()))
721
.count();
722
report.setSuccessRate((double) successfulDeliveries / deliveries.size() * 100);
723
724
// Cost analysis
725
double totalCost = deliveries.stream()
726
.mapToDouble(DeliveryRecord::getCost)
727
.sum();
728
report.setTotalCost(totalCost);
729
report.setAverageCost(totalCost / deliveries.size());
730
731
// Delivery company performance
732
Map<String, CompanyPerformance> companyPerformance = deliveries.stream()
733
.collect(Collectors.groupingBy(DeliveryRecord::getDeliveryCompany))
734
.entrySet().stream()
735
.collect(Collectors.toMap(
736
Map.Entry::getKey,
737
entry -> calculateCompanyPerformance(entry.getValue())
738
));
739
740
report.setCompanyPerformance(companyPerformance);
741
742
return report;
743
}
744
745
private CompanyPerformance calculateCompanyPerformance(List<DeliveryRecord> deliveries) {
746
CompanyPerformance performance = new CompanyPerformance();
747
performance.setTotalOrders(deliveries.size());
748
749
long successful = deliveries.stream()
750
.filter(d -> "delivered".equals(d.getStatus()))
751
.count();
752
performance.setSuccessRate((double) successful / deliveries.size() * 100);
753
754
double avgTime = deliveries.stream()
755
.filter(d -> d.getDeliveredTime() != null)
756
.mapToLong(d -> d.getDeliveredTime().getTime() - d.getCreatedTime().getTime())
757
.average()
758
.orElse(0) / (1000 * 60 * 60);
759
performance.setAverageDeliveryHours(avgTime);
760
761
return performance;
762
}
763
}
764
```
765
766
This logistics module provides comprehensive express delivery, same-city delivery, return logistics, and delivery tracking capabilities for WeChat MiniApp e-commerce and service applications.