T8.6 - D6: the material list uploads the way the location list does
CR-013 accepted free text because the master workbook never arrived; the
Aug 18 call was the CR-005 call again - build the upload path now.
THE component, extracted: T5.4's paste-or-file machinery (file read in the
browser, ONE parser on the server; dry-run check; a report naming every
rejected row with its source line; an editable list that deactivates rather
than deletes) moved from the location-specific functions into
html/wp-list-import.js. The location list and the new material list are both
instances of it - the done-when's "against the same component, not beside it"
made literally true. The loc* names survive as thin delegates because row
handlers, step entry and the probes call them; locations_check re-pointed its
fetch-count assertion to where the fetches now live and still demands every
read and write reach the server.
The material list itself: description, unit, optional code - one new table
(Alembic a1b8c6d4e2f9, additive), GET/import/POST/PATCH routes on the CR-005
pattern, deactivate-never-delete, reactivation reuses the same row so nothing
referencing it orphans. The sample rows are obviously fake (SAMPLE-EMT-075).
NO inventory, price, stock or warehouse field anywhere - the probe walks the
model's columns by regex. The wizard hosts it on step 11 beside the location
list, optional by design: a project with no list still raises free-text
requests (T8.5 wires that).
Parser bug caught by the probe's first run: strip(',;') ate a LEADING comma,
so ',FT' - an empty description - was accepted as a material named FT.
rstrip only, now; the empty first column is rejected with its line number.
Verification (each probe run alone): NEW tests/materials_check.py 17/17.
Regression: locations_check 58/58 through the shared component.
Items: D6
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -12,6 +12,7 @@
|
||||
during their own boot. -->
|
||||
<script src="wp-url.js"></script>
|
||||
<script src="wp-usage.js"></script>
|
||||
<script src="wp-list-import.js"></script>
|
||||
<!-- Autosave, unsaved-work guard, draft recovery (S2). -->
|
||||
<script src="wp-autosave.js"></script>
|
||||
<!-- Which work package sections this project uses (CR-006). Shared with the
|
||||
@@ -466,6 +467,51 @@
|
||||
<div class="field-error" id="loc-add-err" role="alert"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- MATERIAL LIST (D6 / T8.6). Same component as the location list
|
||||
above (wp-list-import.js), same rules: paste or file, dry-run
|
||||
check, rejected rows named by source line, deactivate not
|
||||
delete. Description, unit, optional code - and nothing else:
|
||||
no inventory, no pricing, no warehouse id. -->
|
||||
<div style="margin-top: 2.5rem; border-top: 1px solid var(--border); padding-top: 1.5rem;">
|
||||
<div class="sub-heading">Material list (D6)</div>
|
||||
<div class="step-desc">What a material request picks from (CR-013). Optional —
|
||||
a project with no list still raises requests with free text.</div>
|
||||
<div id="mat-noproject" class="notice" style="display:none; background:var(--warning-bg); color:var(--warning);"></div>
|
||||
<div id="mat-tool">
|
||||
<div class="field-grid col1">
|
||||
<div class="field">
|
||||
<label for="mat-paste">Paste rows, or upload a CSV</label>
|
||||
<textarea id="mat-paste" rows="5" aria-describedby="mat-paste-hint"
|
||||
placeholder="One row per material, e.g. Description, unit, code"></textarea>
|
||||
<small id="mat-paste-hint">One row per material:
|
||||
<strong>description, unit, code</strong> — unit and code optional.
|
||||
Comma, semicolon or tab separated. A header row is ignored.</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="loc-actions">
|
||||
<input type="file" id="mat-file" accept=".csv,.txt,text/csv,text/plain" hidden>
|
||||
<button type="button" class="add-btn" id="mat-file-btn">Choose a CSV file…</button>
|
||||
<button type="button" class="add-btn" id="mat-check-btn">Check without importing</button>
|
||||
<button type="button" class="add-btn" id="mat-import-btn">Import</button>
|
||||
<button type="button" class="add-btn" id="mat-sample-btn">Load sample values</button>
|
||||
</div>
|
||||
<div class="loc-report" id="mat-report" role="status"></div>
|
||||
<div style="margin-top: 1.5rem;">
|
||||
<div class="sub-heading">Current list</div>
|
||||
<p class="field-hint" id="mat-count"></p>
|
||||
<div id="mat-list"></div>
|
||||
<div class="loc-addrow">
|
||||
<label class="loc-addlabel" for="mat-add-name">Description</label>
|
||||
<input type="text" id="mat-add-name" placeholder="e.g. a strut channel">
|
||||
<label class="loc-addlabel" for="mat-add-unit">Unit</label>
|
||||
<input type="text" id="mat-add-unit" placeholder="EA / FT" style="max-width:90px">
|
||||
<button type="button" class="add-btn" id="mat-add-btn">+ Add</button>
|
||||
</div>
|
||||
<div class="field-error" id="mat-add-err" role="alert"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- STEP 12: WORK PACKAGE SECTIONS (CR-006)
|
||||
|
||||
Reference in New Issue
Block a user