u
This commit is contained in:
@@ -101,7 +101,7 @@ class ArticleView extends PureComponent {
|
|||||||
article={article}
|
article={article}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<ArticleViewStock article={article} />
|
<ArticleViewStock article={article} navigate={this.props.navigate} />
|
||||||
|
|
||||||
<ArticleViewBrand article={article} />
|
<ArticleViewBrand article={article} />
|
||||||
|
|
||||||
|
|||||||
@@ -4,11 +4,13 @@ import Typography from '@mui/material/Typography';
|
|||||||
import WarehouseIcon from '@mui/icons-material/Warehouse';
|
import WarehouseIcon from '@mui/icons-material/Warehouse';
|
||||||
import EditOutlinedIcon from '@mui/icons-material/EditOutlined';
|
import EditOutlinedIcon from '@mui/icons-material/EditOutlined';
|
||||||
import LocalShippingOutlinedIcon from '@mui/icons-material/LocalShippingOutlined';
|
import LocalShippingOutlinedIcon from '@mui/icons-material/LocalShippingOutlined';
|
||||||
|
import ShoppingCartOutlinedIcon from '@mui/icons-material/ShoppingCartOutlined';
|
||||||
import Tooltip from '@mui/material/Tooltip';
|
import Tooltip from '@mui/material/Tooltip';
|
||||||
import { PanelTile } from 'dashgui/panels';
|
import { PanelTile } from 'dashgui/panels';
|
||||||
import { formatStock } from '../searchFormat';
|
import { formatStock } from '../searchFormat';
|
||||||
import ArticleStockAdjustDialog from '../ArticleStockAdjustDialog';
|
import ArticleStockAdjustDialog from '../ArticleStockAdjustDialog';
|
||||||
import artikelAutomat, { getArticle } from '../../../automats/artikelAutomat';
|
import artikelAutomat, { getArticle } from '../../../automats/artikelAutomat';
|
||||||
|
import { router } from '../../../appRouter';
|
||||||
import {
|
import {
|
||||||
GREEN_PANEL,
|
GREEN_PANEL,
|
||||||
PETROL_PANEL,
|
PETROL_PANEL,
|
||||||
@@ -96,6 +98,58 @@ function extractIncoming(articleData, isParent) {
|
|||||||
return items;
|
return items;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function extractUndeliveredOrders(articleData, isParent) {
|
||||||
|
const items = [];
|
||||||
|
|
||||||
|
const collect = (article, variantInfo = null) => {
|
||||||
|
if (!article) return;
|
||||||
|
|
||||||
|
if (Array.isArray(article.undeliveredOrders)) {
|
||||||
|
for (const ord of article.undeliveredOrders) {
|
||||||
|
const amount = Number(ord?.amount) || 0;
|
||||||
|
if (amount > 0) {
|
||||||
|
items.push({
|
||||||
|
orderId: ord.orderId,
|
||||||
|
orderNumber: ord.orderNumber || (ord.orderId ? `A-${ord.orderId}` : null),
|
||||||
|
date: ord.date || null,
|
||||||
|
customerName: ord.customerName || null,
|
||||||
|
amount,
|
||||||
|
variantSku: variantInfo?.sku || null,
|
||||||
|
variantName: variantInfo?.name || null,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
collect(articleData);
|
||||||
|
|
||||||
|
if (isParent) {
|
||||||
|
const children = Array.isArray(articleData?.children) ? articleData.children : [];
|
||||||
|
for (const child of children) {
|
||||||
|
const fullChild = getArticle(child.sku) || child;
|
||||||
|
collect(fullChild, {
|
||||||
|
sku: fullChild.sku || child.sku,
|
||||||
|
name: fullChild.name || child.name,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
items.sort((a, b) => {
|
||||||
|
if (a.date && b.date) {
|
||||||
|
const diff = new Date(a.date).getTime() - new Date(b.date).getTime();
|
||||||
|
if (diff !== 0) return diff;
|
||||||
|
} else if (a.date) {
|
||||||
|
return -1;
|
||||||
|
} else if (b.date) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return (Number(a.orderId) || 0) - (Number(b.orderId) || 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
export default class ArticleViewStock extends PureComponent {
|
export default class ArticleViewStock extends PureComponent {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
@@ -104,6 +158,17 @@ export default class ArticleViewStock extends PureComponent {
|
|||||||
};
|
};
|
||||||
this.handleOpenAdjust = this.handleOpenAdjust.bind(this);
|
this.handleOpenAdjust = this.handleOpenAdjust.bind(this);
|
||||||
this.handleCloseAdjust = this.handleCloseAdjust.bind(this);
|
this.handleCloseAdjust = this.handleCloseAdjust.bind(this);
|
||||||
|
this.handleOpenOrder = this.handleOpenOrder.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleOpenOrder(orderId, event) {
|
||||||
|
if (!orderId) return;
|
||||||
|
if (event?.metaKey || event?.ctrlKey) {
|
||||||
|
window.open(`/auftrag/bestellung/${orderId}`, '_blank');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const nav = this.props.navigate || router.navigate;
|
||||||
|
void nav(`/auftrag/bestellung/${orderId}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
@@ -205,6 +270,10 @@ export default class ArticleViewStock extends PureComponent {
|
|||||||
const totalIncoming = incomingItems.reduce((sum, inc) => sum + inc.amount, 0);
|
const totalIncoming = incomingItems.reduce((sum, inc) => sum + inc.amount, 0);
|
||||||
const hasIncoming = totalIncoming > 0;
|
const hasIncoming = totalIncoming > 0;
|
||||||
|
|
||||||
|
const undeliveredOrders = extractUndeliveredOrders(articleData, isParent);
|
||||||
|
const totalUndelivered = undeliveredOrders.reduce((sum, ord) => sum + ord.amount, 0);
|
||||||
|
const hasUndelivered = totalUndelivered > 0;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<PanelTile
|
<PanelTile
|
||||||
@@ -301,8 +370,7 @@ export default class ArticleViewStock extends PureComponent {
|
|||||||
onClick={this.handleOpenAdjust}
|
onClick={this.handleOpenAdjust}
|
||||||
sx={{
|
sx={{
|
||||||
display: 'inline-flex',
|
display: 'inline-flex',
|
||||||
alignItems: 'baseline',
|
flexDirection: 'column',
|
||||||
gap: 0.75,
|
|
||||||
my: 0.5,
|
my: 0.5,
|
||||||
cursor: 'pointer',
|
cursor: 'pointer',
|
||||||
borderRadius: 1,
|
borderRadius: 1,
|
||||||
@@ -314,6 +382,7 @@ export default class ArticleViewStock extends PureComponent {
|
|||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
<Box sx={{ display: 'inline-flex', alignItems: 'baseline', gap: 0.75 }}>
|
||||||
<Typography
|
<Typography
|
||||||
component="div"
|
component="div"
|
||||||
sx={{
|
sx={{
|
||||||
@@ -336,6 +405,7 @@ export default class ArticleViewStock extends PureComponent {
|
|||||||
</Typography>
|
</Typography>
|
||||||
) : null}
|
) : null}
|
||||||
</Box>
|
</Box>
|
||||||
|
</Box>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
) : (
|
) : (
|
||||||
<Box
|
<Box
|
||||||
@@ -374,8 +444,8 @@ export default class ArticleViewStock extends PureComponent {
|
|||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
{/* Bottom section: Per-warehouse breakdown & incoming shipments */}
|
{/* Bottom section: Per-warehouse breakdown, incoming shipments & open orders */}
|
||||||
{hasWarehouses || hasIncoming ? (
|
{hasWarehouses || hasIncoming || hasUndelivered ? (
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
mt: 1,
|
mt: 1,
|
||||||
@@ -461,12 +531,12 @@ export default class ArticleViewStock extends PureComponent {
|
|||||||
<>
|
<>
|
||||||
{incomingItems.map((inc, idx) => {
|
{incomingItems.map((inc, idx) => {
|
||||||
const dateLabel = inc.date ? formatDate(inc.date) : null;
|
const dateLabel = inc.date ? formatDate(inc.date) : null;
|
||||||
const label = [
|
const labelParts = [
|
||||||
|
inc.variantName,
|
||||||
inc.supplierName || 'Lieferant',
|
inc.supplierName || 'Lieferant',
|
||||||
dateLabel,
|
dateLabel,
|
||||||
]
|
].filter(Boolean);
|
||||||
.filter(Boolean)
|
const label = labelParts.join(' – ');
|
||||||
.join(' – ');
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
@@ -528,6 +598,89 @@ export default class ArticleViewStock extends PureComponent {
|
|||||||
})}
|
})}
|
||||||
</>
|
</>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
|
{/* Undelivered / Open Customer Orders */}
|
||||||
|
{hasUndelivered ? (
|
||||||
|
<>
|
||||||
|
{undeliveredOrders.map((ord, idx) => {
|
||||||
|
const dateLabel = ord.date ? formatDate(ord.date) : null;
|
||||||
|
const orderLabel = ord.orderNumber || (ord.orderId ? `Auftrag #${ord.orderId}` : 'Auftrag');
|
||||||
|
const labelParts = [
|
||||||
|
ord.variantName,
|
||||||
|
orderLabel,
|
||||||
|
ord.customerName,
|
||||||
|
dateLabel,
|
||||||
|
].filter(Boolean);
|
||||||
|
const label = labelParts.join(' – ');
|
||||||
|
const tooltipText = ord.orderId
|
||||||
|
? `Auftrag ${orderLabel}${ord.customerName ? ` (${ord.customerName})` : ''} öffnen`
|
||||||
|
: label;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box
|
||||||
|
key={ord.orderId ? `order-${ord.orderId}` : `ord-${idx}`}
|
||||||
|
onClick={(e) => this.handleOpenOrder(ord.orderId, e)}
|
||||||
|
title={tooltipText}
|
||||||
|
sx={{
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
py: 0.35,
|
||||||
|
px: 0.75,
|
||||||
|
borderRadius: 1,
|
||||||
|
backgroundColor: VEIL_PANEL,
|
||||||
|
cursor: ord.orderId ? 'pointer' : 'default',
|
||||||
|
transition: 'background-color 0.15s ease',
|
||||||
|
'&:hover': ord.orderId ? {
|
||||||
|
backgroundColor: TINT_ROW_HOVER,
|
||||||
|
} : undefined,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
minWidth: 0,
|
||||||
|
mr: 1,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ShoppingCartOutlinedIcon
|
||||||
|
sx={{
|
||||||
|
fontSize: 15,
|
||||||
|
color: 'text.secondary',
|
||||||
|
mr: 0.6,
|
||||||
|
flexShrink: 0,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Typography
|
||||||
|
variant="body2"
|
||||||
|
noWrap
|
||||||
|
sx={{
|
||||||
|
fontWeight: 500,
|
||||||
|
fontSize: '0.82rem',
|
||||||
|
color: 'text.primary',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{label}
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
<Typography
|
||||||
|
variant="body2"
|
||||||
|
sx={{
|
||||||
|
fontWeight: 700,
|
||||||
|
fontSize: '0.82rem',
|
||||||
|
flexShrink: 0,
|
||||||
|
color: 'text.primary',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
-{formatStock(ord.amount)}
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</>
|
||||||
|
) : null}
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
) : null}
|
) : null}
|
||||||
|
|||||||
Reference in New Issue
Block a user