Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
f71fa9a
docs: 기능 구현 목록 작성
khcho96 Dec 10, 2025
19d76df
feat: 프로모션 파일을 읽어서 저장
khcho96 Dec 10, 2025
c2acd1b
feat: 재고 파일 열어서 저장하는 기능 구현
khcho96 Dec 10, 2025
7980531
feat: 환영 인사와 재고 상태를 출력하는 기능 구현
khcho96 Dec 10, 2025
e15774d
feat: 구매 상품명과 수량 입력 기능과 검증 및 파싱 기능 구현
khcho96 Dec 10, 2025
03a607d
feat: 구매 상품명과 수량 입력 기능과 검증 및 파싱 기능 구현
khcho96 Dec 10, 2025
c4f213e
feat: 프로모션 적용이 가능한 상품에 대해 고객이 해당 수량보다 적게 가져온 경우 기능 구현
khcho96 Dec 12, 2025
abfe253
feat: 프로모션 재고가 부족하여 일부 수령을 프로모션 혜택 없이 결제해야 하는 경우 기능 구현
khcho96 Dec 12, 2025
230d2dd
feat: 기능 구현 목록 5,6번에 해당하지 않는 프로모션 상품을 구매 및 증정 상품 목록에 추가한다.
khcho96 Dec 12, 2025
2d43b16
feat: 프로모션에 해당하지 않는 상품을 구매 상품 목록에 추가하는 기능 구현
khcho96 Dec 12, 2025
bb8c9dc
feat: 멤버십 할인을 받을지 유무 입력 및 처리 기능 구현
khcho96 Dec 12, 2025
1b89ae2
feat: 구매 및 증정 목록에 기반하여 재고를 업데이트(파일 수정)하는 기능 구현
khcho96 Dec 12, 2025
bd6d277
feat: 영수증을 출력 기능 구현
khcho96 Dec 12, 2025
1504a57
feat: 컨트롤러 및 서비스 도입
khcho96 Dec 12, 2025
2123af3
feat: 다른 상품을 구매할지 여부 입력 및 처리 기능 구현
khcho96 Dec 12, 2025
76a0af6
fix: 출력 내용 버그 수정
khcho96 Dec 12, 2025
3c22f23
test: IOException 처리 코드 추가
khcho96 Dec 12, 2025
6488169
refactor: 리팩토링
khcho96 Jan 5, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 46 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,46 @@
![문제 원문1](description-img/4.편의점_page-0001.jpg)
![문제 원문2](description-img/4.편의점_page-0002.jpg)
![문제 원문3](description-img/4.편의점_page-0003.jpg)
![문제 원문4](description-img/4.편의점_page-0004.jpg)
![문제 원문5](description-img/4.편의점_page-0005.jpg)
![문제 원문6](description-img/4.편의점_page-0006.jpg)
![문제 원문7](description-img/4.편의점_page-0007.jpg)
![문제 원문8](description-img/4.편의점_page-0008.jpg)
![문제 원문9](description-img/4.편의점_page-0009.jpg)
![문제 원문10](description-img/4.편의점_page-0010.jpg)
# 기능 구현 목록
1. 환영 인사와 재고 상태를 출력한다.
1. 프로모션 파일을 읽어서 저장한다.
2. 재고 파일을 읽어서 저장 후 출력한다.
2. 구매 상품명과 수량을 입력받는다.
- 예외 사항
1. 빈 문자열 입력 시 예외 발생
2. 형식에 맞지 않으면 예외 발생
3. 구매 상품명과 수량을 각각 문자열과 숫자로 변환한다.
- 예외 사항
1. 수량이 1 이상이 아니면 예외 발생
2. 존재하지 않는 상품을 입력하면 예외 발생
3. 구매 수량이 재고 수량을 초과하면 예외 발생
4. 프로모션 적용이 가능한 상품에 대해 고객이 해당 수량보다 적게 가져온 경우, 필요한 수량을 추가로 가져오면 혜택을 받을 수 있음을 안내한다.(해당 상품 종류의 개수만큼 안내 내용을 출력한다.)
- Y
1. 무료로 더 받을 수 있는 개수만큼 구매 및 증정 상품 목록에 추가한다.
- N
- 다음 안내로 넘어간다.
5. 프로모션 재고가 부족하여 일부 수령을 프로모션 혜택 없이 결제해야 하는 경우, 일부 수량에 대해 정가로 결제하게 됨을 안내한다.(해당 상품 종류의 개수만큼 안내 내용을 출력한다.)
- Y
1. 프로모션 혜택 없이 일부 수량에 대해 정가로 계산한다.
2. 구매 및 증정 상품 목록에 추가한다.
- N
1. 프로모션 혜택 없는 일부 수량을 제외한 나머지를 구매 및 증정 상품 목록에 추가한다.
6. 5, 6번에 해당하지 않는 프로모션 상품을 구매 및 증정 상품 목록에 추가한다.
7. 프로모션에 해당하지 않는 상품을 구매 상품 목록에 추가한다.
- 프로모션 해당하지 않는 상품: 프로모션 값이 null이거나 프로모션 기간에 오늘 날짜가 포함되지 않는 경우
8. 멤버십 할인을 받을지 유무를 입력받는다.
- Y
1. 프로모션 적용되지 않은 상품에 대한 총 금액의 30%를 멤버십 할인 금액으로 저장한다.
2. 만약 멤버십 할인 금액이 8,000원 초과면 멤버십 할인 금액을 8,000원으로 저장한다.
- N
1. 다음으로 넘어간다.
9. 구매 및 증정 목록에 기반하여 재고를 업데이트한다.
10. 영수증을 출력한다.
- 전체 구매 상품명 및 수량
- 증정 상품명 및 수량
- 총 구매액
- 행사 할인 금액
- 멤버십 할인 금액
- 내실돈
11. 다른 상품을 구매할지 여부를 입력받는다.
- Y
1. 1번부터 다시 시작
- N
1. 프로그램 종료
11 changes: 9 additions & 2 deletions src/main/java/store/Application.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
package store;

import java.io.IOException;
import store.controller.StoreController;
import store.service.StoreService;

public class Application {
public static void main(String[] args) {
// TODO: 프로그램 구현

public static void main(String[] args) throws IOException {
StoreService storeService = new StoreService();
StoreController storeController = new StoreController(storeService);
storeController.run();
}
}
7 changes: 7 additions & 0 deletions src/main/java/store/constant/Constant.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package store.constant;

public final class Constant {

// public static final int = ;
// public static final String = ;
}
20 changes: 20 additions & 0 deletions src/main/java/store/constant/ErrorMessage.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package store.constant;

public enum ErrorMessage {

FORMAT_ERROR("올바르지 않은 형식으로 입력했습니다. 다시 입력해 주세요."),
NO_EXIST_ERROR("존재하지 않는 상품입니다. 다시 입력해 주세요."),
EXCEED_ERROR("재고 수량을 초과하여 구매할 수 없습니다. 다시 입력해 주세요."),
INVALID_ERROR("잘못된 입력입니다. 다시 입력해 주세요.");

private static final String ERROR_MESSAGE_PREFIX = "[ERROR] ";
private final String errorMessage;

ErrorMessage(String errorMessage) {
this.errorMessage = errorMessage;
}

public String getErrorMessage() {
return ERROR_MESSAGE_PREFIX + errorMessage;
}
}
140 changes: 140 additions & 0 deletions src/main/java/store/controller/StoreController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
package store.controller;

import java.io.IOException;
import java.util.List;
import store.dto.ReceiptDto;
import store.dto.StockDto;
import store.service.StoreService;
import store.util.InputParser;
import store.util.file.FileReader;
import store.util.file.FileWriter;
import store.view.InputView;
import store.view.OutputView;

public class StoreController {

private final StoreService storeService;

public StoreController(StoreService storeService) {
this.storeService = storeService;
}

public void run() throws IOException {
while (true) {
readFiles();

StockDto stockDto = storeService.getStockDto();
OutputView.printStock(stockDto);

registerPurchaseProducts();

handleFreeProducts();
handleOverProducts();
handleNormalProducts();
handleNoPromotionProducts();
setMembershipDiscountAmount();

writeStockFile();
printResult();

String rawChoice = InputView.readMorePurchaseChoice();
boolean choice = InputParser.parseChoice(rawChoice);
if (!choice) {
break;
}
}
}

private void readFiles() throws IOException {
FileReader promotionReader = new FileReader("src/main/resources/promotions.md");
List<String> readPromotions = promotionReader.readLines();
storeService.readPromotionFile(readPromotions);

FileReader fr = new FileReader("src/main/resources/products.md");
List<String> readProducts = fr.readLines();
storeService.readProductsFile(readProducts);
}

private void registerPurchaseProducts() {
while (true) {
try {
storeService.registerPurchaseProducts();
return;
} catch (IllegalArgumentException e) {
OutputView.printErrorMessage(e);
}
}
}

private void handleFreeProducts() {
while (true) {
try {
storeService.handleFreeProducts();
return;
} catch (IllegalArgumentException e) {
OutputView.printErrorMessage(e);
}
}
}

private void handleOverProducts() {
while (true) {
try {
storeService.handleOverProducts();
return;
} catch (IllegalArgumentException e) {
OutputView.printErrorMessage(e);
}
}
}

private void handleNormalProducts() {
while (true) {
try {
storeService.handleNormalProducts();
return;
} catch (IllegalArgumentException e) {
OutputView.printErrorMessage(e);
}
}
}

private void handleNoPromotionProducts() {
while (true) {
try {
storeService.handleNoPromotionProducts();
return;
} catch (IllegalArgumentException e) {
OutputView.printErrorMessage(e);
}
}
}

private void setMembershipDiscountAmount() {
while (true) {
try {
String rawChoice = InputView.readMembershipChoice();
boolean choice = InputParser.parseChoice(rawChoice);

if (choice) {
storeService.setMembershipDiscountAmount();
}
break;
} catch (IllegalArgumentException e) {
OutputView.printErrorMessage(e);
}
}
}

private void writeStockFile() throws IOException {
FileWriter fw = new FileWriter("src/main/resources/products.md");

String stockResult = storeService.getStockResult();
fw.writeAll(stockResult);
}

private void printResult() {
ReceiptDto receiptDto = storeService.getReceiptResult();
OutputView.printReceipt(receiptDto);
}
}
79 changes: 79 additions & 0 deletions src/main/java/store/domain/Customer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package store.domain;

import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import store.dto.ReceiptDto;

public class Customer {

private final Map<Product, List<Integer>> purchaseProducts;
private int membershipDiscountAmount;

private Customer() {
purchaseProducts = new LinkedHashMap<>();
}

public static Customer newInstance() {
return new Customer();
}

public void addProductForPromotion(Product product, int purchaseQuantity) {
int buy = product.getPromotion().getBuy();
int get = product.getPromotion().getGet();
int setSize = buy + get;
int setQuantity = purchaseQuantity / setSize;
int setQuantityNotEqual = product.getPromotionQuantity() / setSize;
if (setQuantity > setQuantityNotEqual) {
setQuantity = setQuantityNotEqual;
}
int presentQuantity = get * setQuantity;
int noPromotionQuantity = purchaseQuantity - setSize * setQuantity;

purchaseProducts.put(product, List.of(purchaseQuantity, presentQuantity, noPromotionQuantity));
product.updateStock(purchaseQuantity);
}

public void addProductForNormal(Product product, int purchaseQuantity) {
purchaseProducts.put(product, List.of(purchaseQuantity, 0, purchaseQuantity));
product.updateStock(purchaseQuantity);
}

public void setMembershipDiscountAmount() {
membershipDiscountAmount = calculateMembershipDiscountAmount();
if (membershipDiscountAmount > 8000) {
membershipDiscountAmount = 8000;
}
}

private int calculateMembershipDiscountAmount() {
int sum = 0;
for (Product product : purchaseProducts.keySet()) {
int price = product.getPrice();
int noPromotionQuantity = purchaseProducts.get(product).get(2);
sum += price * noPromotionQuantity;
}
return (int) (sum * 0.3);
}

public Map<Product, List<Integer>> getPurchaseProducts() {
return purchaseProducts;
}

public ReceiptDto getReceipt() {
Map<Product, Integer> purchaseProducts = new LinkedHashMap<>();
Map<Product, Integer> presentProducts = new LinkedHashMap<>();
for (Product product : this.purchaseProducts.keySet()) {
List<Integer> values = this.purchaseProducts.get(product);

int purchaseQuantity = values.get(0);
purchaseProducts.put(product, purchaseQuantity);

int presentQuantity = values.get(1);
if (presentQuantity > 0) {
presentProducts.put(product, presentQuantity);
}
}
return new ReceiptDto(purchaseProducts, presentProducts, membershipDiscountAmount);
}
}
Loading