تیم *انبوهفروشان مشرقزمین* قصد دارد سامانهای تحتوب برای مدیریت آسانتر فروشگاهشان راهاندازی کند. آنها تصمیم گرفتهاند تا وبسرویسشان را با استفاده از *Spring Boot* پیادهسازی کنند. نیازمندیها از قبل بهطور دقیق مشخص شدهاند، اما هنوز برنامهنویسی به تیم آنها اضافه نشده است. از شما میخواهیم تا نسخهی اولیهی این وبسرویس را پیادهسازی کنید.
# جزئیات پروژه
پروژهی اولیه را از [این لینک](/problemset/assignments/4367/download_problem_initial_project/111985/) دانلود کنید.
+ این پروژه از *Maven* استفاده میکند و وابستگیها در *POM* تعریف شدهاند. امکان تغییر این وابستگیها وجود ندارد.
+ از *[Liquibase](https://www.liquibase.org/)* برای مدیریت *schema* دیتابیس استفاده شده است.
+ برای اجرای تستها، از دیتابیس *[H2](https://www.h2database.com/)* استفاده میشود.
+ در این پروژه، وابستگی *[Project Lombok](https://projectlombok.org/)* تعریف شده و قابل استفاده است.
+ بستهی `ir.digipay.bulkshop` شامل موجودیتهای *JPA* برنامه است که مطابق با *schema* دیتابیس طراحی شدهاند. شناسه (`id`) موجودیتها بهصورت خودکار توسط *Hibernate* تولید میشود.
+ کلاس `CustomerEntity`: از این کلاس برای نگهداری اطلاعات هر مشتری استفاده میشود.
+ کلاس `ProductEntity`: از این کلاس برای نگهداری اطلاعات هر محصول استفاده میشود.
+ کلاس `OrderEntity`: از این کلاس برای نگهداری اطلاعات هر سفارش استفاده میشود.
+ بستهی `ir.digipay.bulkshop.api` شامل کلاسهایی برای مدیریت ورودیها و خروجیهای *API* است.
+ بستهی `ir.digipay.bulkshop.rest` شامل *REST controller* های برنامه است. کنترلر مربوط به آدرس `/` برای تست برنامه در کلاس `IndexRestEnpoint` پیادهسازی شده است. سایر کنترلرها را در این بسته پیادهسازی کنید.
+ از آنجا که این برنامه اولین نسخهی سامانه است، هر سفارش میتواند شامل یک نوع محصول باشد، اما تعداد آن را میتوان در سفارش تعیین کرد.
## سرویسها
تعدادی وبسرویس *REST* مطابق نیازمندیهای زیر باید پیادهسازی شود:
| آدرس | عنوان |
| :------------------------ | ----------------------: |
| `GET /api/products` | دریافت اطلاعات محصولات |
| `POST /api/products` | ایجاد محصول |
| `GET /api/products/{id}` | دریافت اطلاعات یک محصول |
| `PUT /api/products` | ویرایش اطلاعات یک محصول |
| `GET /api/customers` | دریافت اطلاعات مشتریان |
| `POST /api/customers` | ایجاد مشتری |
| `GET /api/customers/{id}` | دریافت اطلاعات یک مشتری |
| `PUT /api/customers` | ویرایش اطلاعات یک مشتری |
| `GET /api/orders` | دریافت اطلاعات سفارشات |
| `POST /api/orders` | ایجاد سفارش |
| `GET /api/orders/{id}` | دریافت اطلاعات یک سفارش |
### دریافت اطلاعات محصولات
اطلاعات همهی محصولات در قالب یک آرایه برگردانده میشود:
```yml
URL: "GET /api/products"
http-code: 200
content-type: "application/json"
response: {
"products": [ # Array of ProductModel or ProductEntity
{
"id": "some_uuid",
"name": "x",
"price": 50000,
"availableCount": 100
},
{
"id": "some_uuid",
"name": "y",
"price": 75000,
"availableCount": 50
}
]
}
```
### ایجاد محصول
یک محصول با اطلاعات اولیهی دادهشده ایجاد میشود و شناسهی آن برگردانده میشود:
```yml
URL: "POST /api/products"
request: { # ProductCreateParam
"name": "x",
"price": 40000,
"initialAvailableCount": 100
}
http-code: 201
content-type: "application/json"
response: { # ProductCreateResult
"productId": "some_uuid"
}
```
### دریافت اطلاعات یک محصول
شناسهی محصول بهعنوان ورودی داده میشود و اطلاعات محصول برگردانده میشود:
```yml
URL: "GET /api/products/1234"
http-code: 200
content-type: "application/json"
response: { # ProductModel or ProductEntity
"id": "some_uuid",
"name": "z",
"price": 40000,
"availableCount": 150
}
```
اگر محصولی با شناسهی واردشده موجود نباشد، پاسخ باید بهصورت زیر باشد:
```yml
http-code: 404
content-type: "application/json"
response: {
"message": "Entity not found"
}
```
### ویرایش اطلاعات یک محصول
اطلاعات جدید محصول داده میشود و پس از بهروزرسانی اطلاعات محصول، پاسخی با کد `204` برگردانده میشود:
```yml
URL: "PUT /api/products"
request: { # ProductUpdateParam
"id": "some_uuid",
"name": "x2",
"price": 51000,
"availableCount": 200
}
http-code: 204
```
اگر محصولی با شناسهی واردشده موجود نباشد، پاسخ باید بهصورت زیر باشد:
```yml
http-code: 404
content-type: "application/json"
response: {
"message": "Entity not found"
}
```
### دریافت اطلاعات مشتریان
اطلاعات همهی مشتریان در قالب یک آرایه برگردانده میشود:
```yml
URL: "GET /api/customers"
http-code: 200
content-type: "application/json"
response: {
"customers": [ # Array of CustomerModel or CustomerEntity
{
"id": "some_uuid",
"username": "x",
"firstName": "x",
"lastName": "x"
},
{
"id": "some_uuid",
"username": "y",
"firstName": "y",
"lastName": "y"
}
]
}
```
### ایجاد مشتری
یک مشتری با اطلاعات اولیهی دادهشده ایجاد میشود و شناسهی آن برگردانده میشود:
```yml
URL: "POST /api/customers"
request: { # CustomerCreateParam
"username": "z",
"firstName": "Z",
"lastName": "z"
}
http-code: 201
content-type: "application/json"
response: { # CustomerCreateResult
"customerId": "some_uuid"
}
```
اگر مشتریای با نام کاربری دادهشده از قبل موجود باشد، پاسخ باید بهصورت زیر باشد:
```yml
http-code: 409
content-type: "application/json"
response: {
"message": "Username already taken"
}
```
### دریافت اطلاعات یک مشتری
شناسهی مشتری بهعنوان ورودی داده میشود و اطلاعات مشتری برگردانده میشود:
```yml
URL: "GET /api/customers/1"
http-code: 200
content-type: "application/json"
response: { # CustomerModel or CustomerEntity
"id": "some_uuid",
"username": "x",
"firstName": "x",
"lastName": "x"
}
```
اگر مشتریای با شناسهی واردشده موجود نباشد، پاسخ باید بهصورت زیر باشد:
```yml
http-code: 404
content-type: "application/json"
response: {
"message": "Entity not found"
}
```
### ویرایش اطلاعات یک مشتری
اطلاعات جدید مشتری داده میشود و پس از بهروزرسانی اطلاعات مشتری، پاسخی با کد `204` برگردانده میشود:
```yml
URL: "PUT /api/customers"
request: { # CustomerUpdateParam
"id": "some_uuid",
"username": "x2",
"firstName": "x2",
"lastName": "x2"
}
http-code: 204
```
اگر مشتریای با شناسهی واردشده موجود نباشد، پاسخ باید بهصورت زیر باشد:
```yml
http-code: 404
content-type: "application/json"
response: {
"message": "Entity not found"
}
```
### دریافت اطلاعات سفارشات
اطلاعات همهی محصولات در قالب یک آرایه برگردانده میشود:
```yml
URL: "GET /api/orders"
http-code: 200
content-type: "application/json"
response: {
"orders": [ # Array of OrderModel or OrderEntity
{
"id": "some_uuid",
"customerId": "some_uuid",
"productId": "some_uuid",
"count": 4
},
{
"id": "some_uuid",
"customerId": "some_uuid",
"productId": "some_uuid",
"count": 3
}
]
}
```
### ایجاد سفارش
یک سفارش با اطلاعات دادهشده ایجاد میشود، مقدار موجودی محصول به اندازهی تعداد واردشده کم میشود و شناسهی سفارش برگردانده میشود:
```yml
URL: "POST /api/orders"
request: { # OrderCreateParam
"customerId": "some_uuid",
"productId": "some_uuid",
"count": 6
}
http-code: 201
content-type: "application/json"
response: { # OrderCreateResult
"orderId": "some_uuid"
}
```
اگر مشتری یا محصولی با شناسهی واردشده موجود نباشد، پاسخ باید بهصورت زیر باشد:
```yml
http-code: 404
content-type: "application/json"
response: {
"message": "Entity not found"
}
```
اگر مقدار فیلد `count` کوچکتر یا مساوی صفر باشد، پاسخ باید بهصورت زیر باشد:
```yml
http-code: 400
content-type: "application/json"
response: {
"message": "Invalid count"
}
```
اگر مقدار `count` بزرگتر از موجودی فعلی محصول باشد، پاسخ باید بهصورت زیر باشد:
```yml
http-code: 400
content-type: "application/json"
response: {
"message": "Not enough available count"
}
```
### دریافت اطلاعات یک سفارش
شناسهی سفارش بهعنوان ورودی داده میشود و اطلاعات سفارش برگردانده میشود:
```yml
URL: "GET /api/orders/1234"
http-code: 200
content-type: "application/json"
response: { # OrderModel or OrderEntity
"id": "some_uuid",
"customerId": "some_uuid",
"productId": "some_uuid",
"count": 5
}
```
اگر سفارشی با شناسهی واردشده موجود نباشد، پاسخ باید بهصورت زیر باشد:
```yml
http-code: 404
content-type: "application/json"
response: {
"message": "Entity not found"
}
```
# نکات
+ ممکن است چند درخواست همزمان برای خرید یک محصول به برنامه ارسال شود. این درخواستها باید بهدرستی مدیریت شوند.
+ شما تنها مجاز به اعمال تغییرات در بستهی `ir.digipay.bulkshop` هستید.
# آنچه باید آپلود کنید
پس از پیادهسازی موارد خواستهشده، پوشهی `src` پروژه را زیپ کرده و ارسال کنید. توجه داشته باشید که فقط تغییرات اعمالشده در پوشهی `src/main/java/ir.digipay.bulkshop` در نظر گرفته میشوند.