feat(ui): order totals, decimals, mobile modal cards, set editing

- Dashboard/Logs: Total column with 2 decimals (order_total)
- Order detail modal: totals summary row (items total + order total)
- Order detail modal mobile: compact article cards (d-md-none)
- Mappings: openEditModal loads all CODMATs for SKU, saveMapping
  replaces entire set via delete-all + batch POST
- Add project-specific team agents: ui-templates, ui-js, ui-verify,
  backend-api
- CLAUDE.md: mandatory preview approval before implementation,
  fix-loop after verification, server must start via start.sh

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Claude Agent
2026-03-15 21:55:58 +00:00
parent ac8a01eb3e
commit 137c4a8b0b
11 changed files with 438 additions and 41 deletions

View File

@@ -276,23 +276,50 @@ function clearAddForm() {
addCodmatLine();
}
function openEditModal(sku, codmat, cantitate, procent) {
async function openEditModal(sku, codmat, cantitate, procent) {
editingMapping = { sku, codmat };
document.getElementById('addModalTitle').textContent = 'Editare Mapare';
document.getElementById('inputSku').value = sku;
document.getElementById('inputSku').readOnly = false;
document.getElementById('inputSku').readOnly = true;
document.getElementById('pctWarning').style.display = 'none';
const container = document.getElementById('codmatLines');
container.innerHTML = '';
addCodmatLine();
// Pre-fill the CODMAT line
const line = container.querySelector('.codmat-line');
if (line) {
line.querySelector('.cl-codmat').value = codmat;
line.querySelector('.cl-cantitate').value = cantitate;
line.querySelector('.cl-procent').value = procent;
try {
// Fetch all CODMATs for this SKU
const res = await fetch(`/api/mappings?search=${encodeURIComponent(sku)}&per_page=100`);
const data = await res.json();
const allMappings = (data.mappings || []).filter(m => m.sku === sku && !m.sters);
if (allMappings.length === 0) {
// Fallback to single line with passed values
addCodmatLine();
const line = container.querySelector('.codmat-line');
if (line) {
line.querySelector('.cl-codmat').value = codmat;
line.querySelector('.cl-cantitate').value = cantitate;
line.querySelector('.cl-procent').value = procent;
}
} else {
for (const m of allMappings) {
addCodmatLine();
const lines = container.querySelectorAll('.codmat-line');
const line = lines[lines.length - 1];
line.querySelector('.cl-codmat').value = m.codmat;
line.querySelector('.cl-cantitate').value = m.cantitate_roa;
line.querySelector('.cl-procent').value = m.procent_pret;
}
}
} catch (e) {
// Fallback on error
addCodmatLine();
const line = container.querySelector('.codmat-line');
if (line) {
line.querySelector('.cl-codmat').value = codmat;
line.querySelector('.cl-cantitate').value = cantitate;
line.querySelector('.cl-procent').value = procent;
}
}
new bootstrap.Modal(document.getElementById('addModal')).show();
@@ -395,17 +422,38 @@ async function saveMapping() {
let res;
if (editingMapping) {
// Edit mode: use PUT /api/mappings/{old_sku}/{old_codmat}/edit
res = await fetch(`/api/mappings/${encodeURIComponent(editingMapping.sku)}/${encodeURIComponent(editingMapping.codmat)}/edit`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
new_sku: sku,
new_codmat: mappings[0].codmat,
cantitate_roa: mappings[0].cantitate_roa,
procent_pret: mappings[0].procent_pret
})
});
if (mappings.length === 1) {
// Single CODMAT edit: use existing PUT endpoint
res = await fetch(`/api/mappings/${encodeURIComponent(editingMapping.sku)}/${encodeURIComponent(editingMapping.codmat)}/edit`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
new_sku: sku,
new_codmat: mappings[0].codmat,
cantitate_roa: mappings[0].cantitate_roa,
procent_pret: mappings[0].procent_pret
})
});
} else {
// Multi-CODMAT set: delete all existing then create new batch
const existRes = await fetch(`/api/mappings?search=${encodeURIComponent(editingMapping.sku)}&per_page=100`);
const existData = await existRes.json();
const existing = (existData.mappings || []).filter(m => m.sku === editingMapping.sku && !m.sters);
// Delete each existing CODMAT
for (const m of existing) {
await fetch(`/api/mappings/${encodeURIComponent(m.sku)}/${encodeURIComponent(m.codmat)}`, {
method: 'DELETE'
});
}
// Create new batch
res = await fetch('/api/mappings/batch', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ sku, mappings })
});
}
} else if (mappings.length === 1) {
res = await fetch('/api/mappings', {
method: 'POST',