# TSHIRTORDER-1650 — Thêm checkbox "Use channel user" khi tạo samlingsfaktura

## Yêu cầu gốc

> TSHIRTORDER-1650 Add checkbox to use channel custeorm when create samlingsfaktura

Kèm 2 ảnh mockup:
- `files/create-invoice-modal.jpg` — popup "Skapa faktura", ô vuông xanh "Use channel user" là checkbox cần thêm.
- `files/channel-settings-default-customer.png` — tab Inställningar của channel, field "Kund använd till BULK, Gästorder och faktura" (nguồn customer sẽ được dùng).

---

## Tổng quan

Popup **Skapa faktura** (tạo hóa đơn từ các order đã chọn) hiện có checkbox "Enskild faktura - Avmarkera för samlingsfaktura". Khi bỏ tick (= samlingsfaktura, hóa đơn gộp), các order được nhóm theo customer của từng order, mỗi customer ra 1 hóa đơn.

Yêu cầu: thêm checkbox **"Use channel user"**. Khi tick, hóa đơn gộp sẽ dùng **customer mặc định của channel** (`Channel::bulkOrderDefaultCustomerId`) thay vì customer của từng order. Phạm vi: **backend (API) + frontend (React, repo khác)**. Không cần migration.

> ⚠️ **Phát hiện quan trọng: phần lớn đã có sẵn từ trước**
>
> | Thành phần | File / dòng | Trạng thái |
> |---|---|---|
> | Field customer mặc định của channel | `src/Entity/Channel.php:74` (`bulkOrderDefaultCustomerId`) + getter/setter dòng 1465-1472 | ✅ |
> | Channel API đọc field này | `ChannelService::generateItem()` — `src/Service/ChannelService.php:50` | ✅ |
> | Logic "dùng customer mặc định của channel" cho luồng monthly | `InvoiceService::addFromMultiOrders()` — `src/Service/InvoiceService.php:643-648` | ✅ (chỉ luồng monthly) |
> | Endpoint tạo hóa đơn từ popup | `POST /api/v1/invoices/create-from-multi-orders-individual` → `InvoiceController::addFromMultiOrdersIndividual()` → `InvoiceService::addFromMultiOrdersIndividual()` (`InvoiceService.php:665`) | ✅ — **cần sửa** |
> | Param `useChannelCustomer` | — | ❌ chưa có |

---

## Chi tiết theo mockup

**Popup "Skapa faktura"** (`files/create-invoice-modal.jpg`):

- Hiện có: Order-ID, Fakturadatum, Fakturakommentar, checkbox "Enskild faktura - Avmarkera för samlingsfaktura" (đang tick mặc định).
- Thêm: checkbox **"Use channel user"** ngay dưới checkbox "Enskild faktura", bên phải popup (ô vuông xanh trong mockup).

**Hành vi của backend hiện tại** (`addFromMultiOrdersIndividual`):

| `separateInvoice` | Kết quả |
|---|---|
| true (tick Enskild) | Mỗi order 1 hóa đơn, `customerId = order->getCustomerId()` |
| false (samlingsfaktura) | Nhóm order theo `order->getCustomerId()`, mỗi nhóm 1 hóa đơn |

**Hành vi mới** khi `useChannelCustomer = true` và `separateInvoice = false`:

| Tình huống | Kết quả |
|---|---|
| Channel #88, order 62972 và 62971 thuộc 2 customer khác nhau | **1 hóa đơn** gộp cả 2 order, customer = customer mặc định của channel (VD: NKT3 Nakata) |

Các order được chọn ở FE luôn thuộc cùng 1 channel (FE đã filter theo channel), nên không cần nhóm theo channel. BE vẫn **validate**: nếu các order không cùng 1 channel → 400, không tạo hóa đơn.

---

## Questions / Đã xác nhận

| # | Câu hỏi | Trả lời | Ghi chú kỹ thuật |
|---|---------|---------|-------------------|
| 1 | Order thuộc nhiều channel thì sao? | Đã xác nhận: FE đã filter theo 1 channel sẵn | Không cần nhóm theo `channelId`; BE vẫn validate, khác channel → 400 |
| 2 | Tick "Enskild faktura" + "Use channel user" thì sao? | Sếp: *"new checkbox only for when select samlingsfaktura"* | Checkbox chỉ hiện/enable khi **bỏ tick** "Enskild faktura". BE bỏ qua `useChannelCustomer` nếu `separateInvoice = true` |
| 3 | Channel chưa set customer mặc định thì sao? | Sếp (12/10/2026): *"add text to show its needs to connect one, so it works"* | Chốt phương án (a): khi tick "Use channel user" mà channel chưa chọn "Kund använd till BULK, Gästorder och faktura" → BE trả 400 kèm message, không tạo hóa đơn; FE hiển thị text báo cần kết nối/chọn customer cho channel. Nội dung text/vị trí do dev tự quyết |
| 4 | Giá trị mặc định của checkbox? | Sếp (12/10/2026): *"it should be unchecked as default"* | Mặc định **không tick** (giữ hành vi cũ). BE: không truyền `useChannelCustomer` = false |

### Pending Clarification

1. ~~Câu trả lời #3 của sếp còn mơ hồ~~ — **Đã chốt** (xem bảng trên, #3).
   - Lưu ý kỹ thuật: setter `setBulkOrderDefaultCustomerId` ép kiểu `(int)`, nên giá trị "chưa set" có thể là `0`, không chỉ `null`. BE đã check falsy.
2. ~~Giá trị mặc định của checkbox~~ — **Đã chốt**: không tick (xem bảng trên, #4).
3. **Luồng monthly** (`addFromMultiOrders`) tạo hóa đơn với customer rỗng (status 200) khi channel chưa set customer mặc định — sếp chưa trả lời có sửa trong ticket này không. Mặc định: không đụng vào, ngoài phạm vi; nếu cần thì tách ticket riêng.

---

## API contract / Thiết kế kỹ thuật

**Route**: `POST /api/v1/invoices/create-from-multi-orders-individual` (không đổi route).

**Request** — thêm 1 field:

| Field | Type | Ý nghĩa |
|---|---|---|
| `orderIds` | int[] | (đã có) |
| `separateInvoice` | bool / string / int | (đã có) `true` = Enskild faktura. **Đổi cách parse**, xem bên dưới |
| `useChannelCustomer` | bool / string / int | **MỚI** — dùng customer mặc định của channel. Optional, mặc định `false`. Cùng cách parse với `separateInvoice` |
| `invoiceDate`, `comment`, ... | | (đã có, giữ nguyên) |

**Cách parse boolean** (áp dụng cho cả `separateInvoice` và `useChannelCustomer`):

- **true**: `true`, `'true'`, `'yes'`, `1`, `'1'` (chuỗi không phân biệt hoa thường, bỏ khoảng trắng đầu/cuối: `'True'`, `' YES '` cũng là true).
- **false**: không truyền, `null`, `''`, `false`, `'false'`, `'no'`, `0`, `'0'` và mọi giá trị khác.
- ⚠️ **Thay đổi hành vi so với trước**: trước đây `separateInvoice` không truyền sẽ gây notice/500, và chuỗi bất kỳ không rỗng (VD `'false'`, `'on'`) bị coi là true. Giờ các giá trị đó là false (samlingsfaktura).

**Response**: không đổi (`{ <customerId>: {...add result} }`). Khi dùng channel customer, key sẽ là `customerId` của channel.

**Lỗi 400 mới** (khi `separateInvoice` false và `useChannelCustomer` true):

| Điều kiện | `message` |
|---|---|
| Các order không cùng 1 channel | `Orders must belong to the same channel to use the channel customer` |
| Channel chưa set `bulkOrderDefaultCustomerId`, customer không tồn tại hoặc đã bị xóa mềm | `Channel has no default customer selected (Kund använd till BULK, Gästorder och faktura)` |

#### ⚠️ Lưu ý bẫy quan trọng

- ~~`$separateInvoice = $data['separateInvoice'];` truy cập trực tiếp~~ — **đã sửa**: đọc bằng `?? false` và parse qua closure `$isTruthy` dùng chung với `useChannelCustomer`.
- `Customer::find()` không lọc `dateDeleted` → code phải tự check `getDateDeleted() !== null`.
- Hóa đơn gộp lấy `erReference` / `varReference` từ **order đầu tiên** (`postUpdate`); các order khác bị bỏ qua. Hành vi cũ, không đổi.
- Lỗi nội bộ của `add()` (VD sai định dạng ngày) vẫn trả HTTP 200 với `status_code` lồng trong body. FE nên kiểm tra cả trong `data`.
- `createdFrom` luôn là `individual` → hóa đơn vẫn xuất hiện trong export Reskontralista (xem TSHIRTORDER-1648).
- `$data['customerId']` được gán đè trong vòng lặp rồi truyền vào `add()` cùng `$data`. Khi làm nhánh mới, đặt `customerId` trước khi gọi `add()` một lần duy nhất.
- `getValidOrdersInvoice()` đã loại order đã có hóa đơn hoặc chưa ở trạng thái complete; nếu số order trả về khác `orderIds` thì trả 400 `Invalid orders` (không đổi).

---

## TODO List

### Backend — Entity & Migration
- [x] Không cần: `Channel::bulkOrderDefaultCustomerId` đã tồn tại.

### Backend — Service
- [x] `src/Service/InvoiceService.php` → `addFromMultiOrdersIndividual()`: thêm closure `$isTruthy` (true / `'true'` / `'yes'` / `1` / `'1'`, chuỗi không phân biệt hoa thường); `separateInvoice` và `useChannelCustomer` đều parse qua đây, không truyền = false.
- [x] Trong nhánh samlingsfaktura (`separateInvoice = false`) với `useChannelCustomer` bật: kiểm tra các order cùng 1 channel (khác → 400); lấy `Channel`, đọc `getBulkOrderDefaultCustomerId()`; không có, customer không tồn tại hoặc đã xóa mềm → 400; ngược lại set `$data['customerId']` và `$data['channelId']`, gọi `$this->add($data, $orders, $loginUser)` **1 lần** với toàn bộ `$orders`.
- [x] Nhánh `separateInvoice = true`: giữ nguyên (bỏ qua `useChannelCustomer` — đã xác nhận, câu hỏi #2).
- [x] Khởi tạo `$result = []` trước các nhánh (hiện nhánh `separateInvoice = true` dùng `$result[...]` mà chưa khai báo).

### Backend — Controller & Routing
- [ ] Không cần đổi: `InvoiceController::addFromMultiOrdersIndividual()` đã truyền toàn bộ `$data`.

### Frontend — React *(repo khác, không nằm trong repo này)*
- [ ] Popup "Skapa faktura": thêm checkbox "Use channel user" (label tiếng Thụy Điển nếu PO yêu cầu), đặt dưới checkbox "Enskild faktura".
- [ ] Gửi `useChannelCustomer` trong body request tạo hóa đơn.
- [ ] Chỉ hiện/enable checkbox khi "Enskild faktura" **không** tick (đã xác nhận); reset về không tick khi Enskild được tick lại.
- [ ] Checkbox mặc định **không tick** (đã xác nhận).
- [ ] Hiển thị text thông báo khi channel chưa set customer mặc định, nói rõ cần chọn customer trong channel settings ("Kund använd till BULK, Gästorder och faktura") thì mới dùng được (hiển thị message 400 từ BE, nội dung/vị trí dev tự quyết).

### Test / kiểm tra
- [ ] Channel có customer mặc định, 2 order thuộc 2 customer khác nhau, bỏ tick Enskild + tick "Use channel user" → ra 1 hóa đơn, customer = customer channel, cả 2 order được gắn `invoiceId`.
- [ ] Cùng case nhưng không tick "Use channel user" → hành vi cũ (2 hóa đơn theo customer).
- [ ] Tick Enskild (kể cả có tick "Use channel user") → mỗi order 1 hóa đơn như cũ.
- [ ] Channel chưa set customer mặc định + tick "Use channel user" → 400, không tạo hóa đơn nào.
- [ ] FE không gửi `useChannelCustomer` → hành vi cũ, không lỗi.
- [ ] Order thuộc 2 channel khác nhau + tick "Use channel user" → 400 `Orders must belong to the same channel...`, không tạo hóa đơn nào.
- [ ] Customer mặc định của channel đã bị xóa mềm → 400, không tạo hóa đơn.
- [ ] FE không gửi `separateInvoice` → coi như false (samlingsfaktura), không notice/500.
- [ ] `separateInvoice` = `'false'`, `'no'`, `0`, `'0'` → samlingsfaktura; `'True'`, `'YES'`, `1`, `'1'` → Enskild faktura.

---

## Các file/files liên quan

| File | Mục đích |
|------|----------|
| `src/Service/InvoiceService.php` | `addFromMultiOrdersIndividual()` (dòng 665) — chỗ cần sửa; `addFromMultiOrders()` (dòng 612) — tham khảo cách lấy customer channel; `getValidOrdersInvoice()` (dòng 997) |
| `src/Application/ApiBundle/Controller/InvoiceController.php` | `addFromMultiOrdersIndividual()` (dòng 109) — không cần sửa |
| `src/Application/ApiBundle/Resources/config/route/invoice.yaml` | Route `api_invoice_add_from_multi_orders_individual` |
| `src/Entity/Channel.php` | `bulkOrderDefaultCustomerId` (dòng 74) |
| `src/Service/ChannelService.php` | `generateItem()` dòng 50 — FE đọc customer mặc định của channel |
