├── .gitignore
├── README.md
├── build.gradle
├── docker-compose
└── docker-compose.yml
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── http-test
├── item-api.http
├── order-api.http
└── partner-api.http
├── settings.gradle
└── src
├── main
├── java
│ └── dev
│ │ └── practice
│ │ └── order
│ │ ├── OrderApplication.java
│ │ ├── application
│ │ ├── item
│ │ │ └── ItemFacade.java
│ │ ├── order
│ │ │ └── OrderFacade.java
│ │ └── partner
│ │ │ └── PartnerFacade.java
│ │ ├── common
│ │ ├── exception
│ │ │ ├── BaseException.java
│ │ │ ├── EntityNotFoundException.java
│ │ │ ├── IllegalStatusException.java
│ │ │ └── InvalidParamException.java
│ │ ├── interceptor
│ │ │ └── CommonHttpRequestInterceptor.java
│ │ ├── response
│ │ │ ├── CommonControllerAdvice.java
│ │ │ ├── CommonResponse.java
│ │ │ └── ErrorCode.java
│ │ └── util
│ │ │ └── TokenGenerator.java
│ │ ├── config
│ │ └── JpaAuditingConfiguration.java
│ │ ├── domain
│ │ ├── AbstractEntity.java
│ │ ├── item
│ │ │ ├── Item.java
│ │ │ ├── ItemCommand.java
│ │ │ ├── ItemInfo.java
│ │ │ ├── ItemOptionSeriesFactory.java
│ │ │ ├── ItemReader.java
│ │ │ ├── ItemService.java
│ │ │ ├── ItemServiceImpl.java
│ │ │ ├── ItemStore.java
│ │ │ ├── option
│ │ │ │ ├── ItemOption.java
│ │ │ │ └── ItemOptionStore.java
│ │ │ └── optiongroup
│ │ │ │ ├── ItemOptionGroup.java
│ │ │ │ └── ItemOptionGroupStore.java
│ │ ├── notification
│ │ │ └── NotificationService.java
│ │ ├── order
│ │ │ ├── Order.java
│ │ │ ├── OrderCommand.java
│ │ │ ├── OrderInfo.java
│ │ │ ├── OrderInfoMapper.java
│ │ │ ├── OrderItemSeriesFactory.java
│ │ │ ├── OrderReader.java
│ │ │ ├── OrderService.java
│ │ │ ├── OrderServiceImpl.java
│ │ │ ├── OrderStore.java
│ │ │ ├── fragment
│ │ │ │ └── DeliveryFragment.java
│ │ │ ├── item
│ │ │ │ ├── OrderItem.java
│ │ │ │ ├── OrderItemOption.java
│ │ │ │ └── OrderItemOptionGroup.java
│ │ │ └── payment
│ │ │ │ ├── PayMethod.java
│ │ │ │ ├── PaymentProcessor.java
│ │ │ │ └── validator
│ │ │ │ ├── PayAmountValidator.java
│ │ │ │ ├── PayMethodValidator.java
│ │ │ │ ├── PayStatusValidator.java
│ │ │ │ └── PaymentValidator.java
│ │ └── partner
│ │ │ ├── Partner.java
│ │ │ ├── PartnerCommand.java
│ │ │ ├── PartnerInfo.java
│ │ │ ├── PartnerReader.java
│ │ │ ├── PartnerService.java
│ │ │ ├── PartnerServiceImpl.java
│ │ │ └── PartnerStore.java
│ │ ├── infrastructure
│ │ ├── NotificationExecutor.java
│ │ ├── item
│ │ │ ├── ItemOptionSeriesFactoryImpl.java
│ │ │ ├── ItemReaderImpl.java
│ │ │ ├── ItemRepository.java
│ │ │ ├── ItemStoreImpl.java
│ │ │ ├── option
│ │ │ │ ├── ItemOptionRepository.java
│ │ │ │ └── ItemOptionStoreImpl.java
│ │ │ └── optiongroup
│ │ │ │ ├── ItemOptionGroupRepository.java
│ │ │ │ └── ItemOptionGroupStoreImpl.java
│ │ ├── order
│ │ │ ├── OrderItemOptionGroupRepository.java
│ │ │ ├── OrderItemOptionRepository.java
│ │ │ ├── OrderItemRepository.java
│ │ │ ├── OrderItemSeriesFactoryImpl.java
│ │ │ ├── OrderReaderImpl.java
│ │ │ ├── OrderRepository.java
│ │ │ ├── OrderStoreImpl.java
│ │ │ └── payment
│ │ │ │ ├── KakaoPayApiCaller.java
│ │ │ │ ├── NaverPayApiCaller.java
│ │ │ │ ├── PaymentApiCaller.java
│ │ │ │ ├── PaymentProcessorImpl.java
│ │ │ │ ├── PgCardApiCaller.java
│ │ │ │ └── TossPayApiCaller.java
│ │ └── partner
│ │ │ ├── PartnerReadImpl.java
│ │ │ ├── PartnerRepository.java
│ │ │ └── PartnerStoreImpl.java
│ │ └── interfaces
│ │ ├── item
│ │ ├── ItemApiController.java
│ │ ├── ItemDto.java
│ │ └── ItemDtoMapper.java
│ │ ├── order
│ │ ├── OrderApiController.java
│ │ ├── OrderDto.java
│ │ └── OrderDtoMapper.java
│ │ └── partner
│ │ ├── PartnerApiController.java
│ │ └── PartnerDto.java
└── resources
│ ├── application.yml
│ ├── db
│ └── migration
│ │ └── V1__init_ddl.sql
│ └── logback-local.xml
└── test
└── java
└── dev
└── practice
└── order
└── OrderApplicationTests.java
/.gitignore:
--------------------------------------------------------------------------------
1 | HELP.md
2 | .gradle
3 | build/
4 | !gradle/wrapper/gradle-wrapper.jar
5 | !**/src/main/**/build/
6 | !**/src/test/**/build/
7 |
8 | ### STS ###
9 | .apt_generated
10 | .classpath
11 | .factorypath
12 | .project
13 | .settings
14 | .springBeans
15 | .sts4-cache
16 | bin/
17 | !**/src/main/**/bin/
18 | !**/src/test/**/bin/
19 |
20 | ### IntelliJ IDEA ###
21 | .idea
22 | *.iws
23 | *.iml
24 | *.ipr
25 | out/
26 | !**/src/main/**/out/
27 | !**/src/test/**/out/
28 |
29 | ### NetBeans ###
30 | /nbproject/private/
31 | /nbbuild/
32 | /dist/
33 | /nbdist/
34 | /.nb-gradle/
35 |
36 | ### VS Code ###
37 | .vscode/
38 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 패스트캠퍼스 강의 - 주문 프로젝트
2 | 해당 repo 는 [패스트캠퍼스 RED - 비즈니스 성공을 위한 Java/Spring 기반 서비스 개발과 MSA 구축](https://fastcampus.co.kr/dev_red_lhc) 에 대한 예제 프로젝트 입니다
3 |
4 |
5 |
6 | ### 강의 순서에 따른 branch 순서
7 |
8 | #### 3. 주문 프로젝트 개발
9 |
10 | | branch | 강의 구간 |
11 | |---|:---:|
12 | | partner/domain | 추후 반영 |
13 | | partner/application | 추후 반영 |
14 | | partner/interfaces | 추후 반영 |
15 | | item/domain | 추후 반영 |
16 | | item/domain-service | 추후 반영 |
17 | | item/domain-with-factory | 추후 반영 |
18 | | item/domain-retrieve-info | 추후 반영 |
19 | | item/etc-impl-with-mapstruct | 추후 반영 |
20 | | order/domain | 추후 반영 |
21 | | order/domain-delivery-fragment | 추후 반영 |
22 | | order/domain-service | 추후 반영 |
23 | | order/domain-with-factory | 추후 반영 |
24 | | order/paymentProcessor | 추후 반영 |
25 | | order/paymentProcessor-validator | 추후 반영 |
26 | | order/etc-impl | 추후 반영 |
27 |
28 |
29 | #### 4. 선물하기 프로젝트 개발
30 |
31 | | branch | 강의 구간 | 특이 사항 |
32 | |---|:---:|:---:|
33 | | order/expand-gift | 추후 반영 | |
34 | | order/expand-gift-with-sqs | 추후 반영 | 해당 branch 에서는 aws AMI 계정 발급 후 application.yml 에 반영해야 함 |
35 |
36 |
37 |
38 |
39 |
40 | ### 문의 방법
41 | 강의 또는 코드 구현에 관한 질문은 greg.shiny82@gmail.com 으로 문의 바랍니다.
42 | 수강생에 한하여 답변 드릴 수 있도록 하겠습니다
43 | 현업 업무가 있기 때문에 주말에 몰아서 답변 가능합니다
44 |
45 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'org.springframework.boot' version '2.5.3'
3 | id 'io.spring.dependency-management' version '1.0.11.RELEASE'
4 | id 'java'
5 | }
6 |
7 | group = 'dev.practice'
8 | version = '0.0.1-SNAPSHOT'
9 | sourceCompatibility = '11'
10 |
11 | configurations {
12 | compileOnly {
13 | extendsFrom annotationProcessor
14 | }
15 | }
16 |
17 | repositories {
18 | mavenCentral()
19 | }
20 |
21 | dependencies {
22 | implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
23 | implementation 'org.springframework.boot:spring-boot-starter-web'
24 | implementation 'org.springframework.boot:spring-boot-starter-validation' // NotEmpty
25 |
26 | implementation 'org.flywaydb:flyway-core:7.10.0'
27 | compileOnly 'org.projectlombok:lombok'
28 |
29 | // MapStruct
30 | implementation 'org.mapstruct:mapstruct:1.4.2.Final'
31 | annotationProcessor "org.mapstruct:mapstruct-processor:1.4.2.Final"
32 | annotationProcessor(
33 | 'org.projectlombok:lombok',
34 | 'org.projectlombok:lombok-mapstruct-binding:0.1.0'
35 | )
36 |
37 | implementation 'com.google.guava:guava:28.2-jre'
38 | implementation 'org.apache.commons:commons-lang3:3.9'
39 |
40 | runtimeOnly 'com.h2database:h2'
41 | runtimeOnly 'mysql:mysql-connector-java'
42 | testImplementation 'org.springframework.boot:spring-boot-starter-test'
43 | }
44 |
45 | test {
46 | useJUnitPlatform()
47 | }
48 |
--------------------------------------------------------------------------------
/docker-compose/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: "3.7"
2 | services:
3 | order-db:
4 | image: mysql:8.0
5 | ports:
6 | - "3306:3306"
7 | environment:
8 | - MYSQL_DATABASE=order
9 | - MYSQL_ROOT_PASSWORD=root-pass
10 | - MYSQL_USER=order-svc
11 | - MYSQL_PASSWORD=order-pass
12 | - TZ=UTC
13 | command: # 명령어 실행
14 | - --character-set-server=utf8mb4
15 | - --collation-server=utf8mb4_unicode_ci
16 | - --lower_case_table_names=1
17 | volumes:
18 | - ./mysql:/var/lib/mysql
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gregshiny/example-order/af5570afb0d3509e154bd61955b473b7cba3f043/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.1.1-bin.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | #
4 | # Copyright 2015 the original author or authors.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # https://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 | #
18 |
19 | ##############################################################################
20 | ##
21 | ## Gradle start up script for UN*X
22 | ##
23 | ##############################################################################
24 |
25 | # Attempt to set APP_HOME
26 | # Resolve links: $0 may be a link
27 | PRG="$0"
28 | # Need this for relative symlinks.
29 | while [ -h "$PRG" ]; do
30 | ls=$(ls -ld "$PRG")
31 | link=$(expr "$ls" : '.*-> \(.*\)$')
32 | if expr "$link" : '/.*' >/dev/null; then
33 | PRG="$link"
34 | else
35 | PRG=$(dirname "$PRG")"/$link"
36 | fi
37 | done
38 | SAVED="$(pwd)"
39 | cd "$(dirname \"$PRG\")/" >/dev/null
40 | APP_HOME="$(pwd -P)"
41 | cd "$SAVED" >/dev/null
42 |
43 | APP_NAME="Gradle"
44 | APP_BASE_NAME=$(basename "$0")
45 |
46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
48 |
49 | # Use the maximum available, or set MAX_FD != -1 to use that value.
50 | MAX_FD="maximum"
51 |
52 | warn() {
53 | echo "$*"
54 | }
55 |
56 | die() {
57 | echo
58 | echo "$*"
59 | echo
60 | exit 1
61 | }
62 |
63 | # OS specific support (must be 'true' or 'false').
64 | cygwin=false
65 | msys=false
66 | darwin=false
67 | nonstop=false
68 | case "$(uname)" in
69 | CYGWIN*)
70 | cygwin=true
71 | ;;
72 | Darwin*)
73 | darwin=true
74 | ;;
75 | MSYS* | MINGW*)
76 | msys=true
77 | ;;
78 | NONSTOP*)
79 | nonstop=true
80 | ;;
81 | esac
82 |
83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
84 |
85 | # Determine the Java command to use to start the JVM.
86 | if [ -n "$JAVA_HOME" ]; then
87 | if [ -x "$JAVA_HOME/jre/sh/java" ]; then
88 | # IBM's JDK on AIX uses strange locations for the executables
89 | JAVACMD="$JAVA_HOME/jre/sh/java"
90 | else
91 | JAVACMD="$JAVA_HOME/bin/java"
92 | fi
93 | if [ ! -x "$JAVACMD" ]; then
94 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
95 |
96 | Please set the JAVA_HOME variable in your environment to match the
97 | location of your Java installation."
98 | fi
99 | else
100 | JAVACMD="java"
101 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
102 |
103 | Please set the JAVA_HOME variable in your environment to match the
104 | location of your Java installation."
105 | fi
106 |
107 | # Increase the maximum file descriptors if we can.
108 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ]; then
109 | MAX_FD_LIMIT=$(ulimit -H -n)
110 | if [ $? -eq 0 ]; then
111 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ]; then
112 | MAX_FD="$MAX_FD_LIMIT"
113 | fi
114 | ulimit -n $MAX_FD
115 | if [ $? -ne 0 ]; then
116 | warn "Could not set maximum file descriptor limit: $MAX_FD"
117 | fi
118 | else
119 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
120 | fi
121 | fi
122 |
123 | # For Darwin, add options to specify how the application appears in the dock
124 | if $darwin; then
125 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
126 | fi
127 |
128 | # For Cygwin or MSYS, switch paths to Windows format before running java
129 | if [ "$cygwin" = "true" -o "$msys" = "true" ]; then
130 | APP_HOME=$(cygpath --path --mixed "$APP_HOME")
131 | CLASSPATH=$(cygpath --path --mixed "$CLASSPATH")
132 |
133 | JAVACMD=$(cygpath --unix "$JAVACMD")
134 |
135 | # We build the pattern for arguments to be converted via cygpath
136 | ROOTDIRSRAW=$(find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null)
137 | SEP=""
138 | for dir in $ROOTDIRSRAW; do
139 | ROOTDIRS="$ROOTDIRS$SEP$dir"
140 | SEP="|"
141 | done
142 | OURCYGPATTERN="(^($ROOTDIRS))"
143 | # Add a user-defined pattern to the cygpath arguments
144 | if [ "$GRADLE_CYGPATTERN" != "" ]; then
145 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
146 | fi
147 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
148 | i=0
149 | for arg in "$@"; do
150 | CHECK=$(echo "$arg" | egrep -c "$OURCYGPATTERN" -)
151 | CHECK2=$(echo "$arg" | egrep -c "^-") ### Determine if an option
152 |
153 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ]; then ### Added a condition
154 | eval $(echo args$i)=$(cygpath --path --ignore --mixed "$arg")
155 | else
156 | eval $(echo args$i)="\"$arg\""
157 | fi
158 | i=$(expr $i + 1)
159 | done
160 | case $i in
161 | 0) set -- ;;
162 | 1) set -- "$args0" ;;
163 | 2) set -- "$args0" "$args1" ;;
164 | 3) set -- "$args0" "$args1" "$args2" ;;
165 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
166 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
167 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
168 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
169 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
170 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
171 | esac
172 | fi
173 |
174 | # Escape application args
175 | save() {
176 | for i; do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/"; done
177 | echo " "
178 | }
179 | APP_ARGS=$(save "$@")
180 |
181 | # Collect all arguments for the java command, following the shell quoting and substitution rules
182 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
183 |
184 | exec "$JAVACMD" "$@"
185 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/http-test/item-api.http:
--------------------------------------------------------------------------------
1 | ### 아이템 등록
2 | POST http://localhost:8080/api/v1/items
3 | Content-Type: application/json
4 |
5 | {
6 | "partnerToken": "ptn_oWkmVAFErP2zgALi",
7 | "itemName": "티셔츠",
8 | "itemPrice": 30000,
9 | "itemOptionGroupList": [
10 | {
11 | "ordering": "1",
12 | "itemOptionGroupName": "사이즈",
13 | "itemOptionList": [
14 | {
15 | "ordering": 1,
16 | "itemOptionName": "SMALL",
17 | "itemOptionPrice": 0
18 | },
19 | {
20 | "ordering": 2,
21 | "itemOptionName": "MEDIUM",
22 | "itemOptionPrice": 0
23 | },
24 | {
25 | "ordering": 3,
26 | "itemOptionName": "LARGE",
27 | "itemOptionPrice": 0
28 | }
29 | ]
30 |
31 | },
32 | {
33 | "ordering": "2",
34 | "itemOptionGroupName": "컬러",
35 | "itemOptionList": [
36 | {
37 | "ordering": 1,
38 | "itemOptionName": "RED",
39 | "itemOptionPrice": 0
40 | },
41 | {
42 | "ordering": 2,
43 | "itemOptionName": "GOLD",
44 | "itemOptionPrice": 1000
45 | }
46 | ]
47 | }
48 | ]
49 | }
50 |
51 | ### 아이템 1 활성화
52 | POST http://localhost:8080/api/v1/items/change-on-sales
53 | Content-Type: application/json
54 |
55 | {
56 | "itemToken": "itm_XqbL4h1l5mz1mnMZ"
57 | }
58 |
59 | ### 아이템 등록 2
60 | POST http://localhost:8080/api/v1/items
61 | Content-Type: application/json
62 |
63 | {
64 | "partnerToken": "ptn_oWkmVAFErP2zgALi",
65 | "itemName": "양말",
66 | "itemPrice": 10000,
67 | "itemOptionGroupList": [
68 | {
69 | "ordering": "1",
70 | "itemOptionGroupName": "사이즈",
71 | "itemOptionList": [
72 | {
73 | "ordering": 1,
74 | "itemOptionName": "SMALL",
75 | "itemOptionPrice": 0
76 | },
77 | {
78 | "ordering": 2,
79 | "itemOptionName": "MEDIUM",
80 | "itemOptionPrice": 0
81 | },
82 | {
83 | "ordering": 3,
84 | "itemOptionName": "LARGE",
85 | "itemOptionPrice": 0
86 | }
87 | ]
88 |
89 | },
90 | {
91 | "ordering": "2",
92 | "itemOptionGroupName": "컬러",
93 | "itemOptionList": [
94 | {
95 | "ordering": 1,
96 | "itemOptionName": "RED",
97 | "itemOptionPrice": 0
98 | },
99 | {
100 | "ordering": 2,
101 | "itemOptionName": "BlUE",
102 | "itemOptionPrice": 1000
103 | }
104 | ]
105 | }
106 | ]
107 | }
108 |
109 | ### 아이템 2 활성화
110 | POST http://localhost:8080/api/v1/items/change-on-sales
111 | Content-Type: application/json
112 |
113 | {
114 | "itemToken": "itm_qCPGVzwvLVmCoZs6"
115 | }
116 |
117 | ### 아이템 등록 3
118 | POST http://localhost:8080/api/v1/items
119 | Content-Type: application/json
120 |
121 | {
122 | "partnerToken": "ptn_oWkmVAFErP2zgALi",
123 | "itemName": "양말",
124 | "itemPrice": 10000
125 | }
126 |
127 | ### 아이템 조회
128 | GET http://localhost:8080/api/v1/items/itm_lnTOhyzZcBheBsce
129 | Content-Type: application/json
130 |
--------------------------------------------------------------------------------
/http-test/order-api.http:
--------------------------------------------------------------------------------
1 | ### 주문 요청 초기 저장
2 | POST http://localhost:8080/api/v1/orders/init
3 | Content-Type: application/json
4 |
5 | {
6 | "userId": "12345",
7 | "payMethod": "NAVER_PAY",
8 | "receiverName": "이희창",
9 | "receiverPhone": "01000001234",
10 | "receiverZipcode": "12345",
11 | "receiverAddress1": "서울시 강동구",
12 | "receiverAddress2": "우리집",
13 | "etcMessage": "감사합니다",
14 | "orderItemList": [
15 | {
16 | "orderCount": 2,
17 | "itemToken": "itm_XqbL4h1l5mz1mnMZ",
18 | "itemName": "티셔츠",
19 | "itemPrice": "30000",
20 | "orderItemOptionGroupList": [
21 | {
22 | "ordering": 1,
23 | "itemOptionGroupName": "사이즈",
24 | "orderItemOptionList": [
25 | {
26 | "ordering": 1,
27 | "itemOptionName": "MEDIUM",
28 | "itemOptionPrice": 0
29 | }
30 | ]
31 | },
32 | {
33 | "ordering": 2,
34 | "itemOptionGroupName": "컬러",
35 | "orderItemOptionList": [
36 | {
37 | "ordering": 1,
38 | "itemOptionName": "GOLD",
39 | "itemOptionPrice": 1000
40 | }
41 | ]
42 | }
43 | ]
44 | },
45 | {
46 | "orderCount": 1,
47 | "itemToken": "itm_qCPGVzwvLVmCoZs6",
48 | "itemName": "양말",
49 | "itemPrice": "10000",
50 | "orderItemOptionGroupList": [
51 | {
52 | "ordering": 1,
53 | "itemOptionGroupName": "사이즈",
54 | "orderItemOptionList": [
55 | {
56 | "ordering": 1,
57 | "itemOptionName": "LARGE",
58 | "itemOptionPrice": 0
59 | }
60 | ]
61 | },
62 | {
63 | "ordering": 2,
64 | "itemOptionGroupName": "컬러",
65 | "orderItemOptionList": [
66 | {
67 | "ordering": 1,
68 | "itemOptionName": "RED",
69 | "itemOptionPrice": 0
70 | }
71 | ]
72 | }
73 | ]
74 | }
75 | ]
76 | }
77 |
78 | ### 주문 결제 처리
79 | POST http://localhost:8080/api/v1/orders/payment-order
80 | Content-Type: application/json
81 |
82 | {
83 | "orderToken": "ord_lqAcdTqvORlU7ry3",
84 | "payMethod": "NAVER_PAY",
85 | "amount": "72000",
86 | "orderDescription": "주문테스트"
87 | }
88 |
89 | ### 주문 조회
90 | GET http://localhost:8080/api/v1/orders/ord_lqAcdTqvORlU7ry3
91 |
--------------------------------------------------------------------------------
/http-test/partner-api.http:
--------------------------------------------------------------------------------
1 | ### 파트너 등록
2 | POST http://localhost:8080/api/v1/partners
3 | Content-Type: application/json
4 |
5 | {
6 | "partnerName": "테스트",
7 | "businessNo": "1234123456",
8 | "email": "greg.shiny82@gmail.com"
9 | }
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = 'order'
2 |
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/OrderApplication.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 |
6 | @SpringBootApplication
7 | public class OrderApplication {
8 |
9 | public static void main(String[] args) {
10 | SpringApplication.run(OrderApplication.class, args);
11 | }
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/application/item/ItemFacade.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.application.item;
2 |
3 | import dev.practice.order.domain.notification.NotificationService;
4 | import dev.practice.order.domain.item.ItemCommand;
5 | import dev.practice.order.domain.item.ItemInfo;
6 | import dev.practice.order.domain.item.ItemService;
7 | import lombok.RequiredArgsConstructor;
8 | import lombok.extern.slf4j.Slf4j;
9 | import org.springframework.stereotype.Service;
10 |
11 | @Slf4j
12 | @Service
13 | @RequiredArgsConstructor
14 | public class ItemFacade {
15 | private final ItemService itemService;
16 | private final NotificationService notificationService;
17 |
18 | public String registerItem(ItemCommand.RegisterItemRequest request, String partnerToken) {
19 | var itemToken = itemService.registerItem(request, partnerToken);
20 | notificationService.sendEmail(null, null, null);
21 | return itemToken;
22 | }
23 |
24 | public void changeOnSaleItem(String itemToken) {
25 | itemService.changeOnSale(itemToken);
26 | }
27 |
28 | public void changeEndOfSaleItem(String itemToken) {
29 | itemService.changeEndOfSale(itemToken);
30 | }
31 |
32 | public ItemInfo.Main retrieveItemInfo(String itemToken) {
33 | return itemService.retrieveItemInfo(itemToken);
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/application/order/OrderFacade.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.application.order;
2 |
3 | import dev.practice.order.domain.notification.NotificationService;
4 | import dev.practice.order.domain.order.OrderCommand;
5 | import dev.practice.order.domain.order.OrderInfo;
6 | import dev.practice.order.domain.order.OrderService;
7 | import lombok.RequiredArgsConstructor;
8 | import lombok.extern.slf4j.Slf4j;
9 | import org.springframework.stereotype.Service;
10 |
11 | @Slf4j
12 | @Service
13 | @RequiredArgsConstructor
14 | public class OrderFacade {
15 | private final OrderService orderService;
16 | private final NotificationService notificationService;
17 |
18 | public String registerOrder(OrderCommand.RegisterOrder registerOrder) {
19 | var orderToken = orderService.registerOrder(registerOrder);
20 | notificationService.sendKakao("ORDER_COMPLETE", "content");
21 | return orderToken;
22 | }
23 |
24 | public OrderInfo.Main retrieveOrder(String orderToken) {
25 | return orderService.retrieveOrder(orderToken);
26 | }
27 |
28 | public void paymentOrder(OrderCommand.PaymentRequest paymentRequest) {
29 | orderService.paymentOrder(paymentRequest);
30 | notificationService.sendKakao(null, null);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/application/partner/PartnerFacade.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.application.partner;
2 |
3 | import dev.practice.order.domain.notification.NotificationService;
4 | import dev.practice.order.domain.partner.PartnerCommand;
5 | import dev.practice.order.domain.partner.PartnerInfo;
6 | import dev.practice.order.domain.partner.PartnerService;
7 | import lombok.RequiredArgsConstructor;
8 | import lombok.extern.slf4j.Slf4j;
9 | import org.springframework.stereotype.Service;
10 |
11 | @Slf4j
12 | @Service
13 | @RequiredArgsConstructor
14 | public class PartnerFacade {
15 | private final PartnerService partnerService;
16 | private final NotificationService notificationService;
17 |
18 | public PartnerInfo registerPartner(PartnerCommand command) {
19 | var partnerInfo = partnerService.registerPartner(command);
20 | notificationService.sendEmail(partnerInfo.getEmail(), "title", "description");
21 | return partnerInfo;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/common/exception/BaseException.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.common.exception;
2 |
3 | import dev.practice.order.common.response.ErrorCode;
4 | import lombok.Getter;
5 |
6 | /**
7 | * BaseException 또는 BaseException 을 확장한 Exception 은
8 | * 서비스 운영에서 예상이 가능한 Exception 을 표현한다.
9 | *
10 | * 그렇기 때문에 http status: 200 이면서 result: FAIL 을 표현하고
11 | * 특정 ErrorCode 만 alert 를 포함한 모니터링 대상으로 한다.
12 | */
13 | @Getter
14 | public class BaseException extends RuntimeException {
15 | private ErrorCode errorCode;
16 |
17 | public BaseException() {
18 | }
19 |
20 | public BaseException(ErrorCode errorCode) {
21 | super(errorCode.getErrorMsg());
22 | this.errorCode = errorCode;
23 | }
24 |
25 | public BaseException(String message, ErrorCode errorCode) {
26 | super(message);
27 | this.errorCode = errorCode;
28 | }
29 |
30 | public BaseException(String message, ErrorCode errorCode, Throwable cause) {
31 | super(message, cause);
32 | this.errorCode = errorCode;
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/common/exception/EntityNotFoundException.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.common.exception;
2 |
3 | import dev.practice.order.common.response.ErrorCode;
4 |
5 | public class EntityNotFoundException extends BaseException {
6 |
7 | public EntityNotFoundException() {
8 | super(ErrorCode.COMMON_INVALID_PARAMETER);
9 | }
10 |
11 | public EntityNotFoundException(String message) {
12 | super(message, ErrorCode.COMMON_INVALID_PARAMETER);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/common/exception/IllegalStatusException.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.common.exception;
2 |
3 |
4 | import dev.practice.order.common.response.ErrorCode;
5 |
6 | public class IllegalStatusException extends BaseException {
7 |
8 | public IllegalStatusException() {
9 | super(ErrorCode.COMMON_ILLEGAL_STATUS);
10 | }
11 |
12 | public IllegalStatusException(String message) {
13 | super(message, ErrorCode.COMMON_ILLEGAL_STATUS);
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/common/exception/InvalidParamException.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.common.exception;
2 |
3 | import dev.practice.order.common.response.ErrorCode;
4 |
5 | public class InvalidParamException extends BaseException {
6 |
7 | public InvalidParamException() {
8 | super(ErrorCode.COMMON_INVALID_PARAMETER);
9 | }
10 |
11 | public InvalidParamException(ErrorCode errorCode) {
12 | super(errorCode);
13 | }
14 |
15 | public InvalidParamException(String errorMsg) {
16 | super(errorMsg, ErrorCode.COMMON_INVALID_PARAMETER);
17 | }
18 |
19 | public InvalidParamException(String message, ErrorCode errorCode) {
20 | super(message, errorCode);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/common/interceptor/CommonHttpRequestInterceptor.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.common.interceptor;
2 |
3 | import lombok.extern.slf4j.Slf4j;
4 | import org.slf4j.MDC;
5 | import org.springframework.stereotype.Component;
6 | import org.springframework.util.StringUtils;
7 | import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
8 |
9 | import javax.servlet.http.HttpServletRequest;
10 | import javax.servlet.http.HttpServletResponse;
11 | import java.util.UUID;
12 |
13 | @Slf4j
14 | @Component
15 | public class CommonHttpRequestInterceptor extends HandlerInterceptorAdapter {
16 |
17 | public static final String HEADER_REQUEST_UUID_KEY = "x-request-id";
18 |
19 | @Override
20 | public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
21 | String requestEventId = request.getHeader(HEADER_REQUEST_UUID_KEY);
22 | if (StringUtils.isEmpty(requestEventId)) {
23 | requestEventId = UUID.randomUUID().toString();
24 | }
25 |
26 | MDC.put(HEADER_REQUEST_UUID_KEY, requestEventId);
27 | return true;
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/common/response/CommonControllerAdvice.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.common.response;
2 |
3 | import com.google.common.collect.Lists;
4 | import dev.practice.order.common.exception.BaseException;
5 | import dev.practice.order.common.interceptor.CommonHttpRequestInterceptor;
6 | import lombok.extern.slf4j.Slf4j;
7 | import org.apache.catalina.connector.ClientAbortException;
8 | import org.slf4j.MDC;
9 | import org.springframework.core.NestedExceptionUtils;
10 | import org.springframework.http.HttpStatus;
11 | import org.springframework.validation.BindingResult;
12 | import org.springframework.validation.FieldError;
13 | import org.springframework.web.bind.MethodArgumentNotValidException;
14 | import org.springframework.web.bind.annotation.ControllerAdvice;
15 | import org.springframework.web.bind.annotation.ExceptionHandler;
16 | import org.springframework.web.bind.annotation.ResponseBody;
17 | import org.springframework.web.bind.annotation.ResponseStatus;
18 |
19 | import java.util.List;
20 |
21 | @Slf4j
22 | @ControllerAdvice
23 | public class CommonControllerAdvice {
24 |
25 | private static final List SPECIFIC_ALERT_TARGET_ERROR_CODE_LIST = Lists.newArrayList();
26 |
27 | /**
28 | * http status: 500 AND result: FAIL
29 | * 시스템 예외 상황. 집중 모니터링 대상
30 | *
31 | * @param e
32 | * @return
33 | */
34 | @ResponseBody
35 | @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
36 | @ExceptionHandler(value = Exception.class)
37 | public CommonResponse onException(Exception e) {
38 | String eventId = MDC.get(CommonHttpRequestInterceptor.HEADER_REQUEST_UUID_KEY);
39 | log.error("eventId = {} ", eventId, e);
40 | return CommonResponse.fail(ErrorCode.COMMON_SYSTEM_ERROR);
41 | }
42 |
43 | /**
44 | * http status: 200 AND result: FAIL
45 | * 시스템은 이슈 없고, 비즈니스 로직 처리에서 에러가 발생함
46 | *
47 | * @param e
48 | * @return
49 | */
50 | @ResponseBody
51 | @ResponseStatus(HttpStatus.OK)
52 | @ExceptionHandler(value = BaseException.class)
53 | public CommonResponse onBaseException(BaseException e) {
54 | String eventId = MDC.get(CommonHttpRequestInterceptor.HEADER_REQUEST_UUID_KEY);
55 | if (SPECIFIC_ALERT_TARGET_ERROR_CODE_LIST.contains(e.getErrorCode())) {
56 | log.error("[BaseException] eventId = {}, cause = {}, errorMsg = {}", eventId, NestedExceptionUtils.getMostSpecificCause(e), NestedExceptionUtils.getMostSpecificCause(e).getMessage());
57 | } else {
58 | log.warn("[BaseException] eventId = {}, cause = {}, errorMsg = {}", eventId, NestedExceptionUtils.getMostSpecificCause(e), NestedExceptionUtils.getMostSpecificCause(e).getMessage());
59 | }
60 | return CommonResponse.fail(e.getMessage(), e.getErrorCode().name());
61 | }
62 |
63 | /**
64 | * 예상치 않은 Exception 중에서 모니터링 skip 이 가능한 Exception 을 처리할 때
65 | * ex) ClientAbortException
66 | *
67 | * @param e
68 | * @return
69 | */
70 | @ResponseBody
71 | @ResponseStatus(HttpStatus.OK)
72 | @ExceptionHandler(value = {ClientAbortException.class})
73 | public CommonResponse skipException(Exception e) {
74 | String eventId = MDC.get(CommonHttpRequestInterceptor.HEADER_REQUEST_UUID_KEY);
75 | log.warn("[skipException] eventId = {}, cause = {}, errorMsg = {}", eventId, NestedExceptionUtils.getMostSpecificCause(e), NestedExceptionUtils.getMostSpecificCause(e).getMessage());
76 | return CommonResponse.fail(ErrorCode.COMMON_SYSTEM_ERROR);
77 | }
78 |
79 | /**
80 | * http status: 400 AND result: FAIL
81 | * request parameter 에러
82 | *
83 | * @param e
84 | * @return
85 | */
86 | @ResponseBody
87 | @ResponseStatus(HttpStatus.BAD_REQUEST)
88 | @ExceptionHandler(value = {MethodArgumentNotValidException.class})
89 | public CommonResponse methodArgumentNotValidException(MethodArgumentNotValidException e) {
90 | String eventId = MDC.get(CommonHttpRequestInterceptor.HEADER_REQUEST_UUID_KEY);
91 | log.warn("[BaseException] eventId = {}, errorMsg = {}", eventId, NestedExceptionUtils.getMostSpecificCause(e).getMessage());
92 | BindingResult bindingResult = e.getBindingResult();
93 | FieldError fe = bindingResult.getFieldError();
94 | if (fe != null) {
95 | String message = "Request Error" + " " + fe.getField() + "=" + fe.getRejectedValue() + " (" + fe.getDefaultMessage() + ")";
96 | return CommonResponse.fail(message, ErrorCode.COMMON_INVALID_PARAMETER.name());
97 | } else {
98 | return CommonResponse.fail(ErrorCode.COMMON_INVALID_PARAMETER.getErrorMsg(), ErrorCode.COMMON_INVALID_PARAMETER.name());
99 | }
100 | }
101 | }
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/common/response/CommonResponse.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.common.response;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Builder;
5 | import lombok.Getter;
6 | import lombok.NoArgsConstructor;
7 |
8 | @Getter
9 | @Builder
10 | @NoArgsConstructor
11 | @AllArgsConstructor
12 | public class CommonResponse {
13 | private Result result;
14 | private T data;
15 | private String message;
16 | private String errorCode;
17 |
18 | public static CommonResponse success(T data, String message) {
19 | return (CommonResponse) CommonResponse.builder()
20 | .result(Result.SUCCESS)
21 | .data(data)
22 | .message(message)
23 | .build();
24 | }
25 |
26 | public static CommonResponse success(T data) {
27 | return success(data, null);
28 | }
29 |
30 | public static CommonResponse fail(String message, String errorCode) {
31 | return CommonResponse.builder()
32 | .result(Result.FAIL)
33 | .message(message)
34 | .errorCode(errorCode)
35 | .build();
36 | }
37 |
38 | public static CommonResponse fail(ErrorCode errorCode) {
39 | return CommonResponse.builder()
40 | .result(Result.FAIL)
41 | .message(errorCode.getErrorMsg())
42 | .errorCode(errorCode.name())
43 | .build();
44 | }
45 |
46 | public enum Result {
47 | SUCCESS, FAIL
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/common/response/ErrorCode.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.common.response;
2 |
3 | import lombok.Getter;
4 | import lombok.RequiredArgsConstructor;
5 |
6 | @Getter
7 | @RequiredArgsConstructor
8 | public enum ErrorCode {
9 | COMMON_SYSTEM_ERROR("일시적인 오류가 발생했습니다. 잠시 후 다시 시도해주세요."), // 장애 상황
10 | COMMON_INVALID_PARAMETER("요청한 값이 올바르지 않습니다."),
11 | COMMON_ENTITY_NOT_FOUND("존재하지 않는 엔티티입니다."),
12 | COMMON_ILLEGAL_STATUS("잘못된 상태값입니다."),
13 |
14 | // GIFT
15 | GIFT_NOT_RECEIVABLE_CONDITION("선물 수락이 가능한 상태가 아닙니다."),
16 | GIFT_NOT_MODIFY_DELIVERY_CONDITION("배송지 변경이 가능한 상태가 아닙니다.");
17 |
18 | private final String errorMsg;
19 |
20 | public String getErrorMsg(Object... arg) {
21 | return String.format(errorMsg, arg);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/common/util/TokenGenerator.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.common.util;
2 |
3 | import org.apache.commons.lang3.RandomStringUtils;
4 |
5 | public class TokenGenerator {
6 | private static final int TOKEN_LENGTH = 20;
7 |
8 | public static String randomCharacter(int length) {
9 | return RandomStringUtils.randomAlphanumeric(length);
10 | }
11 |
12 | public static String randomCharacterWithPrefix(String prefix) {
13 | return prefix + randomCharacter(TOKEN_LENGTH - prefix.length());
14 | }
15 | }
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/config/JpaAuditingConfiguration.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.config;
2 |
3 | import org.springframework.context.annotation.Configuration;
4 | import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
5 |
6 | @EnableJpaAuditing
7 | @Configuration
8 | public class JpaAuditingConfiguration {
9 | }
10 |
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/domain/AbstractEntity.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.domain;
2 |
3 | import lombok.Getter;
4 | import org.hibernate.annotations.CreationTimestamp;
5 | import org.hibernate.annotations.UpdateTimestamp;
6 | import org.springframework.data.jpa.domain.support.AuditingEntityListener;
7 |
8 | import javax.persistence.EntityListeners;
9 | import javax.persistence.MappedSuperclass;
10 | import java.time.ZonedDateTime;
11 |
12 | @Getter
13 | @MappedSuperclass
14 | @EntityListeners(AuditingEntityListener.class)
15 | public class AbstractEntity {
16 |
17 | @CreationTimestamp
18 | private ZonedDateTime createdAt;
19 |
20 | @UpdateTimestamp
21 | private ZonedDateTime updatedAt;
22 | }
23 |
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/domain/item/Item.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.domain.item;
2 |
3 | import com.google.common.collect.Lists;
4 | import dev.practice.order.common.exception.InvalidParamException;
5 | import dev.practice.order.common.util.TokenGenerator;
6 | import dev.practice.order.domain.AbstractEntity;
7 | import dev.practice.order.domain.item.optiongroup.ItemOptionGroup;
8 | import lombok.Builder;
9 | import lombok.Getter;
10 | import lombok.NoArgsConstructor;
11 | import lombok.RequiredArgsConstructor;
12 | import org.apache.commons.lang3.StringUtils;
13 |
14 | import javax.persistence.*;
15 | import java.util.List;
16 |
17 | @Getter
18 | @Entity
19 | @NoArgsConstructor
20 | @Table(name = "items")
21 | public class Item extends AbstractEntity {
22 | private static final String ITEM_PREFIX = "itm_";
23 |
24 | @Id
25 | @GeneratedValue(strategy = GenerationType.IDENTITY)
26 | private Long id;
27 | private String itemToken;
28 | private Long partnerId;
29 | private String itemName;
30 | private Long itemPrice;
31 |
32 | @OneToMany(fetch = FetchType.LAZY, mappedBy = "item", cascade = CascadeType.PERSIST)
33 | private List itemOptionGroupList = Lists.newArrayList();
34 |
35 | @Enumerated(EnumType.STRING)
36 | private Status status;
37 |
38 | @Getter
39 | @RequiredArgsConstructor
40 | public enum Status {
41 | PREPARE("판매준비중"),
42 | ON_SALE("판매중"),
43 | END_OF_SALE("판매종료");
44 |
45 | private final String description;
46 | }
47 |
48 | @Builder
49 | public Item(Long partnerId, String itemName, Long itemPrice) {
50 | if (partnerId == null) throw new InvalidParamException("Item.partnerId");
51 | if (StringUtils.isBlank(itemName)) throw new InvalidParamException("Item.itemName");
52 | if (itemPrice == null) throw new InvalidParamException("Item.itemPrice");
53 |
54 | this.partnerId = partnerId;
55 | this.itemToken = TokenGenerator.randomCharacterWithPrefix(ITEM_PREFIX);
56 | this.itemName = itemName;
57 | this.itemPrice = itemPrice;
58 | this.status = Status.PREPARE;
59 | }
60 |
61 | public void changeOnSale() {
62 | this.status = Status.ON_SALE;
63 | }
64 |
65 | public void changeEndOfSale() {
66 | this.status = Status.END_OF_SALE;
67 | }
68 |
69 | public boolean availableSales() {
70 | return this.status == Status.ON_SALE;
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/domain/item/ItemCommand.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.domain.item;
2 |
3 | import dev.practice.order.domain.item.option.ItemOption;
4 | import dev.practice.order.domain.item.optiongroup.ItemOptionGroup;
5 | import lombok.Builder;
6 | import lombok.Getter;
7 | import lombok.ToString;
8 |
9 | import java.util.List;
10 |
11 | public class ItemCommand {
12 |
13 | @Getter
14 | @Builder
15 | @ToString
16 | public static class RegisterItemRequest {
17 | private final String itemName;
18 | private final Long itemPrice;
19 | private final List itemOptionGroupRequestList; // ex) 색상, 사이즈
20 |
21 | public Item toEntity(Long partnerId) {
22 | return Item.builder()
23 | .partnerId(partnerId)
24 | .itemName(itemName)
25 | .itemPrice(itemPrice)
26 | .build();
27 | }
28 | }
29 |
30 | @Getter
31 | @Builder
32 | @ToString
33 | public static class RegisterItemOptionGroupRequest { // ex) 색상
34 | private final Integer ordering;
35 | private final String itemOptionGroupName;
36 | private final List itemOptionRequestList; // ex) R, B, W
37 |
38 | public ItemOptionGroup toEntity(Item item) {
39 | return ItemOptionGroup.builder()
40 | .item(item)
41 | .ordering(ordering)
42 | .itemOptionGroupName(itemOptionGroupName)
43 | .build();
44 | }
45 | }
46 |
47 | @Getter
48 | @Builder
49 | @ToString
50 | public static class RegisterItemOptionRequest {
51 | private final Integer ordering;
52 | private final String itemOptionName;
53 | private final Long itemOptionPrice;
54 |
55 | public ItemOption toEntity(ItemOptionGroup itemOptionGroup) {
56 | return ItemOption.builder()
57 | .itemOptionGroup(itemOptionGroup)
58 | .ordering(ordering)
59 | .itemOptionName(itemOptionName)
60 | .itemOptionPrice(itemOptionPrice)
61 | .build();
62 | }
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/domain/item/ItemInfo.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.domain.item;
2 |
3 | import dev.practice.order.domain.item.option.ItemOption;
4 | import dev.practice.order.domain.item.optiongroup.ItemOptionGroup;
5 | import lombok.Getter;
6 | import lombok.ToString;
7 |
8 | import java.util.List;
9 |
10 | public class ItemInfo {
11 |
12 | @Getter
13 | @ToString
14 | public static class Main {
15 | private final String itemToken;
16 | private final Long partnerId;
17 | private final String itemName;
18 | private final Long itemPrice;
19 | private final Item.Status status;
20 | private final List itemOptionGroupList;
21 |
22 | public Main(Item item, List itemOptionGroupInfoList) {
23 | this.itemToken = item.getItemToken();
24 | this.partnerId = item.getPartnerId();
25 | this.itemName = item.getItemName();
26 | this.itemPrice = item.getItemPrice();
27 | this.status = item.getStatus();
28 | this.itemOptionGroupList = itemOptionGroupInfoList;
29 | }
30 | }
31 |
32 | @Getter
33 | @ToString
34 | public static class ItemOptionGroupInfo {
35 | private final Integer ordering;
36 | private final String itemOptionGroupName;
37 | private final List itemOptionList;
38 |
39 | public ItemOptionGroupInfo(ItemOptionGroup itemOptionGroup, List itemOptionList) {
40 | this.ordering = itemOptionGroup.getOrdering();
41 | this.itemOptionGroupName = itemOptionGroup.getItemOptionGroupName();
42 | this.itemOptionList = itemOptionList;
43 | }
44 | }
45 |
46 | @Getter
47 | @ToString
48 | public static class ItemOptionInfo {
49 | private final Integer ordering;
50 | private final String itemOptionName;
51 | private final Long itemOptionPrice;
52 |
53 | public ItemOptionInfo(ItemOption itemOption) {
54 | this.ordering = itemOption.getOrdering();
55 | this.itemOptionName = itemOption.getItemOptionName();
56 | this.itemOptionPrice = itemOption.getItemOptionPrice();
57 | }
58 | }
59 | }
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/domain/item/ItemOptionSeriesFactory.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.domain.item;
2 |
3 |
4 | import dev.practice.order.domain.item.optiongroup.ItemOptionGroup;
5 |
6 | import java.util.List;
7 |
8 | public interface ItemOptionSeriesFactory {
9 | List store(ItemCommand.RegisterItemRequest request, Item item);
10 | }
11 |
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/domain/item/ItemReader.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.domain.item;
2 |
3 | import java.util.List;
4 |
5 | public interface ItemReader {
6 | Item getItemBy(String itemToken);
7 | List getItemOptionSeries(Item item);
8 | }
9 |
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/domain/item/ItemService.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.domain.item;
2 |
3 | public interface ItemService {
4 | String registerItem(ItemCommand.RegisterItemRequest request, String partnerToken);
5 | void changeOnSale(String itemToken);
6 | void changeEndOfSale(String itemToken);
7 | ItemInfo.Main retrieveItemInfo(String itemToken);
8 | }
9 |
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/domain/item/ItemServiceImpl.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.domain.item;
2 |
3 | import dev.practice.order.domain.partner.PartnerReader;
4 | import lombok.RequiredArgsConstructor;
5 | import lombok.extern.slf4j.Slf4j;
6 | import org.springframework.stereotype.Service;
7 | import org.springframework.transaction.annotation.Transactional;
8 |
9 | @Slf4j
10 | @Service
11 | @RequiredArgsConstructor
12 | public class ItemServiceImpl implements ItemService {
13 | private final PartnerReader partnerReader;
14 | private final ItemStore itemStore;
15 | private final ItemReader itemReader;
16 | private final ItemOptionSeriesFactory itemOptionSeriesFactory;
17 |
18 | @Override
19 | @Transactional
20 | public String registerItem(ItemCommand.RegisterItemRequest command, String partnerToken) {
21 | var partner = partnerReader.getPartner(partnerToken);
22 | var initItem = command.toEntity(partner.getId());
23 | var item = itemStore.store(initItem);
24 | itemOptionSeriesFactory.store(command, item);
25 | return item.getItemToken();
26 | }
27 |
28 | @Override
29 | @Transactional
30 | public void changeOnSale(String itemToken) {
31 | var item = itemReader.getItemBy(itemToken);
32 | item.changeOnSale();
33 | }
34 |
35 | @Override
36 | @Transactional
37 | public void changeEndOfSale(String itemToken) {
38 | var item = itemReader.getItemBy(itemToken);
39 | item.changeEndOfSale();
40 | }
41 |
42 | @Override
43 | @Transactional(readOnly = true)
44 | public ItemInfo.Main retrieveItemInfo(String itemToken) {
45 | var item = itemReader.getItemBy(itemToken);
46 | var itemOptionGroupInfoList = itemReader.getItemOptionSeries(item);
47 | return new ItemInfo.Main(item, itemOptionGroupInfoList);
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/domain/item/ItemStore.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.domain.item;
2 |
3 | public interface ItemStore {
4 | Item store(Item initItem);
5 | }
6 |
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/domain/item/option/ItemOption.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.domain.item.option;
2 |
3 |
4 | import dev.practice.order.common.exception.InvalidParamException;
5 | import dev.practice.order.domain.AbstractEntity;
6 | import dev.practice.order.domain.item.optiongroup.ItemOptionGroup;
7 | import lombok.Builder;
8 | import lombok.Getter;
9 | import lombok.NoArgsConstructor;
10 | import lombok.extern.slf4j.Slf4j;
11 | import org.apache.commons.lang3.StringUtils;
12 |
13 | import javax.persistence.*;
14 |
15 | @Slf4j
16 | @Getter
17 | @Entity
18 | @NoArgsConstructor
19 | @Table(name = "item_options")
20 | public class ItemOption extends AbstractEntity {
21 |
22 | @Id
23 | @GeneratedValue(strategy = GenerationType.IDENTITY)
24 | private Long id;
25 |
26 | @ManyToOne
27 | @JoinColumn(name = "item_option_group_id")
28 | private ItemOptionGroup itemOptionGroup;
29 | private Integer ordering;
30 | private String itemOptionName;
31 | private Long itemOptionPrice;
32 |
33 | @Builder
34 | public ItemOption(
35 | ItemOptionGroup itemOptionGroup,
36 | Integer ordering,
37 | String itemOptionName,
38 | Long itemOptionPrice
39 | ) {
40 | if (itemOptionGroup == null) throw new InvalidParamException("ItemOption.itemOptionGroup");
41 | if (ordering == null) throw new InvalidParamException("ItemOption.ordering");
42 | if (StringUtils.isBlank(itemOptionName)) throw new InvalidParamException("ItemOption.itemOptionName");
43 | if (itemOptionPrice == null) throw new InvalidParamException("ItemOption.itemOptionPrice");
44 |
45 | this.itemOptionGroup = itemOptionGroup;
46 | this.ordering = ordering;
47 | this.itemOptionName = itemOptionName;
48 | this.itemOptionPrice = itemOptionPrice;
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/domain/item/option/ItemOptionStore.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.domain.item.option;
2 |
3 | public interface ItemOptionStore {
4 | void store(ItemOption itemOption);
5 | }
6 |
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/domain/item/optiongroup/ItemOptionGroup.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.domain.item.optiongroup;
2 |
3 | import com.google.common.collect.Lists;
4 | import dev.practice.order.common.exception.InvalidParamException;
5 | import dev.practice.order.domain.AbstractEntity;
6 | import dev.practice.order.domain.item.Item;
7 | import dev.practice.order.domain.item.option.ItemOption;
8 | import lombok.Builder;
9 | import lombok.Getter;
10 | import lombok.NoArgsConstructor;
11 | import lombok.extern.slf4j.Slf4j;
12 | import org.apache.commons.lang3.StringUtils;
13 |
14 | import javax.persistence.*;
15 | import java.util.List;
16 |
17 | @Slf4j
18 | @Getter
19 | @Entity
20 | @NoArgsConstructor
21 | @Table(name = "item_option_groups")
22 | public class ItemOptionGroup extends AbstractEntity {
23 |
24 | @Id
25 | @GeneratedValue(strategy = GenerationType.IDENTITY)
26 | private Long id;
27 |
28 | @ManyToOne
29 | @JoinColumn(name = "item_id")
30 | private Item item;
31 | private Integer ordering;
32 | private String itemOptionGroupName;
33 |
34 | @OneToMany(fetch = FetchType.LAZY, mappedBy = "itemOptionGroup", cascade = CascadeType.PERSIST)
35 | private List itemOptionList = Lists.newArrayList();
36 |
37 | @Builder
38 | public ItemOptionGroup(Item item, Integer ordering, String itemOptionGroupName) {
39 | if (item == null) throw new InvalidParamException("ItemOptionGroup.item");
40 | if (ordering == null) throw new InvalidParamException("ItemOptionGroup.ordering");
41 | if (StringUtils.isBlank(itemOptionGroupName))
42 | throw new InvalidParamException("ItemOptionGroup.itemOptionGroupName");
43 |
44 | this.item = item;
45 | this.ordering = ordering;
46 | this.itemOptionGroupName = itemOptionGroupName;
47 | }
48 |
49 | public ItemOptionGroup addItemOption(ItemOption itemOption) {
50 | this.itemOptionList.add(itemOption);
51 | return this;
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/domain/item/optiongroup/ItemOptionGroupStore.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.domain.item.optiongroup;
2 |
3 | public interface ItemOptionGroupStore {
4 | ItemOptionGroup store(ItemOptionGroup itemOptionGroup);
5 | }
6 |
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/domain/notification/NotificationService.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.domain.notification;
2 |
3 | public interface NotificationService {
4 | void sendEmail(String email, String title, String description);
5 | void sendKakao(String phoneNo, String description);
6 | void sendSms(String phoneNo, String description);
7 | }
8 |
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/domain/order/Order.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.domain.order;
2 |
3 | import com.google.common.collect.Lists;
4 | import dev.practice.order.common.exception.IllegalStatusException;
5 | import dev.practice.order.common.exception.InvalidParamException;
6 | import dev.practice.order.common.util.TokenGenerator;
7 | import dev.practice.order.domain.AbstractEntity;
8 | import dev.practice.order.domain.order.fragment.DeliveryFragment;
9 | import dev.practice.order.domain.order.item.OrderItem;
10 | import lombok.*;
11 | import lombok.extern.slf4j.Slf4j;
12 | import org.apache.commons.lang3.StringUtils;
13 |
14 | import javax.persistence.*;
15 | import java.time.ZonedDateTime;
16 | import java.util.List;
17 |
18 | @Slf4j
19 | @Getter
20 | @Entity
21 | @ToString
22 | @NoArgsConstructor
23 | @Table(name = "orders")
24 | public class Order extends AbstractEntity {
25 |
26 | private static final String ORDER_PREFIX = "ord_";
27 |
28 | @Id
29 | @GeneratedValue(strategy = GenerationType.IDENTITY)
30 | private Long id;
31 | private String orderToken;
32 | private Long userId;
33 | private String payMethod;
34 |
35 | @OneToMany(fetch = FetchType.LAZY, mappedBy = "order", cascade = CascadeType.PERSIST)
36 | private List orderItemList = Lists.newArrayList();
37 |
38 | @Embedded
39 | private DeliveryFragment deliveryFragment;
40 |
41 | private ZonedDateTime orderedAt;
42 |
43 | @Enumerated(EnumType.STRING)
44 | private Status status;
45 |
46 | @Getter
47 | @RequiredArgsConstructor
48 | public enum Status {
49 | INIT("주문시작"),
50 | ORDER_COMPLETE("주문완료"),
51 | DELIVERY_PREPARE("배송준비"),
52 | IN_DELIVERY("배송중"),
53 | DELIVERY_COMPLETE("배송완료");
54 |
55 | private final String description;
56 | }
57 |
58 | @Builder
59 | public Order(
60 | Long userId,
61 | String payMethod,
62 | DeliveryFragment deliveryFragment
63 | ) {
64 | if (userId == null) throw new InvalidParamException("Order.userId");
65 | if (StringUtils.isEmpty(payMethod)) throw new InvalidParamException("Order.payMethod");
66 | if (deliveryFragment == null) throw new InvalidParamException("Order.deliveryFragment");
67 |
68 | this.orderToken = TokenGenerator.randomCharacterWithPrefix(ORDER_PREFIX);
69 | this.userId = userId;
70 | this.payMethod = payMethod;
71 | this.deliveryFragment = deliveryFragment;
72 | this.orderedAt = ZonedDateTime.now();
73 | this.status = Status.INIT;
74 | }
75 |
76 | /**
77 | * 주문 가격 = 주문 상품의 총 가격
78 | * 주문 하나의 상품의 가격 = (상품 가격 + 상품 옵션 가격) * 주문 갯수
79 | */
80 | public Long calculateTotalAmount() {
81 | return orderItemList.stream()
82 | .mapToLong(OrderItem::calculateTotalAmount)
83 | .sum();
84 | }
85 |
86 | public void orderComplete() {
87 | if (this.status != Status.INIT) throw new IllegalStatusException();
88 | this.status = Status.ORDER_COMPLETE;
89 | }
90 |
91 | public boolean isAlreadyPaymentComplete() {
92 | switch (this.status) {
93 | case ORDER_COMPLETE:
94 | case DELIVERY_PREPARE:
95 | case IN_DELIVERY:
96 | case DELIVERY_COMPLETE:
97 | return true;
98 | }
99 | return false;
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/domain/order/OrderCommand.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.domain.order;
2 |
3 | import dev.practice.order.domain.item.Item;
4 | import dev.practice.order.domain.order.fragment.DeliveryFragment;
5 | import dev.practice.order.domain.order.item.OrderItem;
6 | import dev.practice.order.domain.order.item.OrderItemOption;
7 | import dev.practice.order.domain.order.item.OrderItemOptionGroup;
8 | import dev.practice.order.domain.order.payment.PayMethod;
9 | import lombok.Builder;
10 | import lombok.Getter;
11 | import lombok.ToString;
12 |
13 | import java.util.List;
14 |
15 | public class OrderCommand {
16 |
17 | @Getter
18 | @Builder
19 | @ToString
20 | public static class RegisterOrder {
21 | private final Long userId;
22 | private final String payMethod;
23 | private final String receiverName;
24 | private final String receiverPhone;
25 | private final String receiverZipcode;
26 | private final String receiverAddress1;
27 | private final String receiverAddress2;
28 | private final String etcMessage;
29 | private final List orderItemList;
30 |
31 | public Order toEntity() {
32 | var deliveryFragment = DeliveryFragment.builder()
33 | .receiverName(receiverName)
34 | .receiverPhone(receiverPhone)
35 | .receiverZipcode(receiverZipcode)
36 | .receiverAddress1(receiverAddress1)
37 | .receiverAddress2(receiverAddress2)
38 | .etcMessage(etcMessage)
39 | .build();
40 |
41 | return Order.builder()
42 | .userId(userId)
43 | .payMethod(payMethod)
44 | .deliveryFragment(deliveryFragment)
45 | .build();
46 | }
47 | }
48 |
49 | @Getter
50 | @Builder
51 | @ToString
52 | public static class RegisterOrderItem {
53 | private final Integer orderCount;
54 | private final String itemToken;
55 | private final String itemName;
56 | private final Long itemPrice;
57 | private final List orderItemOptionGroupList;
58 |
59 | public OrderItem toEntity(Order order, Item item) {
60 | return OrderItem.builder()
61 | .order(order)
62 | .orderCount(orderCount)
63 | .partnerId(item.getPartnerId())
64 | .itemId(item.getId())
65 | .itemToken(itemToken)
66 | .itemName(itemName)
67 | .itemPrice(itemPrice)
68 | .build();
69 | }
70 | }
71 |
72 | @Getter
73 | @Builder
74 | @ToString
75 | public static class RegisterOrderItemOptionGroup {
76 | private final Integer ordering;
77 | private final String itemOptionGroupName;
78 | private final List orderItemOptionList;
79 |
80 | public OrderItemOptionGroup toEntity(OrderItem orderItem) {
81 | return OrderItemOptionGroup.builder()
82 | .orderItem(orderItem)
83 | .ordering(ordering)
84 | .itemOptionGroupName(itemOptionGroupName)
85 | .build();
86 | }
87 | }
88 |
89 | @Getter
90 | @Builder
91 | @ToString
92 | public static class RegisterOrderItemOption {
93 | private final Integer ordering;
94 | private final String itemOptionName;
95 | private final Long itemOptionPrice;
96 |
97 | public OrderItemOption toEntity(OrderItemOptionGroup orderItemOptionGroup) {
98 | return OrderItemOption.builder()
99 | .orderItemOptionGroup(orderItemOptionGroup)
100 | .ordering(ordering)
101 | .itemOptionName(itemOptionName)
102 | .itemOptionPrice(itemOptionPrice)
103 | .build();
104 | }
105 | }
106 |
107 | @Getter
108 | @Builder
109 | @ToString
110 | public static class PaymentRequest {
111 | private final String orderToken;
112 | private final Long amount;
113 | private final PayMethod payMethod;
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/domain/order/OrderInfo.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.domain.order;
2 |
3 | import lombok.Builder;
4 | import lombok.Getter;
5 | import lombok.ToString;
6 |
7 | import java.time.ZonedDateTime;
8 | import java.util.List;
9 |
10 | public class OrderInfo {
11 |
12 | @Getter
13 | @Builder
14 | @ToString
15 | public static class Main {
16 | private final Long orderId;
17 | private final String orderToken;
18 | private final Long userId;
19 | private final String payMethod;
20 | private final Long totalAmount;
21 | private final DeliveryInfo deliveryInfo;
22 | private final ZonedDateTime orderedAt;
23 | private final String status;
24 | private final String statusDescription;
25 | private final List orderItemList;
26 | }
27 |
28 | @Getter
29 | @Builder
30 | @ToString
31 | public static class DeliveryInfo {
32 | private final String receiverName;
33 | private final String receiverPhone;
34 | private final String receiverZipcode;
35 | private final String receiverAddress1;
36 | private final String receiverAddress2;
37 | private final String etcMessage;
38 | }
39 |
40 | @Getter
41 | @Builder
42 | @ToString
43 | public static class OrderItem {
44 | private final Integer orderCount;
45 | private final Long partnerId;
46 | private final Long itemId;
47 | private final String itemName;
48 | private final Long totalAmount;
49 | private final Long itemPrice;
50 | private final String deliveryStatus;
51 | private final String deliveryStatusDescription;
52 | private final List orderItemOptionGroupList;
53 | }
54 |
55 | @Getter
56 | @Builder
57 | @ToString
58 | public static class OrderItemOptionGroup {
59 | private final Integer ordering;
60 | private final String itemOptionGroupName;
61 | private final List orderItemOptionList;
62 | }
63 |
64 | @Getter
65 | @Builder
66 | @ToString
67 | public static class OrderItemOption {
68 | private final Integer ordering;
69 | private final String itemOptionName;
70 | private final Long itemOptionPrice;
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/domain/order/OrderInfoMapper.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.domain.order;
2 |
3 | import dev.practice.order.domain.order.item.OrderItem;
4 | import dev.practice.order.domain.order.item.OrderItemOption;
5 | import dev.practice.order.domain.order.item.OrderItemOptionGroup;
6 | import org.mapstruct.*;
7 |
8 | import java.util.List;
9 |
10 | @Mapper(
11 | componentModel = "spring",
12 | injectionStrategy = InjectionStrategy.CONSTRUCTOR,
13 | unmappedTargetPolicy = ReportingPolicy.ERROR
14 | )
15 | public interface OrderInfoMapper {
16 |
17 | @Mappings({
18 | @Mapping(source = "order.id", target = "orderId"),
19 | @Mapping(source = "order.deliveryFragment", target = "deliveryInfo"),
20 | @Mapping(expression = "java(order.calculateTotalAmount())", target = "totalAmount"),
21 | @Mapping(expression = "java(order.getStatus().name())", target = "status"),
22 | @Mapping(expression = "java(order.getStatus().getDescription())", target = "statusDescription")
23 | })
24 | OrderInfo.Main of(Order order, List orderItemList);
25 |
26 | @Mappings({
27 | @Mapping(expression = "java(orderItem.getDeliveryStatus().name())", target = "deliveryStatus"),
28 | @Mapping(expression = "java(orderItem.getDeliveryStatus().getDescription())", target = "deliveryStatusDescription"),
29 | @Mapping(expression = "java(orderItem.calculateTotalAmount())", target = "totalAmount")
30 | })
31 | OrderInfo.OrderItem of(OrderItem orderItem);
32 |
33 | OrderInfo.OrderItemOptionGroup of(OrderItemOptionGroup orderItemOptionGroup);
34 |
35 | OrderInfo.OrderItemOption of(OrderItemOption orderItemOption);
36 | }
37 |
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/domain/order/OrderItemSeriesFactory.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.domain.order;
2 |
3 | import dev.practice.order.domain.order.item.OrderItem;
4 |
5 | import java.util.List;
6 |
7 | public interface OrderItemSeriesFactory {
8 | List store(Order order, OrderCommand.RegisterOrder requestOrder);
9 | }
10 |
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/domain/order/OrderReader.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.domain.order;
2 |
3 | public interface OrderReader {
4 | Order getOrder(String orderToken);
5 | }
6 |
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/domain/order/OrderService.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.domain.order;
2 |
3 | public interface OrderService {
4 | String registerOrder(OrderCommand.RegisterOrder registerOrder);
5 |
6 | void paymentOrder(OrderCommand.PaymentRequest paymentRequest);
7 |
8 | OrderInfo.Main retrieveOrder(String orderToken);
9 |
10 | }
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/domain/order/OrderServiceImpl.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.domain.order;
2 |
3 | import dev.practice.order.domain.order.payment.PaymentProcessor;
4 | import lombok.RequiredArgsConstructor;
5 | import lombok.extern.slf4j.Slf4j;
6 | import org.springframework.stereotype.Service;
7 | import org.springframework.transaction.annotation.Transactional;
8 |
9 | @Slf4j
10 | @Service
11 | @RequiredArgsConstructor
12 | public class OrderServiceImpl implements OrderService {
13 | private final OrderStore orderStore;
14 | private final OrderReader orderReader;
15 | private final OrderItemSeriesFactory orderItemSeriesFactory;
16 | private final PaymentProcessor paymentProcessor;
17 | private final OrderInfoMapper orderInfoMapper;
18 |
19 | @Override
20 | @Transactional
21 | public String registerOrder(OrderCommand.RegisterOrder requestOrder) {
22 | Order order = orderStore.store(requestOrder.toEntity());
23 | orderItemSeriesFactory.store(order, requestOrder);
24 | return order.getOrderToken();
25 | }
26 |
27 | @Override
28 | @Transactional
29 | public void paymentOrder(OrderCommand.PaymentRequest paymentRequest) {
30 | var orderToken = paymentRequest.getOrderToken();
31 | var order = orderReader.getOrder(orderToken);
32 | paymentProcessor.pay(order, paymentRequest);
33 | order.orderComplete();
34 | }
35 |
36 | @Override
37 | @Transactional(readOnly = true)
38 | public OrderInfo.Main retrieveOrder(String orderToken) {
39 | var order = orderReader.getOrder(orderToken);
40 | var orderItemList = order.getOrderItemList();
41 | return orderInfoMapper.of(order, orderItemList);
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/domain/order/OrderStore.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.domain.order;
2 |
3 | import dev.practice.order.domain.order.item.OrderItem;
4 | import dev.practice.order.domain.order.item.OrderItemOption;
5 | import dev.practice.order.domain.order.item.OrderItemOptionGroup;
6 |
7 | public interface OrderStore {
8 | Order store(Order order);
9 | OrderItem store(OrderItem orderItem);
10 | OrderItemOptionGroup store(OrderItemOptionGroup orderItemOptionGroup);
11 | OrderItemOption store(OrderItemOption orderItemOption);
12 | }
13 |
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/domain/order/fragment/DeliveryFragment.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.domain.order.fragment;
2 |
3 | import dev.practice.order.common.exception.InvalidParamException;
4 | import lombok.Builder;
5 | import lombok.Getter;
6 | import lombok.NoArgsConstructor;
7 | import org.apache.commons.lang3.StringUtils;
8 |
9 | import javax.persistence.Embeddable;
10 |
11 | @Getter
12 | @Embeddable
13 | @NoArgsConstructor
14 | public class DeliveryFragment {
15 | private String receiverName;
16 | private String receiverPhone;
17 | private String receiverZipcode;
18 | private String receiverAddress1;
19 | private String receiverAddress2;
20 | private String etcMessage;
21 |
22 | @Builder
23 | public DeliveryFragment(
24 | String receiverName,
25 | String receiverPhone,
26 | String receiverZipcode,
27 | String receiverAddress1,
28 | String receiverAddress2,
29 | String etcMessage
30 | ) {
31 | if (StringUtils.isEmpty(receiverName)) throw new InvalidParamException("DeliveryFragment receiverName");
32 | if (StringUtils.isEmpty(receiverPhone)) throw new InvalidParamException("DeliveryFragment receiverPhone");
33 | if (StringUtils.isEmpty(receiverZipcode)) throw new InvalidParamException("DeliveryFragment receiverZipcode");
34 | if (StringUtils.isEmpty(receiverAddress1)) throw new InvalidParamException("DeliveryFragment receiverAddress1");
35 | if (StringUtils.isEmpty(receiverAddress2)) throw new InvalidParamException("DeliveryFragment receiverAddress2");
36 | if (StringUtils.isEmpty(etcMessage)) throw new InvalidParamException("DeliveryFragment etcMessage");
37 |
38 | this.receiverName = receiverName;
39 | this.receiverPhone = receiverPhone;
40 | this.receiverZipcode = receiverZipcode;
41 | this.receiverAddress1 = receiverAddress1;
42 | this.receiverAddress2 = receiverAddress2;
43 | this.etcMessage = etcMessage;
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/domain/order/item/OrderItem.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.domain.order.item;
2 |
3 | import com.google.common.collect.Lists;
4 | import dev.practice.order.common.exception.InvalidParamException;
5 | import dev.practice.order.domain.AbstractEntity;
6 | import dev.practice.order.domain.order.Order;
7 | import lombok.AllArgsConstructor;
8 | import lombok.Builder;
9 | import lombok.Getter;
10 | import lombok.NoArgsConstructor;
11 | import org.apache.commons.lang3.StringUtils;
12 |
13 | import javax.persistence.*;
14 | import java.util.List;
15 |
16 | @Entity
17 | @Getter
18 | @NoArgsConstructor
19 | @Table(name = "order_items")
20 | public class OrderItem extends AbstractEntity {
21 |
22 | @Id
23 | @GeneratedValue(strategy = GenerationType.IDENTITY)
24 | private Long id;
25 |
26 | @ManyToOne
27 | @JoinColumn(name = "order_id")
28 | private Order order;
29 |
30 | private Integer orderCount;
31 | private Long partnerId;
32 | private Long itemId;
33 | private String itemName;
34 | private String itemToken;
35 | private Long itemPrice;
36 |
37 | @OneToMany(fetch = FetchType.LAZY, mappedBy = "orderItem", cascade = CascadeType.PERSIST)
38 | private List orderItemOptionGroupList = Lists.newArrayList();
39 |
40 | @Enumerated(EnumType.STRING)
41 | private DeliveryStatus deliveryStatus;
42 |
43 | @Getter
44 | @AllArgsConstructor
45 | public enum DeliveryStatus {
46 | BEFORE_DELIVERY("배송전"),
47 | DELIVERY_PREPARE("배송준비중"),
48 | DELIVERING("배송중"),
49 | COMPLETE_DELIVERY("배송완료");
50 |
51 | private final String description;
52 | }
53 |
54 | @Builder
55 | public OrderItem(
56 | Order order,
57 | Integer orderCount,
58 | Long partnerId,
59 | Long itemId,
60 | String itemName,
61 | String itemToken,
62 | Long itemPrice
63 | ) {
64 | if (order == null) throw new InvalidParamException("OrderItemLine.order");
65 | if (orderCount == null) throw new InvalidParamException("OrderItemLine.orderCount");
66 | if (partnerId == null) throw new InvalidParamException("OrderItemLine.partnerId");
67 | if (itemId == null && StringUtils.isEmpty(itemName))
68 | throw new InvalidParamException("OrderItemLine.itemNo and itemName");
69 | if (StringUtils.isEmpty(itemToken)) throw new InvalidParamException("OrderItemLine.itemToken");
70 | if (itemPrice == null) throw new InvalidParamException("OrderItemLine.itemPrice");
71 |
72 | this.order = order;
73 | this.orderCount = orderCount;
74 | this.partnerId = partnerId;
75 | this.itemId = itemId;
76 | this.itemName = itemName;
77 | this.itemToken = itemToken;
78 | this.itemPrice = itemPrice;
79 | this.deliveryStatus = DeliveryStatus.BEFORE_DELIVERY;
80 | }
81 |
82 | public Long calculateTotalAmount() {
83 | var itemOptionTotalAmount = orderItemOptionGroupList.stream()
84 | .mapToLong(OrderItemOptionGroup::calculateTotalAmount)
85 | .sum();
86 | return (itemPrice + itemOptionTotalAmount) * orderCount;
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/domain/order/item/OrderItemOption.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.domain.order.item;
2 |
3 | import dev.practice.order.common.exception.InvalidParamException;
4 | import dev.practice.order.domain.AbstractEntity;
5 | import lombok.Builder;
6 | import lombok.Getter;
7 | import lombok.NoArgsConstructor;
8 | import org.apache.commons.lang3.StringUtils;
9 |
10 | import javax.persistence.*;
11 |
12 | @Entity
13 | @Getter
14 | @NoArgsConstructor
15 | @Table(name = "order_item_options")
16 | public class OrderItemOption extends AbstractEntity {
17 |
18 | @Id
19 | @GeneratedValue(strategy = GenerationType.IDENTITY)
20 | private Long id;
21 |
22 | @ManyToOne
23 | @JoinColumn(name = "order_item_option_group_id")
24 | private OrderItemOptionGroup orderItemOptionGroup;
25 | private Integer ordering;
26 | private String itemOptionName;
27 | private Long itemOptionPrice;
28 |
29 | @Builder
30 | public OrderItemOption(
31 | OrderItemOptionGroup orderItemOptionGroup,
32 | Integer ordering,
33 | String itemOptionName,
34 | Long itemOptionPrice) {
35 | if (orderItemOptionGroup == null) throw new InvalidParamException();
36 | if (ordering == null) throw new InvalidParamException();
37 | if (StringUtils.isEmpty(itemOptionName)) throw new InvalidParamException();
38 | if (itemOptionPrice == null) throw new InvalidParamException();
39 |
40 | this.orderItemOptionGroup = orderItemOptionGroup;
41 | this.ordering = ordering;
42 | this.itemOptionName = itemOptionName;
43 | this.itemOptionPrice = itemOptionPrice;
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/domain/order/item/OrderItemOptionGroup.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.domain.order.item;
2 |
3 | import com.google.common.collect.Lists;
4 | import dev.practice.order.common.exception.InvalidParamException;
5 | import dev.practice.order.domain.AbstractEntity;
6 | import lombok.Builder;
7 | import lombok.Getter;
8 | import lombok.NoArgsConstructor;
9 | import lombok.extern.slf4j.Slf4j;
10 | import org.apache.commons.lang3.StringUtils;
11 |
12 | import javax.persistence.*;
13 | import java.util.List;
14 |
15 | @Slf4j
16 | @Getter
17 | @Entity
18 | @NoArgsConstructor
19 | @Table(name = "order_item_option_groups")
20 | public class OrderItemOptionGroup extends AbstractEntity {
21 |
22 | @Id
23 | @GeneratedValue(strategy = GenerationType.IDENTITY)
24 | private Long id;
25 |
26 | @ManyToOne
27 | @JoinColumn(name = "order_item_id")
28 | private OrderItem orderItem;
29 | private Integer ordering;
30 | private String itemOptionGroupName;
31 |
32 | @OneToMany(fetch = FetchType.LAZY, mappedBy = "orderItemOptionGroup", cascade = CascadeType.PERSIST)
33 | private List orderItemOptionList = Lists.newArrayList();
34 |
35 | @Builder
36 | public OrderItemOptionGroup(
37 | OrderItem orderItem,
38 | Integer ordering,
39 | String itemOptionGroupName
40 | ) {
41 | if (orderItem == null) throw new InvalidParamException();
42 | if (ordering == null) throw new InvalidParamException();
43 | if (StringUtils.isEmpty(itemOptionGroupName)) throw new InvalidParamException();
44 |
45 | this.orderItem = orderItem;
46 | this.ordering = ordering;
47 | this.itemOptionGroupName = itemOptionGroupName;
48 | }
49 |
50 | public Long calculateTotalAmount() {
51 | return orderItemOptionList.stream()
52 | .mapToLong(OrderItemOption::getItemOptionPrice)
53 | .sum();
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/domain/order/payment/PayMethod.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.domain.order.payment;
2 |
3 | public enum PayMethod {
4 | CARD, NAVER_PAY, TOSS_PAY, KAKAO_PAY
5 | }
6 |
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/domain/order/payment/PaymentProcessor.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.domain.order.payment;
2 |
3 | import dev.practice.order.domain.order.Order;
4 | import dev.practice.order.domain.order.OrderCommand;
5 |
6 | public interface PaymentProcessor {
7 | void pay(Order order, OrderCommand.PaymentRequest request);
8 | }
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/domain/order/payment/validator/PayAmountValidator.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.domain.order.payment.validator;
2 |
3 | import dev.practice.order.common.exception.InvalidParamException;
4 | import dev.practice.order.domain.order.Order;
5 | import dev.practice.order.domain.order.OrderCommand;
6 | import org.springframework.stereotype.Component;
7 |
8 | @org.springframework.core.annotation.Order(value = 1)
9 | @Component
10 | public class PayAmountValidator implements PaymentValidator {
11 |
12 | @Override
13 | public void validate(Order order, OrderCommand.PaymentRequest paymentRequest) {
14 | if (!order.calculateTotalAmount().equals(paymentRequest.getAmount()))
15 | throw new InvalidParamException("주문가격이 불일치합니다");
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/domain/order/payment/validator/PayMethodValidator.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.domain.order.payment.validator;
2 |
3 | import dev.practice.order.common.exception.InvalidParamException;
4 | import dev.practice.order.domain.order.Order;
5 | import dev.practice.order.domain.order.OrderCommand;
6 | import org.springframework.stereotype.Component;
7 |
8 | @org.springframework.core.annotation.Order(value = 2)
9 | @Component
10 | public class PayMethodValidator implements PaymentValidator {
11 |
12 | @Override
13 | public void validate(Order order, OrderCommand.PaymentRequest paymentRequest) {
14 | if (!order.getPayMethod().equals(paymentRequest.getPayMethod().name())) {
15 | throw new InvalidParamException("주문 과정에서의 결제수단이 다릅니다.");
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/domain/order/payment/validator/PayStatusValidator.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.domain.order.payment.validator;
2 |
3 | import dev.practice.order.common.exception.InvalidParamException;
4 | import dev.practice.order.domain.order.Order;
5 | import dev.practice.order.domain.order.OrderCommand;
6 | import org.springframework.stereotype.Component;
7 |
8 | @org.springframework.core.annotation.Order(value = 3)
9 | @Component
10 | public class PayStatusValidator implements PaymentValidator {
11 |
12 | @Override
13 | public void validate(Order order, OrderCommand.PaymentRequest paymentRequest) {
14 | if (order.isAlreadyPaymentComplete()) throw new InvalidParamException("이미 결제완료된 주문입니다");
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/domain/order/payment/validator/PaymentValidator.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.domain.order.payment.validator;
2 |
3 | import dev.practice.order.domain.order.Order;
4 | import dev.practice.order.domain.order.OrderCommand;
5 |
6 | public interface PaymentValidator {
7 | void validate(Order order, OrderCommand.PaymentRequest paymentRequest);
8 | }
9 |
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/domain/partner/Partner.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.domain.partner;
2 |
3 | import dev.practice.order.common.exception.InvalidParamException;
4 | import dev.practice.order.common.util.TokenGenerator;
5 | import dev.practice.order.domain.AbstractEntity;
6 | import lombok.Builder;
7 | import lombok.Getter;
8 | import lombok.NoArgsConstructor;
9 | import lombok.RequiredArgsConstructor;
10 | import lombok.extern.slf4j.Slf4j;
11 | import org.apache.commons.lang3.StringUtils;
12 |
13 | import javax.persistence.*;
14 |
15 | @Slf4j
16 | @Getter
17 | @Entity
18 | @NoArgsConstructor
19 | @Table(name = "partners")
20 | public class Partner extends AbstractEntity {
21 | private static final String PREFIX_PARTNER = "ptn_";
22 |
23 | @Id
24 | @GeneratedValue(strategy = GenerationType.IDENTITY)
25 | private Long id;
26 | private String partnerToken;
27 | private String partnerName;
28 | private String businessNo;
29 | private String email;
30 |
31 | @Enumerated(EnumType.STRING)
32 | private Status status;
33 |
34 | @Getter
35 | @RequiredArgsConstructor
36 | public enum Status {
37 | ENABLE("활성화"), DISABLE("비활성화");
38 | private final String description;
39 | }
40 |
41 | @Builder
42 | public Partner(String partnerName, String businessNo, String email) {
43 | if (StringUtils.isEmpty(partnerName)) throw new InvalidParamException("empty partnerName");
44 | if (StringUtils.isEmpty(businessNo)) throw new InvalidParamException("empty businessNo");
45 | if (StringUtils.isEmpty(email)) throw new InvalidParamException("empty email");
46 |
47 | this.partnerToken = TokenGenerator.randomCharacterWithPrefix(PREFIX_PARTNER);
48 | this.partnerName = partnerName;
49 | this.businessNo = businessNo;
50 | this.email = email;
51 | this.status = Status.ENABLE;
52 | }
53 |
54 | public void enable() {
55 | this.status = Status.ENABLE;
56 | }
57 |
58 | public void disable() {
59 | this.status = Status.DISABLE;
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/domain/partner/PartnerCommand.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.domain.partner;
2 |
3 | import lombok.Builder;
4 | import lombok.Getter;
5 | import lombok.ToString;
6 |
7 | @Getter
8 | @Builder
9 | @ToString
10 | public class PartnerCommand {
11 | private final String partnerName;
12 | private final String businessNo;
13 | private final String email;
14 |
15 | public Partner toEntity() {
16 | return Partner.builder()
17 | .partnerName(partnerName)
18 | .businessNo(businessNo)
19 | .email(email)
20 | .build();
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/domain/partner/PartnerInfo.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.domain.partner;
2 |
3 | import lombok.Getter;
4 |
5 | @Getter
6 | public class PartnerInfo {
7 | private final Long id;
8 | private final String partnerToken;
9 | private final String partnerName;
10 | private final String businessNo;
11 | private final String email;
12 | private final Partner.Status status;
13 |
14 | public PartnerInfo(Partner partner) {
15 | this.id = partner.getId();
16 | this.partnerToken = partner.getPartnerToken();
17 | this.partnerName = partner.getPartnerName();
18 | this.businessNo = partner.getBusinessNo();
19 | this.email = partner.getEmail();
20 | this.status = partner.getStatus();
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/domain/partner/PartnerReader.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.domain.partner;
2 |
3 | public interface PartnerReader {
4 | Partner getPartner(Long partnerId);
5 | Partner getPartner(String partnerToken);
6 | }
7 |
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/domain/partner/PartnerService.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.domain.partner;
2 |
3 | public interface PartnerService {
4 | PartnerInfo registerPartner(PartnerCommand command);
5 | PartnerInfo getPartnerInfo(String partnerToken);
6 | PartnerInfo enablePartner(String partnerToken);
7 | PartnerInfo disablePartner(String partnerToken);
8 | }
9 |
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/domain/partner/PartnerServiceImpl.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.domain.partner;
2 |
3 | import lombok.RequiredArgsConstructor;
4 | import lombok.extern.slf4j.Slf4j;
5 | import org.springframework.stereotype.Service;
6 | import org.springframework.transaction.annotation.Transactional;
7 |
8 | @Slf4j
9 | @Service
10 | @RequiredArgsConstructor
11 | public class PartnerServiceImpl implements PartnerService {
12 | private final PartnerStore partnerStore;
13 | private final PartnerReader partnerReader;
14 |
15 | @Override
16 | @Transactional
17 | public PartnerInfo registerPartner(PartnerCommand command) {
18 | var initPartner = command.toEntity();
19 | Partner partner = partnerStore.store(initPartner);
20 | return new PartnerInfo(partner);
21 | }
22 |
23 | @Override
24 | @Transactional(readOnly = true)
25 | public PartnerInfo getPartnerInfo(String partnerToken) {
26 | Partner partner = partnerReader.getPartner(partnerToken);
27 | return new PartnerInfo(partner);
28 | }
29 |
30 | @Override
31 | @Transactional
32 | public PartnerInfo enablePartner(String partnerToken) {
33 | Partner partner = partnerReader.getPartner(partnerToken);
34 | partner.enable();
35 | return new PartnerInfo(partner);
36 | }
37 |
38 | @Override
39 | @Transactional
40 | public PartnerInfo disablePartner(String partnerToken) {
41 | Partner partner = partnerReader.getPartner(partnerToken);
42 | partner.disable();
43 | return new PartnerInfo(partner);
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/domain/partner/PartnerStore.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.domain.partner;
2 |
3 | public interface PartnerStore {
4 | Partner store(Partner initPartner);
5 | }
6 |
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/infrastructure/NotificationExecutor.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.infrastructure;
2 |
3 | import dev.practice.order.domain.notification.NotificationService;
4 | import lombok.extern.slf4j.Slf4j;
5 | import org.springframework.stereotype.Component;
6 |
7 | @Slf4j
8 | @Component
9 | public class NotificationExecutor implements NotificationService {
10 |
11 | @Override
12 | public void sendEmail(String email, String title, String description) {
13 | log.info("sendEmail");
14 | }
15 |
16 | @Override
17 | public void sendKakao(String phoneNo, String description) {
18 | log.info("sendKakao");
19 | }
20 |
21 | @Override
22 | public void sendSms(String phoneNo, String description) {
23 | log.info("sendSms");
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/infrastructure/item/ItemOptionSeriesFactoryImpl.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.infrastructure.item;
2 |
3 | import dev.practice.order.domain.item.Item;
4 | import dev.practice.order.domain.item.ItemCommand;
5 | import dev.practice.order.domain.item.ItemOptionSeriesFactory;
6 | import dev.practice.order.domain.item.option.ItemOptionStore;
7 | import dev.practice.order.domain.item.optiongroup.ItemOptionGroup;
8 | import dev.practice.order.domain.item.optiongroup.ItemOptionGroupStore;
9 | import lombok.RequiredArgsConstructor;
10 | import lombok.extern.slf4j.Slf4j;
11 | import org.springframework.stereotype.Component;
12 | import org.springframework.util.CollectionUtils;
13 |
14 | import java.util.Collections;
15 | import java.util.List;
16 | import java.util.stream.Collectors;
17 |
18 | @Slf4j
19 | @Component
20 | @RequiredArgsConstructor
21 | public class ItemOptionSeriesFactoryImpl implements ItemOptionSeriesFactory {
22 | private final ItemOptionGroupStore itemOptionGroupStore;
23 | private final ItemOptionStore itemOptionStore;
24 |
25 | @Override
26 | public List store(ItemCommand.RegisterItemRequest command, Item item) {
27 | var itemOptionGroupRequestList = command.getItemOptionGroupRequestList();
28 | if (CollectionUtils.isEmpty(itemOptionGroupRequestList)) return Collections.emptyList();
29 |
30 | return itemOptionGroupRequestList.stream()
31 | .map(requestItemOptionGroup -> {
32 | // itemOptionGroup store
33 | var initItemOptionGroup = requestItemOptionGroup.toEntity(item);
34 | var itemOptionGroup = itemOptionGroupStore.store(initItemOptionGroup);
35 |
36 | // itemOption store
37 | requestItemOptionGroup.getItemOptionRequestList().forEach(requestItemOption -> {
38 | var initItemOption = requestItemOption.toEntity(itemOptionGroup);
39 | itemOptionStore.store(initItemOption);
40 | });
41 |
42 | return itemOptionGroup;
43 | }).collect(Collectors.toList());
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/infrastructure/item/ItemReaderImpl.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.infrastructure.item;
2 |
3 | import dev.practice.order.common.exception.EntityNotFoundException;
4 | import dev.practice.order.domain.item.Item;
5 | import dev.practice.order.domain.item.ItemInfo;
6 | import dev.practice.order.domain.item.ItemReader;
7 | import lombok.RequiredArgsConstructor;
8 | import lombok.extern.slf4j.Slf4j;
9 | import org.springframework.stereotype.Component;
10 |
11 | import java.util.List;
12 | import java.util.stream.Collectors;
13 |
14 | @Slf4j
15 | @Component
16 | @RequiredArgsConstructor
17 | public class ItemReaderImpl implements ItemReader {
18 | private final ItemRepository itemRepository;
19 |
20 | @Override
21 | public Item getItemBy(String itemToken) {
22 | return itemRepository.findByItemToken(itemToken)
23 | .orElseThrow(EntityNotFoundException::new);
24 | }
25 |
26 | @Override
27 | public List getItemOptionSeries(Item item) {
28 | var itemOptionGroupList = item.getItemOptionGroupList();
29 | return itemOptionGroupList.stream()
30 | .map(itemOptionGroup -> {
31 | var itemOptionList = itemOptionGroup.getItemOptionList();
32 | var itemOptionInfoList = itemOptionList.stream()
33 | .map(ItemInfo.ItemOptionInfo::new)
34 | .collect(Collectors.toList());
35 |
36 | return new ItemInfo.ItemOptionGroupInfo(itemOptionGroup, itemOptionInfoList);
37 | }).collect(Collectors.toList());
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/infrastructure/item/ItemRepository.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.infrastructure.item;
2 |
3 |
4 | import dev.practice.order.domain.item.Item;
5 | import org.springframework.data.jpa.repository.JpaRepository;
6 |
7 | import java.util.Optional;
8 |
9 | public interface ItemRepository extends JpaRepository- {
10 | Optional
- findByItemToken(String itemToken);
11 | }
12 |
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/infrastructure/item/ItemStoreImpl.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.infrastructure.item;
2 |
3 | import dev.practice.order.common.exception.InvalidParamException;
4 | import dev.practice.order.domain.item.Item;
5 | import dev.practice.order.domain.item.ItemStore;
6 | import lombok.RequiredArgsConstructor;
7 | import lombok.extern.slf4j.Slf4j;
8 | import org.apache.commons.lang3.StringUtils;
9 | import org.springframework.stereotype.Component;
10 |
11 | @Slf4j
12 | @Component
13 | @RequiredArgsConstructor
14 | public class ItemStoreImpl implements ItemStore {
15 | private final ItemRepository itemRepository;
16 |
17 | @Override
18 | public Item store(Item item) {
19 | validCheck(item);
20 | return itemRepository.save(item);
21 | }
22 |
23 | private void validCheck(Item item) {
24 | if (StringUtils.isEmpty(item.getItemToken())) throw new InvalidParamException("Item.itemToken");
25 | if (StringUtils.isEmpty(item.getItemName())) throw new InvalidParamException("Item.itemName");
26 | if (item.getPartnerId() == null) throw new InvalidParamException("Item.partnerId");
27 | if (item.getItemPrice() == null) throw new InvalidParamException("Item.itemPrice");
28 | if (item.getStatus() == null) throw new InvalidParamException("Item.status");
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/infrastructure/item/option/ItemOptionRepository.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.infrastructure.item.option;
2 |
3 |
4 | import dev.practice.order.domain.item.option.ItemOption;
5 | import org.springframework.data.jpa.repository.JpaRepository;
6 |
7 | public interface ItemOptionRepository extends JpaRepository {
8 | }
9 |
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/infrastructure/item/option/ItemOptionStoreImpl.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.infrastructure.item.option;
2 |
3 | import dev.practice.order.domain.item.option.ItemOption;
4 | import dev.practice.order.domain.item.option.ItemOptionStore;
5 | import lombok.RequiredArgsConstructor;
6 | import lombok.extern.slf4j.Slf4j;
7 | import org.springframework.stereotype.Component;
8 |
9 | @Slf4j
10 | @Component
11 | @RequiredArgsConstructor
12 | public class ItemOptionStoreImpl implements ItemOptionStore {
13 |
14 | private final ItemOptionRepository itemOptionRepository;
15 |
16 | @Override
17 | public void store(ItemOption itemOption) {
18 | itemOptionRepository.save(itemOption);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/infrastructure/item/optiongroup/ItemOptionGroupRepository.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.infrastructure.item.optiongroup;
2 |
3 | import dev.practice.order.domain.item.optiongroup.ItemOptionGroup;
4 | import org.springframework.data.jpa.repository.JpaRepository;
5 |
6 | public interface ItemOptionGroupRepository extends JpaRepository {
7 | }
8 |
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/infrastructure/item/optiongroup/ItemOptionGroupStoreImpl.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.infrastructure.item.optiongroup;
2 |
3 | import dev.practice.order.domain.item.optiongroup.ItemOptionGroup;
4 | import dev.practice.order.domain.item.optiongroup.ItemOptionGroupStore;
5 | import lombok.RequiredArgsConstructor;
6 | import lombok.extern.slf4j.Slf4j;
7 | import org.springframework.stereotype.Component;
8 |
9 | @Slf4j
10 | @Component
11 | @RequiredArgsConstructor
12 | public class ItemOptionGroupStoreImpl implements ItemOptionGroupStore {
13 |
14 | private final ItemOptionGroupRepository itemOptionGroupRepository;
15 |
16 | @Override
17 | public ItemOptionGroup store(ItemOptionGroup itemOptionGroup) {
18 | return itemOptionGroupRepository.save(itemOptionGroup);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/infrastructure/order/OrderItemOptionGroupRepository.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.infrastructure.order;
2 |
3 | import dev.practice.order.domain.order.item.OrderItemOptionGroup;
4 | import org.springframework.data.jpa.repository.JpaRepository;
5 |
6 | public interface OrderItemOptionGroupRepository extends JpaRepository {
7 | }
8 |
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/infrastructure/order/OrderItemOptionRepository.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.infrastructure.order;
2 |
3 | import dev.practice.order.domain.order.item.OrderItemOption;
4 | import org.springframework.data.jpa.repository.JpaRepository;
5 |
6 | public interface OrderItemOptionRepository extends JpaRepository {
7 | }
8 |
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/infrastructure/order/OrderItemRepository.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.infrastructure.order;
2 |
3 | import dev.practice.order.domain.order.item.OrderItem;
4 | import org.springframework.data.jpa.repository.JpaRepository;
5 |
6 | public interface OrderItemRepository extends JpaRepository {
7 | }
8 |
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/infrastructure/order/OrderItemSeriesFactoryImpl.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.infrastructure.order;
2 |
3 | import dev.practice.order.domain.item.ItemReader;
4 | import dev.practice.order.domain.order.Order;
5 | import dev.practice.order.domain.order.OrderCommand;
6 | import dev.practice.order.domain.order.OrderItemSeriesFactory;
7 | import dev.practice.order.domain.order.OrderStore;
8 | import dev.practice.order.domain.order.item.OrderItem;
9 | import lombok.RequiredArgsConstructor;
10 | import org.springframework.stereotype.Component;
11 |
12 | import java.util.List;
13 | import java.util.stream.Collectors;
14 |
15 | @Component
16 | @RequiredArgsConstructor
17 | public class OrderItemSeriesFactoryImpl implements OrderItemSeriesFactory {
18 | private final ItemReader itemReader;
19 | private final OrderStore orderStore;
20 |
21 | @Override
22 | public List store(Order order, OrderCommand.RegisterOrder requestOrder) {
23 | return requestOrder.getOrderItemList().stream()
24 | .map(orderItemRequest -> {
25 | var item = itemReader.getItemBy(orderItemRequest.getItemToken());
26 | var initOrderItem = orderItemRequest.toEntity(order, item);
27 | var orderItem = orderStore.store(initOrderItem);
28 |
29 | orderItemRequest.getOrderItemOptionGroupList().forEach(orderItemOptionGroupRequest -> {
30 | var initOrderItemOptionGroup = orderItemOptionGroupRequest.toEntity(orderItem);
31 | var orderItemOptionGroup = orderStore.store(initOrderItemOptionGroup);
32 |
33 | orderItemOptionGroupRequest.getOrderItemOptionList().forEach(orderItemOptionRequest -> {
34 | var initOrderItemOption = orderItemOptionRequest.toEntity(orderItemOptionGroup);
35 | orderStore.store(initOrderItemOption);
36 | });
37 | });
38 | return orderItem;
39 | }).collect(Collectors.toList());
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/infrastructure/order/OrderReaderImpl.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.infrastructure.order;
2 |
3 | import dev.practice.order.common.exception.EntityNotFoundException;
4 | import dev.practice.order.domain.order.Order;
5 | import dev.practice.order.domain.order.OrderReader;
6 | import lombok.RequiredArgsConstructor;
7 | import lombok.extern.slf4j.Slf4j;
8 | import org.springframework.stereotype.Component;
9 |
10 | @Slf4j
11 | @Component
12 | @RequiredArgsConstructor
13 | public class OrderReaderImpl implements OrderReader {
14 |
15 | private final OrderRepository orderRepository;
16 |
17 | @Override
18 | public Order getOrder(String orderToken) {
19 | return orderRepository.findByOrderToken(orderToken)
20 | .orElseThrow(EntityNotFoundException::new);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/infrastructure/order/OrderRepository.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.infrastructure.order;
2 |
3 | import dev.practice.order.domain.order.Order;
4 | import org.springframework.data.jpa.repository.JpaRepository;
5 |
6 | import java.util.Optional;
7 |
8 | public interface OrderRepository extends JpaRepository {
9 | Optional findByOrderToken(String orderToken);
10 | }
11 |
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/infrastructure/order/OrderStoreImpl.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.infrastructure.order;
2 |
3 | import dev.practice.order.domain.order.Order;
4 | import dev.practice.order.domain.order.OrderStore;
5 | import dev.practice.order.domain.order.item.OrderItem;
6 | import dev.practice.order.domain.order.item.OrderItemOption;
7 | import dev.practice.order.domain.order.item.OrderItemOptionGroup;
8 | import lombok.RequiredArgsConstructor;
9 | import lombok.extern.slf4j.Slf4j;
10 | import org.springframework.stereotype.Component;
11 |
12 | @Slf4j
13 | @Component
14 | @RequiredArgsConstructor
15 | public class OrderStoreImpl implements OrderStore {
16 | private final OrderRepository orderRepository;
17 | private final OrderItemRepository orderItemRepository;
18 | private final OrderItemOptionGroupRepository orderItemOptionGroupRepository;
19 | private final OrderItemOptionRepository orderItemOptionRepository;
20 |
21 | @Override
22 | public Order store(Order order) {
23 | return orderRepository.save(order);
24 | }
25 |
26 | @Override
27 | public OrderItem store(OrderItem orderItem) {
28 | return orderItemRepository.save(orderItem);
29 | }
30 |
31 | @Override
32 | public OrderItemOptionGroup store(OrderItemOptionGroup orderItemOptionGroup) {
33 | return orderItemOptionGroupRepository.save(orderItemOptionGroup);
34 | }
35 |
36 | @Override
37 | public OrderItemOption store(OrderItemOption orderItemOption) {
38 | return orderItemOptionRepository.save(orderItemOption);
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/infrastructure/order/payment/KakaoPayApiCaller.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.infrastructure.order.payment;
2 |
3 | import dev.practice.order.domain.order.OrderCommand;
4 | import dev.practice.order.domain.order.payment.PayMethod;
5 | import lombok.RequiredArgsConstructor;
6 | import lombok.extern.slf4j.Slf4j;
7 | import org.springframework.stereotype.Component;
8 |
9 | @Slf4j
10 | @Component
11 | @RequiredArgsConstructor
12 | public class KakaoPayApiCaller implements PaymentApiCaller {
13 |
14 | @Override
15 | public boolean support(PayMethod payMethod) {
16 | return PayMethod.KAKAO_PAY == payMethod;
17 | }
18 |
19 | @Override
20 | public void pay(OrderCommand.PaymentRequest request) {
21 | // TODO - 구현
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/infrastructure/order/payment/NaverPayApiCaller.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.infrastructure.order.payment;
2 |
3 | import dev.practice.order.domain.order.OrderCommand;
4 | import dev.practice.order.domain.order.payment.PayMethod;
5 | import lombok.RequiredArgsConstructor;
6 | import lombok.extern.slf4j.Slf4j;
7 | import org.springframework.stereotype.Component;
8 |
9 | @Slf4j
10 | @Component
11 | @RequiredArgsConstructor
12 | public class NaverPayApiCaller implements PaymentApiCaller {
13 |
14 | @Override
15 | public boolean support(PayMethod payMethod) {
16 | return PayMethod.NAVER_PAY == payMethod;
17 | }
18 |
19 | @Override
20 | public void pay(OrderCommand.PaymentRequest request) {
21 | // TODO - 구현
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/infrastructure/order/payment/PaymentApiCaller.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.infrastructure.order.payment;
2 |
3 | import dev.practice.order.domain.order.OrderCommand;
4 | import dev.practice.order.domain.order.payment.PayMethod;
5 |
6 | public interface PaymentApiCaller {
7 | boolean support(PayMethod payMethod);
8 | void pay(OrderCommand.PaymentRequest request);
9 | }
10 |
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/infrastructure/order/payment/PaymentProcessorImpl.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.infrastructure.order.payment;
2 |
3 | import dev.practice.order.common.exception.InvalidParamException;
4 | import dev.practice.order.domain.order.Order;
5 | import dev.practice.order.domain.order.OrderCommand;
6 | import dev.practice.order.domain.order.payment.PaymentProcessor;
7 | import dev.practice.order.domain.order.payment.validator.PaymentValidator;
8 | import lombok.RequiredArgsConstructor;
9 | import lombok.extern.slf4j.Slf4j;
10 | import org.springframework.stereotype.Component;
11 |
12 | import java.util.List;
13 |
14 | @Slf4j
15 | @Component
16 | @RequiredArgsConstructor
17 | public class PaymentProcessorImpl implements PaymentProcessor {
18 | private final List paymentValidatorList;
19 | private final List paymentApiCallerList;
20 |
21 | @Override
22 | public void pay(Order order, OrderCommand.PaymentRequest paymentRequest) {
23 | paymentValidatorList.forEach(paymentValidator -> paymentValidator.validate(order, paymentRequest));
24 | PaymentApiCaller payApiCaller = routingApiCaller(paymentRequest);
25 | payApiCaller.pay(paymentRequest);
26 | }
27 |
28 | private PaymentApiCaller routingApiCaller(OrderCommand.PaymentRequest request) {
29 | return paymentApiCallerList.stream()
30 | .filter(paymentApiCaller -> paymentApiCaller.support(request.getPayMethod()))
31 | .findFirst()
32 | .orElseThrow(InvalidParamException::new);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/infrastructure/order/payment/PgCardApiCaller.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.infrastructure.order.payment;
2 |
3 | import dev.practice.order.domain.order.OrderCommand;
4 | import dev.practice.order.domain.order.payment.PayMethod;
5 | import lombok.RequiredArgsConstructor;
6 | import lombok.extern.slf4j.Slf4j;
7 | import org.springframework.stereotype.Component;
8 |
9 | @Slf4j
10 | @Component
11 | @RequiredArgsConstructor
12 | public class PgCardApiCaller implements PaymentApiCaller {
13 |
14 | @Override
15 | public boolean support(PayMethod payMethod) {
16 | return PayMethod.CARD == payMethod;
17 | }
18 |
19 | @Override
20 | public void pay(OrderCommand.PaymentRequest request) {
21 | // TODO - 구현
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/infrastructure/order/payment/TossPayApiCaller.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.infrastructure.order.payment;
2 |
3 | import dev.practice.order.domain.order.OrderCommand;
4 | import dev.practice.order.domain.order.payment.PayMethod;
5 | import lombok.RequiredArgsConstructor;
6 | import lombok.extern.slf4j.Slf4j;
7 | import org.springframework.stereotype.Component;
8 |
9 | @Slf4j
10 | @Component
11 | @RequiredArgsConstructor
12 | public class TossPayApiCaller implements PaymentApiCaller {
13 |
14 | @Override
15 | public boolean support(PayMethod payMethod) {
16 | return PayMethod.TOSS_PAY == payMethod;
17 | }
18 |
19 | @Override
20 | public void pay(OrderCommand.PaymentRequest request) {
21 | // TODO - 구현
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/infrastructure/partner/PartnerReadImpl.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.infrastructure.partner;
2 |
3 | import dev.practice.order.common.exception.EntityNotFoundException;
4 | import dev.practice.order.domain.partner.Partner;
5 | import dev.practice.order.domain.partner.PartnerReader;
6 | import lombok.RequiredArgsConstructor;
7 | import lombok.extern.slf4j.Slf4j;
8 | import org.springframework.stereotype.Component;
9 |
10 | @Slf4j
11 | @Component
12 | @RequiredArgsConstructor
13 | public class PartnerReadImpl implements PartnerReader {
14 | private final PartnerRepository partnerRepository;
15 |
16 | @Override
17 | public Partner getPartner(Long partnerId) {
18 | return partnerRepository.findById(partnerId)
19 | .orElseThrow(EntityNotFoundException::new);
20 | }
21 |
22 | @Override
23 | public Partner getPartner(String partnerToken) {
24 | return partnerRepository.findByPartnerToken(partnerToken)
25 | .orElseThrow(EntityNotFoundException::new);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/infrastructure/partner/PartnerRepository.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.infrastructure.partner;
2 |
3 | import dev.practice.order.domain.partner.Partner;
4 | import org.springframework.data.jpa.repository.JpaRepository;
5 |
6 | import java.util.Optional;
7 |
8 | public interface PartnerRepository extends JpaRepository {
9 | Optional findByPartnerToken(String partnerToken);
10 | }
11 |
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/infrastructure/partner/PartnerStoreImpl.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.infrastructure.partner;
2 |
3 | import dev.practice.order.common.exception.InvalidParamException;
4 | import dev.practice.order.domain.partner.Partner;
5 | import dev.practice.order.domain.partner.PartnerStore;
6 | import lombok.RequiredArgsConstructor;
7 | import lombok.extern.slf4j.Slf4j;
8 | import org.apache.commons.lang3.StringUtils;
9 | import org.springframework.stereotype.Component;
10 |
11 | @Slf4j
12 | @Component
13 | @RequiredArgsConstructor
14 | public class PartnerStoreImpl implements PartnerStore {
15 |
16 | private final PartnerRepository partnerRepository;
17 |
18 | @Override
19 | public Partner store(Partner partner) {
20 | if (StringUtils.isEmpty(partner.getPartnerToken())) throw new InvalidParamException("partner.getPartnerToken()");
21 | if (StringUtils.isEmpty(partner.getPartnerName())) throw new InvalidParamException("partner.getPartnerName()");
22 | if (StringUtils.isEmpty(partner.getBusinessNo())) throw new InvalidParamException("partner.getBusinessNo()");
23 | if (StringUtils.isEmpty(partner.getEmail())) throw new InvalidParamException("partner.getEmail()");
24 | if (partner.getStatus() == null) throw new InvalidParamException("partner.getStatus()");
25 |
26 | return partnerRepository.save(partner);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/interfaces/item/ItemApiController.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.interfaces.item;
2 |
3 | import dev.practice.order.application.item.ItemFacade;
4 | import dev.practice.order.common.response.CommonResponse;
5 | import lombok.RequiredArgsConstructor;
6 | import lombok.extern.slf4j.Slf4j;
7 | import org.springframework.web.bind.annotation.*;
8 |
9 | import javax.validation.Valid;
10 |
11 | @Slf4j
12 | @RestController
13 | @RequiredArgsConstructor
14 | @RequestMapping("/api/v1/items")
15 | public class ItemApiController {
16 | private final ItemFacade itemFacade;
17 | private final ItemDtoMapper itemDtoMapper;
18 |
19 | @PostMapping
20 | public CommonResponse registerItem(@RequestBody @Valid ItemDto.RegisterItemRequest request) {
21 | var partnerToken = request.getPartnerToken();
22 | var itemCommand = itemDtoMapper.of(request);
23 | var itemToken = itemFacade.registerItem(itemCommand, partnerToken);
24 | var response = itemDtoMapper.of(itemToken);
25 | return CommonResponse.success(response);
26 | }
27 |
28 | @PostMapping("/change-on-sales")
29 | public CommonResponse changeOnSaleItem(@RequestBody @Valid ItemDto.ChangeStatusItemRequest request) {
30 | var itemToken = request.getItemToken();
31 | itemFacade.changeOnSaleItem(itemToken);
32 | return CommonResponse.success("OK");
33 | }
34 |
35 | @PostMapping("/change-end-of-sales")
36 | public CommonResponse changeEndOfSaleItem(@RequestBody @Valid ItemDto.ChangeStatusItemRequest request) {
37 | var itemToken = request.getItemToken();
38 | itemFacade.changeEndOfSaleItem(itemToken);
39 | return CommonResponse.success("OK");
40 | }
41 |
42 | @GetMapping("/{itemToken}")
43 | public CommonResponse retrieve(@PathVariable("itemToken") String itemToken) {
44 | var itemInfo = itemFacade.retrieveItemInfo(itemToken);
45 | var response = itemDtoMapper.of(itemInfo);
46 | return CommonResponse.success(response);
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/interfaces/item/ItemDto.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.interfaces.item;
2 |
3 | import dev.practice.order.domain.item.Item;
4 | import lombok.Builder;
5 | import lombok.Getter;
6 | import lombok.Setter;
7 | import lombok.ToString;
8 |
9 | import java.util.List;
10 |
11 | public class ItemDto {
12 |
13 | @Getter
14 | @Setter
15 | @ToString
16 | public static class RegisterItemRequest {
17 | private String partnerToken;
18 | private String itemName;
19 | private Long itemPrice;
20 | private List itemOptionGroupList;
21 | }
22 |
23 | @Getter
24 | @Setter
25 | @ToString
26 | public static class RegisterItemOptionGroupRequest {
27 | private Integer ordering;
28 | private String itemOptionGroupName;
29 | private List itemOptionList;
30 | }
31 |
32 | @Getter
33 | @Setter
34 | @ToString
35 | public static class RegisterItemOptionRequest {
36 | private Integer ordering;
37 | private String itemOptionName;
38 | private Long itemOptionPrice;
39 | }
40 |
41 | @Getter
42 | @Builder
43 | @ToString
44 | public static class RegisterResponse {
45 | private final String itemToken;
46 | }
47 |
48 | @Getter
49 | @Setter
50 | @ToString
51 | public static class ChangeStatusItemRequest {
52 | private String itemToken;
53 | }
54 |
55 | @Getter
56 | @Builder
57 | @ToString
58 | public static class Main {
59 | private final String itemToken;
60 | private final Long partnerId;
61 | private final String itemName;
62 | private final Long itemPrice;
63 | private final Item.Status status;
64 | private final List itemOptionGroupList;
65 | }
66 |
67 | @Getter
68 | @Builder
69 | @ToString
70 | public static class ItemOptionGroupInfo {
71 | private final Integer ordering;
72 | private final String itemOptionGroupName;
73 | private final List itemOptionList;
74 | }
75 |
76 | @Getter
77 | @Builder
78 | @ToString
79 | public static class ItemOptionInfo {
80 | private final Integer ordering;
81 | private final String itemOptionName;
82 | private final Long itemOptionPrice;
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/interfaces/item/ItemDtoMapper.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.interfaces.item;
2 |
3 | import dev.practice.order.domain.item.ItemCommand;
4 | import dev.practice.order.domain.item.ItemInfo;
5 | import org.mapstruct.*;
6 |
7 | @Mapper(
8 | componentModel = "spring",
9 | injectionStrategy = InjectionStrategy.CONSTRUCTOR,
10 | unmappedTargetPolicy = ReportingPolicy.ERROR
11 | )
12 | public interface ItemDtoMapper {
13 |
14 | // register
15 | @Mappings({@Mapping(source = "request.itemOptionGroupList", target = "itemOptionGroupRequestList")})
16 | ItemCommand.RegisterItemRequest of(ItemDto.RegisterItemRequest request);
17 |
18 | @Mappings({@Mapping(source = "itemOptionList", target = "itemOptionRequestList")})
19 | ItemCommand.RegisterItemOptionGroupRequest of(ItemDto.RegisterItemOptionGroupRequest request);
20 |
21 | ItemCommand.RegisterItemOptionRequest of(ItemDto.RegisterItemOptionRequest request);
22 |
23 | ItemDto.RegisterResponse of(String itemToken);
24 |
25 | // retrieve
26 | ItemDto.Main of(ItemInfo.Main main);
27 |
28 | ItemDto.ItemOptionGroupInfo of(ItemInfo.ItemOptionGroupInfo itemOptionGroup);
29 |
30 | ItemDto.ItemOptionInfo of(ItemInfo.ItemOptionInfo itemOption);
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/interfaces/order/OrderApiController.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.interfaces.order;
2 |
3 | import dev.practice.order.application.order.OrderFacade;
4 | import dev.practice.order.common.response.CommonResponse;
5 | import lombok.RequiredArgsConstructor;
6 | import lombok.extern.slf4j.Slf4j;
7 | import org.springframework.web.bind.annotation.*;
8 |
9 | import javax.validation.Valid;
10 |
11 | @Slf4j
12 | @RestController
13 | @RequiredArgsConstructor
14 | @RequestMapping("/api/v1/orders")
15 | public class OrderApiController {
16 | private final OrderFacade orderFacade;
17 | private final OrderDtoMapper orderDtoMapper;
18 |
19 | @PostMapping("/init")
20 | public CommonResponse registerOrder(@RequestBody @Valid OrderDto.RegisterOrderRequest request) {
21 | var orderCommand = orderDtoMapper.of(request);
22 | var orderToken = orderFacade.registerOrder(orderCommand);
23 | var response = orderDtoMapper.of(orderToken);
24 | return CommonResponse.success(response);
25 | }
26 |
27 | @GetMapping("/{orderToken}")
28 | public CommonResponse retrieveOrder(@PathVariable String orderToken) {
29 | var orderResult = orderFacade.retrieveOrder(orderToken);
30 | var response = orderDtoMapper.of(orderResult);
31 | return CommonResponse.success(response);
32 | }
33 |
34 | @PostMapping("/payment-order")
35 | public CommonResponse paymentOrder(@RequestBody @Valid OrderDto.PaymentRequest paymentRequest) {
36 | var paymentCommand = orderDtoMapper.of(paymentRequest);
37 | orderFacade.paymentOrder(paymentCommand);
38 | return CommonResponse.success("OK");
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/interfaces/order/OrderDto.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.interfaces.order;
2 |
3 | import dev.practice.order.domain.order.payment.PayMethod;
4 | import lombok.Builder;
5 | import lombok.Getter;
6 | import lombok.Setter;
7 | import lombok.ToString;
8 |
9 | import javax.validation.constraints.NotBlank;
10 | import javax.validation.constraints.NotNull;
11 | import java.util.List;
12 |
13 | public class OrderDto {
14 |
15 | @Getter
16 | @Setter
17 | @ToString
18 | public static class RegisterOrderRequest {
19 | @NotNull(message = "userId 는 필수값입니다")
20 | private Long userId;
21 |
22 | @NotBlank(message = "payMethod 는 필수값입니다")
23 | private String payMethod;
24 |
25 | @NotBlank(message = "receiverName 는 필수값입니다")
26 | private String receiverName;
27 |
28 | @NotBlank(message = "receiverPhone 는 필수값입니다")
29 | private String receiverPhone;
30 |
31 | @NotBlank(message = "receiverZipcode 는 필수값입니다")
32 | private String receiverZipcode;
33 |
34 | @NotBlank(message = "receiverAddress1 는 필수값입니다")
35 | private String receiverAddress1;
36 |
37 | @NotBlank(message = "receiverAddress2 는 필수값입니다")
38 | private String receiverAddress2;
39 |
40 | @NotBlank(message = "etcMessage 는 필수값입니다")
41 | private String etcMessage;
42 |
43 | private List orderItemList;
44 | }
45 |
46 | @Getter
47 | @Setter
48 | @ToString
49 | public static class RegisterOrderItem {
50 | @NotNull(message = "orderCount 는 필수값입니다")
51 | private Integer orderCount;
52 |
53 | @NotBlank(message = "itemToken 는 필수값입니다")
54 | private String itemToken;
55 |
56 | @NotBlank(message = "itemName 는 필수값입니다")
57 | private String itemName;
58 |
59 | @NotNull(message = "itemPrice 는 필수값입니다")
60 | private Long itemPrice;
61 |
62 | private List orderItemOptionGroupList;
63 | }
64 |
65 | @Getter
66 | @Setter
67 | @ToString
68 | public static class RegisterOrderItemOptionGroupRequest {
69 | @NotNull(message = "ordering 는 필수값입니다")
70 | private Integer ordering;
71 |
72 | @NotBlank(message = "itemOptionGroupName 는 필수값입니다")
73 | private String itemOptionGroupName;
74 |
75 | private List orderItemOptionList;
76 | }
77 |
78 | @Getter
79 | @Setter
80 | @ToString
81 | public static class RegisterOrderItemOptionRequest {
82 | @NotNull(message = "ordering 는 필수값입니다")
83 | private Integer ordering;
84 |
85 | @NotBlank(message = "itemOptionName 는 필수값입니다")
86 | private String itemOptionName;
87 |
88 | @NotNull(message = "itemOptionPrice 는 필수값입니다")
89 | private Long itemOptionPrice;
90 | }
91 |
92 | @Getter
93 | @Builder
94 | @ToString
95 | public static class RegisterResponse {
96 | private final String orderToken;
97 | }
98 |
99 | @Getter
100 | @Setter
101 | @ToString
102 | public static class PaymentRequest {
103 | @NotBlank(message = "orderToken 는 필수값입니다")
104 | private String orderToken;
105 |
106 | @NotNull(message = "payMethod 는 필수값입니다")
107 | private PayMethod payMethod;
108 |
109 | @NotNull(message = "amount 는 필수값입니다")
110 | private Long amount;
111 |
112 | @NotBlank(message = "orderDescription 는 필수값입니다")
113 | private String orderDescription;
114 | }
115 |
116 | // 조회
117 | @Getter
118 | @Builder
119 | @ToString
120 | public static class Main {
121 | private final String orderToken;
122 | private final Long userId;
123 | private final String payMethod;
124 | private final Long totalAmount;
125 | private final DeliveryInfo deliveryInfo;
126 | private final String orderedAt;
127 | private final String status;
128 | private final String statusDescription;
129 | private final List orderItemList;
130 | }
131 |
132 | @Getter
133 | @Builder
134 | @ToString
135 | public static class DeliveryInfo {
136 | private final String receiverName;
137 | private final String receiverPhone;
138 | private final String receiverZipcode;
139 | private final String receiverAddress1;
140 | private final String receiverAddress2;
141 | private final String etcMessage;
142 | }
143 |
144 | @Getter
145 | @Builder
146 | @ToString
147 | public static class OrderItem {
148 | private final Integer orderCount;
149 | private final Long partnerId;
150 | private final Long itemId;
151 | private final String itemName;
152 | private final Long totalAmount;
153 | private final Long itemPrice;
154 | private final String deliveryStatus;
155 | private final String deliveryStatusDescription;
156 | private final List orderItemOptionGroupList;
157 | }
158 |
159 | @Getter
160 | @Builder
161 | @ToString
162 | public static class OrderItemOptionGroup {
163 | private final Integer ordering;
164 | private final String itemOptionGroupName;
165 | private final List orderItemOptionList;
166 | }
167 |
168 | @Getter
169 | @Builder
170 | @ToString
171 | public static class OrderItemOption {
172 | private final Integer ordering;
173 | private final String itemOptionName;
174 | private final Long itemOptionPrice;
175 | }
176 | }
177 |
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/interfaces/order/OrderDtoMapper.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.interfaces.order;
2 |
3 | import dev.practice.order.domain.order.OrderCommand;
4 | import dev.practice.order.domain.order.OrderInfo;
5 | import org.mapstruct.*;
6 |
7 | @Mapper(
8 | componentModel = "spring",
9 | injectionStrategy = InjectionStrategy.CONSTRUCTOR,
10 | unmappedTargetPolicy = ReportingPolicy.ERROR
11 | )
12 | public interface OrderDtoMapper {
13 |
14 | @Mappings({
15 | @Mapping(source = "orderedAt", target = "orderedAt", dateFormat = "yyyy-MM-dd HH:mm:ss")
16 | })
17 | OrderDto.Main of(OrderInfo.Main mainResult);
18 |
19 | OrderDto.DeliveryInfo of(OrderInfo.DeliveryInfo deliveryResult);
20 |
21 | OrderDto.OrderItem of(OrderInfo.OrderItem orderItemResult);
22 |
23 | OrderCommand.RegisterOrder of(OrderDto.RegisterOrderRequest request);
24 |
25 | OrderCommand.RegisterOrderItem of(OrderDto.RegisterOrderItem request);
26 |
27 | OrderCommand.RegisterOrderItemOptionGroup of(OrderDto.RegisterOrderItemOptionGroupRequest request);
28 |
29 | OrderCommand.RegisterOrderItemOption of(OrderDto.RegisterOrderItemOptionRequest request);
30 |
31 | OrderDto.RegisterResponse of(String orderToken);
32 |
33 | OrderCommand.PaymentRequest of(OrderDto.PaymentRequest request);
34 | }
35 |
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/interfaces/partner/PartnerApiController.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.interfaces.partner;
2 |
3 | import dev.practice.order.application.partner.PartnerFacade;
4 | import dev.practice.order.common.response.CommonResponse;
5 | import lombok.RequiredArgsConstructor;
6 | import lombok.extern.slf4j.Slf4j;
7 | import org.springframework.web.bind.annotation.PostMapping;
8 | import org.springframework.web.bind.annotation.RequestBody;
9 | import org.springframework.web.bind.annotation.RequestMapping;
10 | import org.springframework.web.bind.annotation.RestController;
11 |
12 | import javax.validation.Valid;
13 |
14 | @Slf4j
15 | @RestController
16 | @RequiredArgsConstructor
17 | @RequestMapping("/api/v1/partners")
18 | public class PartnerApiController {
19 | private final PartnerFacade partnerFacade;
20 |
21 | @PostMapping
22 | public CommonResponse registerPartner(@RequestBody @Valid PartnerDto.RegisterRequest request) {
23 | var command = request.toCommand();
24 | var partnerInfo = partnerFacade.registerPartner(command);
25 | var response = new PartnerDto.RegisterResponse(partnerInfo);
26 | return CommonResponse.success(response);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/java/dev/practice/order/interfaces/partner/PartnerDto.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order.interfaces.partner;
2 |
3 | import dev.practice.order.domain.partner.Partner;
4 | import dev.practice.order.domain.partner.PartnerCommand;
5 | import dev.practice.order.domain.partner.PartnerInfo;
6 | import lombok.Getter;
7 | import lombok.Setter;
8 | import lombok.ToString;
9 |
10 | import javax.validation.constraints.Email;
11 | import javax.validation.constraints.NotEmpty;
12 |
13 | public class PartnerDto {
14 |
15 | @Getter
16 | @Setter
17 | @ToString
18 | public static class RegisterRequest {
19 | @NotEmpty(message = "partnerName 는 필수값입니다")
20 | private String partnerName;
21 |
22 | @NotEmpty(message = "businessNo 는 필수값입니다")
23 | private String businessNo;
24 |
25 | @Email(message = "email 형식에 맞아야 합니다")
26 | @NotEmpty(message = "email 는 필수값입니다")
27 | private String email;
28 |
29 | public PartnerCommand toCommand() {
30 | return PartnerCommand.builder()
31 | .partnerName(partnerName)
32 | .businessNo(businessNo)
33 | .email(email)
34 | .build();
35 | }
36 | }
37 |
38 | @Getter
39 | @ToString
40 | public static class RegisterResponse {
41 | private final String partnerToken;
42 | private final String partnerName;
43 | private final String businessNo;
44 | private final String email;
45 | private final Partner.Status status;
46 |
47 | public RegisterResponse(PartnerInfo partnerInfo) {
48 | this.partnerToken = partnerInfo.getPartnerToken();
49 | this.partnerName = partnerInfo.getPartnerName();
50 | this.businessNo = partnerInfo.getBusinessNo();
51 | this.email = partnerInfo.getEmail();
52 | this.status = partnerInfo.getStatus();
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/main/resources/application.yml:
--------------------------------------------------------------------------------
1 | server:
2 | shutdown: graceful
3 |
4 | spring:
5 | lifecycle:
6 | timeout-per-shutdown-phase: 20s
7 | jpa:
8 | show-sql: true
9 | # database-platform: mysql
10 | hibernate:
11 | ddl-auto: none
12 | datasource:
13 | hikari:
14 | driver-class-name: com.mysql.cj.jdbc.Driver
15 | jdbc-url: jdbc:mysql://localhost:3306/order?serverTimezone=UTC&characterEncoding=UTF-8
16 | username: order-svc
17 | password: order-pass
18 | flyway:
19 | user: order-svc
20 | password: order-pass
21 | schemas: order
22 | url: jdbc:mysql://localhost:3306/order?serverTimezone=UTC&characterEncoding=UTF-8
23 | enabled: true
24 |
25 | # h2:
26 | # console:
27 | # enabled: true
28 | # path: /h2-console
29 |
30 | logging:
31 | config: classpath:logback-local.xml
--------------------------------------------------------------------------------
/src/main/resources/db/migration/V1__init_ddl.sql:
--------------------------------------------------------------------------------
1 | -- partner
2 | create table partners
3 | (
4 | id bigint auto_increment primary key comment 'ID',
5 | partner_token varchar(255) not null comment 'partner_token',
6 | partner_name varchar(255) not null comment '파트너명',
7 | business_no varchar(255) not null comment '사업자등록번호',
8 | email varchar(255) not null comment 'email',
9 | status varchar(30) not null default 'ENABLE' comment '상태',
10 | created_at datetime(6) not null comment '생성 일시',
11 | updated_at datetime(6) null comment '수정 일시'
12 | ) comment 'partners' charset = utf8mb4;
13 |
14 | create
15 | index partner_idx01 on partners (partner_token);
16 |
17 | create
18 | index partner_idx02 on partners (created_at);
19 |
20 | create
21 | index partner_idx03 on partners (updated_at);
22 |
23 | -- item
24 | create table items
25 | (
26 | id bigint auto_increment primary key comment 'ID',
27 | item_token varchar(255) not null comment 'item_token',
28 | partner_id bigint not null comment '파트너 ID',
29 | item_name varchar(255) not null comment '상품명',
30 | item_price int(11) not null comment '상품 가격',
31 | status varchar(30) not null default 'PREPARE' comment '상태',
32 | deleted_at datetime(6) null comment '삭제 일시',
33 | created_at datetime(6) not null comment '생성 일시',
34 | updated_at datetime(6) null comment '수정 일시'
35 | ) comment 'items' charset = utf8mb4;
36 |
37 | create
38 | index item_idx01 on items (item_token);
39 |
40 | create
41 | index item_idx02 on items (partner_id);
42 |
43 | create
44 | index item_idx03 on items (created_at);
45 |
46 | create
47 | index item_idx04 on items (updated_at);
48 |
49 | create
50 | index item_idx05 on items (deleted_at);
51 |
52 |
53 | -- item_option_group
54 | create table item_option_groups
55 | (
56 | id bigint auto_increment primary key comment 'ID',
57 | item_id bigint not null comment '상품 ID',
58 | ordering tinyint(3) not null comment '정렬순서',
59 | item_option_group_name varchar(30) not null comment '옵션그룹명 (색상, 사이즈 등)',
60 | created_at datetime(6) not null comment '생성 일시',
61 | updated_at datetime(6) null comment '수정 일시'
62 | ) comment 'item_option_groups' charset = utf8mb4;
63 |
64 | create
65 | index item_option_group_idx01 on item_option_groups (item_id);
66 |
67 | create
68 | index item_option_group_idx02 on item_option_groups (created_at);
69 |
70 | create
71 | index item_option_group_idx03 on item_option_groups (updated_at);
72 |
73 |
74 | -- item_option
75 | create table item_options
76 | (
77 | id bigint auto_increment primary key comment 'ID',
78 | item_option_group_id bigint not null comment '상품 옵션 그룹 ID',
79 | ordering tinyint(3) not null comment '정렬순서',
80 | item_option_name varchar(30) not null comment '옵션명 (빨강, 파랑, XL, L)',
81 | item_option_price int(11) not null comment '상품 옵션 가격',
82 | created_at datetime(6) not null comment '생성 일시',
83 | updated_at datetime(6) null comment '수정 일시'
84 | ) comment 'item_options' charset = utf8mb4;
85 |
86 | create
87 | index item_option_idx01 on item_options (item_option_group_id);
88 |
89 | create
90 | index item_option_idx02 on item_options (created_at);
91 |
92 | create
93 | index item_option_idx03 on item_options (updated_at);
94 |
95 |
96 | -- order
97 | create table orders
98 | (
99 | id bigint auto_increment primary key comment 'ID',
100 | order_token varchar(255) not null comment 'order_token',
101 | user_id bigint not null comment '유저 ID',
102 | pay_method varchar(30) not null comment '결제수단',
103 | receiver_name varchar(30) not null comment '수령자명',
104 | receiver_phone varchar(30) not null comment '수령자 휴대폰번호',
105 | receiver_zipcode varchar(10) not null comment '수령자 우편번호',
106 | receiver_address1 varchar(255) not null comment '수령자 주소1',
107 | receiver_address2 varchar(255) not null comment '수령자 주소2',
108 | etc_message varchar(255) not null comment '남기는 말',
109 | status varchar(30) not null default 'INIT' comment '상태',
110 | ordered_at datetime(6) not null comment '주문 일시',
111 | created_at datetime(6) not null comment '생성 일시',
112 | updated_at datetime(6) null comment '수정 일시'
113 | ) comment 'orders' charset = utf8mb4;
114 |
115 | create
116 | index order_idx01 on orders (order_token);
117 |
118 | create
119 | index order_idx02 on orders (user_id);
120 |
121 | create
122 | index order_idx03 on orders (ordered_at);
123 |
124 | create
125 | index order_idx04 on orders (created_at);
126 |
127 | create
128 | index order_idx05 on orders (updated_at);
129 |
130 |
131 | -- order_items
132 | create table order_items
133 | (
134 | id bigint auto_increment primary key comment 'ID',
135 | order_id bigint not null comment 'order_id',
136 | order_count tinyint not null comment '주문갯수',
137 | partner_id bigint not null comment '파트너 ID',
138 | item_id bigint not null comment '상품 ID',
139 | item_name varchar(255) not null comment '상품명',
140 | item_token varchar(30) not null comment '상품 token',
141 | item_price int(11) not null comment '상품 가격',
142 | delivery_status varchar(30) not null default 'BEFORE_DELIVERY' comment '상태',
143 | created_at datetime(6) not null comment '생성 일시',
144 | updated_at datetime(6) null comment '수정 일시'
145 | ) comment 'order_items' charset = utf8mb4;
146 |
147 | create
148 | index order_item_idx01 on order_items (order_id);
149 |
150 | create
151 | index order_item_idx02 on order_items (partner_id);
152 |
153 | create
154 | index order_item_idx03 on order_items (item_id);
155 |
156 | create
157 | index order_item_idx04 on order_items (item_token);
158 |
159 | create
160 | index order_item_idx05 on order_items (created_at);
161 |
162 | create
163 | index order_item_idx06 on order_items (updated_at);
164 |
165 |
166 | -- order_item_option_groups
167 | create table order_item_option_groups
168 | (
169 | id bigint auto_increment primary key comment 'ID',
170 | order_item_id bigint not null comment 'order_item_id',
171 | ordering tinyint(3) not null comment '정렬순서',
172 | item_option_group_name varchar(255) not null comment '상품 옵션 그룹명',
173 | created_at datetime(6) not null comment '생성 일시',
174 | updated_at datetime(6) null comment '수정 일시'
175 | ) comment 'order_item_option_groups' charset = utf8mb4;
176 |
177 | create
178 | index order_item_option_groups_idx01 on order_item_option_groups (order_item_id);
179 |
180 | create
181 | index order_item_option_groups_idx02 on order_item_option_groups (created_at);
182 |
183 | create
184 | index order_item_option_groups_idx03 on order_item_option_groups (updated_at);
185 |
186 |
187 | -- order_item_options
188 | create table order_item_options
189 | (
190 | id bigint auto_increment primary key comment 'ID',
191 | order_item_option_group_id bigint not null comment 'order_item_option_group_id',
192 | ordering tinyint(3) not null comment '정렬순서',
193 | item_option_name varchar(255) not null comment '상품 옵션명',
194 | item_option_price int(11) not null comment '상품 옵션 가격',
195 | created_at datetime(6) not null comment '생성 일시',
196 | updated_at datetime(6) null comment '수정 일시'
197 | ) comment 'order_item_options' charset = utf8mb4;
198 |
199 | create
200 | index order_item_options_idx01 on order_item_options (order_item_option_group_id);
201 |
202 | create
203 | index order_item_options_idx02 on order_item_options (created_at);
204 |
205 | create
206 | index order_item_options_idx03 on order_item_options (updated_at);
--------------------------------------------------------------------------------
/src/main/resources/logback-local.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | %d{yyyy:MM:dd HH:mm:ss.SSS} %-5level --- [%thread] %logger{35} : %msg %n
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/src/test/java/dev/practice/order/OrderApplicationTests.java:
--------------------------------------------------------------------------------
1 | package dev.practice.order;
2 |
3 | import org.junit.jupiter.api.Test;
4 | import org.springframework.boot.test.context.SpringBootTest;
5 |
6 | @SpringBootTest
7 | class OrderApplicationTests {
8 |
9 | @Test
10 | void contextLoads() {
11 | }
12 |
13 | }
14 |
--------------------------------------------------------------------------------