# API Documentation - Income Management System

## Tổng quan

Hệ thống quản lý doanh thu (Income Management) cung cấp các API để quản lý doanh thu và danh mục doanh thu. Hệ thống bao gồm 2 controller chính:

- **IncomeCategoryController**: Quản lý danh mục doanh thu (tree hierarchy)
- **IncomeController**: Quản lý doanh thu và các quy trình phê duyệt

## Base URL

```
https://localhost:7284/api
```

## Authentication

Tất cả các API đều yêu cầu authentication qua JWT token. Thêm header vào request:

```
Authorization: Bearer {token}
```

## Permission Requirements

Mỗi endpoint yêu cầu permission cụ thể. User phải có role tương ứng để có thể gọi API.

---

## IncomeCategory Controller

### 1. Search Income Categories

Tìm kiếm danh mục doanh thu với phân trang và filter.

**Endpoint**: `POST /api/IncomeCategory/Search`

**Permission**: `IncomeCategory.Search`

**Request Body**:

```json
{
  "Pagination": {
    "PageIndex": 1,
    "PageSize": 10,
    "From": 0,
    "Total": 0,
    "TotalPages": 0,
    "TotalItemCount": 0,
    "Number": 0,
    "NumberOfPages": 0
  },
  "Search": {
    "PredicateObject": {
      "Name": "Doanh thu",
      "Description": ""
    }
  },
  "Sort": {
    "Predicate": "Name",
    "Reverse": false
  },
  "IsExport": false
}
```

**Response**:

```json
{
  "Items": [
    {
      "Id": 1,
      "Name": "Doanh thu bán hàng",
      "Description": "Doanh thu từ hoạt động bán hàng",
      "DisplayOrder": 1,
      "ParentId": null,
      "ParentName": null,
      "ApprovedBy": 5,
      "ApprovedByUserName": "admin",
      "Children": [],
      "Level": 0,
      "IsDeleted": false,
      "CreatedDate": "2025-01-15T10:00:00Z",
      "CreatedBy": 1,
      "ModifiedDate": "2025-01-15T10:00:00Z",
      "ModifiedBy": 1
    }
  ],
  "TotalRecord": 100,
  "NumberOfPages": 10,
  "From": 1,
  "To": 10,
  "LastPage": 10
}
```

---

### 2. Get Income Category By Id

Lấy thông tin chi tiết một danh mục doanh thu.

**Endpoint**: `GET /api/IncomeCategory/{id}`

**Permission**: `IncomeCategory.GetById`

**Parameters**:

- `id` (int, required): ID của danh mục doanh thu

**Response**:

```json
{
  "Id": 1,
  "Name": "Doanh thu bán hàng",
  "Description": "Doanh thu từ hoạt động bán hàng",
  "DisplayOrder": 1,
  "ParentId": null,
  "ParentName": null,
  "ApprovedBy": 5,
  "ApprovedByUserName": "admin",
  "Children": [],
  "Level": 0,
  "IsDeleted": false,
  "CreatedDate": "2025-01-15T10:00:00Z",
  "CreatedBy": 1,
  "ModifiedDate": "2025-01-15T10:00:00Z",
  "ModifiedBy": 1
}
```

---

### 3. Create Or Update Income Category

Tạo mới hoặc cập nhật danh mục doanh thu.

**Endpoint**: `POST /api/IncomeCategory/CreateOrUpdate`

**Permission**: `IncomeCategory.CreateOrUpdate`

**Request Body**:

```json
{
  "Id": 0,
  "Name": "Doanh thu bán hàng",
  "Description": "Doanh thu từ hoạt động bán hàng",
  "DisplayOrder": 1,
  "ParentId": null,
  "ApprovedBy": 5,
  "ApprovedByUserName": "admin"
}
```

**Response**:

```json
{
  "Result": 1,
  "Message": ""
}
```

**Validation Rules**:

- `Name`: Required, MaxLength = 128
- `Description`: MaxLength = 256
- `DisplayOrder`: Range = [0, int.MaxValue]

**Response Codes**:

- `Result = 1`: Thành công
- `Result = 2`: Thất bại (validation error hoặc business logic error)

---

### 4. Delete Income Category

Xóa danh mục doanh thu (soft delete).

**Endpoint**: `DELETE /api/IncomeCategory/{id}`

**Permission**: `IncomeCategory.Delete`

**Parameters**:

- `id` (int, required): ID của danh mục doanh thu

**Response**:

```json
{
  "Result": 1,
  "Message": ""
}
```

**Note**: Không thể xóa danh mục có danh mục con.

---

### 5. Get All Income Categories

Lấy danh sách tất cả danh mục doanh thu (không phân trang).

**Endpoint**: `GET /api/IncomeCategory/GetAll`

**Permission**: `IncomeCategory.GetAll`

**Response**:

```json
[
  {
    "Id": 1,
    "Name": "Doanh thu bán hàng",
    "Description": "Doanh thu từ hoạt động bán hàng",
    "DisplayOrder": 1,
    "ParentId": null,
    "ParentName": null,
    "ApprovedBy": 5,
    "ApprovedByUserName": "admin",
    "Children": [],
    "Level": 0,
    "IsDeleted": false,
    "CreatedDate": "2025-01-15T10:00:00Z",
    "CreatedBy": 1,
    "ModifiedDate": "2025-01-15T10:00:00Z",
    "ModifiedBy": 1
  }
]
```

---

### 6. Check Name Exists

Kiểm tra tên danh mục có trùng không.

**Endpoint**: `GET /api/IncomeCategory/CheckNameExists`

**Permission**: `IncomeCategory.CheckNameExists`

**Query Parameters**:

- `name` (string, required): Tên danh mục cần kiểm tra
- `excludeId` (int, optional): ID loại trừ (khi update)

**Response**:

```json
{
  "exists": false
}
```

---

### 7. Get Hierarchy

Lấy danh sách danh mục doanh thu theo cây phân cấp.

**Endpoint**: `GET /api/IncomeCategory/Hierarchy`

**Permission**: `IncomeCategory.GetHierarchy`

**Response**:

```json
[
  {
    "Id": 1,
    "Name": "Doanh thu bán hàng",
    "Description": "Doanh thu từ hoạt động bán hàng",
    "DisplayOrder": 1,
    "ParentId": null,
    "ParentName": null,
    "ApprovedBy": 5,
    "ApprovedByUserName": "admin",
    "Children": [
      {
        "Id": 2,
        "Name": "Doanh thu tại cửa hàng",
        "Description": "",
        "DisplayOrder": 1,
        "ParentId": 1,
        "ParentName": "Doanh thu bán hàng",
        "ApprovedBy": 5,
        "ApprovedByUserName": "admin",
        "Children": [],
        "Level": 1,
        "IsDeleted": false,
        "CreatedDate": "2025-01-15T10:00:00Z",
        "CreatedBy": 1,
        "ModifiedDate": "2025-01-15T10:00:00Z",
        "ModifiedBy": 1
      }
    ],
    "Level": 0,
    "IsDeleted": false,
    "CreatedDate": "2025-01-15T10:00:00Z",
    "CreatedBy": 1,
    "ModifiedDate": "2025-01-15T10:00:00Z",
    "ModifiedBy": 1
  }
]
```

---

### 8. Get Root Categories

Lấy danh sách danh mục gốc (không có ParentId).

**Endpoint**: `GET /api/IncomeCategory/RootCategories`

**Permission**: `IncomeCategory.GetRootCategories`

**Response**:

```json
[
  {
    "Id": 1,
    "Name": "Doanh thu bán hàng",
    "Description": "Doanh thu từ hoạt động bán hàng",
    "DisplayOrder": 1,
    "ParentId": null,
    "ParentName": null,
    "ApprovedBy": 5,
    "ApprovedByUserName": "admin",
    "Children": [],
    "Level": 0,
    "IsDeleted": false,
    "CreatedDate": "2025-01-15T10:00:00Z",
    "CreatedBy": 1,
    "ModifiedDate": "2025-01-15T10:00:00Z",
    "ModifiedBy": 1
  }
]
```

---

### 9. Get Children

Lấy danh sách danh mục con theo ParentId.

**Endpoint**: `GET /api/IncomeCategory/Children/{parentId}`

**Permission**: `IncomeCategory.GetChildren`

**Parameters**:

- `parentId` (int, required): ID của danh mục cha

**Response**:

```json
[
  {
    "Id": 2,
    "Name": "Doanh thu tại cửa hàng",
    "Description": "",
    "DisplayOrder": 1,
    "ParentId": 1,
    "ParentName": "Doanh thu bán hàng",
    "ApprovedBy": 5,
    "ApprovedByUserName": "admin",
    "Children": [],
    "Level": 1,
    "IsDeleted": false,
    "CreatedDate": "2025-01-15T10:00:00Z",
    "CreatedBy": 1,
    "ModifiedDate": "2025-01-15T10:00:00Z",
    "ModifiedBy": 1
  }
]
```

---

### 10. Can Delete

Kiểm tra có thể xóa danh mục không (không có danh mục con).

**Endpoint**: `GET /api/IncomeCategory/CanDelete/{id}`

**Permission**: `IncomeCategory.CanDelete`

**Parameters**:

- `id` (int, required): ID của danh mục

**Response**:

```json
{
  "canDelete": true
}
```

---

## Income Controller

### 1. Search Incomes

Tìm kiếm doanh thu với phân trang và filter.

**Endpoint**: `POST /api/Income/Search`

**Permission**: `Income.Search`

**Request Body**:

```json
{
  "Pagination": {
    "PageIndex": 1,
    "PageSize": 10,
    "From": 0,
    "Total": 0,
    "TotalPages": 0,
    "TotalItemCount": 0,
    "Number": 0,
    "NumberOfPages": 0
  },
  "Search": {
    "PredicateObject": {
      "Description": "Doanh thu",
      "Status": 0,
      "IncomeCategoryId": 1
    }
  },
  "Sort": {
    "Predicate": "CreatedDate",
    "Reverse": true
  },
  "IsExport": false
}
```

**Response**:

```json
{
  "Items": [
    {
      "Id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "Description": "Doanh thu bán hàng tháng 1",
      "Note": "Ghi chú",
      "Amount": 1000000,
      "IncomeCategoryId": 1,
      "IncomeCategoryName": "Doanh thu bán hàng",
      "Status": 0,
      "ApprovedBy": 5,
      "ApprovedByUserName": "admin",
      "RejectReason": null,
      "CanApprove": true,
      "CanReject": true,
      "CanMarkAsReceived": false,
      "CreatedDate": "2025-01-15T10:00:00Z",
      "CreatedBy": 1,
      "ModifiedDate": "2025-01-15T10:00:00Z",
      "ModifiedBy": 1
    }
  ],
  "TotalRecord": 50,
  "NumberOfPages": 5,
  "From": 1,
  "To": 10,
  "LastPage": 5
}
```

---

### 2. Get Income By Id

Lấy thông tin chi tiết một doanh thu.

**Endpoint**: `GET /api/Income/{id}`

**Permission**: `Income.GetById`

**Parameters**:

- `id` (Guid, required): ID của doanh thu

**Response**:

```json
{
  "Id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "Description": "Doanh thu bán hàng tháng 1",
  "Note": "Ghi chú",
  "Amount": 1000000,
  "IncomeCategoryId": 1,
  "IncomeCategoryName": "Doanh thu bán hàng",
  "Status": 0,
  "ApprovedBy": 5,
  "ApprovedByUserName": "admin",
  "RejectReason": null,
  "CanApprove": true,
  "CanReject": true,
  "CanMarkAsReceived": false,
  "CreatedDate": "2025-01-15T10:00:00Z",
  "CreatedBy": 1,
  "ModifiedDate": "2025-01-15T10:00:00Z",
  "ModifiedBy": 1
}
```

---

### 3. Create Or Update Income

Tạo mới hoặc cập nhật doanh thu.

**Endpoint**: `POST /api/Income/CreateOrUpdate`

**Permission**: `Income.CreateOrUpdate`

**Request Body**:

```json
{
  "Id": "00000000-0000-0000-0000-000000000000",
  "Description": "Doanh thu bán hàng tháng 1",
  "Note": "Ghi chú",
  "Amount": 1000000,
  "IncomeCategoryId": 1,
  "IncomeCategoryName": "",
  "Status": 0,
  "ApprovedBy": null,
  "RejectReason": null
}
```

**Response**:

```json
{
  "Result": 1,
  "Message": ""
}
```

**Note**:

- Status mặc định = Pending (0)
- ApprovedBy tự động lấy từ IncomeCategory
- Khi update, chỉ có thể cập nhật các field: Description, Note, Amount, IncomeCategoryId

---

### 4. Approve Income

Duyệt doanh thu (chuyển từ Pending sang Approved).

**Endpoint**: `POST /api/Income/Approve/{id}`

**Permission**: `Income.Approve`

**Parameters**:

- `id` (Guid, required): ID của doanh thu

**Response**:

```json
{
  "Result": 1,
  "Message": ""
}
```

**Note**:

- Chỉ có thể duyệt khi Status = Pending
- Tự động tạo IncomeHistory
- Status chuyển: Pending → Approved

---

### 5. Reject Income

Từ chối doanh thu (chuyển từ Pending sang Rejected).

**Endpoint**: `POST /api/Income/Reject/{id}`

**Permission**: `Income.Reject`

**Parameters**:

- `id` (Guid, required): ID của doanh thu

**Request Body**:

```json
{
  "RejectReason": "Lý do từ chối"
}
```

**Response**:

```json
{
  "Result": 1,
  "Message": ""
}
```

**Note**:

- Chỉ có thể từ chối khi Status = Pending
- RejectReason là bắt buộc
- Tự động tạo IncomeHistory
- Status chuyển: Pending → Rejected

---

### 6. Mark As Received

Đánh dấu doanh thu đã nhận tiền (chuyển từ Approved sang Received).

**Endpoint**: `POST /api/Income/MarkAsReceived/{id}`

**Permission**: `Income.MarkAsReceived`

**Parameters**:

- `id` (Guid, required): ID của doanh thu

**Request Body**:

```json
{
  "Note": "Ghi chú nhận tiền"
}
```

**Response**:

```json
{
  "Result": 1,
  "Message": ""
}
```

**Note**:

- Chỉ có thể đánh dấu khi Status = Approved
- Tự động tạo Transaction với IncomeId
- Tự động cộng tiền vào ví (TransactionDirection.Income)
- Status chuyển: Approved → Received

---

### 7. Delete Income

Xóa doanh thu (soft delete).

**Endpoint**: `DELETE /api/Income/{id}`

**Permission**: `Income.Delete`

**Parameters**:

- `id` (Guid, required): ID của doanh thu

**Response**:

```json
{
  "Result": 1,
  "Message": ""
}
```

**Note**: Không thể xóa doanh thu đã được nhận tiền (Status = Received).

---

## Data Models

### Result Enum

Tất cả các response đều có field `Result` kiểu int:

```csharp
public enum Result
{
    Success = 1,        // Thành công
    Failed = 2,          // Thất bại
    SystemError = 3      // Lỗi hệ thống
}
```

**Ý nghĩa**:

- `Result = 1`: Thành công
- `Result = 2`: Thất bại (lỗi validation hoặc business logic)
- `Result = 3`: Lỗi hệ thống

### IncomeStatus Enum

```csharp
public enum IncomeStatus
{
    Pending = 0,      // Chờ duyệt
    Approved = 1,     // Đã duyệt
    Rejected = 2,     // Từ chối
    Received = 3      // Đã nhận tiền
}
```

### Base Fields

Tất cả các entities đều kế thừa các field sau:

```json
{
  "Id": "string or int",
  "CreatedDate": "datetime",
  "CreatedBy": "int",
  "ModifiedDate": "datetime",
  "ModifiedBy": "int",
  "IsDeleted": "bool"
}
```

---

## Error Responses

### 400 Bad Request

```json
{
  "Result": 2,
  "Message": "Lỗi validation hoặc business logic"
}
```

### 401 Unauthorized

```json
{
  "Result": 2,
  "Message": "Unauthorized"
}
```

### 403 Forbidden

```json
{
  "Result": 2,
  "Message": "Không có quyền truy cập"
}
```

### 404 Not Found

```json
{
  "Result": 2,
  "Message": "Không tìm thấy dữ liệu"
}
```

### 500 Internal Server Error

```json
{
  "Result": 3,
  "Message": "Lỗi hệ thống: {error message}"
}
```

---

## Workflow

### Quy trình xử lý doanh thu

1. **Tạo doanh thu**: POST `/api/Income/CreateOrUpdate`

   - Status = Pending
   - ApprovedBy tự động lấy từ IncomeCategory

2. **Duyệt doanh thu**: POST `/api/Income/Approve/{id}`

   - Status: Pending → Approved
   - Tạo IncomeHistory

3. **Nhận tiền**: POST `/api/Income/MarkAsReceived/{id}`

   - Status: Approved → Received
   - Tạo Transaction với IncomeId
   - Cộng tiền vào ví

4. **Từ chối doanh thu**: POST `/api/Income/Reject/{id}`
   - Status: Pending → Rejected
   - Bắt buộc nhập RejectReason
   - Tạo IncomeHistory

---

## SmartTableParam Structure

Tất cả các API Search sử dụng cấu trúc `SmartTableParam`:

### Request Structure

```json
{
  "Pagination": {
    "PageIndex": 1, // Số trang (bắt đầu từ 1)
    "PageSize": 10, // Số lượng records mỗi trang
    "From": 0, // Record bắt đầu (tự động tính)
    "Total": 0, // Tổng số records (tự động tính)
    "TotalPages": 0, // Tổng số trang (tự động tính)
    "TotalItemCount": 0, // Tổng số items (tự động tính)
    "Number": 0, // Số trang hiện tại (tự động tính)
    "NumberOfPages": 0 // Số trang (tự động tính)
  },
  "Search": {
    "PredicateObject": {
      // Các điều kiện filter
      "Name": "Search text",
      "Status": 0,
      "IncomeCategoryId": 1
    }
  },
  "Sort": {
    "Predicate": "Name", // Tên field để sort
    "Reverse": false // false = ASC, true = DESC
  },
  "IsExport": false // Có phải xuất dữ liệu không
}
```

### Response Structure

```json
{
  "Items": [], // Mảng dữ liệu
  "TotalRecord": 100, // Tổng số records
  "NumberOfPages": 10, // Tổng số trang
  "From": 1, // Record bắt đầu
  "To": 10, // Record kết thúc
  "LastPage": 10 // Trang cuối cùng
}
```

### Notes

- Chỉ cần gửi `PageIndex`, `PageSize`, `Search.PredicateObject`, và `Sort` trong request
- Các fields khác trong `Pagination` sẽ được tự động tính toán
- `Search.PredicateObject` chứa các điều kiện filter theo format JSON Object
- `Sort.Reverse = false` là ASC, `true` là DESC

## Notes

1. **Permissions**: Cần được cấu hình trong database trước khi sử dụng
2. **Transaction Integration**: Khi MarkAsReceived, hệ thống tự động tạo Transaction và cộng tiền vào ví
3. **Status Flow**: Chỉ cho phép chuyển trạng thái theo workflow đã định nghĩa
4. **Soft Delete**: Xóa chỉ đánh dấu IsDeleted = true, không xóa khỏi database
5. **Can\* Flags**: Các flag CanApprove, CanReject, CanMarkAsReceived được tính toán tự động dựa trên Status và Permission
6. **Search Parameters**: Tất cả API Search sử dụng SmartTableParam với cấu trúc chuẩn như trên
