محمدرضا و تیمش مشغول طراحی سامانهای برای مدیریت کیف پول دیجیتال بهنام *دیجیوالِت* هستند. در نسخهی اولیهی این سامانه قرار است قابلیتهای زیر وجود داشته باشد:
+ امکان ایجاد تراکنش و تغییر وضعیت آن
+ امکان مشاهدهی لیست تراکنشها
+ امکان تسویهحساب
+ امکان مشاهدهی موجودی کیف پول
تیم محمدرضا ساختار برنامه را طراحی کردهاند و از شما میخواهند تا پیادهسازی آن را انجام دهید.
# جزئیات پروژه
پروژهی اولیه را از [این لینک](/problemset/assignments/4367/download_problem_initial_project/111987/) دانلود کنید.
<details class="grey">
<summary>ساختار فایلها</summary>
```
src
└── ir
└── digipay
└── digiwallet
├── model
│ ├── AdminWallet.java
│ ├── Transaction.java
│ ├── TransactionStatus.java
│ ├── TransactionType.java
│ └── Wallet.java
├── repository
│ ├── CrudRepository.java
│ ├── TransactionRepository.java
│ └── TransactionRepositoryImpl.java
├── service
│ ├── AdminWalletService.java
│ └── WalletService.java
├── Application.java
└── DigiWalletSampleTest.java
```
</details>
## مدلها
+ کیف پول (`Wallet`)
+ این مدل تنها شامل یک شناسه از نوع `String` است.
+ کیف پول مربوط به ادمینهای برنامه (`AdminWallet`)
+ این مدل از کلاس `Wallet` ارثبری میکند و هیچ پیادهسازی اضافهای نسبت به مدل `Wallet` ندارد.
+ نوع تراکنش (`TransactionType`): این کلاس یک `enum` است که بهترتیب شامل دو مقدار `DEPOSIT` و `WITHDRAWAL` است.
+ تراکنشهایی که از نوع `DEPOSIT` هستند، بیانگر واریزهایی هستند که مقصد آنها، کیف پول فعلی است.
+ تراکنشهایی که از نوع `WITHDRAWAL` هستند، بیانگر برداشتهایی هستند که از کیف پول به حساب بانکی صاحب کیف پول منتقل میشوند.
+ وضعیت تراکنش (`TransactionStatus`): این کلاس یک `enum` است که بهترتیب شامل سه مقدار `CANCELED`، `PENDING` و `ACCEPTED` است.
+ تراکنش (`Transaction`)
+ این مدل بهترتیب شامل پراپرتیهای زیر است:
+ `long id`: شناسهی تراکنش
+ `Wallet wallet`: کیف پول مربوط به تراکنش
+ `TransactionType type`: نوع تراکنش
+ `BigDecimal amount`: مبلغ تراکنش
+ `Date createdAt`: زمان ایجاد تراکنش
+ `TransactionStatus status`: وضعیت تراکنش با مقدار اولیهی `PENDING`
+ `Date updatedAt`: زمان تغییر وضعیت تراکنش
+ همهی پراپرتیها بهجز پراپرتی `updatedAt` در کانستراکتور مقداردهی میشوند.
+ متد `setStatus` را طوری پیادهسازی کنید که با دریافت یک `TransactionStatus`، وضعیت تراکنش را به وضعیت واردشده تغییر داده و مقدار پراپرتی `updatedAt` را برابر با یک آبجکت جدید از نوع `Date` قرار دهد.
## مخزنها
+ اینترفیس `CrudRepository<T, ID>`
+ این اینترفیس شامل دو پارامتر جنریک `T` (نوع مدل) و `ID` (نوع شناسهی مدل) است.
+ این اینترفیس شامل تعریف متدهای زیر است:
+ `boolean add(T t)`: این متد، مدل را به مخزن اضافه میکند؛ به شرط آن که مدل از قبل در مخزن وجود نداشته باشد. اگر مدل از قبل در مخزن موجود باشد، مقدار `false` و در غیر اینصورت، مقدار `true` را برمیگرداند.
+ `List<T> getAll()`: این متد، لیست همهی مدلهای ذخیرهشده را بهترتیب درج برمیگرداند.
+ `T get(ID id)`: این متد، مدلی که شناسهی آن برابر با `id` است را برمیگرداند. اگر چنین مدلی یافت نشود، مقدار `null` را برمیگرداند.
+ `List<T> get(Predicate<T> predicate)`: این متد، لیست مدلهایی که شرایط دادهشده در `predicate` را دارند بهترتیب درج برمیگرداند.
+ اینترفیس `TransactionRepository`
+ این اینترفیس از اینترفیس `CrudRepository` ارثبری میکند و صرفاً نوع تراکنشها (که `Transaction` است) و نوع شناسهی آنها (که `Long` است) را مشخص میکند.
+ کلاس `TransactionRepositoryImpl`
+ این کلاس، اینترفیس `TransactionRepository` را پیادهسازی میکند و تراکنشهای مربوط به همهی کیف پولها در آن ذخیره میشود.
+ متدهای این کلاس را مطابق توضیحات اینترفیس `CrudRepository` پیادهسازی کنید.
+ در متد `add` اگر مبلغ تراکنش کوچکتر یا مساوی صفر باشد، یک `IllegalArgumentException` باید پرتاب شود.
## سرویسها
+ سرویس `WalletService`
+ از این کلاس برای مدیریت کیف پولها استفاده میشود.
+ متد `addTransaction` را طوری پیادهسازی کنید که با دریافت یک تراکنش، با فراخوانی متد `add` از `transactionRepository`، آن را به لیست تراکنشها اضافه کند. این متد در صورتی که تراکنش از قبل موجود باشد، باید مقدار `false` و در غیر اینصورت، باید مقدار `true` را برگرداند.
+ متد `getTransactions(Wallet wallet)` را طوری پیادهسازی کنید که لیست همهی تراکنشهایی که مربوط به کیف پول ورودی هستند را بهترتیب درج برگرداند.
+ متد `getTransactions(Wallet wallet, Predicate<Transaction> predicate)` را طوری پیادهسازی کنید که لیست همهی تراکنشهایی که مربوط به کیف پول ورودی هستند و شرایط دادهشده در `predicate` را دارند بهترتیب درج برگرداند.
+ متد `getBalance` را طوری پیادهسازی کنید که با دریافت یک کیف پول، موجودی حساب کیف پول را در قالب یک `BigDecimal` برگرداند. موجودی حساب برابر با مجموع مبلغ `DEPOSIT`های `ACCEPTED` منهای مجموع مبلغ `WITHDRAWAL`های `ACCEPTED` است.
+ متد `setTransactionStatus` را طوری پیادهسازی کنید که با دریافت یک تراکنش و وضعیت جدید، در صورتی که وضعیت تراکنش `PENDING` نبود یا وضعیت جدید برابر با `PENDING` بود، مقدار `false` را برگرداند. در غیر اینصورت، اگر تراکنش از نوع `WITHDRAWAL` بود و موجودی کیف پول به اندازهی مبلغ تراکنش نبود، یک `IllegalArgumentException` پرتاب شود. در غیر اینصورت، وضعیت تراکنش به وضعیت جدید تغییر کند، مقدار پراپرتی `updatedAt` تراکنش بهروز شود و مقدار `true` برگردانده شود.
+ سرویس `AdminWalletService`
+ این کلاس از کلاس `WalletService` ارثبری میکند.
+ متد `getTransactions(Predicate<Transaction> predicate)` را طوری پیادهسازی کنید که لیست همهی تراکنشهای مربوط به همهی کیف پولها که شرایط دادهشده در `predicate` را دارند بهترتیب درج برگرداند.
+ متد `getAllTransactions` را طوری پیادهسازی کنید که لیست همهی تراکنشهای مربوط به همهی کیف پولها (همهی تراکنشهای موجود در مخزن) را بهترتیب درج برگرداند.
# نکات
+ لازم نیست که ذخیرهسازی مقدار مدلها *persistent* باشد (تنها یک بار اجرای برنامه را در نظر بگیرید).
+ هر نمونه از مخزن باید دادهها را بهصورت جداگانه در خودش ذخیره کند.
+ در صورت نیاز، میتوانید پراپرتیها و متدهای جدیدی به کلاسها (بهجز کلاس `Application`) اضافه کنید.
# مثال
با اجرای متد `main` موجود در کلاس `Application`، خروجی زیر مورد انتظار است:
```
true
1000
[[Id: 1, Wallet Id: x-y-z, Type: DEPOSIT, Amount: 1000, Status: ACCEPTED]]
[[Id: 1, Wallet Id: x-y-z, Type: DEPOSIT, Amount: 1000, Status: ACCEPTED]]
```
# آنچه باید آپلود کنید
پس از پیادهسازی موارد خواستهشده، یک فایل زیر آپلود کنید که وقتی آن را باز میکنیم، با ساختار زیر مواجه شویم (از سایر فایلها صرفنظر میشود):
```
.
└── ir
└── digipay
└── digiwallet
├── model
│ └── Transaction.java
├── repository
│ └── TransactionRepositoryImpl.java
├── service
│ ├── AdminWalletService.java
└── └── WalletService.java
```