diff --git a/backend/src/main/java/com/linhelp/common/api/ApiResponse.java b/backend/src/main/java/com/linhelp/common/api/ApiResponse.java new file mode 100644 index 0000000..e3887e4 --- /dev/null +++ b/backend/src/main/java/com/linhelp/common/api/ApiResponse.java @@ -0,0 +1,52 @@ +package com.linhelp.common.api; + +public class ApiResponse { + private int code; + private String message; + private T data; + + public ApiResponse() { + } + + public ApiResponse(int code, String message, T data) { + this.code = code; + this.message = message; + this.data = data; + } + + public static ApiResponse ok(T data) { + return new ApiResponse(0, "ok", data); + } + + public static ApiResponse ok() { + return new ApiResponse(0, "ok", null); + } + + public static ApiResponse fail(int code, String message) { + return new ApiResponse(code, message, null); + } + + public int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public T getData() { + return data; + } + + public void setData(T data) { + this.data = data; + } +} diff --git a/backend/src/main/java/com/linhelp/common/api/PageResponse.java b/backend/src/main/java/com/linhelp/common/api/PageResponse.java new file mode 100644 index 0000000..8686cc3 --- /dev/null +++ b/backend/src/main/java/com/linhelp/common/api/PageResponse.java @@ -0,0 +1,52 @@ +package com.linhelp.common.api; + +import java.util.List; + +public class PageResponse { + private long total; + private long pageNo; + private long pageSize; + private List records; + + public PageResponse() { + } + + public PageResponse(long total, long pageNo, long pageSize, List records) { + this.total = total; + this.pageNo = pageNo; + this.pageSize = pageSize; + this.records = records; + } + + public long getTotal() { + return total; + } + + public void setTotal(long total) { + this.total = total; + } + + public long getPageNo() { + return pageNo; + } + + public void setPageNo(long pageNo) { + this.pageNo = pageNo; + } + + public long getPageSize() { + return pageSize; + } + + public void setPageSize(long pageSize) { + this.pageSize = pageSize; + } + + public List getRecords() { + return records; + } + + public void setRecords(List records) { + this.records = records; + } +} diff --git a/backend/src/main/java/com/linhelp/common/enums/DeliveryMethod.java b/backend/src/main/java/com/linhelp/common/enums/DeliveryMethod.java new file mode 100644 index 0000000..a5ba98c --- /dev/null +++ b/backend/src/main/java/com/linhelp/common/enums/DeliveryMethod.java @@ -0,0 +1,7 @@ +package com.linhelp.common.enums; + +public enum DeliveryMethod { + IMMEDIATE, + SCHEDULED, + SELF_PICKUP +} diff --git a/backend/src/main/java/com/linhelp/common/enums/DeliveryTaskStatus.java b/backend/src/main/java/com/linhelp/common/enums/DeliveryTaskStatus.java new file mode 100644 index 0000000..0f73aa0 --- /dev/null +++ b/backend/src/main/java/com/linhelp/common/enums/DeliveryTaskStatus.java @@ -0,0 +1,11 @@ +package com.linhelp.common.enums; + +public enum DeliveryTaskStatus { + ASSIGNED, + ACCEPTED, + DELIVERING, + DELIVERED, + EXCEPTION, + COMPLETED, + CANCELED +} diff --git a/backend/src/main/java/com/linhelp/common/enums/ExpressOrderStatus.java b/backend/src/main/java/com/linhelp/common/enums/ExpressOrderStatus.java new file mode 100644 index 0000000..3a34546 --- /dev/null +++ b/backend/src/main/java/com/linhelp/common/enums/ExpressOrderStatus.java @@ -0,0 +1,34 @@ +package com.linhelp.common.enums; + +import java.util.Collections; +import java.util.EnumMap; +import java.util.EnumSet; +import java.util.Map; +import java.util.Set; + +public enum ExpressOrderStatus { + PENDING_CONFIRM, + PENDING_PICKUP, + PICKING_UP, + DELIVERING, + DELIVERED, + COMPLETED, + CANCELED; + + private static final Map> TRANSITIONS; + + static { + Map> transitions = new EnumMap>(ExpressOrderStatus.class); + transitions.put(PENDING_CONFIRM, EnumSet.of(PENDING_PICKUP, CANCELED)); + transitions.put(PENDING_PICKUP, EnumSet.of(PICKING_UP, CANCELED)); + transitions.put(PICKING_UP, EnumSet.of(DELIVERING, CANCELED)); + transitions.put(DELIVERING, EnumSet.of(DELIVERED, CANCELED)); + transitions.put(DELIVERED, EnumSet.of(COMPLETED)); + TRANSITIONS = Collections.unmodifiableMap(transitions); + } + + public boolean canMoveTo(ExpressOrderStatus target) { + Set targets = TRANSITIONS.get(this); + return targets != null && targets.contains(target); + } +} diff --git a/backend/src/main/java/com/linhelp/common/enums/GoodsOrderStatus.java b/backend/src/main/java/com/linhelp/common/enums/GoodsOrderStatus.java new file mode 100644 index 0000000..e1da8ac --- /dev/null +++ b/backend/src/main/java/com/linhelp/common/enums/GoodsOrderStatus.java @@ -0,0 +1,34 @@ +package com.linhelp.common.enums; + +import java.util.Collections; +import java.util.EnumMap; +import java.util.EnumSet; +import java.util.Map; +import java.util.Set; + +public enum GoodsOrderStatus { + PENDING_CONFIRM, + PREPARING, + PENDING_DELIVERY, + PENDING_PICKUP, + DELIVERING, + COMPLETED, + CANCELED; + + private static final Map> TRANSITIONS; + + static { + Map> transitions = new EnumMap>(GoodsOrderStatus.class); + transitions.put(PENDING_CONFIRM, EnumSet.of(PREPARING, CANCELED)); + transitions.put(PREPARING, EnumSet.of(PENDING_DELIVERY, PENDING_PICKUP, CANCELED)); + transitions.put(PENDING_DELIVERY, EnumSet.of(DELIVERING, CANCELED)); + transitions.put(PENDING_PICKUP, EnumSet.of(COMPLETED, CANCELED)); + transitions.put(DELIVERING, EnumSet.of(COMPLETED, CANCELED)); + TRANSITIONS = Collections.unmodifiableMap(transitions); + } + + public boolean canMoveTo(GoodsOrderStatus target) { + Set targets = TRANSITIONS.get(this); + return targets != null && targets.contains(target); + } +} diff --git a/backend/src/main/java/com/linhelp/common/enums/GroupBuyOrderStatus.java b/backend/src/main/java/com/linhelp/common/enums/GroupBuyOrderStatus.java new file mode 100644 index 0000000..f34adb1 --- /dev/null +++ b/backend/src/main/java/com/linhelp/common/enums/GroupBuyOrderStatus.java @@ -0,0 +1,11 @@ +package com.linhelp.common.enums; + +public enum GroupBuyOrderStatus { + PENDING_CONFIRM, + CONFIRMED, + PENDING_DELIVERY, + PENDING_PICKUP, + DELIVERING, + COMPLETED, + CANCELED +} diff --git a/backend/src/main/java/com/linhelp/common/enums/OfflinePayStatus.java b/backend/src/main/java/com/linhelp/common/enums/OfflinePayStatus.java new file mode 100644 index 0000000..6e31a48 --- /dev/null +++ b/backend/src/main/java/com/linhelp/common/enums/OfflinePayStatus.java @@ -0,0 +1,8 @@ +package com.linhelp.common.enums; + +public enum OfflinePayStatus { + UNPAID, + PAID, + FREE, + EXCEPTION +} diff --git a/backend/src/main/java/com/linhelp/common/enums/SecondGoodsStatus.java b/backend/src/main/java/com/linhelp/common/enums/SecondGoodsStatus.java new file mode 100644 index 0000000..2ddc32c --- /dev/null +++ b/backend/src/main/java/com/linhelp/common/enums/SecondGoodsStatus.java @@ -0,0 +1,9 @@ +package com.linhelp.common.enums; + +public enum SecondGoodsStatus { + PENDING_REVIEW, + PUBLISHED, + REJECTED, + OFF_SHELF, + SOLD +} diff --git a/backend/src/main/java/com/linhelp/common/exception/BizException.java b/backend/src/main/java/com/linhelp/common/exception/BizException.java new file mode 100644 index 0000000..194a3e1 --- /dev/null +++ b/backend/src/main/java/com/linhelp/common/exception/BizException.java @@ -0,0 +1,18 @@ +package com.linhelp.common.exception; + +public class BizException extends RuntimeException { + private final int code; + + public BizException(String message) { + this(400, message); + } + + public BizException(int code, String message) { + super(message); + this.code = code; + } + + public int getCode() { + return code; + } +} diff --git a/backend/src/main/java/com/linhelp/common/exception/GlobalExceptionHandler.java b/backend/src/main/java/com/linhelp/common/exception/GlobalExceptionHandler.java new file mode 100644 index 0000000..ef0c74f --- /dev/null +++ b/backend/src/main/java/com/linhelp/common/exception/GlobalExceptionHandler.java @@ -0,0 +1,26 @@ +package com.linhelp.common.exception; + +import com.linhelp.common.api.ApiResponse; +import org.springframework.validation.BindException; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +@RestControllerAdvice +public class GlobalExceptionHandler { + + @ExceptionHandler(BizException.class) + public ApiResponse handleBizException(BizException exception) { + return ApiResponse.fail(exception.getCode(), exception.getMessage()); + } + + @ExceptionHandler({MethodArgumentNotValidException.class, BindException.class}) + public ApiResponse handleValidationException(Exception exception) { + return ApiResponse.fail(422, "请求参数不正确"); + } + + @ExceptionHandler(Exception.class) + public ApiResponse handleException(Exception exception) { + return ApiResponse.fail(500, "系统繁忙,请稍后再试"); + } +} diff --git a/backend/src/main/resources/db/migration/V1__init_schema.sql b/backend/src/main/resources/db/migration/V1__init_schema.sql new file mode 100644 index 0000000..cca8d3d --- /dev/null +++ b/backend/src/main/resources/db/migration/V1__init_schema.sql @@ -0,0 +1,458 @@ +CREATE TABLE tenant ( + id BIGINT PRIMARY KEY AUTO_INCREMENT, + name VARCHAR(80) NOT NULL, + status VARCHAR(24) NOT NULL DEFAULT 'ENABLED', + created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + deleted TINYINT NOT NULL DEFAULT 0 +); + +CREATE TABLE community ( + id BIGINT PRIMARY KEY AUTO_INCREMENT, + tenant_id BIGINT NOT NULL, + name VARCHAR(80) NOT NULL, + address VARCHAR(255) NOT NULL, + contact_name VARCHAR(40), + contact_phone VARCHAR(32), + status VARCHAR(24) NOT NULL DEFAULT 'ENABLED', + created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + deleted TINYINT NOT NULL DEFAULT 0, + INDEX idx_community_tenant (tenant_id) +); + +CREATE TABLE community_module_config ( + id BIGINT PRIMARY KEY AUTO_INCREMENT, + tenant_id BIGINT NOT NULL, + community_id BIGINT NOT NULL, + module_code VARCHAR(40) NOT NULL, + enabled TINYINT NOT NULL DEFAULT 1, + created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + UNIQUE KEY uk_community_module (community_id, module_code) +); + +CREATE TABLE app_user ( + id BIGINT PRIMARY KEY AUTO_INCREMENT, + tenant_id BIGINT NOT NULL, + community_id BIGINT NOT NULL, + openid VARCHAR(80), + nickname VARCHAR(80), + avatar_url VARCHAR(255), + phone VARCHAR(32), + status VARCHAR(24) NOT NULL DEFAULT 'ENABLED', + created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + deleted TINYINT NOT NULL DEFAULT 0, + INDEX idx_app_user_openid (openid), + INDEX idx_app_user_community (community_id) +); + +CREATE TABLE user_address ( + id BIGINT PRIMARY KEY AUTO_INCREMENT, + tenant_id BIGINT NOT NULL, + community_id BIGINT NOT NULL, + user_id BIGINT NOT NULL, + contact_name VARCHAR(40) NOT NULL, + phone VARCHAR(32) NOT NULL, + building VARCHAR(80) NOT NULL, + room VARCHAR(80) NOT NULL, + detail VARCHAR(255), + is_default TINYINT NOT NULL DEFAULT 0, + created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + deleted TINYINT NOT NULL DEFAULT 0, + INDEX idx_user_address_user (user_id) +); + +CREATE TABLE sys_role ( + id BIGINT PRIMARY KEY AUTO_INCREMENT, + code VARCHAR(40) NOT NULL UNIQUE, + name VARCHAR(80) NOT NULL +); + +CREATE TABLE user_role ( + id BIGINT PRIMARY KEY AUTO_INCREMENT, + user_id BIGINT NOT NULL, + role_code VARCHAR(40) NOT NULL, + tenant_id BIGINT NOT NULL, + community_id BIGINT, + merchant_id BIGINT, + created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + UNIQUE KEY uk_user_role_scope (user_id, role_code, tenant_id, community_id, merchant_id) +); + +CREATE TABLE merchant ( + id BIGINT PRIMARY KEY AUTO_INCREMENT, + tenant_id BIGINT NOT NULL, + community_id BIGINT NOT NULL, + name VARCHAR(100) NOT NULL, + merchant_type VARCHAR(40) NOT NULL, + contact_name VARCHAR(40), + contact_phone VARCHAR(32), + status VARCHAR(24) NOT NULL DEFAULT 'ENABLED', + created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + deleted TINYINT NOT NULL DEFAULT 0, + INDEX idx_merchant_community (community_id) +); + +CREATE TABLE product_category ( + id BIGINT PRIMARY KEY AUTO_INCREMENT, + tenant_id BIGINT NOT NULL, + community_id BIGINT NOT NULL, + name VARCHAR(80) NOT NULL, + sort_no INT NOT NULL DEFAULT 0, + enabled TINYINT NOT NULL DEFAULT 1, + created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + deleted TINYINT NOT NULL DEFAULT 0 +); + +CREATE TABLE product ( + id BIGINT PRIMARY KEY AUTO_INCREMENT, + tenant_id BIGINT NOT NULL, + community_id BIGINT NOT NULL, + merchant_id BIGINT NOT NULL, + category_id BIGINT NOT NULL, + name VARCHAR(120) NOT NULL, + cover_url VARCHAR(255), + description TEXT, + unit_name VARCHAR(20) NOT NULL DEFAULT '件', + status VARCHAR(24) NOT NULL DEFAULT 'OFF_SHELF', + created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + deleted TINYINT NOT NULL DEFAULT 0, + INDEX idx_product_category (category_id), + INDEX idx_product_merchant (merchant_id) +); + +CREATE TABLE product_sku ( + id BIGINT PRIMARY KEY AUTO_INCREMENT, + tenant_id BIGINT NOT NULL, + community_id BIGINT NOT NULL, + product_id BIGINT NOT NULL, + sku_name VARCHAR(80) NOT NULL, + price_cent INT NOT NULL, + origin_price_cent INT, + stock INT NOT NULL DEFAULT 0, + enabled TINYINT NOT NULL DEFAULT 1, + created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + deleted TINYINT NOT NULL DEFAULT 0, + INDEX idx_product_sku_product (product_id) +); + +CREATE TABLE goods_order ( + id BIGINT PRIMARY KEY AUTO_INCREMENT, + order_no VARCHAR(40) NOT NULL UNIQUE, + tenant_id BIGINT NOT NULL, + community_id BIGINT NOT NULL, + user_id BIGINT NOT NULL, + merchant_id BIGINT NOT NULL, + address_id BIGINT, + delivery_method VARCHAR(24) NOT NULL, + scheduled_time DATETIME, + status VARCHAR(32) NOT NULL, + offline_pay_status VARCHAR(24) NOT NULL DEFAULT 'UNPAID', + total_amount_cent INT NOT NULL, + remark VARCHAR(255), + cancel_reason VARCHAR(255), + created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + deleted TINYINT NOT NULL DEFAULT 0, + INDEX idx_goods_order_user (user_id), + INDEX idx_goods_order_status (community_id, status) +); + +CREATE TABLE goods_order_item ( + id BIGINT PRIMARY KEY AUTO_INCREMENT, + tenant_id BIGINT NOT NULL, + community_id BIGINT NOT NULL, + order_id BIGINT NOT NULL, + product_id BIGINT NOT NULL, + sku_id BIGINT NOT NULL, + product_name VARCHAR(120) NOT NULL, + sku_name VARCHAR(80) NOT NULL, + quantity INT NOT NULL, + price_cent INT NOT NULL, + amount_cent INT NOT NULL, + created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + INDEX idx_goods_order_item_order (order_id) +); + +CREATE TABLE stock_log ( + id BIGINT PRIMARY KEY AUTO_INCREMENT, + tenant_id BIGINT NOT NULL, + community_id BIGINT NOT NULL, + product_id BIGINT NOT NULL, + sku_id BIGINT NOT NULL, + change_quantity INT NOT NULL, + before_stock INT NOT NULL, + after_stock INT NOT NULL, + biz_type VARCHAR(32) NOT NULL, + biz_order_id BIGINT, + note VARCHAR(255), + created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + INDEX idx_stock_log_sku (sku_id) +); + +CREATE TABLE order_log ( + id BIGINT PRIMARY KEY AUTO_INCREMENT, + tenant_id BIGINT NOT NULL, + community_id BIGINT NOT NULL, + biz_type VARCHAR(32) NOT NULL, + biz_order_id BIGINT NOT NULL, + from_status VARCHAR(32), + to_status VARCHAR(32), + action VARCHAR(64) NOT NULL, + operator_id BIGINT, + note VARCHAR(255), + created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + INDEX idx_order_log_biz (biz_type, biz_order_id) +); + +CREATE TABLE express_order ( + id BIGINT PRIMARY KEY AUTO_INCREMENT, + order_no VARCHAR(40) NOT NULL UNIQUE, + tenant_id BIGINT NOT NULL, + community_id BIGINT NOT NULL, + user_id BIGINT NOT NULL, + address_id BIGINT NOT NULL, + express_company VARCHAR(80) NOT NULL, + pickup_code VARCHAR(120) NOT NULL, + pickup_address VARCHAR(255) NOT NULL, + package_count INT NOT NULL, + service_fee_cent INT NOT NULL, + phone VARCHAR(32) NOT NULL, + image_url VARCHAR(255), + status VARCHAR(32) NOT NULL, + offline_pay_status VARCHAR(24) NOT NULL DEFAULT 'UNPAID', + remark VARCHAR(255), + cancel_reason VARCHAR(255), + created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + deleted TINYINT NOT NULL DEFAULT 0, + INDEX idx_express_order_status (community_id, status) +); + +CREATE TABLE express_log ( + id BIGINT PRIMARY KEY AUTO_INCREMENT, + tenant_id BIGINT NOT NULL, + community_id BIGINT NOT NULL, + express_order_id BIGINT NOT NULL, + from_status VARCHAR(32), + to_status VARCHAR(32), + action VARCHAR(64) NOT NULL, + operator_id BIGINT, + note VARCHAR(255), + created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + INDEX idx_express_log_order (express_order_id) +); + +CREATE TABLE group_buy ( + id BIGINT PRIMARY KEY AUTO_INCREMENT, + tenant_id BIGINT NOT NULL, + community_id BIGINT NOT NULL, + merchant_id BIGINT NOT NULL, + title VARCHAR(120) NOT NULL, + cover_url VARCHAR(255), + description TEXT, + price_cent INT NOT NULL, + origin_price_cent INT, + stock INT NOT NULL, + deadline_at DATETIME NOT NULL, + expected_delivery_at DATETIME, + status VARCHAR(32) NOT NULL DEFAULT 'NOT_STARTED', + created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + deleted TINYINT NOT NULL DEFAULT 0, + INDEX idx_group_buy_status (community_id, status) +); + +CREATE TABLE group_buy_order ( + id BIGINT PRIMARY KEY AUTO_INCREMENT, + order_no VARCHAR(40) NOT NULL UNIQUE, + tenant_id BIGINT NOT NULL, + community_id BIGINT NOT NULL, + group_buy_id BIGINT NOT NULL, + user_id BIGINT NOT NULL, + address_id BIGINT, + delivery_method VARCHAR(24) NOT NULL, + quantity INT NOT NULL, + amount_cent INT NOT NULL, + status VARCHAR(32) NOT NULL, + offline_pay_status VARCHAR(24) NOT NULL DEFAULT 'UNPAID', + remark VARCHAR(255), + cancel_reason VARCHAR(255), + created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + deleted TINYINT NOT NULL DEFAULT 0, + INDEX idx_group_buy_order_activity (group_buy_id), + INDEX idx_group_buy_order_user (user_id) +); + +CREATE TABLE delivery_user ( + id BIGINT PRIMARY KEY AUTO_INCREMENT, + tenant_id BIGINT NOT NULL, + community_id BIGINT NOT NULL, + user_id BIGINT NOT NULL, + name VARCHAR(40) NOT NULL, + phone VARCHAR(32) NOT NULL, + status VARCHAR(24) NOT NULL DEFAULT 'ENABLED', + created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + deleted TINYINT NOT NULL DEFAULT 0 +); + +CREATE TABLE delivery_order ( + id BIGINT PRIMARY KEY AUTO_INCREMENT, + tenant_id BIGINT NOT NULL, + community_id BIGINT NOT NULL, + biz_type VARCHAR(32) NOT NULL, + biz_order_id BIGINT NOT NULL, + delivery_user_id BIGINT NOT NULL, + status VARCHAR(32) NOT NULL, + delivered_photo_url VARCHAR(255), + exception_type VARCHAR(64), + exception_note VARCHAR(255), + created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + deleted TINYINT NOT NULL DEFAULT 0, + UNIQUE KEY uk_delivery_biz_order (biz_type, biz_order_id), + INDEX idx_delivery_user_status (delivery_user_id, status) +); + +CREATE TABLE delivery_log ( + id BIGINT PRIMARY KEY AUTO_INCREMENT, + tenant_id BIGINT NOT NULL, + community_id BIGINT NOT NULL, + delivery_order_id BIGINT NOT NULL, + from_status VARCHAR(32), + to_status VARCHAR(32), + action VARCHAR(64) NOT NULL, + operator_id BIGINT, + note VARCHAR(255), + created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + INDEX idx_delivery_log_order (delivery_order_id) +); + +CREATE TABLE second_goods ( + id BIGINT PRIMARY KEY AUTO_INCREMENT, + tenant_id BIGINT NOT NULL, + community_id BIGINT NOT NULL, + user_id BIGINT NOT NULL, + title VARCHAR(120) NOT NULL, + price_cent INT NOT NULL, + description TEXT, + category VARCHAR(40) NOT NULL, + contact_phone VARCHAR(32) NOT NULL, + trade_method VARCHAR(32) NOT NULL, + status VARCHAR(32) NOT NULL, + reject_reason VARCHAR(255), + created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + deleted TINYINT NOT NULL DEFAULT 0, + INDEX idx_second_goods_status (community_id, status), + INDEX idx_second_goods_user (user_id) +); + +CREATE TABLE second_goods_img ( + id BIGINT PRIMARY KEY AUTO_INCREMENT, + tenant_id BIGINT NOT NULL, + community_id BIGINT NOT NULL, + second_goods_id BIGINT NOT NULL, + image_url VARCHAR(255) NOT NULL, + sort_no INT NOT NULL DEFAULT 0, + created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + INDEX idx_second_goods_img_goods (second_goods_id) +); + +CREATE TABLE second_goods_comment ( + id BIGINT PRIMARY KEY AUTO_INCREMENT, + tenant_id BIGINT NOT NULL, + community_id BIGINT NOT NULL, + second_goods_id BIGINT NOT NULL, + user_id BIGINT NOT NULL, + content VARCHAR(500) NOT NULL, + created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted TINYINT NOT NULL DEFAULT 0, + INDEX idx_second_goods_comment_goods (second_goods_id) +); + +CREATE TABLE notice ( + id BIGINT PRIMARY KEY AUTO_INCREMENT, + tenant_id BIGINT NOT NULL, + community_id BIGINT NOT NULL, + title VARCHAR(120) NOT NULL, + content TEXT NOT NULL, + category VARCHAR(40) NOT NULL, + pinned TINYINT NOT NULL DEFAULT 0, + status VARCHAR(24) NOT NULL DEFAULT 'DRAFT', + published_at DATETIME, + created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + deleted TINYINT NOT NULL DEFAULT 0, + INDEX idx_notice_status (community_id, status, pinned) +); + +CREATE TABLE banner ( + id BIGINT PRIMARY KEY AUTO_INCREMENT, + tenant_id BIGINT NOT NULL, + community_id BIGINT NOT NULL, + title VARCHAR(120) NOT NULL, + image_url VARCHAR(255) NOT NULL, + link_type VARCHAR(32), + link_value VARCHAR(255), + sort_no INT NOT NULL DEFAULT 0, + enabled TINYINT NOT NULL DEFAULT 1, + created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + deleted TINYINT NOT NULL DEFAULT 0, + INDEX idx_banner_community (community_id, enabled) +); + +CREATE TABLE feedback ( + id BIGINT PRIMARY KEY AUTO_INCREMENT, + tenant_id BIGINT NOT NULL, + community_id BIGINT NOT NULL, + user_id BIGINT NOT NULL, + biz_type VARCHAR(32), + biz_order_id BIGINT, + content VARCHAR(500) NOT NULL, + status VARCHAR(24) NOT NULL DEFAULT 'OPEN', + reply VARCHAR(500), + created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + deleted TINYINT NOT NULL DEFAULT 0, + INDEX idx_feedback_status (community_id, status) +); + +CREATE TABLE payment_record ( + id BIGINT PRIMARY KEY AUTO_INCREMENT, + tenant_id BIGINT NOT NULL, + community_id BIGINT NOT NULL, + biz_type VARCHAR(32) NOT NULL, + biz_order_id BIGINT NOT NULL, + amount_cent INT NOT NULL, + pay_method VARCHAR(32) NOT NULL DEFAULT 'OFFLINE', + pay_status VARCHAR(24) NOT NULL, + paid_at DATETIME, + created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + INDEX idx_payment_biz (biz_type, biz_order_id) +); + +CREATE TABLE refund_record ( + id BIGINT PRIMARY KEY AUTO_INCREMENT, + tenant_id BIGINT NOT NULL, + community_id BIGINT NOT NULL, + payment_record_id BIGINT, + biz_type VARCHAR(32) NOT NULL, + biz_order_id BIGINT NOT NULL, + amount_cent INT NOT NULL, + refund_status VARCHAR(24) NOT NULL, + reason VARCHAR(255), + created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + INDEX idx_refund_biz (biz_type, biz_order_id) +); diff --git a/backend/src/test/java/com/linhelp/common/enums/StatusTransitionTests.java b/backend/src/test/java/com/linhelp/common/enums/StatusTransitionTests.java new file mode 100644 index 0000000..2a7098f --- /dev/null +++ b/backend/src/test/java/com/linhelp/common/enums/StatusTransitionTests.java @@ -0,0 +1,25 @@ +package com.linhelp.common.enums; + +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +class StatusTransitionTests { + + @Test + void goodsOrderCanMoveFromPendingConfirmToPreparing() { + assertThat(GoodsOrderStatus.PENDING_CONFIRM.canMoveTo(GoodsOrderStatus.PREPARING)).isTrue(); + } + + @Test + void goodsOrderCannotMoveFromCompletedToDelivering() { + assertThat(GoodsOrderStatus.COMPLETED.canMoveTo(GoodsOrderStatus.DELIVERING)).isFalse(); + } + + @Test + void expressOrderCanMoveThroughPickupFlow() { + assertThat(ExpressOrderStatus.PENDING_CONFIRM.canMoveTo(ExpressOrderStatus.PENDING_PICKUP)).isTrue(); + assertThat(ExpressOrderStatus.PENDING_PICKUP.canMoveTo(ExpressOrderStatus.PICKING_UP)).isTrue(); + assertThat(ExpressOrderStatus.PICKING_UP.canMoveTo(ExpressOrderStatus.DELIVERING)).isTrue(); + } +}