# Core Edit — TODO / Pending Fixes

---

## [TODO] pdf_vinci.modules.php — tabela BOM/consumption niezgodna z MO lines

**Plik:** `htdocs/core/modules/mrp/doc/pdf_vinci.modules.php`  
**Data odkrycia:** 2026-03-29  
**Status:** Do naprawy — czeka na zgodę

### Problem

Szablon w pętli renderującej tabelę komponentów (linie BOM) iteruje po `$bom->lines` zamiast po `$object->lines` (aktualnych liniach MO).

```php
// AKTUALNY KOD (błędny):
$bom = new BOM($this->db);
$bom->fetch($object->fk_bom);
$nblines = count($bom->lines);

for ($i = 0; $i < $nblines; $i++) {
    $prod = new Product($this->db);
    $prod->fetch($bom->lines[$i]->fk_product);
    $qty    = $bom->lines[$i]->qty;
    $qtytot = $object->qty * $bom->lines[$i]->qty;
    $dim    = implode("x", [$prod->length, $prod->width, $prod->height]);
}
```

### Efekty

| Co widzisz w PDF | Skąd | Co powinno być |
|---|---|---|
| `2940x1900x2` | wymiary produktu z BOM | wymiary z linii MO (consumption) |
| `Qty: 1` trzy razy | `bom->lines[i]->qty` | faktyczna qty z `$object->lines` |
| `Qty Total: 10` | `$object->qty × bom_qty` | ilość z consumption |
| 3 linie (w tym operacja) | wszystkie linie BOM | tylko materiały z MO |

Gdy qty w liniach MO jest ręcznie zmieniona, BOM pozostaje niezmieniony — PDF pokazuje dane historyczne z BOM, nie bieżące z consumption.

### Proponowana naprawa

Zmienić pętlę tak, żeby iterowała po `$object->lines` z filtrowaniem wierszy typu `TYPE_PRODUCT` (pomijanie operacji jak FM7). Qty i wymiary pobierać z linii MO, nie z BOM.

### Wymagana zgoda przed edycją

Plik należy do core Dolibarr — zgodnie z [CORE_EDIT_RULES.md](CORE_EDIT_RULES.md) wymagana jest wyraźna zgoda użytkownika przed pierwszą modyfikacją.

---

## [TODO] productionrules — pole Material: `REFxQTY` → prefill linii MO

**Moduł:** `custom/productionrules`  
**Dotknięte pliki:** tylko custom (chyba że wybrana zostanie Opcja B — PHP w `mo_production.php`)  
**Data:** 2026-03-29  
**Status:** Do implementacji — czeka na start

---

### Cel

Użytkownik wpisuje w pole **Material** wartości w formacie `62133x5, 61111x5`.  
Przy tworzeniu MO z tego flow te wartości mają automatycznie prefillować linie consumption (`$object->lines`) zamiast pobierać je z BOM.

---

### Zasada: BOM pozostaje niezmieniony

BOM tworzy się normalnie z komponentów SO ruleset — flow istniejący bez zmian.  
`material_packs` **nie trafia** do linii BOM. Służy wyłącznie do późniejszego prefillowania MO.

---

### Gdzie jest `material_packs` teraz

W `productionrules_rules.php` i `class/productionrules.class.php`:
- odczytywany jako `GETPOST('bom_raw_ref')` (format: `62133` lub `62133x5`)
- walidowany i parsowany podczas preview/confirm akcji `generate_bom`
- używany do tworzenia linii BOM SF (materiał), ale bez trwałego mapowania pod prefill MO
- trafia do notatek BOM (informacyjnie), jednak brak dedykowanego storage pod `mo_production.php`

---

### Proponowana architektura

#### Krok 1 — Parser `pr_parse_material_packs()`

Nowa funkcja w `class/productionrules.class.php`:

```php
function pr_parse_material_packs(string $raw): array
{
    // "62133x5, 61111x5" → [['ref'=>'62133','qty'=>5], ['ref'=>'61111','qty'=>5]]
    $out = [];
    foreach (preg_split('/[,;\s]+/', trim($raw)) as $token) {
        if (preg_match('/^([A-Za-z0-9\-]+)[xX×](\d+(?:\.\d+)?)$/', trim($token), $m)) {
            $out[] = ['ref' => $m[1], 'qty' => (float) $m[2]];
        }
    }
    return $out;
}
```

#### Krok 2 — Nowa tabela `llx_prod_mo_material_overrides`

```sql
-- custom/productionrules/sql/llx_prod_mo_material_overrides.sql
CREATE TABLE llx_prod_mo_material_overrides (
    rowid         INT AUTO_INCREMENT PRIMARY KEY,
    entity        INT NOT NULL DEFAULT 1,
    fk_bom        INT NOT NULL,      -- powiązanie z BOM tworzonym przez generate_bom
    fk_product    INT NOT NULL,      -- produkt wyszukany po ref z tokenu
    qty           DOUBLE NOT NULL DEFAULT 1,
    pos           INT NOT NULL DEFAULT 0,
    datec         DATETIME,
    fk_user_creat INT
);
```

#### Krok 3 — Zapis overrides przy `generate_bom`

W `productionrules_rules.php` po udanym `$prodRules->generateBomForRuleset(...)` oraz w `class/productionrules.class.php` (tam gdzie znamy finalne `fk_bom`):  
zapisujemy sparsowane packi do `llx_prod_mo_material_overrides` jako źródło prawdy dla prefill MO.

#### Krok 4 — Prefill linii MO

**Opcja A — JS (bez core edit, zalecana na start):**
- Nowy endpoint `ajax/get_mo_material_overrides.php` (POST: `fk_bom`) → zwraca JSON z listą `[{fk_product, ref, qty}]`
- Skrypt JS modułu ładowany na stronie MO: jeśli `fk_bom` ustawione → wywołaj AJAX → podmień qty/ref w liniach consumption w DOM
- Działa tylko w przeglądarce; nie wpływa na API

**Opcja B — PHP w `mo_production.php` (core edit, wymaga zgody):**
- Przy inicjalizacji MO z BOM → zapytaj o overrides → wstrzyknij do `$object->lines` przed renderem
- Solidniejsze, działa też przez API
- Wymaga wyraźnej zgody per [CORE_EDIT_RULES.md](CORE_EDIT_RULES.md) przed edycją

---

### Kolejność wdrożenia

1. `pr_parse_material_packs()` → `class/productionrules.class.php`
2. SQL `llx_prod_mo_material_overrides.sql` + autorun migracja (jak `planning_migrate.php`)
3. Zapis overrides w akcji `generate_bom`
4. Endpoint `ajax/get_mo_material_overrides.php`
5. JS prefill (Opcja A) **lub** uzyskać zgodę + wdrożyć `mo_production.php` (Opcja B)

---

### Decyzja do podjęcia przed startem

Opcja A (JS tylko przeglądarka) czy Opcja B (PHP w core)?  
Jeśli B — wymagana wyraźna zgoda per [CORE_EDIT_RULES.md](CORE_EDIT_RULES.md).

---

## Notka testowa — Virtual stock (ważne)

- Przy testach flow `productionrules` zawsze najpierw sprawdź otwarte SO/MO dla testowanych FG.
- Ujemny `stock_theorique` (Virtual stock) może wynikać z aktywnego popytu, nawet gdy BOM/MO logicznie działa poprawnie.
- Potwierdzony przypadek z 2026-03-29: po zamknięciu/usunięciu otwartych SO wartości virtual stock wróciły do oczekiwanych poziomów.

---
