# API Cân Ví (Balance Adjustment)

## Tổng quan

API này cho phép **chỉ Founder** điều chỉnh số dư ví bằng cách tạo giao dịch để khớp số dư hiện tại với số dư mong muốn. Hệ thống sẽ tự động tạo giao dịch Income (cộng tiền) hoặc Outcome (trừ tiền) tùy theo chênh lệch.

---

## Endpoint

### Điều chỉnh số dư ví

```
POST /api/Wallet/BalanceAdjustment/{walletId}
```

**Authorization**: Bearer Token (Chỉ Founder)

**Role Required**: `Founder`

---

## Request

### Path Parameters

| Tham số | Kiểu dữ liệu | Bắt buộc | Mô tả |
|---------|-------------|----------|-------|
| `walletId` | `int` | ✅ | ID của ví cần điều chỉnh |

### Request Body

```json
{
  "DesiredBalance": 1000000,
  "Reason": "Điều chỉnh số dư sau kiểm kê tháng 12/2024"
}
```

#### Request Model

| Thuộc tính | Kiểu dữ liệu | Bắt buộc | Ràng buộc | Mô tả |
|------------|-------------|----------|-----------|-------|
| `DesiredBalance` | `decimal` | ✅ | >= 0 | Số dư mong muốn sau khi điều chỉnh |
| `Reason` | `string` | ✅ | Max 500 ký tự | Lý do điều chỉnh số dư |

> [!IMPORTANT]
> - `UpdatedBy` và `UpdatedByUserName` sẽ được tự động lấy từ JWT token
> - Không cần truyền 2 trường này trong request body

---

## Response

### Success Response (200 OK)

```json
{
  "Result": "Success",
  "Message": "Điều chỉnh số dư thành công. Cộng 500,000 VND",
  "OldBalance": 500000,
  "NewBalance": 1000000,
  "AdjustmentAmount": 500000,
  "TransactionId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "TransactionDirection": "Cộng tiền"
}
```

#### Response Model

| Thuộc tính | Kiểu dữ liệu | Mô tả |
|------------|-------------|-------|
| `Result` | `string` | Kết quả: `Success`, `Failed`, `SystemError` |
| `Message` | `string` | Thông báo kết quả |
| `OldBalance` | `decimal` | Số dư cũ trước khi điều chỉnh |
| `NewBalance` | `decimal` | Số dư mới sau khi điều chỉnh |
| `AdjustmentAmount` | `decimal` | Số tiền điều chỉnh (dương = cộng, âm = trừ) |
| `TransactionId` | `Guid?` | ID của giao dịch được tạo |
| `TransactionDirection` | `string` | Hướng giao dịch: "Cộng tiền" hoặc "Trừ tiền" |

### Error Responses

#### 400 Bad Request - Ví không tồn tại

```json
{
  "Result": "Failed",
  "Message": "Không tìm thấy ví",
  "OldBalance": 0,
  "NewBalance": 0,
  "AdjustmentAmount": 0,
  "TransactionId": null,
  "TransactionDirection": ""
}
```

#### 400 Bad Request - Ví không hoạt động

```json
{
  "Result": "Failed",
  "Message": "Ví không ở trạng thái hoạt động",
  "OldBalance": 0,
  "NewBalance": 0,
  "AdjustmentAmount": 0,
  "TransactionId": null,
  "TransactionDirection": ""
}
```

#### 400 Bad Request - Validation Error

```json
{
  "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
  "title": "One or more validation errors occurred.",
  "status": 400,
  "errors": {
    "DesiredBalance": [
      "Số dư mong muốn phải >= 0"
    ],
    "Reason": [
      "Lý do điều chỉnh là bắt buộc"
    ]
  }
}
```

#### 401 Unauthorized

```json
{
  "message": "Unauthorized"
}
```

#### 403 Forbidden - Không phải Founder

```json
{
  "message": "User is not in role 'Founder'"
}
```

---

## Business Logic

### Quy trình điều chỉnh

```mermaid
graph TD
    A[Nhận request] --> B{Kiểm tra ví tồn tại?}
    B -->|Không| C[Trả về lỗi: Không tìm thấy ví]
    B -->|Có| D{Ví đang hoạt động?}
    D -->|Không| E[Trả về lỗi: Ví không hoạt động]
    D -->|Có| F[Tính chênh lệch = DesiredBalance - CurrentBalance]
    F --> G{Chênh lệch = 0?}
    G -->|Có| H[Trả về thành công: Số dư đã khớp]
    G -->|Không| I{Chênh lệch > 0?}
    I -->|Có| J[Tạo giao dịch Income - Cộng tiền]
    I -->|Không| K[Tạo giao dịch Outcome - Trừ tiền]
    J --> L[Cập nhật số dư ví]
    K --> L
    L --> M[Trả về kết quả thành công]
```

### Chi tiết xử lý

1. **Kiểm tra ví**:
   - Ví phải tồn tại
   - Ví phải ở trạng thái `Active`

2. **Tính toán chênh lệch**:
   - `difference = DesiredBalance - CurrentBalance`
   - Nếu `difference = 0`: Không cần điều chỉnh
   - Nếu `difference > 0`: Cộng tiền (Income)
   - Nếu `difference < 0`: Trừ tiền (Outcome)

3. **Tạo giao dịch**:
   - `TransactionType`: `BalanceAdjustment` (8)
   - `TransactionDirection`: `Income` (1) hoặc `Outcome` (2)
   - `Amount`: `Math.Abs(difference)`
   - `Description`: "Điều chỉnh số dư ví: {Reason}"
   - `Note`: Chi tiết số dư cũ, mới và lý do

4. **Cập nhật ví**:
   - `Balance = DesiredBalance`
   - `UpdatedTime = DateTimeOffset.Now`
   - `UpdatedBy` và `UpdatedByUserName` từ token

---

## Ví dụ sử dụng

### Ví dụ 1: Cộng tiền vào ví

**Request**:
```bash
POST /api/Wallet/BalanceAdjustment/123
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Content-Type: application/json

{
  "DesiredBalance": 2000000,
  "Reason": "Bù tiền thiếu sau kiểm kê"
}
```

**Response** (Số dư hiện tại: 1,500,000 VND):
```json
{
  "Result": "Success",
  "Message": "Điều chỉnh số dư thành công. Cộng 500,000 VND",
  "OldBalance": 1500000,
  "NewBalance": 2000000,
  "AdjustmentAmount": 500000,
  "TransactionId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "TransactionDirection": "Cộng tiền"
}
```

### Ví dụ 2: Trừ tiền khỏi ví

**Request**:
```bash
POST /api/Wallet/BalanceAdjustment/123
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Content-Type: application/json

{
  "DesiredBalance": 800000,
  "Reason": "Điều chỉnh số dư thừa sau đối soát"
}
```

**Response** (Số dư hiện tại: 1,200,000 VND):
```json
{
  "Result": "Success",
  "Message": "Điều chỉnh số dư thành công. Trừ 400,000 VND",
  "OldBalance": 1200000,
  "NewBalance": 800000,
  "AdjustmentAmount": -400000,
  "TransactionDirection": "Trừ tiền"
}
```

### Ví dụ 3: Số dư đã khớp

**Request**:
```bash
POST /api/Wallet/BalanceAdjustment/123
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Content-Type: application/json

{
  "DesiredBalance": 1000000,
  "Reason": "Kiểm tra số dư"
}
```

**Response** (Số dư hiện tại: 1,000,000 VND):
```json
{
  "Result": "Success",
  "Message": "Số dư hiện tại đã khớp với số dư mong muốn",
  "OldBalance": 1000000,
  "NewBalance": 1000000,
  "AdjustmentAmount": 0,
  "TransactionId": null,
  "TransactionDirection": ""
}
```

---

## Giao dịch được tạo

Khi điều chỉnh số dư, hệ thống sẽ tạo một giao dịch với thông tin:

```json
{
  "Id": "guid",
  "WalletId": 123,
  "Amount": 500000,
  "TransactionType": "BalanceAdjustment",
  "TransactionDirection": "Income",
  "Description": "Điều chỉnh số dư ví: Bù tiền thiếu sau kiểm kê",
  "Note": "Số dư cũ: 1,500,000 VND, Số dư mới: 2,000,000 VND. Lý do: Bù tiền thiếu sau kiểm kê",
  "CashAmount": 0,
  "TransferAmount": 500000,
  "CreatedTime": "2024-12-17T14:30:00+07:00",
  "CreatedBy": 1,
  "CreatedByUserName": "founder"
}
```

---

## Kiểm tra quyền cân ví

Để kiểm tra user hiện tại có quyền cân ví hay không, sử dụng API `GetMyWallet` hoặc `GetById`:

### Request:
```bash
GET /api/Wallet/GetMyWallet
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
```

### Response:
```json
{
  "Id": 123,
  "Balance": 1000000,
  "WalletStatus": "Đang hoạt động",
  "UserId": 456,
  "UserName": "founder",
  "FullName": "Nguyễn Văn A",
  "CanAdjustBalance": true
}
```

> [!NOTE]
> `CanAdjustBalance` sẽ là `true` nếu user là **Founder**, ngược lại là `false`

---

## Security & Best Practices

### Bảo mật

1. **Chỉ Founder được phép**:
   - API yêu cầu role `Founder`
   - Không có role nào khác được phép thực hiện

2. **Audit Trail**:
   - Mọi điều chỉnh đều được ghi lại trong bảng `Transaction`
   - Lưu đầy đủ: số dư cũ, mới, lý do, người thực hiện

3. **Validation**:
   - Số dư mong muốn phải >= 0
   - Lý do bắt buộc và tối đa 500 ký tự
   - Ví phải ở trạng thái Active

### Best Practices

1. **Lý do rõ ràng**:
   ```json
   {
     "DesiredBalance": 1000000,
     "Reason": "Điều chỉnh số dư sau kiểm kê tháng 12/2024 - Phát hiện thiếu 500k do lỗi hệ thống"
   }
   ```

2. **Kiểm tra trước khi điều chỉnh**:
   - Gọi `GetById` để xem số dư hiện tại
   - Kiểm tra `CanAdjustBalance = true`
   - Xác nhận số tiền cần điều chỉnh

3. **Xử lý response**:
   ```javascript
   if (response.Result === "Success") {
     console.log(`Điều chỉnh thành công: ${response.Message}`);
     console.log(`Giao dịch ID: ${response.TransactionId}`);
   } else {
     console.error(`Lỗi: ${response.Message}`);
   }
   ```

---

## Error Handling

### Common Errors

| Mã lỗi | Nguyên nhân | Giải pháp |
|--------|-------------|-----------|
| 400 | Ví không tồn tại | Kiểm tra lại `walletId` |
| 400 | Ví không hoạt động | Kích hoạt ví trước khi điều chỉnh |
| 400 | Validation error | Kiểm tra `DesiredBalance >= 0` và `Reason` không rỗng |
| 401 | Chưa đăng nhập | Đảm bảo có Bearer token hợp lệ |
| 403 | Không phải Founder | Chỉ Founder mới được phép |
| 500 | Lỗi hệ thống | Liên hệ admin, kiểm tra logs |

### Retry Strategy

```javascript
async function adjustBalance(walletId, desiredBalance, reason, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      const response = await fetch(`/api/Wallet/BalanceAdjustment/${walletId}`, {
        method: 'POST',
        headers: {
          'Authorization': `Bearer ${token}`,
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({
          DesiredBalance: desiredBalance,
          Reason: reason
        })
      });
      
      if (response.ok) {
        return await response.json();
      }
      
      if (response.status === 400 || response.status === 403) {
        // Không retry với lỗi business logic
        throw new Error(await response.text());
      }
      
      // Retry với lỗi server
      if (i === maxRetries - 1) throw new Error('Max retries reached');
      await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1)));
      
    } catch (error) {
      if (i === maxRetries - 1) throw error;
    }
  }
}
```

---

## Changelog

### Version 1.0.0 (2024-12-17)
- ✅ Tạo API điều chỉnh số dư ví
- ✅ Chỉ cho phép Founder thực hiện
- ✅ Tự động tạo giao dịch Income/Outcome
- ✅ Thêm `CanAdjustBalance` vào `GetMyWallet` và `GetById`
- ✅ Validation đầy đủ
- ✅ Audit trail hoàn chỉnh

---

## Related APIs

- [GET /api/Wallet/GetMyWallet](./API_Wallet_GetMyWallet.md) - Lấy thông tin ví của user hiện tại
- [GET /api/Wallet/GetById](./API_Wallet_GetById.md) - Lấy thông tin ví theo ID
- [POST /api/Wallet/Transfer](./API_Wallet_Transfer.md) - Chuyển tiền giữa các ví
- [POST /api/Transaction/SearchWalletTransactions](./API_Transaction_Search.md) - Xem lịch sử giao dịch
