Skip to content

Commit fb8bcd4

Browse files
authored
Merge: RentalHistory View 생성, 시리얼라이저 생성, 테스트코드 작성
[Feature/rental] RentalHistory View 생성, 시리얼라이저 생성, 테스트코드 작성
2 parents ec0e65c + 92eb452 commit fb8bcd4

File tree

7 files changed

+299
-33
lines changed

7 files changed

+299
-33
lines changed

apps/chat/views.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,9 @@ def get(self, request: Request) -> Response:
4545
def post(self, request: Request) -> Response:
4646
product_uuid = request.data.get("product")
4747
lender_id = request.data.get("lender")
48-
if Chatroom.objects.filter(product=product_uuid, lender_id=lender_id).exists():
48+
if Chatroom.objects.filter(
49+
product=product_uuid, lender_id=lender_id, lender_status=True, borrower_status=True
50+
).exists():
4951
return Response({"msg": "이미 개설된 채팅방 내역이 존재합니다."}, status=status.HTTP_400_BAD_REQUEST)
5052
serializer = serializers.CreateChatroomSerializer(data=request.data)
5153
if serializer.is_valid():

apps/product/admin.py

+2
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,9 @@ class ProductAdmin(admin.ModelAdmin[Product]):
4242
@admin.register(RentalHistory)
4343
class RentalHistoryAdmin(admin.ModelAdmin[RentalHistory]):
4444
list_display = [
45+
"id",
4546
"product",
47+
"status",
4648
# "product_lender",
4749
"rental_date",
4850
"return_date",

apps/product/serializers.py

+57-6
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,6 @@
1212
logger = logging.getLogger(__name__)
1313

1414

15-
class RentalHistorySerializer(serializers.ModelSerializer[RentalHistory]):
16-
class Meta:
17-
model = RentalHistory
18-
fields = "__all__"
19-
20-
2115
class ProductImageSerializer(serializers.ModelSerializer[ProductImage]):
2216
image = serializers.ImageField(use_url=True)
2317

@@ -132,3 +126,60 @@ def update(self, instance: Product, validated_data: Any) -> Product:
132126
styles = self.set_styles(styles_data)
133127
instance.styles.set(styles)
134128
return instance
129+
130+
131+
class ProductInfoSerializer(serializers.ModelSerializer[Product]):
132+
style = serializers.SerializerMethodField() # type: ignore
133+
category = serializers.SerializerMethodField()
134+
images = ProductImageSerializer(many=True, read_only=True)
135+
136+
class Meta:
137+
model = Product
138+
fields = [
139+
"uuid",
140+
"name",
141+
"brand",
142+
"size",
143+
"purchase_price",
144+
"rental_fee",
145+
"category",
146+
"style",
147+
"images",
148+
"description",
149+
]
150+
151+
def get_style(self, obj: Product) -> list[str]:
152+
return [style.name for style in obj.styles.all()]
153+
154+
def get_category(self, obj: Product) -> str:
155+
return obj.product_category.name
156+
157+
158+
class RentalHistorySerializer(serializers.ModelSerializer[RentalHistory]):
159+
product_info = ProductInfoSerializer(read_only=True, source="product")
160+
lender_nickname = serializers.SerializerMethodField()
161+
borrower_nickname = serializers.SerializerMethodField()
162+
borrower_id = serializers.IntegerField(write_only=True)
163+
164+
class Meta:
165+
model = RentalHistory
166+
exclude = ("borrower",)
167+
read_only_fields = ("created_at", "updated_at", "rental_date")
168+
169+
def get_lender_nickname(self, obj: RentalHistory) -> str:
170+
return obj.product.lender.nickname
171+
172+
def get_borrower_nickname(self, obj: RentalHistory) -> str:
173+
return obj.borrower.nickname
174+
175+
def to_representation(self, instance: RentalHistory) -> dict[str, Any]:
176+
data = super().to_representation(instance)
177+
if instance.status == "REQUEST":
178+
data["status"] = "대여 요청"
179+
elif instance.status == "ACCEPT":
180+
data["status"] = "대여 요청 수락"
181+
elif instance.status == "RETURNED":
182+
data["status"] = "반납 완료"
183+
elif instance.status == "BORROWING":
184+
data["status"] = "대여 진행중"
185+
return data

apps/product/tests.py

+182
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,17 @@
66
# from rest_framework.test import APIClient
77
#
88
# from apps.product.models import Product
9+
from datetime import timedelta
10+
11+
from django.urls import reverse
12+
from django.utils import timezone
13+
from rest_framework import status
14+
from rest_framework.test import APITestCase
15+
from rest_framework_simplejwt.tokens import AccessToken
16+
17+
from apps.category.models import Category, Style
18+
from apps.product.models import Product, RentalHistory
19+
from apps.user.models import Account
920

1021
# class ProductListAPITest(TestCase):
1122
# def setUp(self):
@@ -88,3 +99,174 @@
8899
# self.assertEqual(response.status_code, status.HTTP_200_OK)
89100
# #내가 셋업에 만든 상품이랑 이 뷰에서 조회 하고자 하는 상품의 데이터가 일치 하는 지를 확인해야함
90101
#
102+
103+
104+
class RentalHistoryTestBase(APITestCase):
105+
def setUp(self) -> None:
106+
self.borrower = Account.objects.create_user(
107+
email="[email protected]", nickname="test_borrower", password="password1234@", phone="010-2211-1111"
108+
)
109+
self.lender = Account.objects.create_user(
110+
email="[email protected]", nickname="test_lender", password="password1234@", phone="010-2211-1112"
111+
)
112+
self.category = Category.objects.create(name="test_category")
113+
self.styles = Style.objects.create(name="test_style_tag")
114+
self.product = Product.objects.create(
115+
name="testproduct",
116+
lender=self.lender,
117+
condition="testcondition",
118+
purchase_date=timezone.now(),
119+
purchase_price=50000,
120+
rental_fee=5000,
121+
size="XL",
122+
product_category=self.category,
123+
)
124+
self.product.styles.add(self.styles)
125+
self.token = AccessToken.for_user(self.borrower)
126+
127+
128+
class RentalHistoryBorrowerViewTests(RentalHistoryTestBase):
129+
def setUp(self) -> None:
130+
super().setUp()
131+
self.url = reverse("borrowed_rental_history")
132+
133+
def test_대여자가_정상적인_물품_대여신청을_했을때(self) -> None:
134+
data = {
135+
"product": self.product.uuid,
136+
"rental_date": timezone.now(),
137+
"return_date": timezone.now() + timedelta(days=3),
138+
}
139+
response = self.client.post(self.url, data, headers={"Authorization": f"Bearer {self.token}"})
140+
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
141+
self.assertEqual(RentalHistory.objects.count(), 1)
142+
self.assertEqual(response.data.get("product_info")["uuid"], str(self.product.uuid))
143+
self.assertEqual(response.data.get("borrower_nickname"), self.borrower.nickname)
144+
self.assertEqual(response.data.get("status"), "대여 요청")
145+
146+
def test_이미_대여중인_상품을_대여하려고_시도하는경우_테스트(self) -> None:
147+
history = RentalHistory.objects.create(
148+
product=self.product,
149+
borrower=self.borrower,
150+
rental_date=timezone.now(),
151+
return_date=timezone.now() + timedelta(days=3),
152+
)
153+
self.assertEqual(RentalHistory.objects.count(), 1)
154+
data = {
155+
"product": history.product.uuid,
156+
"rental_date": history.rental_date.isoformat(),
157+
"return_date": history.return_date.isoformat(), # type: ignore
158+
}
159+
response = self.client.post(self.url, data, headers={"Authorization": f"Bearer {self.token}"})
160+
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
161+
162+
def test_생성된_대여내역_정상적인_조회_테스트(self) -> None:
163+
# given
164+
lender2 = Account.objects.create_user(
165+
email="[email protected]", nickname="test_lender2", password="password1234@", phone="010-2211-1113"
166+
)
167+
product2 = Product.objects.create(
168+
name="testproduct2",
169+
lender=lender2,
170+
condition="testcondition",
171+
purchase_date=timezone.now(),
172+
purchase_price=40000,
173+
rental_fee=3000,
174+
size="M",
175+
product_category=self.category,
176+
)
177+
RentalHistory.objects.create(
178+
product=self.product,
179+
borrower=self.borrower,
180+
rental_date=timezone.now(),
181+
return_date=timezone.now() + timedelta(days=3),
182+
)
183+
RentalHistory.objects.create(
184+
product=product2,
185+
borrower=self.borrower,
186+
rental_date=timezone.now(),
187+
return_date=timezone.now() + timedelta(days=3),
188+
)
189+
190+
response = self.client.get(self.url, headers={"Authorization": f"Bearer {self.token}"})
191+
self.assertEqual(response.status_code, status.HTTP_200_OK)
192+
self.assertEqual(len(response.data), RentalHistory.objects.count())
193+
self.assertEqual(response.data[0]["product_info"]["uuid"], str(self.product.uuid))
194+
self.assertEqual(response.data[1]["product_info"]["uuid"], str(product2.uuid))
195+
self.assertEqual(response.data[0]["borrower_nickname"], self.borrower.nickname)
196+
self.assertEqual(response.data[1]["borrower_nickname"], self.borrower.nickname)
197+
198+
199+
class RentalHistoryLenderViewTests(RentalHistoryTestBase):
200+
def setUp(self) -> None:
201+
super().setUp()
202+
self.url = reverse("lending_rental_history")
203+
self.lender2 = Account.objects.create_user(
204+
email="[email protected]", nickname="test_lender2", password="password1234@", phone="010-2211-1113"
205+
)
206+
self.product2 = Product.objects.create(
207+
name="testproduct2",
208+
lender=self.lender2,
209+
condition="testcondition",
210+
purchase_date=timezone.now(),
211+
purchase_price=40000,
212+
rental_fee=3000,
213+
size="M",
214+
product_category=self.category,
215+
)
216+
self.history1 = RentalHistory.objects.create(
217+
product=self.product,
218+
borrower=self.borrower,
219+
rental_date=timezone.now(),
220+
return_date=timezone.now() + timedelta(days=3),
221+
)
222+
self.history2 = RentalHistory.objects.create(
223+
product=self.product2,
224+
borrower=self.borrower,
225+
rental_date=timezone.now(),
226+
return_date=timezone.now() + timedelta(days=3),
227+
)
228+
229+
def test_lender의_판매내역_조회_테스트(self) -> None:
230+
self.token = AccessToken.for_user(self.lender)
231+
232+
response = self.client.get(self.url, headers={"Authorization": f"Bearer {self.token}"})
233+
self.assertEqual(response.status_code, status.HTTP_200_OK)
234+
self.assertEqual(response.data[0]["product_info"]["uuid"], str(self.product.uuid))
235+
self.assertEqual(response.data[0]["borrower_nickname"], self.borrower.nickname)
236+
self.assertEqual(response.data[0]["lender_nickname"], self.lender.nickname)
237+
238+
def test_lender2의_판매내역_조회_테스트(self) -> None:
239+
self.token = AccessToken.for_user(self.lender2)
240+
241+
response = self.client.get(self.url, headers={"Authorization": f"Bearer {self.token}"})
242+
self.assertEqual(response.status_code, status.HTTP_200_OK)
243+
self.assertEqual(response.data[0]["product_info"]["uuid"], str(self.product2.uuid))
244+
self.assertEqual(response.data[0]["borrower_nickname"], self.borrower.nickname)
245+
self.assertEqual(response.data[0]["lender_nickname"], self.lender2.nickname)
246+
247+
248+
class RentalHistoryUpdateViewTests(RentalHistoryTestBase):
249+
def setUp(self) -> None:
250+
super().setUp()
251+
self.history = RentalHistory.objects.create(
252+
product=self.product,
253+
borrower=self.borrower,
254+
rental_date=timezone.now(),
255+
return_date=timezone.now() + timedelta(days=3),
256+
)
257+
self.url = reverse("rental_history_update", kwargs={"pk": self.history.pk})
258+
259+
def test_대여요청에서_상태_업데이트_테스트(self) -> None:
260+
data = {"status": "ACCEPT"}
261+
response = self.client.patch(self.url, data=data, headers={"Authorization": f"Bearer {self.token}"})
262+
263+
self.assertEqual(response.status_code, status.HTTP_200_OK)
264+
self.assertEqual(response.data.get("status"), "대여 요청 수락")
265+
266+
def test_대여날짜_변경_테스트(self) -> None:
267+
data = {"return_date": timezone.now() + timedelta(days=4)}
268+
269+
response = self.client.patch(self.url, data=data, headers={"Authorization": f"Bearer {self.token}"})
270+
print(response.data)
271+
self.assertEqual(response.status_code, status.HTTP_200_OK)
272+
self.assertEqual(response.data.get("return_date").split("T")[0], data["return_date"].date().isoformat())

apps/product/urls.py

+9-2
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,20 @@
11
from django.urls import include, path
22
from rest_framework.routers import DefaultRouter
33

4-
from apps.product.views import ProductViewSet, RentalHistoryViewSet
4+
from apps.product.views import (
5+
ProductViewSet,
6+
RentalHistoryBorrowerView,
7+
RentalHistoryLenderView,
8+
RentalHistoryUpdateView,
9+
)
510

611
router = DefaultRouter()
712
router.register(r"", ProductViewSet, basename="product")
8-
router.register(r"rental-records", RentalHistoryViewSet, basename="rental-history")
913

1014
urlpatterns = [
1115
path("", include(router.urls)),
16+
path("rental_history/borrow", RentalHistoryBorrowerView.as_view(), name="borrowed_rental_history"),
17+
path("rental_history/lending", RentalHistoryLenderView.as_view(), name="lending_rental_history"),
18+
path("rental_history/<int:pk>/", RentalHistoryUpdateView.as_view(), name="rental_history_update"),
1219
# path('api-auth/', include('rest_framework.urls', namespace='rest_framework'))
1320
]

0 commit comments

Comments
 (0)