u
This commit is contained in:
1214
src/components/article/ArticleUnifyDialog.jsx
Normal file
1214
src/components/article/ArticleUnifyDialog.jsx
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1485,7 +1485,7 @@ export default class ArticleViewLists extends PureComponent {
|
|||||||
<Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
|
<Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
|
||||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 0.5 }}>
|
<Box sx={{ display: 'flex', alignItems: 'center', gap: 0.5 }}>
|
||||||
<Typography variant="subtitle2" sx={{ fontWeight: 700, fontSize: '0.88rem' }}>
|
<Typography variant="subtitle2" sx={{ fontWeight: 700, fontSize: '0.88rem' }}>
|
||||||
Variantsvater für
|
Vater für Auswahl-Merkmal
|
||||||
</Typography>
|
</Typography>
|
||||||
<Chip
|
<Chip
|
||||||
label={articleData.parentAttributeName || parentAttrDef?.name || 'Varianten'}
|
label={articleData.parentAttributeName || parentAttrDef?.name || 'Varianten'}
|
||||||
|
|||||||
@@ -5,3 +5,4 @@ export { default as ArticleImageSearchDialog } from './ArticleImageSearchDialog'
|
|||||||
export { default as ArticleTileTab } from './ArticleTileTab';
|
export { default as ArticleTileTab } from './ArticleTileTab';
|
||||||
export { default as NewArticleTile } from './NewArticleTile';
|
export { default as NewArticleTile } from './NewArticleTile';
|
||||||
export { default as ArticleSearch } from './ArticleSearch';
|
export { default as ArticleSearch } from './ArticleSearch';
|
||||||
|
export { default as ArticleUnifyDialog } from './ArticleUnifyDialog';
|
||||||
|
|||||||
@@ -1,16 +1,53 @@
|
|||||||
import { Component } from 'react';
|
import { Component } from 'react';
|
||||||
import Box from '@mui/material/Box';
|
import Box from '@mui/material/Box';
|
||||||
import Button from '@mui/material/Button';
|
import Button from '@mui/material/Button';
|
||||||
|
import Stack from '@mui/material/Stack';
|
||||||
|
import Tooltip from '@mui/material/Tooltip';
|
||||||
import DeleteIcon from '@mui/icons-material/Delete';
|
import DeleteIcon from '@mui/icons-material/Delete';
|
||||||
|
import CallMergeIcon from '@mui/icons-material/CallMerge';
|
||||||
|
import { enqueueSnackbar } from 'notistack';
|
||||||
|
|
||||||
import { article as articleApi } from '../../../api';
|
import { article as articleApi } from '../../../api';
|
||||||
import { artikelAutomat } from '../../../automats';
|
import { artikelAutomat, getArticle } from '../../../automats';
|
||||||
import { notifyError } from '../../../utils/notify';
|
import { notifyError } from '../../../utils/notify';
|
||||||
|
import ArticleSearch from '../ArticleSearch';
|
||||||
|
import ArticleUnifyDialog from '../ArticleUnifyDialog';
|
||||||
|
|
||||||
|
export function isArticleFather(article) {
|
||||||
|
if (!article) return false;
|
||||||
|
return Boolean(
|
||||||
|
article.isParent ||
|
||||||
|
article.is_parent ||
|
||||||
|
(article.childCount ?? 0) > 0 ||
|
||||||
|
(Array.isArray(article.children) && article.children.length > 0) ||
|
||||||
|
article.parent_attribute_id != null ||
|
||||||
|
article.parentAttributeNameId != null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isArticleStueckliste(article) {
|
||||||
|
if (!article) return false;
|
||||||
|
return Boolean(
|
||||||
|
article.articlelistId != null ||
|
||||||
|
(article.articleListCount ?? 0) > 0 ||
|
||||||
|
(Array.isArray(article.articlelist) && article.articlelist.length > 0) ||
|
||||||
|
(Array.isArray(article.components) && article.components.length > 0) ||
|
||||||
|
(Array.isArray(article.stueckliste) && article.stueckliste.length > 0)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export default class ArticleSettingsTab extends Component {
|
export default class ArticleSettingsTab extends Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = { busy: false };
|
this.state = {
|
||||||
|
busy: false,
|
||||||
|
searchOpen: false,
|
||||||
|
unifyOpen: false,
|
||||||
|
targetArticle: null,
|
||||||
|
};
|
||||||
this.handleDeleteArticle = this.handleDeleteArticle.bind(this);
|
this.handleDeleteArticle = this.handleDeleteArticle.bind(this);
|
||||||
|
this.handleOpenSearch = this.handleOpenSearch.bind(this);
|
||||||
|
this.handleSelectTargetArticle = this.handleSelectTargetArticle.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
async handleDeleteArticle() {
|
async handleDeleteArticle() {
|
||||||
@@ -31,21 +68,131 @@ export default class ArticleSettingsTab extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleOpenSearch() {
|
||||||
|
const { article: articleData } = this.props;
|
||||||
|
if (isArticleFather(articleData)) {
|
||||||
|
enqueueSnackbar('Ein Vaterartikel kann nicht vereint werden.', { variant: 'warning' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (isArticleStueckliste(articleData)) {
|
||||||
|
enqueueSnackbar('Ein Stücklisten-Artikel kann nicht vereint werden.', { variant: 'warning' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.setState({ searchOpen: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
async handleSelectTargetArticle(selected) {
|
||||||
|
if (!selected?.sku) return;
|
||||||
|
this.setState({ searchOpen: false, busy: true });
|
||||||
|
try {
|
||||||
|
let fullTarget = getArticle(selected.sku);
|
||||||
|
if (!fullTarget || !fullTarget.warehouses || !fullTarget.prices) {
|
||||||
|
fullTarget = await artikelAutomat.actions.loadArticle(selected.sku);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isArticleFather(fullTarget)) {
|
||||||
|
enqueueSnackbar('Der ausgewählte Artikel ist ein Vaterartikel und kann nicht vereint werden.', {
|
||||||
|
variant: 'error',
|
||||||
|
});
|
||||||
|
this.setState({ busy: false });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isArticleStueckliste(fullTarget)) {
|
||||||
|
enqueueSnackbar('Der ausgewählte Artikel ist ein Stücklisten-Artikel und kann nicht vereint werden.', {
|
||||||
|
variant: 'error',
|
||||||
|
});
|
||||||
|
this.setState({ busy: false });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
busy: false,
|
||||||
|
targetArticle: fullTarget,
|
||||||
|
unifyOpen: true,
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
this.setState({ busy: false });
|
||||||
|
notifyError(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { busy } = this.state;
|
const { busy, searchOpen, unifyOpen, targetArticle } = this.state;
|
||||||
|
const { article: articleData } = this.props;
|
||||||
|
|
||||||
|
const isFather = isArticleFather(articleData);
|
||||||
|
const isStueckliste = isArticleStueckliste(articleData);
|
||||||
|
const cannotUnify = isFather || isStueckliste;
|
||||||
|
const unifyDisabledReason = isFather
|
||||||
|
? 'Ein Vaterartikel kann nicht vereint werden.'
|
||||||
|
: isStueckliste
|
||||||
|
? 'Ein Stücklisten-Artikel kann nicht vereint werden.'
|
||||||
|
: null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box>
|
<Box>
|
||||||
<Button
|
<Stack direction="row" spacing={1.5} alignItems="center" flexWrap="wrap">
|
||||||
type="button"
|
<Button
|
||||||
color="error"
|
type="button"
|
||||||
variant="contained"
|
color="error"
|
||||||
startIcon={<DeleteIcon />}
|
variant="contained"
|
||||||
disabled={busy}
|
startIcon={<DeleteIcon />}
|
||||||
onClick={() => void this.handleDeleteArticle()}
|
disabled={busy}
|
||||||
>
|
onClick={() => void this.handleDeleteArticle()}
|
||||||
Artikel löschen
|
>
|
||||||
</Button>
|
Artikel löschen
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
{unifyDisabledReason ? (
|
||||||
|
<Tooltip title={unifyDisabledReason}>
|
||||||
|
<span>
|
||||||
|
<Button
|
||||||
|
type="button"
|
||||||
|
color="primary"
|
||||||
|
variant="outlined"
|
||||||
|
startIcon={<CallMergeIcon />}
|
||||||
|
disabled
|
||||||
|
>
|
||||||
|
Artikel vereinen
|
||||||
|
</Button>
|
||||||
|
</span>
|
||||||
|
</Tooltip>
|
||||||
|
) : (
|
||||||
|
<Button
|
||||||
|
type="button"
|
||||||
|
color="primary"
|
||||||
|
variant="outlined"
|
||||||
|
startIcon={<CallMergeIcon />}
|
||||||
|
disabled={busy}
|
||||||
|
onClick={this.handleOpenSearch}
|
||||||
|
>
|
||||||
|
Artikel vereinen
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</Stack>
|
||||||
|
|
||||||
|
<ArticleSearch
|
||||||
|
open={searchOpen}
|
||||||
|
allowParent={false}
|
||||||
|
excludeSkus={[articleData.sku]}
|
||||||
|
title="Artikel zum Vereinen auswählen"
|
||||||
|
placeholder="Artikel suchen…"
|
||||||
|
actionLabel="Auswählen"
|
||||||
|
onClose={() => this.setState({ searchOpen: false })}
|
||||||
|
onSelect={this.handleSelectTargetArticle}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{unifyOpen && targetArticle && (
|
||||||
|
<ArticleUnifyDialog
|
||||||
|
open={unifyOpen}
|
||||||
|
articleLeft={articleData}
|
||||||
|
articleRight={targetArticle}
|
||||||
|
onClose={() => this.setState({ unifyOpen: false, targetArticle: null })}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ import DeleteSweepOutlinedIcon from '@mui/icons-material/DeleteSweepOutlined';
|
|||||||
import { PanelTile } from 'dashgui/panels';
|
import { PanelTile } from 'dashgui/panels';
|
||||||
import { LINE_COLUMNS, hasArticleLines } from './manifestConfig';
|
import { LINE_COLUMNS, hasArticleLines } from './manifestConfig';
|
||||||
import ManifestFormLine from './ManifestFormLine';
|
import ManifestFormLine from './ManifestFormLine';
|
||||||
import ArticleSearch from '../article/ArticleSearch';
|
|
||||||
|
|
||||||
class ManifestLines extends PureComponent {
|
class ManifestLines extends PureComponent {
|
||||||
render() {
|
render() {
|
||||||
@@ -23,7 +22,6 @@ class ManifestLines extends PureComponent {
|
|||||||
linesColor,
|
linesColor,
|
||||||
onLineChange,
|
onLineChange,
|
||||||
onAddLine,
|
onAddLine,
|
||||||
onAddArticleLine,
|
|
||||||
onRemoveLine,
|
onRemoveLine,
|
||||||
onRemoveAllLines,
|
onRemoveAllLines,
|
||||||
columns = LINE_COLUMNS,
|
columns = LINE_COLUMNS,
|
||||||
@@ -120,24 +118,13 @@ class ManifestLines extends PureComponent {
|
|||||||
</Table>
|
</Table>
|
||||||
</TableContainer>
|
</TableContainer>
|
||||||
<Box sx={{ display: 'flex', gap: 1.5, alignItems: 'center', flexWrap: 'wrap' }}>
|
<Box sx={{ display: 'flex', gap: 1.5, alignItems: 'center', flexWrap: 'wrap' }}>
|
||||||
{onAddArticleLine && (
|
|
||||||
<ArticleSearch
|
|
||||||
size="small"
|
|
||||||
clearOnSelect
|
|
||||||
allowParent={false}
|
|
||||||
placeholder="Artikel suchen und hinzufügen…"
|
|
||||||
disabled={saving}
|
|
||||||
onSelect={onAddArticleLine}
|
|
||||||
sx={{ minWidth: 260, flex: 1, maxWidth: 440 }}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
<Button
|
<Button
|
||||||
size="small"
|
size="small"
|
||||||
startIcon={<AddIcon />}
|
startIcon={<AddIcon />}
|
||||||
disabled={saving}
|
disabled={saving}
|
||||||
onClick={onAddLine}
|
onClick={onAddLine}
|
||||||
>
|
>
|
||||||
{onAddArticleLine ? 'Leere Zeile' : 'Zeile hinzufügen'}
|
Zeile
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
size="small"
|
size="small"
|
||||||
|
|||||||
Reference in New Issue
Block a user