@@ -0,0 +1,81 @@
+package store.view;
+
+import static store.util.Constant.BLANK;
+import static store.util.ErrorMessage.ERROR_TAG;
+import static store.util.Constant.RECEIPT_AMOUNT_INFO_TITLE;
+import static store.util.Constant.RECEIPT_GIVEAWAY_TITLE;
+import static store.util.Constant.RECEIPT_TITLE;
+import static store.util.InformationMessage.INTRODUCE_PRODUCT_MESSAGE;
+import static store.util.MessageTemplate.PRODUCT_INFO;
+import static store.util.MessageTemplate.PRODUCT_INFO_ZERO_QUANTITY;
+import static store.util.MessageTemplate.RECEIPT_DISCOUNT;
+import static store.util.MessageTemplate.RECEIPT_GIVEAWAY_HISTORY;
+import static store.util.MessageTemplate.RECEIPT_HEADER;
+import static store.util.MessageTemplate.RECEIPT_PAYMENT;
+import static store.util.MessageTemplate.RECEIPT_PURCHASE_HISTORY;
+import static store.util.MessageTemplate.RECEIPT_TOTAL_PURCHASE_AMOUNT;
+
+import java.util.List;
+import java.util.Map;
+import store.domain.Inventory;
+import store.domain.Product;
+import store.domain.Receipt;
+
+public class OutputView extends View {
+
+    private OutputView() {}
+
+    public static void printInventory(Inventory inventory) {
+        printMessage(INTRODUCE_PRODUCT_MESSAGE);
+        printNewLine();
+        List<Product> products = inventory.getProducts();
+        for (Product product : products) {
+            printProductInfo(product);
+        }
+    }
+
+    public static void printProductInfo(Product product) {
+        if (!product.isZeroQuantity()) {
+            printMessage(PRODUCT_INFO.format(product.getName(), product.getPrice(), product.getQuantity(),
+                    product.getPromotionName()));
+            return;
+        }
+        printMessage(
+                PRODUCT_INFO_ZERO_QUANTITY.format(product.getName(), product.getPrice(), product.getPromotionName()));
+    }
+
+    public static void displayReceipt(Receipt receipt) {
+        printMessage(RECEIPT_TITLE);
+        printMessage(RECEIPT_HEADER.format("상품명", "수량", "금액"));
+        displayPurchaseHistory(receipt);
+        displayGiveAwayHistory(receipt);
+        displayAmountInfo(receipt);
+    }
+
+    private static void displayAmountInfo(Receipt receipt) {
+        printMessage(RECEIPT_AMOUNT_INFO_TITLE);
+        printMessage(RECEIPT_TOTAL_PURCHASE_AMOUNT.format("총구매액", receipt.calculateTotalQuantity(),
+                receipt.calculateTotalPurchaseAmount()));
+        printMessage(RECEIPT_DISCOUNT.format("행사할인", BLANK, receipt.calculatePromotionDiscount()));
+        printMessage(RECEIPT_DISCOUNT.format("멤버십할인", BLANK, receipt.calculateMembershipDiscount()));
+        printMessage(RECEIPT_PAYMENT.format("내실돈", BLANK, receipt.calculatePayment()));
+    }
+
+    private static void displayGiveAwayHistory(Receipt receipt) {
+        printMessage(RECEIPT_GIVEAWAY_TITLE);
+        receipt.getGiveAwayHistory().forEach((product, quantity) -> {
+            printMessage(RECEIPT_GIVEAWAY_HISTORY.format(product.getName(), quantity));
+        });
+    }
+
+    private static void displayPurchaseHistory(Receipt receipt) {
+        Map<Product, Integer> purchaseHistory = receipt.getPurchaseHistory();
+        purchaseHistory.forEach((product, quantity) -> {
+            printMessage(RECEIPT_PURCHASE_HISTORY.format(product.getName(), quantity, product.getPrice() * quantity));
+        });
+    }
+
+    public static void printError(String errorMessage) {
+        printMessage(ERROR_TAG + errorMessage);
+    }
+}

리뷰: 안녕하세요!

혹시 아래와 같이 포맷을 설정하셨을 때, 띄어쓰기 때문에 출력이 올바르게 정렬이 되셨나요??
4주 차 진행하면서 영수증 출력 부분을 보기 좋게 정리하는 것이 요구사항이었어서 많이 찾아봤습니다!

그 과정에서 알게 된 점은, 한국어는 2글자로 취급되지만, 띄어쓰기와 영어는 1글자로 취급된다는 것입니다. 그래서 띄어쓰기를 한글처럼 2글자 역할을 할 수 있는 방법이 있을까 고민하다가, \u3000 (유니코드 공백)을 알게 되었습니다!

예를 들어, 아래와 같이 사용할 수 있습니다:
`String name = String.format("%-14s", "총구매액").replace(" ", "\u3000");`
이 방법을 사용하면 한글처럼 띄어쓰기를 2글자 취급할 수 있어서 정렬 문제를 해결할 수 있습니다! 😊