# API: Lấy Chi Tiết Phiếu Đối Soát Khách Hàng

## Thông Tin Cơ Bản

**Endpoint:** `GET /api/CustomerReconciliationSlip/GetById/{id}`

**Mô tả:** API này lấy thông tin chi tiết đầy đủ của một phiếu đối soát khách hàng, bao gồm thông tin phiếu, danh sách đơn hàng trong phiếu, và lịch sử thao tác.

**Yêu cầu xác thực:** Có (Bearer Token)

**Quyền cần thiết:** Một trong các quyền sau:
- `CustomerReconciliationSlip.View`
- `Founder`

---

## Request

### Headers
```json
{
  "Authorization": "Bearer {access_token}",
  "Content-Type": "application/json"
}
```

### URL Parameters

| Tham số | Kiểu | Bắt buộc | Mô tả |
|---------|------|----------|-------|
| `id` | `int` | Có | ID của phiếu đối soát cần lấy thông tin |

### Ví dụ URL
```
GET /api/CustomerReconciliationSlip/GetById/1234
```

---

## Response

### Success Response (200 OK)

```json
{
  "Slip": {
    "Id": 1234,
    "Code": "CR-241208-A3F2",
    "CustomerId": 125,
    "CustomerName": "Công ty TNHH ABC",
    "CustomerPhone": "0912345678",
    "Type": 1,
    "TypeName": "Phiếu Thu",
    "Status": 3,
    "StatusName": "Đã duyệt",
    "TotalCodAmount": 45000000,
    "TotalFeeAmount": 18000000,
    "FinalAmount": 27000000,
    "FinalAmountFormatted": "27,000,000 ₫",
    "OrderCount": 3,
    "CreatedByUserName": "nguyenvana",
    "CreatedTime": "2024-12-08T10:30:00+07:00",
    "ApprovedByUsername": "ketoan01",
    "ApprovedTime": "2024-12-08T11:00:00+07:00",
    "CompletedByUsername": "",
    "CompletedTime": null,
    "InternalNote": "Đối soát tháng 11/2024 - Đợt 1",
    "PaymentMethod": "",
    "TransactionCode": "",
    "ProofImageUrl": ""
  },
  "Details": [
    {
      "Id": 5001,
      "CustomerReconciliationSlipId": 1234,
      "OrderId": 10523,
      "OrderCode": "LD2411280001",
      "PartnerCode": "GHN123456",
      "AppliedCodAmount": 15000000,
      "AppliedFeeAmount": 6000000,
      "NetAmount": 9000000,
      "DeliveredDate": "2024-11-28T14:30:00+07:00",
      "CodCollectedDate": "2024-11-29T10:00:00+07:00",
      "OrderStatus": "Delivered",
      "PhysicalStatus": "Completed",
      "ChargeWeight": 1.5,
      "ShippingFee": 6000000,
      "DeliveryAddress": "123 Đường ABC, Phường 1, Quận 1, TP.HCM",
      "ReceiverName": "Nguyễn Văn A",
      "ReceiverPhone": "0901234567",
      "Note": "Giao hàng buổi sáng"
    },
    {
      "Id": 5002,
      "CustomerReconciliationSlipId": 1234,
      "OrderId": 10524,
      "OrderCode": "LD2411280002",
      "PartnerCode": "GHN123457",
      "AppliedCodAmount": 20000000,
      "AppliedFeeAmount": 7000000,
      "NetAmount": 13000000,
      "DeliveredDate": "2024-11-28T16:45:00+07:00",
      "CodCollectedDate": "2024-11-29T11:00:00+07:00",
      "OrderStatus": "Delivered",
      "PhysicalStatus": "Completed",
      "ChargeWeight": 2.3,
      "ShippingFee": 7000000,
      "DeliveryAddress": "456 Đường XYZ, Phường 5, Quận 3, TP.HCM",
      "ReceiverName": "Trần Thị B",
      "ReceiverPhone": "0987654321",
      "Note": ""
    },
    {
      "Id": 5003,
      "CustomerReconciliationSlipId": 1234,
      "OrderId": 10530,
      "OrderCode": "LD2411290005",
      "PartnerCode": "GHTK789012",
      "AppliedCodAmount": 10000000,
      "AppliedFeeAmount": 5000000,
      "NetAmount": 5000000,
      "DeliveredDate": "2024-11-29T09:15:00+07:00",
      "CodCollectedDate": "2024-11-30T08:00:00+07:00",
      "OrderStatus": "Delivered",
      "PhysicalStatus": "Completed",
      "ChargeWeight": 1.8,
      "ShippingFee": 5000000,
      "DeliveryAddress": "789 Đường DEF, Phường 10, Quận 7, TP.HCM",
      "ReceiverName": "Lê Văn C",
      "ReceiverPhone": "0912345678",
      "Note": ""
    }
  ],
  "Logs": [
    {
      "Id": 3002,
      "CustomerReconciliationSlipId": 1234,
      "ActorId": 10,
      "ActorUsername": "ketoan01",
      "ActionType": 4,
      "ActionTypeName": "Phê duyệt",
      "OldStatus": "Chờ duyệt",
      "NewStatus": "Đã duyệt",
      "Note": "Phiếu hợp lệ, đã kiểm tra đầy đủ",
      "CreatedTime": "2024-12-08T11:00:00+07:00"
    },
    {
      "Id": 3001,
      "CustomerReconciliationSlipId": 1234,
      "ActorId": 5,
      "ActorUsername": "nguyenvana",
      "ActionType": 1,
      "ActionTypeName": "Tạo phiếu",
      "OldStatus": "",
      "NewStatus": "Chờ duyệt",
      "Note": "Tạo mới phiếu đối soát",
      "CreatedTime": "2024-12-08T10:30:00+07:00"
    }
  ]
}
```

### Response Fields

#### Slip (CustomerReconciliationSlipItem)

| Trường | Kiểu | Mô tả |
|--------|------|-------|
| `Id` | `int` | ID phiếu đối soát |
| `Code` | `string` | Mã phiếu (VD: CR-241208-A3F2) |
| `CustomerId` | `int` | ID khách hàng |
| `CustomerName` | `string` | Tên khách hàng |
| `CustomerPhone` | `string` | Số điện thoại khách hàng |
| `Type` | `int` | Loại phiếu: 1 = Receivable (Thu), 2 = Payable (Chi) |
| `TypeName` | `string` | Tên loại phiếu: "Phiếu Thu" hoặc "Phiếu Chi" |
| `Status` | `int` | Trạng thái phiếu: 1=Draft, 2=PendingApproval, 3=Approved, 4=Completed, 8=Rejected |
| `StatusName` | `string` | Tên trạng thái (VD: "Chờ duyệt", "Đã duyệt", "Hoàn thành") |
| `TotalCodAmount` | `decimal` | Tổng tiền COD thu hộ (VNĐ) |
| `TotalFeeAmount` | `decimal` | Tổng phí vận chuyển (VNĐ) |
| `FinalAmount` | `decimal` | Số tiền cuối cùng = \|TotalCodAmount - TotalFeeAmount\| (VNĐ) |
| `FinalAmountFormatted` | `string` | Số tiền cuối cùng đã format (VD: "27,000,000 ₫") |
| `OrderCount` | `int` | Số lượng đơn hàng trong phiếu |
| `CreatedByUserName` | `string` | Username người tạo phiếu |
| `CreatedTime` | `string` (ISO 8601) | Thời gian tạo phiếu |
| `ApprovedByUsername` | `string` | Username người duyệt phiếu |
| `ApprovedTime` | `string` (ISO 8601) / `null` | Thời gian duyệt phiếu |
| `CompletedByUsername` | `string` | Username người hoàn thành phiếu |
| `CompletedTime` | `string` (ISO 8601) / `null` | Thời gian hoàn thành phiếu |
| `InternalNote` | `string` | Ghi chú nội bộ |
| `PaymentMethod` | `string` | Phương thức thanh toán (tên ngân hàng/ví) |
| `TransactionCode` | `string` | Mã giao dịch ngân hàng |
| `ProofImageUrl` | `string` | URL ảnh chứng từ thanh toán |

#### Details[] (CustomerReconciliationSlipDetailItem)

| Trường | Kiểu | Mô tả |
|--------|------|-------|
| `Id` | `int` | ID chi tiết đơn hàng |
| `CustomerReconciliationSlipId` | `int` | ID phiếu đối soát |
| `OrderId` | `int` | ID đơn hàng |
| `OrderCode` | `string` | Mã đơn hàng nội bộ |
| `PartnerCode` | `string` | Mã vận đơn đối tác (GHN, GHTK, VNPost...) |
| `AppliedCodAmount` | `decimal` | Số tiền COD áp dụng cho phiếu này (VNĐ) |
| `AppliedFeeAmount` | `decimal` | Tổng phí vận chuyển áp dụng (VNĐ) |
| `NetAmount` | `decimal` | Số tiền ròng = AppliedCodAmount - AppliedFeeAmount (VNĐ) |
| `DeliveredDate` | `string` (ISO 8601) / `null` | Ngày giao hàng thành công |
| `CodCollectedDate` | `string` (ISO 8601) / `null` | Ngày thu COD |
| `OrderStatus` | `string` | Trạng thái đơn hàng (VD: "Delivered", "Returned") |
| `PhysicalStatus` | `string` | Trạng thái vật lý (VD: "Completed") |
| `ChargeWeight` | `decimal` | Trọng lượng tính cước (kg) |
| `ShippingFee` | `decimal` | Phí vận chuyển cơ bản (VNĐ) |
| `DeliveryAddress` | `string` | Địa chỉ giao hàng |
| `ReceiverName` | `string` | Tên người nhận |
| `ReceiverPhone` | `string` | Số điện thoại người nhận |
| `Note` | `string` | Ghi chú đơn hàng |

#### Logs[] (CustomerReconciliationLogItem)

| Trường | Kiểu | Mô tả |
|--------|------|-------|
| `Id` | `int` | ID log |
| `CustomerReconciliationSlipId` | `int` | ID phiếu đối soát |
| `ActorId` | `int` | ID người thực hiện hành động |
| `ActorUsername` | `string` | Username người thực hiện |
| `ActionType` | `int` | Loại hành động (xem bảng Action Types) |
| `ActionTypeName` | `string` | Tên hành động (VD: "Tạo phiếu", "Phê duyệt") |
| `OldStatus` | `string` | Trạng thái trước khi thay đổi |
| `NewStatus` | `string` | Trạng thái sau khi thay đổi |
| `Note` | `string` | Ghi chú kèm theo hành động |
| `CreatedTime` | `string` (ISO 8601) | Thời gian thực hiện hành động |

#### Action Types (CustomerReconciliationActionType):

| Giá trị | Tên | Mô tả |
|---------|-----|-------|
| `1` | Create | Tạo phiếu |
| `2` | Update | Cập nhật phiếu |
| `3` | Submit | Gửi phê duyệt |
| `4` | Approve | Phê duyệt phiếu |
| `5` | Reject | Từ chối phiếu |
| `6` | ConfirmPayment | Xác nhận thanh toán |
| `7` | Cancel | Hủy phiếu |

---

## Error Response

### 401 Unauthorized
```json
{
  "type": "https://tools.ietf.org/html/rfc7235#section-3.1",
  "title": "Unauthorized",
  "status": 401,
  "traceId": "00-xxxxx"
}
```

**Nguyên nhân:** Token không hợp lệ hoặc đã hết hạn

---

### 403 Forbidden
```json
{
  "type": "https://tools.ietf.org/html/rfc7231#section-6.5.3",
  "title": "Forbidden",
  "status": 403,
  "traceId": "00-xxxxx"
}
```

**Nguyên nhân:** User không có quyền `CustomerReconciliationSlip.View` hoặc `Founder`

---

### 500 Internal Server Error - Phiếu không tồn tại
```json
{
  "type": "https://tools.ietf.org/html/rfc7231#section-6.6.1",
  "title": "An error occurred while processing your request.",
  "status": 500,
  "detail": "Phiếu không tồn tại",
  "traceId": "00-xxxxx"
}
```

**Nguyên nhân:** ID phiếu không tồn tại trong hệ thống

---

### 500 Internal Server Error - Không có quyền xem
```json
{
  "type": "https://tools.ietf.org/html/rfc7231#section-6.6.1",
  "title": "An error occurred while processing your request.",
  "status": 500,
  "detail": "Bạn không có quyền xem phiếu này",
  "traceId": "00-xxxxx"
}
```

**Nguyên nhân:** User không có quyền xem phiếu này (không phải Founder/Kế toán, không phải người tạo, không phải Manager của khách hàng)

---

## Business Logic

### 1. Phân Quyền Xem Chi Tiết

Hệ thống áp dụng phân quyền theo role:

| Role | Phạm vi truy cập |
|------|------------------|
| **Founder** | Xem tất cả phiếu đối soát |
| **CustomerReconciliationSlip.View** (Kế toán) | Xem tất cả phiếu đối soát |
| **Sale/Manager** | Chỉ xem phiếu do mình tạo HOẶC phiếu của khách hàng mình quản lý |

**Logic phân quyền:**
```csharp
if (!isFounder && !isAccountant && 
    slip.Customer.ManagerId != userId && 
    slip.CreatedBy != userId)
{
    throw new Exception("Bạn không có quyền xem phiếu này");
}
```

### 2. Dữ Liệu Trả Về

API trả về 3 phần chính:

#### a) **Slip** - Thông tin tổng quan phiếu
- Thông tin khách hàng
- Tổng hợp tài chính (TotalCodAmount, TotalFeeAmount, FinalAmount)
- Trạng thái và loại phiếu
- Thông tin người tạo, duyệt, hoàn thành
- Thông tin thanh toán (nếu có)

#### b) **Details** - Danh sách đơn hàng trong phiếu
- Chi tiết từng đơn hàng
- Số tiền COD và phí của từng đơn
- Thông tin giao hàng
- Trọng lượng và phí vận chuyển

#### c) **Logs** - Lịch sử thao tác
- Sắp xếp theo thời gian giảm dần (mới nhất lên đầu)
- Ghi lại tất cả hành động: Tạo, Duyệt, Từ chối, Hoàn thành
- Thông tin người thực hiện và thời gian
- Ghi chú kèm theo (nếu có)

### 3. Eager Loading

API sử dụng `Include()` để load trước các navigation properties:
- `Customer` - Thông tin khách hàng
- `Details` - Chi tiết đơn hàng
- `Logs` - Lịch sử thao tác

Điều này đảm bảo hiệu năng tốt và tránh N+1 query problem.

---

## Ví dụ sử dụng

### Example 1: Lấy chi tiết phiếu đối soát

**Request:**
```bash
curl -X GET "https://api.yourdomain.com/api/CustomerReconciliationSlip/GetById/1234" \
  -H "Authorization: Bearer {your_token}" \
  -H "Content-Type: application/json"
```

**Response:** Xem phần Success Response (200 OK) ở trên

---

### Example 2: Frontend integration (JavaScript)

```javascript
// Service function để lấy chi tiết phiếu đối soát
async function getReconciliationSlipById(id) {
  try {
    const response = await fetch(
      `/api/CustomerReconciliationSlip/GetById/${id}`,
      {
        method: 'GET',
        headers: {
          'Authorization': `Bearer ${getAccessToken()}`,
          'Content-Type': 'application/json'
        }
      }
    );

    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }

    const result = await response.json();
    return result;
  } catch (error) {
    console.error('Failed to fetch reconciliation slip:', error);
    throw error;
  }
}

// Sử dụng
const slipData = await getReconciliationSlipById(1234);

console.log(`Mã phiếu: ${slipData.Slip.Code}`);
console.log(`Khách hàng: ${slipData.Slip.CustomerName}`);
console.log(`Trạng thái: ${slipData.Slip.StatusName}`);
console.log(`Số đơn hàng: ${slipData.Details.length}`);
console.log(`Số lượng log: ${slipData.Logs.length}`);

// Tính tổng
const totalNet = slipData.Details.reduce((sum, d) => sum + d.NetAmount, 0);
console.log(`Tổng tiền ròng: ${totalNet.toLocaleString('vi-VN')} ₫`);
```

---

### Example 3: Vue.js Component

```javascript
// Component Vue.js để hiển thị chi tiết phiếu
export default {
  data() {
    return {
      slip: null,
      details: [],
      logs: [],
      loading: false
    };
  },
  
  computed: {
    canApprove() {
      return this.slip && 
             this.slip.Status === 2 && // PendingApproval
             this.hasRole('CustomerReconciliationSlip.Approve');
    },
    
    canComplete() {
      return this.slip && 
             this.slip.Status === 3 && // Approved
             this.hasRole('CustomerReconciliationSlip.Complete');
    },
    
    statusColor() {
      if (!this.slip) return 'default';
      
      switch (this.slip.Status) {
        case 2: return 'warning';  // PendingApproval
        case 3: return 'primary';  // Approved
        case 4: return 'success';  // Completed
        case 8: return 'danger';   // Rejected
        default: return 'default';
      }
    }
  },
  
  methods: {
    async loadSlipDetail(id) {
      this.loading = true;
      
      try {
        const result = await getReconciliationSlipById(id);
        
        this.slip = result.Slip;
        this.details = result.Details;
        this.logs = result.Logs;
      } catch (error) {
        this.$message.error('Không thể tải chi tiết phiếu đối soát');
        console.error(error);
      } finally {
        this.loading = false;
      }
    },
    
    async handleApprove() {
      // Gọi API Approve
      await this.approveSlip(this.slip.Id);
      await this.loadSlipDetail(this.slip.Id); // Reload
    },
    
    async handleComplete() {
      // Gọi API Complete
      await this.completeSlip(this.slip.Id);
      await this.loadSlipDetail(this.slip.Id); // Reload
    }
  },
  
  mounted() {
    const id = this.$route.params.id;
    this.loadSlipDetail(id);
  }
};
```

---

### Example 4: React Hook

```typescript
import { useState, useEffect } from 'react';

interface ReconciliationSlipDetail {
  Slip: CustomerReconciliationSlipItem;
  Details: CustomerReconciliationSlipDetailItem[];
  Logs: CustomerReconciliationLogItem[];
}

function useReconciliationSlipDetail(id: number) {
  const [data, setData] = useState<ReconciliationSlipDetail | null>(null);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<Error | null>(null);

  useEffect(() => {
    const fetchData = async () => {
      setLoading(true);
      setError(null);

      try {
        const result = await getReconciliationSlipById(id);
        setData(result);
      } catch (err) {
        setError(err as Error);
      } finally {
        setLoading(false);
      }
    };

    if (id) {
      fetchData();
    }
  }, [id]);

  return { data, loading, error, refetch: () => fetchData() };
}

// Sử dụng trong component
function ReconciliationSlipDetailPage({ id }: { id: number }) {
  const { data, loading, error, refetch } = useReconciliationSlipDetail(id);

  if (loading) return <div>Loading...</div>;
  if (error) return <div>Error: {error.message}</div>;
  if (!data) return null;

  return (
    <div>
      <h1>Phiếu đối soát: {data.Slip.Code}</h1>
      <p>Khách hàng: {data.Slip.CustomerName}</p>
      <p>Trạng thái: {data.Slip.StatusName}</p>
      
      <h2>Danh sách đơn hàng ({data.Details.length})</h2>
      <table>
        {data.Details.map(detail => (
          <tr key={detail.Id}>
            <td>{detail.OrderCode}</td>
            <td>{detail.AppliedCodAmount.toLocaleString()} ₫</td>
            <td>{detail.AppliedFeeAmount.toLocaleString()} ₫</td>
            <td>{detail.NetAmount.toLocaleString()} ₫</td>
          </tr>
        ))}
      </table>
      
      <h2>Lịch sử thao tác</h2>
      <ul>
        {data.Logs.map(log => (
          <li key={log.Id}>
            {log.CreatedTime} - {log.ActorUsername}: {log.ActionTypeName}
            {log.Note && <p>{log.Note}</p>}
          </li>
        ))}
      </ul>
    </div>
  );
}
```

---

## TypeScript Interface

```typescript
// Response Model
interface CustomerReconciliationSlipResult {
  Slip: CustomerReconciliationSlipItem;
  Details: CustomerReconciliationSlipDetailItem[];
  Logs: CustomerReconciliationLogItem[];
}

interface CustomerReconciliationSlipItem {
  Id: number;
  Code: string;
  CustomerId: number;
  CustomerName: string;
  CustomerPhone: string;
  Type: CustomerReconciliationSlipType;
  TypeName: string;
  Status: CustomerReconciliationSlipStatus;
  StatusName: string;
  TotalCodAmount: number;
  TotalFeeAmount: number;
  FinalAmount: number;
  FinalAmountFormatted: string;
  OrderCount: number;
  CreatedByUserName: string;
  CreatedTime: string;
  ApprovedByUsername: string;
  ApprovedTime: string | null;
  CompletedByUsername: string;
  CompletedTime: string | null;
  InternalNote: string;
  PaymentMethod: string;
  TransactionCode: string;
  ProofImageUrl: string;
}

interface CustomerReconciliationSlipDetailItem {
  Id: number;
  CustomerReconciliationSlipId: number;
  OrderId: number;
  OrderCode: string;
  PartnerCode: string;
  AppliedCodAmount: number;
  AppliedFeeAmount: number;
  NetAmount: number;
  DeliveredDate: string | null;
  CodCollectedDate: string | null;
  OrderStatus: string;
  PhysicalStatus: string;
  ChargeWeight: number;
  ShippingFee: number;
  DeliveryAddress: string;
  ReceiverName: string;
  ReceiverPhone: string;
  Note: string;
}

interface CustomerReconciliationLogItem {
  Id: number;
  CustomerReconciliationSlipId: number;
  ActorId: number;
  ActorUsername: string;
  ActionType: CustomerReconciliationActionType;
  ActionTypeName: string;
  OldStatus: string;
  NewStatus: string;
  Note: string;
  CreatedTime: string;
}

// Enums
enum CustomerReconciliationSlipType {
  Receivable = 1,
  Payable = 2
}

enum CustomerReconciliationSlipStatus {
  Draft = 1,
  PendingApproval = 2,
  Approved = 3,
  Completed = 4,
  Rejected = 8
}

enum CustomerReconciliationActionType {
  Create = 1,
  Update = 2,
  Submit = 3,
  Approve = 4,
  Reject = 5,
  ConfirmPayment = 6,
  Cancel = 7
}

// API Function
async function getReconciliationSlipById(
  id: number
): Promise<CustomerReconciliationSlipResult> {
  const response = await fetch(
    `/api/CustomerReconciliationSlip/GetById/${id}`,
    {
      method: 'GET',
      headers: {
        'Authorization': `Bearer ${getAccessToken()}`,
        'Content-Type': 'application/json'
      }
    }
  );

  if (!response.ok) {
    throw new Error('Failed to fetch reconciliation slip');
  }

  return response.json();
}
```

---

## Workflow

API này thường được sử dụng trong các màn hình sau:

### 1. Màn hình chi tiết phiếu đối soát
- Hiển thị thông tin tổng quan phiếu
- Danh sách đơn hàng trong phiếu
- Lịch sử thao tác
- Các nút hành động: Duyệt, Từ chối, Hoàn thành

### 2. Xem trước khi duyệt/từ chối
- Kế toán xem chi tiết trước khi phê duyệt
- Kiểm tra danh sách đơn hàng
- Xem lịch sử thao tác

### 3. Xác nhận thanh toán
- Xem chi tiết phiếu đã duyệt
- Nhập thông tin thanh toán
- Upload chứng từ

---

## Notes

- **Định dạng thời gian:** Sử dụng ISO 8601 với timezone (`2024-12-08T10:30:00+07:00`)
- **Định dạng tiền tệ:** `FinalAmountFormatted` đã được format theo chuẩn Việt Nam với ký hiệu `₫`
- **Logs ordering:** Logs được sắp xếp theo thời gian giảm dần (mới nhất lên đầu)
- **Security:** 
  - API yêu cầu Bearer Token hợp lệ
  - Phân quyền theo role: Founder/Kế toán xem tất cả, Sale chỉ xem phiếu liên quan
  - Kiểm tra quyền trước khi trả về dữ liệu
- **Performance:** 
  - Sử dụng `Include()` để eager load Customer, Details, Logs
  - Tránh N+1 query problem
  - Single database query với joins

---

## Data Validation

### Các trường hợp lỗi phổ biến:

| Lỗi | HTTP Code | Message | Nguyên nhân |
|-----|-----------|---------|-------------|
| Phiếu không tồn tại | 500 | "Phiếu không tồn tại" | ID không có trong database |
| Không có quyền xem | 500 | "Bạn không có quyền xem phiếu này" | User không phải Founder/Kế toán/Creator/Manager |
| Token hết hạn | 401 | "Unauthorized" | Bearer token không hợp lệ |
| Thiếu quyền | 403 | "Forbidden" | Không có role View hoặc Founder |

---

## Use Cases

### 1. Kế toán xem phiếu chờ duyệt
```
1. Lấy danh sách phiếu chờ duyệt (Search API với Status=2)
2. Click vào một phiếu
3. Gọi GetById để xem chi tiết
4. Kiểm tra danh sách đơn hàng
5. Xem lịch sử (ai tạo, khi nào)
6. Quyết định Duyệt hoặc Từ chối
```

### 2. Sale xem phiếu của mình
```
1. Vào màn hình "Phiếu của tôi"
2. Click vào một phiếu đã tạo
3. Gọi GetById để xem chi tiết
4. Xem trạng thái hiện tại
5. Xem lịch sử (đã duyệt chưa, ai duyệt)
```

### 3. Xác nhận thanh toán
```
1. Lấy danh sách phiếu đã duyệt (Status=3)
2. Click vào phiếu cần thanh toán
3. Gọi GetById để xem chi tiết
4. Nhập thông tin thanh toán
5. Upload chứng từ
6. Gọi Complete API
```

---

## Change Log

| Version | Date | Author | Changes |
|---------|------|--------|---------|
| 1.0 | 2024-12-08 | Development Team | Initial release |

---

## Related APIs

- `POST /api/CustomerReconciliationSlip/Search` - Tìm kiếm phiếu đối soát
- `POST /api/CustomerReconciliationSlip/Create` - Tạo phiếu đối soát mới
- `PUT /api/CustomerReconciliationSlip/Approve/{id}` - Duyệt phiếu đối soát
- `POST /api/CustomerReconciliationSlip/Reject` - Từ chối phiếu đối soát
- `POST /api/CustomerReconciliationSlip/Complete` - Hoàn thành phiếu (xác nhận thanh toán)
- `GET /api/CustomerReconciliationSlip/GetLogs/{id}` - Lấy lịch sử thao tác (nếu cần riêng)
- `POST /api/CustomerReconciliationSlip/GetCustomersOverview` - Lấy danh sách khách hàng cần đối soát
- `GET /api/CustomerReconciliationSlip/GetReconciliableOrders` - Lấy danh sách đơn hàng có thể đối soát
