Nem mérendő tételnél a súly mindig származtatott, a kliens és a szerver azonos képlettel

- recalcWeights: megszűnt a "csak ha üres" feltétel — a rekeszszám módosítása újraszámol, és az AI kiolvasott
  súlyát is felülírja
- A kliens képlete a szerverével azonos: ceil(Pallets) x raklapsúly, a dokumentum raklapszáma helyett (az az
  AI-tól mindig 1); a tűrés a keret PalletTolerance konstansából jön, nem kézzel írt epszilonból
- selectProduct: a termékkel jön a tare, az averageWeight és az isMeasurable is — eddig csak a cratesPerPallet
  másolódott át, ezért termékcsere vagy kézzel felvett sor után a számítás némán kilépett
- A súlymezők nem mérendő terméknél írásvédettek: ha mindig számolunk, a szerkeszthető mező hazudik
- CreateShippingItem: már a kiolvasáskor a törzsadatból számol, nem csak mentéskor — eddig az admin az AI
  számát látta, a mentés pedig csendben mást írt ki
This commit is contained in:
2026-08-20 21:17:23 +02:00
parent b5e57ce659
commit a794293d99
2 changed files with 51 additions and 9 deletions
@@ -721,6 +721,18 @@ namespace Nop.Plugin.Misc.FruitBank.Controllers
// A raklapigény a rekeszszámból; a szállítólevél raklapszáma (mindig 1) csak becslés. Az admin felülírhatja.
shippingItem.Pallets = ShippingCapacityHelper.CalculatePallets(shippingItem);
// Nem mérendőnél a súly a törzsadatból következik, ezért az AI kiolvasott súlyát MÁR ITT eldobjuk —
// ugyanazzal a képlettel, amit a mentés is használ. Enélkül az admin a kiolvasáson még az AI számát
// látná, a mentés pedig csendben mást írna ki (FBANKAPP ADR 0001; Adam, 2026-08-16).
if (!productDto.IsMeasurable)
{
shippingItem.GrossWeightOnDocument =
ShippingCapacityHelper.CeilPallets(shippingItem.Pallets) * FruitBankConstClient.PalletWeightKg
+ shippingItem.QuantityOnDocument * (productDto.Tare + productDto.AverageWeight);
shippingItem.NetWeightOnDocument = shippingItem.QuantityOnDocument * productDto.AverageWeight;
}
return shippingItem;
}
@@ -712,11 +712,11 @@
</div>
<div>
<label>Nettó súly (kg) ${weightHint(item, item.netWeightOnDocument)}</label>
<input type="number" step="0.01" class="form-control form-control-sm ${weightClass(item, item.netWeightOnDocument)}" value="${item.netWeightOnDocument ? item.netWeightOnDocument.toFixed(2) : '0.00'}" data-field="netWeightOnDocument" data-index="${index}">
<input type="number" step="0.01" class="form-control form-control-sm ${weightClass(item, item.netWeightOnDocument)}" value="${item.netWeightOnDocument ? item.netWeightOnDocument.toFixed(2) : '0.00'}" data-field="netWeightOnDocument" data-index="${index}" ${isDerivedWeight(item) ? 'readonly title="Nem mérendő termék: a súly a törzsadatból számolódik, kézzel nem írható. A mentés is ezt írja ki."' : ''}>
</div>
<div>
<label>Bruttó súly (kg) ${weightHint(item, item.grossWeightOnDocument)}</label>
<input type="number" step="0.01" class="form-control form-control-sm ${weightClass(item, item.grossWeightOnDocument)}" value="${item.grossWeightOnDocument ? item.grossWeightOnDocument.toFixed(2) : '0.00'}" data-field="grossWeightOnDocument" data-index="${index}">
<input type="number" step="0.01" class="form-control form-control-sm ${weightClass(item, item.grossWeightOnDocument)}" value="${item.grossWeightOnDocument ? item.grossWeightOnDocument.toFixed(2) : '0.00'}" data-field="grossWeightOnDocument" data-index="${index}" ${isDerivedWeight(item) ? 'readonly title="Nem mérendő termék: a súly a törzsadatból számolódik, kézzel nem írható. A mentés is ezt írja ki."' : ''}>
</div>
<div>
<label>Egységár</label>
@@ -781,7 +781,9 @@
}
// A súlyok azonnal, MENTÉS ELŐTT álljanak elő — az admin eddig csak mentés után látta őket.
if (['palletsOnDocument', 'quantityOnDocument', 'netWeightOnDocument', 'grossWeightOnDocument'].includes(field))
// A képlet bemenetei a rekeszszám és a raklapszám; a súly-mezők maguk nem váltanak ki számolást
// (nem mérendőnél amúgy is írásvédettek, mérendőnél pedig nincs mit számolni).
if (['palletsOnDocument', 'quantityOnDocument', 'pallets'].includes(field))
recalcWeights(idx);
});
});
@@ -797,6 +799,7 @@
/* Teljesen minősítve: a plugin nézeteinek nincs `@@using FruitBank.Common`-ja, és a .cshtml FUTÁSIDŐBEN
fordul — egy hiányzó névtér itt nem build-hibaként, hanem az oldal megnyitásakor csap le. */
var PALLET_WEIGHT_KG = @FruitBank.Common.FruitBankConstClient.PalletWeightKg;
var PALLET_TOLERANCE = @FruitBank.Common.Helpers.ShippingCapacityHelper.PalletTolerance;
/* MÉRENDŐ terméknél a 0 súly HIÁNYZÓ ADAT, nem nulla: a dokumentumon kötelezően szerepel, az adminnak
kézzel kell kikeresnie. Ezért pirosan jelöljük — nem tudjuk és nem is szabad kiszámolni helyette. */
@@ -813,6 +816,16 @@
return (value > 0) ? '<small class="text-muted">(számított)</small>' : '';
}
/* NEM MÉRENDŐ terméknél a súly MINDIG származtatott: a törzsadatból következik, és az megbízhatóbb, mint egy
szállítólevélről kiolvasott szám (FBANKAPP ADR 0001; Adam, 2026-08-16). Ezért nincs „csak ha üres" feltétel —
a rekeszszám módosítása újraszámol, és az AI kiolvasott súlyát is felülírja.
A képlet SZÓ SZERINT a szerverével azonos (FileManagerController mentési ág):
bruttó = ceil(Pallets) × raklapsúly + rekesz × (tára + átlagsúly)
nettó = rekesz × átlagsúly
A raklapsúly a FELKEREKÍTETT raklapszámra jár (a másfél raklapos áru két fizikai raklapon áll), és NEM a
dokumentum raklapszámára — az az AI-tól mindig 1. Korábban a kliens ezzel a két ponton is mást számolt,
mint amit a mentés kiírt. */
function recalcWeights(idx) {
var item = shippingItems[idx];
if (!item || item.isMeasurable) { renderShippingItems(); return; }
@@ -822,15 +835,24 @@
var crates = item.quantityOnDocument || 0;
if (tare <= 0 && avg <= 0) { renderShippingItems(); return; } // nincs termék-törzsadat, nincs miből
if (!(item.grossWeightOnDocument > 0))
item.grossWeightOnDocument = Math.round(((item.palletsOnDocument || 0) * PALLET_WEIGHT_KG + crates * (tare + avg)) * 100) / 100;
if (!(item.netWeightOnDocument > 0))
item.netWeightOnDocument = Math.round((crates * avg) * 100) / 100;
item.grossWeightOnDocument = Math.round((ceilPallets(item.pallets) * PALLET_WEIGHT_KG + crates * (tare + avg)) * 100) / 100;
item.netWeightOnDocument = Math.round((crates * avg) * 100) / 100;
renderShippingItems();
}
/* A ShippingCapacityHelper.CeilPallets párja. A tűrés a keretből jön: a helper kimondja, hogy minden tört
raklapszám-összehasonlítás AZT használja, saját epszilont ne írjunk helyette. */
function ceilPallets(pallets) {
return (pallets > 0) ? Math.ceil(pallets - PALLET_TOLERANCE) : 0;
}
/* Igaz, ha a súly SZÁMÍTOTT, tehát kézzel nem írható: nem mérendő termék, amihez van súly-törzsadat.
Törzsadat híján a mező szerkeszthető marad, különben az admin nem tudná pótolni a hiányt. */
function isDerivedWeight(item) {
return !item.isMeasurable && ((item.tare || 0) > 0 || (item.averageWeight || 0) > 0);
}
function addNewShippingItem() {
shippingItems.push({
name: '', hungarianName: '', nameOnDocument: '', productId: null,
@@ -981,11 +1003,19 @@
// és eltűnik a „nincs rekesz/raklap arány" jelzés (ADR 0004-M9F3). Ha a terméken nincs kitöltve,
// a jelzés marad, a mező pedig kézzel írható.
cratesPerPallet,
// A mérendőség és a súly-törzsadat IS a termékkel jön — a keresőt szolgáló végpont kifejezetten
// ezért küldi. Enélkül a nem mérendő tétel súlya nem számolódna: a recalcWeights azt látná, hogy
// „nincs termék-törzsadat", és némán kilépne.
isMeasurable: product.isMeasurable ?? shippingItems[itemIndex].isMeasurable ?? false,
tare: product.tare ?? 0,
averageWeight: product.averageWeight ?? 0,
pallets: cratesPerPallet > 0 && quantity > 0
? Math.round(quantity / cratesPerPallet * 1000) / 1000
: shippingItems[itemIndex].pallets
};
renderShippingItems();
// A termékváltás új törzsadatot hoz — a súlynak azonnal követnie kell.
recalcWeights(itemIndex);
showMessage(prev ? `Termék módosítva: ${name}` : `Termék párosítva: ${name}`, prev ? 'info' : 'success');
}