feat: add express pickup orders
This commit is contained in:
@@ -0,0 +1,13 @@
|
|||||||
|
package com.linhelp.express;
|
||||||
|
|
||||||
|
public class ExpressCancelRequest {
|
||||||
|
private String reason;
|
||||||
|
|
||||||
|
public String getReason() {
|
||||||
|
return reason;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setReason(String reason) {
|
||||||
|
this.reason = reason;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package com.linhelp.express;
|
||||||
|
|
||||||
|
import javax.validation.constraints.Min;
|
||||||
|
import javax.validation.constraints.NotBlank;
|
||||||
|
|
||||||
|
public class ExpressFeeAdjustRequest {
|
||||||
|
@Min(0)
|
||||||
|
private int feeCent;
|
||||||
|
|
||||||
|
@NotBlank
|
||||||
|
private String reason;
|
||||||
|
|
||||||
|
public int getFeeCent() {
|
||||||
|
return feeCent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFeeCent(int feeCent) {
|
||||||
|
this.feeCent = feeCent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getReason() {
|
||||||
|
return reason;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setReason(String reason) {
|
||||||
|
this.reason = reason;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package com.linhelp.express;
|
||||||
|
|
||||||
|
public final class ExpressFeeCalculator {
|
||||||
|
private ExpressFeeCalculator() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int calculateCent(int packageCount) {
|
||||||
|
if (packageCount <= 0) {
|
||||||
|
throw new IllegalArgumentException("件数必须大于0");
|
||||||
|
}
|
||||||
|
return 300 + Math.max(0, packageCount - 1) * 100;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package com.linhelp.express;
|
||||||
|
|
||||||
|
import com.linhelp.common.enums.OfflinePayStatus;
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
|
||||||
|
public class ExpressOfflinePayRequest {
|
||||||
|
@NotNull
|
||||||
|
private OfflinePayStatus status;
|
||||||
|
|
||||||
|
public OfflinePayStatus getStatus() {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStatus(OfflinePayStatus status) {
|
||||||
|
this.status = status;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
package com.linhelp.express;
|
||||||
|
|
||||||
|
import com.linhelp.common.api.ApiResponse;
|
||||||
|
import com.linhelp.common.enums.ExpressOrderStatus;
|
||||||
|
import com.linhelp.common.security.AuthService;
|
||||||
|
import com.linhelp.common.security.CurrentUser;
|
||||||
|
import com.linhelp.common.security.RequireRole;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PutMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import javax.validation.Valid;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
public class ExpressOrderController {
|
||||||
|
private final ExpressOrderService expressOrderService;
|
||||||
|
private final AuthService authService;
|
||||||
|
|
||||||
|
public ExpressOrderController(ExpressOrderService expressOrderService, AuthService authService) {
|
||||||
|
this.expressOrderService = expressOrderService;
|
||||||
|
this.authService = authService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/api/mini/express-orders")
|
||||||
|
public ApiResponse<ExpressOrderResponse> create(@Valid @RequestBody ExpressOrderRequest request) {
|
||||||
|
CurrentUser user = authService.currentUser();
|
||||||
|
request.setTenantId(user.getTenantId());
|
||||||
|
request.setCommunityId(user.getCommunityId());
|
||||||
|
return ApiResponse.ok(expressOrderService.create(user.getUserId(), request));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/api/mini/express-orders")
|
||||||
|
public ApiResponse<List<ExpressOrderResponse>> listMine() {
|
||||||
|
CurrentUser user = authService.currentUser();
|
||||||
|
return ApiResponse.ok(expressOrderService.listMine(user.getUserId()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/api/mini/express-orders/{id}")
|
||||||
|
public ApiResponse<ExpressOrderResponse> miniDetail(@PathVariable Long id) {
|
||||||
|
return ApiResponse.ok(expressOrderService.detail(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PutMapping("/api/mini/express-orders/{id}/cancel")
|
||||||
|
public ApiResponse<ExpressOrderResponse> miniCancel(@PathVariable Long id, @RequestBody(required = false) ExpressCancelRequest request) {
|
||||||
|
return ApiResponse.ok(expressOrderService.cancel(id, request == null ? null : request.getReason()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PutMapping("/api/mini/express-orders/{id}/complete")
|
||||||
|
public ApiResponse<ExpressOrderResponse> miniComplete(@PathVariable Long id) {
|
||||||
|
return ApiResponse.ok(expressOrderService.complete(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/api/admin/express-orders")
|
||||||
|
@RequireRole({"PLATFORM_ADMIN", "COMMUNITY_ADMIN", "MERCHANT"})
|
||||||
|
public ApiResponse<List<ExpressOrderResponse>> listAdmin(@RequestParam(required = false) ExpressOrderStatus status) {
|
||||||
|
CurrentUser user = authService.currentUser();
|
||||||
|
return ApiResponse.ok(expressOrderService.listAdmin(user.getCommunityId(), status));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/api/admin/express-orders/{id}")
|
||||||
|
@RequireRole({"PLATFORM_ADMIN", "COMMUNITY_ADMIN", "MERCHANT"})
|
||||||
|
public ApiResponse<ExpressOrderResponse> adminDetail(@PathVariable Long id) {
|
||||||
|
return ApiResponse.ok(expressOrderService.detail(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PutMapping("/api/admin/express-orders/{id}/confirm")
|
||||||
|
@RequireRole({"PLATFORM_ADMIN", "COMMUNITY_ADMIN", "MERCHANT"})
|
||||||
|
public ApiResponse<ExpressOrderResponse> confirm(@PathVariable Long id) {
|
||||||
|
return ApiResponse.ok(expressOrderService.confirm(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PutMapping("/api/admin/express-orders/{id}/adjust-fee")
|
||||||
|
@RequireRole({"PLATFORM_ADMIN", "COMMUNITY_ADMIN", "MERCHANT"})
|
||||||
|
public ApiResponse<ExpressOrderResponse> adjustFee(@PathVariable Long id,
|
||||||
|
@Valid @RequestBody ExpressFeeAdjustRequest request) {
|
||||||
|
return ApiResponse.ok(expressOrderService.adjustFee(id, request.getFeeCent(), request.getReason()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PutMapping("/api/admin/express-orders/{id}/cancel")
|
||||||
|
@RequireRole({"PLATFORM_ADMIN", "COMMUNITY_ADMIN", "MERCHANT"})
|
||||||
|
public ApiResponse<ExpressOrderResponse> adminCancel(@PathVariable Long id, @RequestBody(required = false) ExpressCancelRequest request) {
|
||||||
|
return ApiResponse.ok(expressOrderService.cancel(id, request == null ? null : request.getReason()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PutMapping("/api/admin/express-orders/{id}/offline-pay-status")
|
||||||
|
@RequireRole({"PLATFORM_ADMIN", "COMMUNITY_ADMIN", "MERCHANT"})
|
||||||
|
public ApiResponse<ExpressOrderResponse> updateOfflinePayStatus(@PathVariable Long id,
|
||||||
|
@Valid @RequestBody ExpressOfflinePayRequest request) {
|
||||||
|
return ApiResponse.ok(expressOrderService.updateOfflinePayStatus(id, request.getStatus()));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
package com.linhelp.express;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
public class ExpressOrderLogResponse {
|
||||||
|
private Long id;
|
||||||
|
private Long orderId;
|
||||||
|
private String action;
|
||||||
|
private String content;
|
||||||
|
private LocalDateTime createdAt;
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getOrderId() {
|
||||||
|
return orderId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOrderId(Long orderId) {
|
||||||
|
this.orderId = orderId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAction() {
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAction(String action) {
|
||||||
|
this.action = action;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getContent() {
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setContent(String content) {
|
||||||
|
this.content = content;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDateTime getCreatedAt() {
|
||||||
|
return createdAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCreatedAt(LocalDateTime createdAt) {
|
||||||
|
this.createdAt = createdAt;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
package com.linhelp.express;
|
||||||
|
|
||||||
|
import javax.validation.constraints.Min;
|
||||||
|
import javax.validation.constraints.NotBlank;
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
|
||||||
|
public class ExpressOrderRequest {
|
||||||
|
private Long tenantId;
|
||||||
|
private Long communityId;
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private Long addressId;
|
||||||
|
|
||||||
|
@NotBlank
|
||||||
|
private String expressCompany;
|
||||||
|
|
||||||
|
@NotBlank
|
||||||
|
private String pickupCode;
|
||||||
|
|
||||||
|
@NotBlank
|
||||||
|
private String pickupAddress;
|
||||||
|
|
||||||
|
private String receiverPhone;
|
||||||
|
|
||||||
|
@Min(1)
|
||||||
|
private int packageCount = 1;
|
||||||
|
|
||||||
|
private String remark;
|
||||||
|
|
||||||
|
public Long getTenantId() {
|
||||||
|
return tenantId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTenantId(Long tenantId) {
|
||||||
|
this.tenantId = tenantId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getCommunityId() {
|
||||||
|
return communityId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCommunityId(Long communityId) {
|
||||||
|
this.communityId = communityId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getAddressId() {
|
||||||
|
return addressId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAddressId(Long addressId) {
|
||||||
|
this.addressId = addressId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getExpressCompany() {
|
||||||
|
return expressCompany;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExpressCompany(String expressCompany) {
|
||||||
|
this.expressCompany = expressCompany;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPickupCode() {
|
||||||
|
return pickupCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPickupCode(String pickupCode) {
|
||||||
|
this.pickupCode = pickupCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPickupAddress() {
|
||||||
|
return pickupAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPickupAddress(String pickupAddress) {
|
||||||
|
this.pickupAddress = pickupAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getReceiverPhone() {
|
||||||
|
return receiverPhone;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setReceiverPhone(String receiverPhone) {
|
||||||
|
this.receiverPhone = receiverPhone;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPackageCount() {
|
||||||
|
return packageCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPackageCount(int packageCount) {
|
||||||
|
this.packageCount = packageCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRemark() {
|
||||||
|
return remark;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRemark(String remark) {
|
||||||
|
this.remark = remark;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,218 @@
|
|||||||
|
package com.linhelp.express;
|
||||||
|
|
||||||
|
import com.linhelp.common.enums.ExpressOrderStatus;
|
||||||
|
import com.linhelp.common.enums.OfflinePayStatus;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class ExpressOrderResponse {
|
||||||
|
private Long id;
|
||||||
|
private String orderNo;
|
||||||
|
private Long tenantId;
|
||||||
|
private Long communityId;
|
||||||
|
private Long userId;
|
||||||
|
private Long addressId;
|
||||||
|
private String contactName;
|
||||||
|
private String contactPhone;
|
||||||
|
private String deliveryAddress;
|
||||||
|
private String expressCompany;
|
||||||
|
private String pickupCode;
|
||||||
|
private String pickupAddress;
|
||||||
|
private String receiverPhone;
|
||||||
|
private int packageCount;
|
||||||
|
private int feeCent;
|
||||||
|
private OfflinePayStatus offlinePayStatus;
|
||||||
|
private ExpressOrderStatus status;
|
||||||
|
private String remark;
|
||||||
|
private String cancelReason;
|
||||||
|
private String deliveredPhotoUrl;
|
||||||
|
private List<ExpressOrderLogResponse> logs = new ArrayList<ExpressOrderLogResponse>();
|
||||||
|
private LocalDateTime createdAt;
|
||||||
|
private LocalDateTime updatedAt;
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getOrderNo() {
|
||||||
|
return orderNo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOrderNo(String orderNo) {
|
||||||
|
this.orderNo = orderNo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getTenantId() {
|
||||||
|
return tenantId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTenantId(Long tenantId) {
|
||||||
|
this.tenantId = tenantId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getCommunityId() {
|
||||||
|
return communityId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCommunityId(Long communityId) {
|
||||||
|
this.communityId = communityId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getUserId() {
|
||||||
|
return userId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUserId(Long userId) {
|
||||||
|
this.userId = userId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getAddressId() {
|
||||||
|
return addressId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAddressId(Long addressId) {
|
||||||
|
this.addressId = addressId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getContactName() {
|
||||||
|
return contactName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setContactName(String contactName) {
|
||||||
|
this.contactName = contactName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getContactPhone() {
|
||||||
|
return contactPhone;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setContactPhone(String contactPhone) {
|
||||||
|
this.contactPhone = contactPhone;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDeliveryAddress() {
|
||||||
|
return deliveryAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDeliveryAddress(String deliveryAddress) {
|
||||||
|
this.deliveryAddress = deliveryAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getExpressCompany() {
|
||||||
|
return expressCompany;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExpressCompany(String expressCompany) {
|
||||||
|
this.expressCompany = expressCompany;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPickupCode() {
|
||||||
|
return pickupCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPickupCode(String pickupCode) {
|
||||||
|
this.pickupCode = pickupCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPickupAddress() {
|
||||||
|
return pickupAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPickupAddress(String pickupAddress) {
|
||||||
|
this.pickupAddress = pickupAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getReceiverPhone() {
|
||||||
|
return receiverPhone;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setReceiverPhone(String receiverPhone) {
|
||||||
|
this.receiverPhone = receiverPhone;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPackageCount() {
|
||||||
|
return packageCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPackageCount(int packageCount) {
|
||||||
|
this.packageCount = packageCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getFeeCent() {
|
||||||
|
return feeCent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFeeCent(int feeCent) {
|
||||||
|
this.feeCent = feeCent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OfflinePayStatus getOfflinePayStatus() {
|
||||||
|
return offlinePayStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOfflinePayStatus(OfflinePayStatus offlinePayStatus) {
|
||||||
|
this.offlinePayStatus = offlinePayStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ExpressOrderStatus getStatus() {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStatus(ExpressOrderStatus status) {
|
||||||
|
this.status = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRemark() {
|
||||||
|
return remark;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRemark(String remark) {
|
||||||
|
this.remark = remark;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCancelReason() {
|
||||||
|
return cancelReason;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCancelReason(String cancelReason) {
|
||||||
|
this.cancelReason = cancelReason;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDeliveredPhotoUrl() {
|
||||||
|
return deliveredPhotoUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDeliveredPhotoUrl(String deliveredPhotoUrl) {
|
||||||
|
this.deliveredPhotoUrl = deliveredPhotoUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<ExpressOrderLogResponse> getLogs() {
|
||||||
|
return logs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLogs(List<ExpressOrderLogResponse> logs) {
|
||||||
|
this.logs = logs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDateTime getCreatedAt() {
|
||||||
|
return createdAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCreatedAt(LocalDateTime createdAt) {
|
||||||
|
this.createdAt = createdAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDateTime getUpdatedAt() {
|
||||||
|
return updatedAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUpdatedAt(LocalDateTime updatedAt) {
|
||||||
|
this.updatedAt = updatedAt;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,229 @@
|
|||||||
|
package com.linhelp.express;
|
||||||
|
|
||||||
|
import com.linhelp.common.enums.ExpressOrderStatus;
|
||||||
|
import com.linhelp.common.enums.OfflinePayStatus;
|
||||||
|
import com.linhelp.common.exception.BizException;
|
||||||
|
import com.linhelp.user.AddressResponse;
|
||||||
|
import com.linhelp.user.UserAddressService;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class ExpressOrderService {
|
||||||
|
private final UserAddressService addressService;
|
||||||
|
private final AtomicLong orderIds = new AtomicLong(1L);
|
||||||
|
private final AtomicLong logIds = new AtomicLong(1L);
|
||||||
|
private final Map<Long, ExpressOrderResponse> orders = new LinkedHashMap<Long, ExpressOrderResponse>();
|
||||||
|
|
||||||
|
public ExpressOrderService(UserAddressService addressService) {
|
||||||
|
this.addressService = addressService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized ExpressOrderResponse create(Long userId, ExpressOrderRequest request) {
|
||||||
|
AddressResponse address = addressService.detailMine(userId, request.getAddressId());
|
||||||
|
Long orderId = orderIds.getAndIncrement();
|
||||||
|
ExpressOrderResponse order = new ExpressOrderResponse();
|
||||||
|
order.setId(orderId);
|
||||||
|
order.setOrderNo("EO" + String.format("%08d", orderId));
|
||||||
|
order.setTenantId(request.getTenantId());
|
||||||
|
order.setCommunityId(request.getCommunityId());
|
||||||
|
order.setUserId(userId);
|
||||||
|
order.setAddressId(request.getAddressId());
|
||||||
|
order.setContactName(address.getContactName());
|
||||||
|
order.setContactPhone(address.getPhone());
|
||||||
|
order.setDeliveryAddress(buildDeliveryAddress(address));
|
||||||
|
order.setExpressCompany(request.getExpressCompany());
|
||||||
|
order.setPickupCode(request.getPickupCode());
|
||||||
|
order.setPickupAddress(request.getPickupAddress());
|
||||||
|
order.setReceiverPhone(request.getReceiverPhone());
|
||||||
|
order.setPackageCount(request.getPackageCount());
|
||||||
|
order.setFeeCent(ExpressFeeCalculator.calculateCent(request.getPackageCount()));
|
||||||
|
order.setOfflinePayStatus(OfflinePayStatus.UNPAID);
|
||||||
|
order.setStatus(ExpressOrderStatus.PENDING_CONFIRM);
|
||||||
|
order.setRemark(request.getRemark());
|
||||||
|
order.setCreatedAt(LocalDateTime.now());
|
||||||
|
order.setUpdatedAt(order.getCreatedAt());
|
||||||
|
addLog(order, "CREATE", "用户提交快递代取");
|
||||||
|
orders.put(order.getId(), order);
|
||||||
|
return copyOrder(order);
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized ExpressOrderResponse detail(Long id) {
|
||||||
|
return copyOrder(requireOrder(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized List<ExpressOrderResponse> listMine(Long userId) {
|
||||||
|
List<ExpressOrderResponse> result = new ArrayList<ExpressOrderResponse>();
|
||||||
|
for (ExpressOrderResponse order : orders.values()) {
|
||||||
|
if (userId.equals(order.getUserId())) {
|
||||||
|
result.add(copyOrder(order));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized List<ExpressOrderResponse> listAdmin(Long communityId, ExpressOrderStatus status) {
|
||||||
|
List<ExpressOrderResponse> result = new ArrayList<ExpressOrderResponse>();
|
||||||
|
for (ExpressOrderResponse order : orders.values()) {
|
||||||
|
if (!communityId.equals(order.getCommunityId())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (status != null && status != order.getStatus()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
result.add(copyOrder(order));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized ExpressOrderResponse confirm(Long id) {
|
||||||
|
ExpressOrderResponse order = requireOrder(id);
|
||||||
|
move(order, ExpressOrderStatus.PENDING_PICKUP, "CONFIRM", "后台确认快递代取");
|
||||||
|
return copyOrder(order);
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized ExpressOrderResponse adjustFee(Long id, int feeCent, String reason) {
|
||||||
|
ExpressOrderResponse order = requireOrder(id);
|
||||||
|
order.setFeeCent(feeCent);
|
||||||
|
order.setUpdatedAt(LocalDateTime.now());
|
||||||
|
addLog(order, "ADJUST_FEE", "调整服务费为" + feeCent + "分:" + reason);
|
||||||
|
return copyOrder(order);
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized ExpressOrderResponse cancel(Long id, String reason) {
|
||||||
|
ExpressOrderResponse order = requireOrder(id);
|
||||||
|
order.setCancelReason(reason);
|
||||||
|
move(order, ExpressOrderStatus.CANCELED, "CANCEL", "取消订单:" + nullToEmpty(reason));
|
||||||
|
return copyOrder(order);
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized ExpressOrderResponse complete(Long id) {
|
||||||
|
ExpressOrderResponse order = requireOrder(id);
|
||||||
|
move(order, ExpressOrderStatus.COMPLETED, "COMPLETE", "订单完成");
|
||||||
|
return copyOrder(order);
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized ExpressOrderResponse markPickingUp(Long id) {
|
||||||
|
ExpressOrderResponse order = requireOrder(id);
|
||||||
|
move(order, ExpressOrderStatus.PICKING_UP, "PICKING_UP", "配送员开始取件");
|
||||||
|
return copyOrder(order);
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized ExpressOrderResponse markDelivering(Long id) {
|
||||||
|
ExpressOrderResponse order = requireOrder(id);
|
||||||
|
move(order, ExpressOrderStatus.DELIVERING, "DELIVERING", "配送员开始配送");
|
||||||
|
return copyOrder(order);
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized ExpressOrderResponse markDelivered(Long id, String photoUrl) {
|
||||||
|
ExpressOrderResponse order = requireOrder(id);
|
||||||
|
order.setDeliveredPhotoUrl(photoUrl);
|
||||||
|
move(order, ExpressOrderStatus.DELIVERED, "DELIVERED", "配送员送达");
|
||||||
|
return copyOrder(order);
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized ExpressOrderResponse updateOfflinePayStatus(Long id, OfflinePayStatus status) {
|
||||||
|
ExpressOrderResponse order = requireOrder(id);
|
||||||
|
order.setOfflinePayStatus(status);
|
||||||
|
order.setUpdatedAt(LocalDateTime.now());
|
||||||
|
addLog(order, "OFFLINE_PAY", "线下收款状态:" + status.name());
|
||||||
|
return copyOrder(order);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void move(ExpressOrderResponse order, ExpressOrderStatus target, String action, String content) {
|
||||||
|
if (!order.getStatus().canMoveTo(target)) {
|
||||||
|
throw new BizException("订单状态不允许操作");
|
||||||
|
}
|
||||||
|
order.setStatus(target);
|
||||||
|
order.setUpdatedAt(LocalDateTime.now());
|
||||||
|
addLog(order, action, content);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ExpressOrderResponse requireOrder(Long id) {
|
||||||
|
ExpressOrderResponse order = orders.get(id);
|
||||||
|
if (order == null) {
|
||||||
|
throw new BizException(404, "快递代取订单不存在");
|
||||||
|
}
|
||||||
|
return order;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addLog(ExpressOrderResponse order, String action, String content) {
|
||||||
|
ExpressOrderLogResponse log = new ExpressOrderLogResponse();
|
||||||
|
log.setId(logIds.getAndIncrement());
|
||||||
|
log.setOrderId(order.getId());
|
||||||
|
log.setAction(action);
|
||||||
|
log.setContent(content);
|
||||||
|
log.setCreatedAt(LocalDateTime.now());
|
||||||
|
order.getLogs().add(log);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String buildDeliveryAddress(AddressResponse address) {
|
||||||
|
StringBuilder builder = new StringBuilder();
|
||||||
|
append(builder, address.getBuilding());
|
||||||
|
append(builder, address.getRoom());
|
||||||
|
append(builder, address.getDetail());
|
||||||
|
return builder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void append(StringBuilder builder, String value) {
|
||||||
|
if (value == null || value.trim().isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (builder.length() > 0) {
|
||||||
|
builder.append(' ');
|
||||||
|
}
|
||||||
|
builder.append(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String nullToEmpty(String value) {
|
||||||
|
return value == null ? "" : value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ExpressOrderResponse copyOrder(ExpressOrderResponse source) {
|
||||||
|
ExpressOrderResponse target = new ExpressOrderResponse();
|
||||||
|
target.setId(source.getId());
|
||||||
|
target.setOrderNo(source.getOrderNo());
|
||||||
|
target.setTenantId(source.getTenantId());
|
||||||
|
target.setCommunityId(source.getCommunityId());
|
||||||
|
target.setUserId(source.getUserId());
|
||||||
|
target.setAddressId(source.getAddressId());
|
||||||
|
target.setContactName(source.getContactName());
|
||||||
|
target.setContactPhone(source.getContactPhone());
|
||||||
|
target.setDeliveryAddress(source.getDeliveryAddress());
|
||||||
|
target.setExpressCompany(source.getExpressCompany());
|
||||||
|
target.setPickupCode(source.getPickupCode());
|
||||||
|
target.setPickupAddress(source.getPickupAddress());
|
||||||
|
target.setReceiverPhone(source.getReceiverPhone());
|
||||||
|
target.setPackageCount(source.getPackageCount());
|
||||||
|
target.setFeeCent(source.getFeeCent());
|
||||||
|
target.setOfflinePayStatus(source.getOfflinePayStatus());
|
||||||
|
target.setStatus(source.getStatus());
|
||||||
|
target.setRemark(source.getRemark());
|
||||||
|
target.setCancelReason(source.getCancelReason());
|
||||||
|
target.setDeliveredPhotoUrl(source.getDeliveredPhotoUrl());
|
||||||
|
target.setCreatedAt(source.getCreatedAt());
|
||||||
|
target.setUpdatedAt(source.getUpdatedAt());
|
||||||
|
target.setLogs(copyLogs(source.getLogs()));
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<ExpressOrderLogResponse> copyLogs(List<ExpressOrderLogResponse> sourceLogs) {
|
||||||
|
List<ExpressOrderLogResponse> logs = new ArrayList<ExpressOrderLogResponse>();
|
||||||
|
for (ExpressOrderLogResponse source : sourceLogs) {
|
||||||
|
ExpressOrderLogResponse target = new ExpressOrderLogResponse();
|
||||||
|
target.setId(source.getId());
|
||||||
|
target.setOrderId(source.getOrderId());
|
||||||
|
target.setAction(source.getAction());
|
||||||
|
target.setContent(source.getContent());
|
||||||
|
target.setCreatedAt(source.getCreatedAt());
|
||||||
|
logs.add(target);
|
||||||
|
}
|
||||||
|
return logs;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -39,6 +39,10 @@ public class UserAddressService {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public synchronized AddressResponse detailMine(Long userId, Long id) {
|
||||||
|
return requireMine(userId, id);
|
||||||
|
}
|
||||||
|
|
||||||
public synchronized AddressResponse update(Long userId, Long id, AddressRequest request) {
|
public synchronized AddressResponse update(Long userId, Long id, AddressRequest request) {
|
||||||
AddressResponse address = requireMine(userId, id);
|
AddressResponse address = requireMine(userId, id);
|
||||||
copy(request, address);
|
copy(request, address);
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package com.linhelp.express;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||||
|
|
||||||
|
class ExpressFeeCalculatorTests {
|
||||||
|
@Test
|
||||||
|
void firstPackageCostsThreeYuan() {
|
||||||
|
assertThat(ExpressFeeCalculator.calculateCent(1)).isEqualTo(300);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void extraPackagesCostOneYuanEach() {
|
||||||
|
assertThat(ExpressFeeCalculator.calculateCent(3)).isEqualTo(500);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void packageCountMustBePositive() {
|
||||||
|
assertThatThrownBy(() -> ExpressFeeCalculator.calculateCent(0))
|
||||||
|
.hasMessageContaining("件数必须大于0");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
package com.linhelp.express;
|
||||||
|
|
||||||
|
import com.linhelp.common.enums.ExpressOrderStatus;
|
||||||
|
import com.linhelp.user.AddressRequest;
|
||||||
|
import com.linhelp.user.AddressResponse;
|
||||||
|
import com.linhelp.user.UserAddressService;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||||
|
|
||||||
|
class ExpressOrderServiceTests {
|
||||||
|
@Test
|
||||||
|
void confirmedExpressOrderMovesToPendingPickup() {
|
||||||
|
UserAddressService addressService = new UserAddressService();
|
||||||
|
AddressResponse address = addressService.create(1L, addressRequest());
|
||||||
|
ExpressOrderService expressOrderService = new ExpressOrderService(addressService);
|
||||||
|
|
||||||
|
ExpressOrderRequest request = expressRequest(address.getId());
|
||||||
|
request.setPackageCount(3);
|
||||||
|
ExpressOrderResponse order = expressOrderService.create(1L, request);
|
||||||
|
|
||||||
|
assertThat(order.getFeeCent()).isEqualTo(500);
|
||||||
|
|
||||||
|
expressOrderService.confirm(order.getId());
|
||||||
|
|
||||||
|
assertThat(expressOrderService.detail(order.getId()).getStatus()).isEqualTo(ExpressOrderStatus.PENDING_PICKUP);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void addressMustBelongToCurrentUser() {
|
||||||
|
UserAddressService addressService = new UserAddressService();
|
||||||
|
AddressResponse otherUserAddress = addressService.create(2L, addressRequest());
|
||||||
|
ExpressOrderService expressOrderService = new ExpressOrderService(addressService);
|
||||||
|
|
||||||
|
assertThatThrownBy(() -> expressOrderService.create(1L, expressRequest(otherUserAddress.getId())))
|
||||||
|
.hasMessageContaining("地址不存在");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void feeAdjustmentWritesLog() {
|
||||||
|
UserAddressService addressService = new UserAddressService();
|
||||||
|
AddressResponse address = addressService.create(1L, addressRequest());
|
||||||
|
ExpressOrderService expressOrderService = new ExpressOrderService(addressService);
|
||||||
|
ExpressOrderResponse order = expressOrderService.create(1L, expressRequest(address.getId()));
|
||||||
|
|
||||||
|
expressOrderService.adjustFee(order.getId(), 800, "大件加价");
|
||||||
|
|
||||||
|
ExpressOrderResponse detail = expressOrderService.detail(order.getId());
|
||||||
|
assertThat(detail.getFeeCent()).isEqualTo(800);
|
||||||
|
assertThat(detail.getLogs()).extracting(ExpressOrderLogResponse::getContent)
|
||||||
|
.anyMatch(content -> content.contains("大件加价"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private ExpressOrderRequest expressRequest(Long addressId) {
|
||||||
|
ExpressOrderRequest request = new ExpressOrderRequest();
|
||||||
|
request.setTenantId(1L);
|
||||||
|
request.setCommunityId(1L);
|
||||||
|
request.setExpressCompany("顺丰");
|
||||||
|
request.setPickupCode("A-1234");
|
||||||
|
request.setPickupAddress("北门快递站");
|
||||||
|
request.setReceiverPhone("13800000000");
|
||||||
|
request.setAddressId(addressId);
|
||||||
|
request.setPackageCount(1);
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
|
||||||
|
private AddressRequest addressRequest() {
|
||||||
|
AddressRequest request = new AddressRequest();
|
||||||
|
request.setTenantId(1L);
|
||||||
|
request.setCommunityId(1L);
|
||||||
|
request.setContactName("张三");
|
||||||
|
request.setPhone("13800000000");
|
||||||
|
request.setBuilding("1栋");
|
||||||
|
request.setRoom("101");
|
||||||
|
request.setDetail("门口");
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user