Skip to content

Commit 6c8d181

Browse files
authored
Merge pull request #53 from MutsaDemoDay/feat/auth
feat: 사업자등록정보 상태조회 기능 구현
2 parents 07866af + d8ad1ba commit 6c8d181

8 files changed

Lines changed: 222 additions & 2 deletions

File tree

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package backend.stamp.auth.dto.external;
2+
3+
import com.fasterxml.jackson.annotation.JsonProperty;
4+
import lombok.AllArgsConstructor;
5+
import lombok.Getter;
6+
import lombok.NoArgsConstructor;
7+
import lombok.Setter;
8+
9+
@Getter
10+
@Setter
11+
@NoArgsConstructor
12+
@AllArgsConstructor
13+
public class NtsStatusData {
14+
@JsonProperty("b_no")
15+
private String businessNumber;
16+
17+
@JsonProperty("b_stt")
18+
private String status; // 계속사업자, 폐업자, 국세청에 등록되지 않은 사업자등록번호입니다. 등
19+
20+
@JsonProperty("b_stt_cd")
21+
private String statusCode;
22+
23+
@JsonProperty("tax_type")
24+
private String taxType; // 부가가치세 일반과세자, 국세청에 등록되지 않은 사업자등록번호입니다. 등
25+
26+
@JsonProperty("tax_type_cd")
27+
private String taxTypeCode;
28+
29+
@JsonProperty("end_dt")
30+
private String closedDate;
31+
32+
@JsonProperty("utcc_yn")
33+
private String utccYn;
34+
35+
@JsonProperty("tax_type_change_dt")
36+
private String taxTypeChangeDate;
37+
38+
@JsonProperty("invoice_apply_dt")
39+
private String invoiceApplyDate;
40+
41+
@JsonProperty("rbf_tax_type")
42+
private String previousTaxType;
43+
44+
@JsonProperty("rbf_tax_type_cd")
45+
private String previousTaxTypeCode;
46+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package backend.stamp.auth.dto.external;
2+
3+
import com.fasterxml.jackson.annotation.JsonProperty;
4+
import lombok.AllArgsConstructor;
5+
import lombok.Getter;
6+
import lombok.NoArgsConstructor;
7+
import lombok.Setter;
8+
9+
import java.util.List;
10+
11+
@Getter
12+
@Setter
13+
@NoArgsConstructor
14+
@AllArgsConstructor
15+
public class NtsStatusRequest {
16+
@JsonProperty("b_no")
17+
private List<String> businessNumbers;
18+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package backend.stamp.auth.dto.external;
2+
3+
import com.fasterxml.jackson.annotation.JsonProperty;
4+
import lombok.AllArgsConstructor;
5+
import lombok.Getter;
6+
import lombok.NoArgsConstructor;
7+
import lombok.Setter;
8+
9+
import java.util.List;
10+
11+
@Getter
12+
@Setter
13+
@NoArgsConstructor
14+
@AllArgsConstructor
15+
public class NtsStatusResponse {
16+
@JsonProperty("request_cnt")
17+
private int requestCnt;
18+
19+
@JsonProperty("match_cnt")
20+
private int matchCnt;
21+
22+
@JsonProperty("status_code")
23+
private String statusCode;
24+
25+
private List<NtsStatusData> data;
26+
}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
package backend.stamp.auth.service;
2+
3+
import backend.stamp.auth.dto.external.NtsStatusData;
4+
import backend.stamp.auth.dto.external.NtsStatusRequest;
5+
import backend.stamp.auth.dto.external.NtsStatusResponse;
6+
import backend.stamp.global.exception.ApplicationException;
7+
import backend.stamp.global.exception.ErrorCode;
8+
import lombok.RequiredArgsConstructor;
9+
import org.springframework.beans.factory.annotation.Value;
10+
import org.springframework.http.HttpEntity;
11+
import org.springframework.http.HttpMethod;
12+
import org.springframework.http.MediaType;
13+
import org.springframework.http.ResponseEntity;
14+
import org.springframework.stereotype.Service;
15+
import org.springframework.web.client.RestClientException;
16+
import org.springframework.web.client.RestTemplate;
17+
import org.springframework.web.util.UriComponentsBuilder;
18+
import org.springframework.http.HttpHeaders;
19+
import java.util.List;
20+
21+
@Service
22+
@RequiredArgsConstructor
23+
public class BusinessStatusClient {
24+
private final RestTemplate restTemplate;
25+
26+
@Value("${nts.status.base-url}")
27+
private String baseUrl;
28+
29+
@Value("${nts.status.service-key}")
30+
private String serviceKey;
31+
32+
public NtsStatusData inquireStatus(String rawBusinessNumber) {
33+
String bizNo = rawBusinessNumber.replaceAll("[^0-9]", "");
34+
if (bizNo.length() != 10) {
35+
throw new ApplicationException(ErrorCode.INVALID_BUSINESS_NUMBER);
36+
}
37+
38+
String url = UriComponentsBuilder
39+
.fromHttpUrl(baseUrl + "/api/nts-businessman/v1/status")
40+
.queryParam("serviceKey", serviceKey)
41+
.build(true)
42+
.toUriString();
43+
44+
NtsStatusRequest requestBody = new NtsStatusRequest(List.of(bizNo));
45+
46+
HttpHeaders headers = new HttpHeaders();
47+
headers.setContentType(MediaType.APPLICATION_JSON);
48+
headers.setAccept(List.of(MediaType.APPLICATION_JSON));
49+
50+
HttpEntity<NtsStatusRequest> entity = new HttpEntity<>(requestBody, headers);
51+
52+
try {
53+
ResponseEntity<NtsStatusResponse> response = restTemplate.exchange(
54+
url,
55+
HttpMethod.POST,
56+
entity,
57+
NtsStatusResponse.class
58+
);
59+
60+
NtsStatusResponse body = response.getBody();
61+
if (body == null || body.getData() == null || body.getData().isEmpty()) {
62+
throw new ApplicationException(ErrorCode.BUSINESS_STATUS_CHECK_FAILED);
63+
}
64+
65+
NtsStatusData data = body.getData().get(0);
66+
67+
if (isNotRegistered(data)) {
68+
throw new ApplicationException(ErrorCode.INVALID_BUSINESS_NUMBER);
69+
}
70+
71+
return data;
72+
} catch (RestClientException e) {
73+
throw new ApplicationException(ErrorCode.BUSINESS_STATUS_CHECK_FAILED);
74+
}
75+
}
76+
77+
private boolean isNotRegistered(NtsStatusData data) {
78+
String status = data.getStatus();
79+
String taxType = data.getTaxType();
80+
String notRegisteredMessage = "국세청에 등록되지 않은 사업자등록번호입니다.";
81+
82+
return (status != null && status.contains(notRegisteredMessage))
83+
|| (taxType != null && taxType.contains(notRegisteredMessage));
84+
}
85+
}

src/main/java/backend/stamp/auth/service/EmailService.java

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ public void sendVerificationCode(String email) {
3232
try {
3333
SimpleMailMessage message = new SimpleMailMessage();
3434
message.setTo(email);
35-
message.setSubject("[STAMP] 이메일 인증번호 안내");
35+
message.setSubject("[DANGO] 이메일 인증번호 안내");
3636
message.setText("인증번호는 " + code + " 입니다.");
3737
mailSender.send(message);
3838
} catch (Exception e) {
@@ -64,4 +64,21 @@ public void verifyCodeOrThrow(String email, String inputCode) {
6464
private String generateCode() {
6565
return String.format("%06d", new Random().nextInt(1_000_000));
6666
}
67+
68+
public void sendBusinessVerifiedMail(String email) {
69+
try {
70+
SimpleMailMessage message = new SimpleMailMessage();
71+
message.setTo(email);
72+
message.setSubject("[DANGO] 사업자 등록 인증이 완료되었습니다.");
73+
message.setText(
74+
"안녕하세요.\n\n" +
75+
"요청하신 사업자 등록 인증이 정상적으로 완료되었습니다.\n" +
76+
"이제 STAMP에서 매장 정보를 등록하고, 서비스를 이용하실 수 있습니다.\n\n" +
77+
"감사합니다."
78+
);
79+
mailSender.send(message);
80+
} catch (Exception e) {
81+
e.printStackTrace();
82+
}
83+
}
6784
}

src/main/java/backend/stamp/auth/service/ManagerSignUpService.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package backend.stamp.auth.service;
22

3+
import backend.stamp.auth.dto.external.NtsStatusData;
34
import backend.stamp.account.entity.Account;
45
import backend.stamp.account.entity.UserType;
56
import backend.stamp.account.repository.AccountRepository;
@@ -28,6 +29,8 @@ public class ManagerSignUpService {
2829
private final StoreRepository storeRepository;
2930
private final PasswordEncoder passwordEncoder;
3031
private final TokenProvider tokenProvider;
32+
private final BusinessStatusClient businessStatusClient;
33+
private final EmailService emailService;
3134

3235
public SignUpResponse signUp(ManagerSignUpRequest request) {
3336

@@ -41,6 +44,12 @@ public SignUpResponse signUp(ManagerSignUpRequest request) {
4144
throw new ApplicationException(ErrorCode.DUPLICATE_EMAIL);
4245
}
4346

47+
NtsStatusData statusData = businessStatusClient.inquireStatus(request.getBusinessNum());
48+
49+
if (!"계속사업자".equals(statusData.getStatus())) {
50+
throw new ApplicationException(ErrorCode.INVALID_BUSINESS_NUMBER);
51+
}
52+
4453
String encodedPassword = passwordEncoder.encode(request.getPassword());
4554

4655
Account newAccount = new Account(
@@ -70,6 +79,7 @@ public SignUpResponse signUp(ManagerSignUpRequest request) {
7079

7180
storeRepository.save(newStore);
7281

82+
emailService.sendBusinessVerifiedMail(request.getEmail());
7383

7484
String accessToken = tokenProvider.createAccessToken(savedAccount);
7585
String refreshToken = tokenProvider.createRefreshToken(savedAccount);
@@ -83,5 +93,7 @@ public SignUpResponse signUp(ManagerSignUpRequest request) {
8393
.refreshToken(refreshToken)
8494
.build();
8595
}
86-
96+
private String cleanBizNo(String rawBusinessNumber) {
97+
return rawBusinessNumber.replaceAll("[^0-9]", "");
98+
}
8799
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package backend.stamp.global.config;
2+
3+
import org.springframework.context.annotation.Bean;
4+
import org.springframework.context.annotation.Configuration;
5+
import org.springframework.web.client.RestTemplate;
6+
7+
@Configuration
8+
public class RestTemplateConfig {
9+
@Bean
10+
public RestTemplate restTemplate() {
11+
return new RestTemplate();
12+
}
13+
}

src/main/java/backend/stamp/global/exception/ErrorCode.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ public enum ErrorCode {
5656
MENU_LIMIT_EXCEEDED(HttpStatus.BAD_REQUEST, 428, "메뉴 추가는 10개까지 가능합니다."),
5757
REVIEW_ALREADY_EXISTS(HttpStatus.BAD_REQUEST,429, "이미 리뷰를 작성하셨습니다."),
5858
STAMP_NOT_COMPLETED(HttpStatus.BAD_REQUEST, 430, "스탬프판을 완성하지 않아 리뷰 작성 권한이 없습니다."),
59+
INVALID_BUSINESS_NUMBER(HttpStatus.BAD_REQUEST, 431, "사업자번호를 다시 확인해 주세요."),
60+
INVALID_EMAIL_VERIFICATION_TOKEN(HttpStatus.BAD_REQUEST, 432, "이메일 인증이 완료되지 않았습니다."),
5961

6062
// 500: Internal Error
6163
INTERNAL_SERVER_EXCEPTION(HttpStatus.INTERNAL_SERVER_ERROR, 501, "예기치 못한 오류가 발생했습니다."),
@@ -66,6 +68,7 @@ public enum ErrorCode {
6668
EMAIL_CODE_NOT_FOUND(HttpStatus.NOT_FOUND, 504, "요청하신 이메일의 인증번호가 존재하지 않습니다."),
6769
INVALID_EMAIL_CODE(HttpStatus.BAD_REQUEST, 505, "이메일 인증번호가 일치하지 않습니다."),
6870

71+
BUSINESS_STATUS_CHECK_FAILED(HttpStatus.INTERNAL_SERVER_ERROR, 506, "사업자 상태 조회 중 오류가 발생했습니다."),
6972

7073
// object 업로드 실패
7174
OBJECT_UPLOAD_FAIL(HttpStatus.INTERNAL_SERVER_ERROR, 600, "이미지 업로드에 실패했습니다.");

0 commit comments

Comments
 (0)