u
This commit is contained in:
@@ -17,7 +17,7 @@ import artikelAutomat, { getArticle } from '../../automats/artikelAutomat';
|
||||
import entityAutomat from '../../automats/entityAutomat';
|
||||
import supplierAutomat from '../../automats/supplierAutomat';
|
||||
import companyAutomat, { selectCompanyTaxrate } from '../../automats/companyAutomat';
|
||||
import { netFromGross, getArticleGross } from '../../utils/price';
|
||||
import { netFromGross, grossFromNet, getArticleGross } from '../../utils/price';
|
||||
import {
|
||||
buildManifestBody,
|
||||
restoreAttachmentsFromApi,
|
||||
@@ -421,10 +421,11 @@ class ManifestForm extends PureComponent {
|
||||
|
||||
if (field === 'gross') {
|
||||
const taxVal = parseNum(line.tax ?? line.taxrate) ?? 0;
|
||||
const rebateVal = parseNum(line.rebate) ?? 0;
|
||||
const grossNum = parseNum(value);
|
||||
let updatedNet = line.net;
|
||||
if (grossNum != null) {
|
||||
const netNum = netFromGross(grossNum, taxVal);
|
||||
const netNum = netFromGross(grossNum, taxVal, rebateVal);
|
||||
if (netNum != null) {
|
||||
updatedNet = String(netNum);
|
||||
}
|
||||
@@ -441,11 +442,12 @@ class ManifestForm extends PureComponent {
|
||||
|
||||
if (field === 'net' || field === 'netprice') {
|
||||
const taxVal = parseNum(line.tax ?? line.taxrate) ?? 0;
|
||||
const rebateVal = parseNum(line.rebate) ?? 0;
|
||||
const netNum = parseNum(value);
|
||||
let updatedGross = line.gross;
|
||||
if (netNum != null) {
|
||||
const grossNum = Math.round((netNum * (1 + taxVal / 100) + Number.EPSILON) * 100) / 100;
|
||||
updatedGross = String(grossNum);
|
||||
const grossNum = grossFromNet(netNum, taxVal, rebateVal);
|
||||
updatedGross = grossNum != null ? String(grossNum) : '';
|
||||
} else if (value === '') {
|
||||
updatedGross = '';
|
||||
}
|
||||
@@ -460,11 +462,12 @@ class ManifestForm extends PureComponent {
|
||||
|
||||
if (field === 'tax' || field === 'taxrate') {
|
||||
const taxNum = parseNum(value) ?? 0;
|
||||
const rebateVal = parseNum(line.rebate) ?? 0;
|
||||
const netNum = parseNum(line.net ?? line.netprice);
|
||||
let updatedGross = line.gross;
|
||||
if (netNum != null) {
|
||||
const grossNum = Math.round((netNum * (1 + taxNum / 100) + Number.EPSILON) * 100) / 100;
|
||||
updatedGross = String(grossNum);
|
||||
const grossNum = grossFromNet(netNum, taxNum, rebateVal);
|
||||
updatedGross = grossNum != null ? String(grossNum) : '';
|
||||
}
|
||||
return {
|
||||
...line,
|
||||
@@ -475,6 +478,22 @@ class ManifestForm extends PureComponent {
|
||||
};
|
||||
}
|
||||
|
||||
if (field === 'rebate') {
|
||||
const rebateNum = parseNum(value) ?? 0;
|
||||
const taxVal = parseNum(line.tax ?? line.taxrate) ?? 0;
|
||||
const netNum = parseNum(line.net ?? line.netprice);
|
||||
let updatedGross = line.gross;
|
||||
if (netNum != null) {
|
||||
const grossNum = grossFromNet(netNum, taxVal, rebateNum);
|
||||
updatedGross = grossNum != null ? String(grossNum) : '';
|
||||
}
|
||||
return {
|
||||
...line,
|
||||
rebate: value,
|
||||
gross: updatedGross,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
...line,
|
||||
[field]: value,
|
||||
@@ -508,13 +527,15 @@ class ManifestForm extends PureComponent {
|
||||
: '';
|
||||
const netNum = parseNum(netVal);
|
||||
const taxNum = parseNum(taxVal);
|
||||
const rebateNum = parseNum(l.rebate) ?? 0;
|
||||
const artGross = getArticleGross(art, taxNum ?? 0);
|
||||
let grossVal = '';
|
||||
if (artGross != null) {
|
||||
if (artGross != null && rebateNum === 0) {
|
||||
grossVal = String(artGross);
|
||||
} else if (netNum != null) {
|
||||
const g = Math.round((netNum * (1 + (taxNum ?? 0) / 100) + Number.EPSILON) * 100) / 100;
|
||||
grossVal = String(g);
|
||||
grossVal = String(grossFromNet(netNum, taxNum ?? 0, rebateNum));
|
||||
} else if (artGross != null) {
|
||||
grossVal = String(Math.round((artGross * (1 - rebateNum / 100) + Number.EPSILON) * 100) / 100);
|
||||
}
|
||||
const normTax = selectCompanyTaxrate() != null ? String(selectCompanyTaxrate()) : '19';
|
||||
const finalTax =
|
||||
@@ -640,13 +661,15 @@ class ManifestForm extends PureComponent {
|
||||
: normTax;
|
||||
const netNum = parseNum(netVal);
|
||||
const taxNum = parseNum(taxVal);
|
||||
const rebateNum = parseNum(targetLine.rebate) ?? 0;
|
||||
const artGross = getArticleGross(article, taxNum ?? 0);
|
||||
let grossVal = '';
|
||||
if (artGross != null) {
|
||||
if (artGross != null && rebateNum === 0) {
|
||||
grossVal = String(artGross);
|
||||
} else if (netNum != null) {
|
||||
const g = Math.round((netNum * (1 + (taxNum ?? 0) / 100) + Number.EPSILON) * 100) / 100;
|
||||
grossVal = String(g);
|
||||
grossVal = String(grossFromNet(netNum, taxNum ?? 0, rebateNum));
|
||||
} else if (artGross != null) {
|
||||
grossVal = String(Math.round((artGross * (1 - rebateNum / 100) + Number.EPSILON) * 100) / 100);
|
||||
}
|
||||
|
||||
this.setState((prev) => ({
|
||||
|
||||
@@ -19,11 +19,13 @@ import SearchIcon from '@mui/icons-material/Search';
|
||||
import LinkOffOutlinedIcon from '@mui/icons-material/LinkOffOutlined';
|
||||
import { getFirstVal, parseNum, LINE_COLUMNS } from './manifestConfig';
|
||||
import ArticlePhoto from '../article/ArticlePhoto';
|
||||
import { formatPrice } from '../../utils/price';
|
||||
import { formatPrice, grossFromNet } from '../../utils/price';
|
||||
import { primaryPrice, priceBrutto } from '../../utils/articleDetail';
|
||||
import artikelAutomat, { createArticleSelector, getArticle } from '../../automats/artikelAutomat';
|
||||
import { artikelDetailPath } from '../article/articleRoute';
|
||||
import { BrandLabel } from '../brand';
|
||||
import { articleSupplierAutomat } from '../../automats/articleDetailAutomat';
|
||||
import { selectCompanyTaxrate } from '../../automats/companyAutomat';
|
||||
import {
|
||||
BORDER,
|
||||
} from '../../colors';
|
||||
@@ -35,6 +37,7 @@ class ManifestFormLine extends PureComponent {
|
||||
this.state = {
|
||||
cachedArticle: sku ? getArticle(sku) : null,
|
||||
loadingArticle: false,
|
||||
fallbackSuppliers: [],
|
||||
};
|
||||
this.handleRemove = this.handleRemove.bind(this);
|
||||
this.handleBlur = this.handleBlur.bind(this);
|
||||
@@ -64,14 +67,18 @@ class ManifestFormLine extends PureComponent {
|
||||
|
||||
componentWillUnmount() {
|
||||
this.unsubArticle?.();
|
||||
this.unsubSupplier?.();
|
||||
}
|
||||
|
||||
subscribeArticle(sku) {
|
||||
this.unsubArticle?.();
|
||||
this.unsubArticle = null;
|
||||
this.unsubSupplier?.();
|
||||
this.unsubSupplier = null;
|
||||
|
||||
if (!sku) {
|
||||
if (this.state.cachedArticle || this.state.loadingArticle) {
|
||||
this.setState({ cachedArticle: null, loadingArticle: false });
|
||||
if (this.state.cachedArticle || this.state.loadingArticle || this.state.fallbackSuppliers?.length) {
|
||||
this.setState({ cachedArticle: null, loadingArticle: false, fallbackSuppliers: [] });
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -99,6 +106,15 @@ class ManifestFormLine extends PureComponent {
|
||||
...(art ? { loadingArticle: false } : {}),
|
||||
};
|
||||
});
|
||||
|
||||
// Fallback: subscribe to articleSupplierAutomat if cachedArticle doesn't have suppliers
|
||||
if (!current?.suppliers?.length) {
|
||||
const supKey = articleSupplierAutomat.key(sku);
|
||||
this.unsubSupplier = supKey.subscribe(this, (item) => ({
|
||||
fallbackSuppliers: Array.isArray(item?.data) ? item.data : [],
|
||||
}));
|
||||
void articleSupplierAutomat.load(sku).catch(() => {});
|
||||
}
|
||||
}
|
||||
|
||||
handleRemove() {
|
||||
@@ -235,8 +251,9 @@ class ManifestFormLine extends PureComponent {
|
||||
} else if (id === 'gross') {
|
||||
const netNum = parseNum(line.netprice ?? line.net);
|
||||
const taxNum = parseNum(line.taxrate ?? line.tax) ?? 0;
|
||||
const rebateNum = parseNum(line.rebate) ?? 0;
|
||||
if (netNum != null) {
|
||||
val = String(Math.round((netNum * (1 + taxNum / 100) + Number.EPSILON) * 100) / 100);
|
||||
val = String(grossFromNet(netNum, taxNum, rebateNum));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -375,6 +392,41 @@ class ManifestFormLine extends PureComponent {
|
||||
: null)
|
||||
: null;
|
||||
|
||||
const suppliers =
|
||||
Array.isArray(cachedArticle.suppliers) && cachedArticle.suppliers.length > 0
|
||||
? cachedArticle.suppliers
|
||||
: (this.state.fallbackSuppliers ?? []);
|
||||
|
||||
const topSupplier =
|
||||
suppliers.find((s) => s.sort === 0) ??
|
||||
(suppliers.length > 0
|
||||
? [...suppliers].sort((a, b) => (Number(a.sort) || 0) - (Number(b.sort) || 0))[0]
|
||||
: null);
|
||||
|
||||
const ekNetto =
|
||||
topSupplier?.price?.net != null
|
||||
? Number(topSupplier.price.net)
|
||||
: topSupplier?.netPrice != null
|
||||
? Number(topSupplier.netPrice)
|
||||
: topSupplier?.net != null
|
||||
? Number(topSupplier.net)
|
||||
: null;
|
||||
|
||||
const ekTaxRate =
|
||||
topSupplier?.price?.taxRate != null
|
||||
? Number(topSupplier.price.taxRate)
|
||||
: topSupplier?.taxRate != null
|
||||
? Number(topSupplier.taxRate)
|
||||
: parseNum(this.props.line?.taxrate ?? this.props.line?.tax) ?? selectCompanyTaxrate() ?? 19;
|
||||
|
||||
const ekBrutto =
|
||||
ekNetto != null
|
||||
? Math.round((ekNetto * (1 + Number(ekTaxRate) / 100) + Number.EPSILON) * 100) / 100
|
||||
: null;
|
||||
|
||||
const hasPriceInfo =
|
||||
vkNetto != null || vkBrutto != null || ekNetto != null || ekBrutto != null || kind === 'quote';
|
||||
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
@@ -480,8 +532,8 @@ class ManifestFormLine extends PureComponent {
|
||||
</Typography>
|
||||
)}
|
||||
|
||||
{/* VK Netto & VK Brutto: omit end on 2nd line for order */}
|
||||
{!isOrder && (vkNetto != null || vkBrutto != null) && (
|
||||
{/* EK Netto, EK Brutto, VK Netto, VK Brutto */}
|
||||
{!isOrder && hasPriceInfo && (
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
@@ -491,6 +543,47 @@ class ManifestFormLine extends PureComponent {
|
||||
whiteSpace: 'nowrap',
|
||||
}}
|
||||
>
|
||||
{/* EK Netto */}
|
||||
<Tooltip
|
||||
title={
|
||||
topSupplier?.supplierName
|
||||
? `Lieferant: ${topSupplier.supplierName}${topSupplier.sku ? ` (Lief.-Art.-Nr.: ${topSupplier.sku})` : ''} (Sort: ${topSupplier.sort ?? 0})`
|
||||
: 'Kein Lieferant mit EK-Preis hinterlegt'
|
||||
}
|
||||
>
|
||||
<Typography
|
||||
variant="caption"
|
||||
fontWeight={600}
|
||||
sx={{
|
||||
color: ekNetto != null ? 'text.secondary' : 'text.disabled',
|
||||
fontSize: '0.72rem',
|
||||
}}
|
||||
>
|
||||
EK Netto: {ekNetto != null ? formatPrice(ekNetto) : '—'}
|
||||
</Typography>
|
||||
</Tooltip>
|
||||
|
||||
{/* EK Brutto */}
|
||||
<Tooltip
|
||||
title={
|
||||
topSupplier?.supplierName
|
||||
? `Lieferant: ${topSupplier.supplierName} (inkl. ${ekTaxRate}% MwSt.)`
|
||||
: 'Kein Lieferant mit EK-Preis hinterlegt'
|
||||
}
|
||||
>
|
||||
<Typography
|
||||
variant="caption"
|
||||
fontWeight={600}
|
||||
sx={{
|
||||
color: ekBrutto != null ? 'text.secondary' : 'text.disabled',
|
||||
fontSize: '0.72rem',
|
||||
}}
|
||||
>
|
||||
EK Brutto: {ekBrutto != null ? formatPrice(ekBrutto) : '—'}
|
||||
</Typography>
|
||||
</Tooltip>
|
||||
|
||||
{/* VK Netto */}
|
||||
{vkNetto != null && (
|
||||
<Typography
|
||||
variant="caption"
|
||||
@@ -500,6 +593,8 @@ class ManifestFormLine extends PureComponent {
|
||||
VK Netto: {formatPrice(vkNetto)}
|
||||
</Typography>
|
||||
)}
|
||||
|
||||
{/* VK Brutto */}
|
||||
{vkBrutto != null && (
|
||||
<Typography
|
||||
variant="caption"
|
||||
|
||||
@@ -107,12 +107,13 @@ export function lineFromApi(row) {
|
||||
const taxVal = row.taxrate != null ? String(row.taxrate) : row.tax != null ? String(row.tax) : '';
|
||||
const netNum = parseNum(netVal);
|
||||
const taxNum = parseNum(taxVal);
|
||||
const rebateNum = parseNum(row.rebate) ?? 0;
|
||||
let grossVal = '';
|
||||
if (row.gross != null && row.gross !== '') {
|
||||
grossVal = String(row.gross);
|
||||
} else if (netNum != null) {
|
||||
const rate = taxNum ?? 0;
|
||||
const g = Math.round((netNum * (1 + rate / 100) + Number.EPSILON) * 100) / 100;
|
||||
const g = Math.round((netNum * (1 + rate / 100) * (1 - rebateNum / 100) + Number.EPSILON) * 100) / 100;
|
||||
grossVal = String(g);
|
||||
}
|
||||
return {
|
||||
@@ -175,10 +176,10 @@ export function buildLines(lines, { requireAtLeastOne }) {
|
||||
const tax = parseNum(rawTax);
|
||||
const rawGross = getFirstVal(line.gross);
|
||||
const gross = parseNum(rawGross);
|
||||
if (net == null && gross != null && tax != null) {
|
||||
net = netFromGross(gross, tax);
|
||||
}
|
||||
const rebate = parseNum(getFirstVal(line.rebate));
|
||||
if (net == null && gross != null && tax != null) {
|
||||
net = netFromGross(gross, tax, rebate ?? 0);
|
||||
}
|
||||
const rawPu = getFirstVal(line.pu, line.vpe);
|
||||
const pu = parseNum(rawPu);
|
||||
const blank = !sku && !name && net == null && gross == null;
|
||||
|
||||
Reference in New Issue
Block a user