This commit is contained in:
seb
2026-10-28 00:08:45 +01:00
parent fab291f68e
commit 96d0ae6742
88 changed files with 3871 additions and 5334 deletions

View File

@@ -37,7 +37,7 @@ import {
} from '../../utils/deliveryLedger';
import { formatStock } from '../article/searchFormat';
import artikelAutomat, { getArticle } from '../../automats/artikelAutomat';
import warehouseAutomat from '../../automats/warehouseAutomat';
import companyAutomat from '../../automats/companyAutomat';
import { supplier as supplierApi } from '../../api';
import deliveryEditorAutomat, { buildSupplierArticlesMap } from '../../automats/deliveryEditorAutomat';
import {
@@ -65,7 +65,7 @@ export default class BookDeliveryDialog extends PureComponent {
}
}
const initialWarehouses = warehouseAutomat.state.warehouses || [];
const initialWarehouses = companyAutomat.state.warehouses || [];
const initialSupplierMap =
props.supplierArticlesMap ||
(deliveryEditorAutomat?.state?.supplierArticlesMap ?? {});
@@ -107,7 +107,7 @@ export default class BookDeliveryDialog extends PureComponent {
}
componentDidMount() {
this.unsubWarehouse = warehouseAutomat.subscribe((state) => {
this.unsubWarehouse = companyAutomat.subscribe((state) => {
const warehouses = state.warehouses || [];
this.setState((prev) => {
const selectedId =
@@ -118,11 +118,11 @@ export default class BookDeliveryDialog extends PureComponent {
selectedWarehouseId: selectedId,
};
});
});
}, ['warehouses']);
this.unsubArticle = artikelAutomat.subscribe(() => {
this.forceUpdate();
});
void warehouseAutomat.actions.load().catch(() => { });
void companyAutomat.actions.loadWarehouses().catch(() => { });
this.loadSupplierArticlesIfNeeded();
if (this.props.open) {
@@ -205,7 +205,7 @@ export default class BookDeliveryDialog extends PureComponent {
componentDidUpdate(prevProps) {
if (this.props.open && !prevProps.open) {
const currentWarehouses = this.state.warehouses || warehouseAutomat.state.warehouses || [];
const currentWarehouses = this.state.warehouses || companyAutomat.state.warehouses || [];
const currentSupplierMap =
this.props.supplierArticlesMap ||
(deliveryEditorAutomat?.state?.supplierArticlesMap ?? this.state.supplierArticlesMap ?? {});
@@ -225,7 +225,7 @@ export default class BookDeliveryDialog extends PureComponent {
supplierArticlesMap: currentSupplierMap,
},
() => {
void warehouseAutomat.actions.load().catch(() => { });
void companyAutomat.actions.loadWarehouses().catch(() => { });
this.loadSupplierArticlesIfNeeded();
if (this.props.summary) {
this.initAmountsFromSummary(this.props.summary, this.props.prefillLineId);

View File

@@ -23,7 +23,7 @@ import FillSpace from 'dashgui/FillSpace';
import { PanelTile, PanelTileGrid } from 'dashgui/panels';
import BackendError from '../BackendError';
import deliveryAutomat, { CHUNK_SIZE } from '../../automats/deliveryAutomat';
import numberAutomat from '../../automats/numberAutomat';
import companyAutomat from '../../automats/companyAutomat';
import { delivery as deliveryApi } from '../../api';
import { backendErrorFrom } from '../../utils/backendError';
import { notifyError } from '../../utils/notify';
@@ -693,11 +693,15 @@ export class DeliveryList extends PureComponent {
supplierId: deliveryAutomat.state.supplierId ?? null,
});
}
this.unsubNumber = numberAutomat.subscribe(this, () => {
this.headerItem = createDummyTestDelivery();
this.forceUpdate();
});
void numberAutomat.actions.ensureLoaded().catch(() => { });
this.unsubNumber = companyAutomat.subscribe(
this,
() => {
this.headerItem = createDummyTestDelivery();
this.forceUpdate();
},
['numbers'],
);
void companyAutomat.actions.ensureNumbersLoaded().catch(() => { });
void this.loadSuppliers();
}

View File

@@ -17,12 +17,9 @@ import OrderDocumentsTiles from './OrderDocumentsTiles';
import OrderShipmentDialog from './OrderShipmentDialog';
import artikelAutomat, { getArticle } from '../../automats/artikelAutomat';
import entityAutomat from '../../automats/entityAutomat';
import customergroupAutomat from '../../automats/customergroupAutomat';
import supplierAutomat from '../../automats/supplierAutomat';
import orderAutomat from '../../automats/orderAutomat';
import retoureAutomat from '../../automats/retoureAutomat';
import companyAutomat, { selectCompanyTaxrate } from '../../automats/companyAutomat';
import warehouseAutomat from '../../automats/warehouseAutomat';
import sseAutomat from '../../automats/sseAutomat';
import OrderLedgerPanel from './OrderLedgerPanel';
import { fetchOrderLedgerEntries } from '../../utils/orderLedger';
@@ -67,15 +64,15 @@ class ManifestForm extends PureComponent {
constructor(props) {
super(props);
this.cfg = manifestConfig(props.kind);
const groups = customergroupAutomat.state.items ?? [];
const groups = companyAutomat.state.customergroups ?? [];
const initialParties = props.kind === 'delivery'
? (supplierAutomat.state.status === 'ready' ? (supplierAutomat.state.suppliers ?? []) : [])
? (companyAutomat.state.suppliersStatus === 'ready' ? (companyAutomat.state.suppliers ?? []) : [])
: (entityAutomat.state.status === 'ready'
? filterNonSupplierEntities(entityAutomat.state.items ?? [], groups)
: []);
const partiesReady = props.kind === 'delivery'
? supplierAutomat.state.status === 'ready'
: (entityAutomat.state.status === 'ready' && customergroupAutomat.state.status === 'ready');
? companyAutomat.state.suppliersStatus === 'ready'
: (entityAutomat.state.status === 'ready' && companyAutomat.state.customergroupsStatus === 'ready');
this.draftAutomat = props.mode === 'create' ? getManifestDraftAutomat(props.kind) : null;
this.editAutomat = props.mode === 'edit' ? getManifestEditAutomat(props.kind) : null;
@@ -184,64 +181,69 @@ class ManifestForm extends PureComponent {
componentDidMount() {
this._cancelled = false;
if (this.props.kind === 'delivery') {
this.unsubParties = supplierAutomat.subscribe(this, (state) => ({
parties: state.status === 'ready' ? (state.suppliers ?? []) : [],
partiesLoading: state.status === 'loading',
}));
} else {
const updateParties = () => {
const syncPartiesFromState = () => {
if (this.props.kind === 'delivery') {
this.setState({
parties: companyAutomat.state.suppliersStatus === 'ready' ? (companyAutomat.state.suppliers ?? []) : [],
partiesLoading: companyAutomat.state.suppliersStatus === 'loading',
});
} else {
const entities = entityAutomat.state.items ?? [];
const groups = customergroupAutomat.state.items ?? [];
const groups = companyAutomat.state.customergroups ?? [];
this.setState({
parties: filterNonSupplierEntities(entities, groups),
partiesLoading:
entityAutomat.state.status === 'loading' ||
customergroupAutomat.state.status === 'loading',
companyAutomat.state.customergroupsStatus === 'loading',
});
};
}
};
if (this.props.kind !== 'delivery') {
this.unsubParties = entityAutomat.subscribe(this, () => {
updateParties();
syncPartiesFromState();
return null;
});
this.unsubGroups = customergroupAutomat.subscribe(this, () => {
updateParties();
return null;
});
void customergroupAutomat.actions.ensureLoaded();
void companyAutomat.actions.ensureCustomergroupsLoaded();
}
if (companyAutomat.state.status === 'idle') {
void companyAutomat.actions.load();
}
this.unsubCompany = companyAutomat.subscribe(this, (state) => {
const taxrate = state.current?.taxrate;
if (taxrate != null) {
this.setState((prev) => {
if (
prev.lines.length === 1 &&
!prev.lines[0].sku &&
!prev.lines[0].name &&
!prev.lines[0].net &&
prev.lines[0].tax !== String(taxrate)
) {
return {
lines: [
{
...prev.lines[0],
tax: String(taxrate),
taxrate: String(taxrate),
},
],
};
}
return null;
});
}
});
this.unsubCompany = companyAutomat.subscribe(
this,
(state) => {
syncPartiesFromState();
const taxrate = state.current?.taxrate;
if (taxrate != null) {
this.setState((prev) => {
if (
prev.lines.length === 1 &&
!prev.lines[0].sku &&
!prev.lines[0].name &&
!prev.lines[0].net &&
prev.lines[0].tax !== String(taxrate)
) {
return {
lines: [
{
...prev.lines[0],
tax: String(taxrate),
taxrate: String(taxrate),
},
],
};
}
return null;
});
}
return null;
},
['current', 'suppliers', 'suppliersStatus', 'customergroups', 'customergroupsStatus'],
);
if (warehouseAutomat.state.status === 'idle') {
void warehouseAutomat.actions.load();
if (companyAutomat.state.warehousesStatus === 'idle') {
void companyAutomat.actions.loadWarehouses();
}
if (this.props.mode === 'edit') {
@@ -304,32 +306,29 @@ class ManifestForm extends PureComponent {
if (prevProps.kind !== this.props.kind) {
this.cfg = manifestConfig(this.props.kind);
this.unsubParties?.();
this.unsubGroups?.();
this.unsubParties = null;
if (this.props.kind === 'delivery') {
this.unsubParties = supplierAutomat.subscribe(this, (state) => ({
parties: state.status === 'ready' ? (state.suppliers ?? []) : [],
partiesLoading: state.status === 'loading',
}));
this.setState({
parties: companyAutomat.state.suppliersStatus === 'ready' ? (companyAutomat.state.suppliers ?? []) : [],
partiesLoading: companyAutomat.state.suppliersStatus === 'loading',
});
} else {
const updateParties = () => {
const entities = entityAutomat.state.items ?? [];
const groups = customergroupAutomat.state.items ?? [];
const groups = companyAutomat.state.customergroups ?? [];
this.setState({
parties: filterNonSupplierEntities(entities, groups),
partiesLoading:
entityAutomat.state.status === 'loading' ||
customergroupAutomat.state.status === 'loading',
companyAutomat.state.customergroupsStatus === 'loading',
});
};
this.unsubParties = entityAutomat.subscribe(this, () => {
updateParties();
return null;
});
this.unsubGroups = customergroupAutomat.subscribe(this, () => {
updateParties();
return null;
});
void customergroupAutomat.actions.ensureLoaded();
updateParties();
void companyAutomat.actions.ensureCustomergroupsLoaded();
}
}

View File

@@ -25,9 +25,7 @@ import {
} from './manifestConfig';
import { notifyError, notifyErrorMessage } from '../../utils/notify';
import entityAutomat from '../../automats/entityAutomat';
import customergroupAutomat from '../../automats/customergroupAutomat';
import supplierAutomat from '../../automats/supplierAutomat';
import numberAutomat from '../../automats/numberAutomat';
import companyAutomat from '../../automats/companyAutomat';
import quoteAutomat from '../../automats/quoteAutomat';
import orderAutomat from '../../automats/orderAutomat';
import deliveryAutomat from '../../automats/deliveryAutomat';
@@ -42,7 +40,7 @@ class ManifestHeader extends PureComponent {
const selected =
(props.parties || []).find((row) => row.id === props.partyId) ??
(props.kind === 'delivery'
? (supplierAutomat.state.suppliers || []).find((row) => row.id === props.partyId)
? (companyAutomat.state.suppliers || []).find((row) => row.id === props.partyId)
: (entityAutomat.state.items || []).find((row) => row.id === props.partyId)) ??
null;
this.state = {
@@ -68,7 +66,7 @@ class ManifestHeader extends PureComponent {
(this.props.parties || []).find((row) => row.id === this.props.partyId) ??
(this.state.createdParty?.id === this.props.partyId ? this.state.createdParty : null) ??
(this.props.kind === 'delivery'
? (supplierAutomat.state.suppliers || []).find((row) => row.id === this.props.partyId)
? (companyAutomat.state.suppliers || []).find((row) => row.id === this.props.partyId)
: (entityAutomat.state.items || []).find((row) => row.id === this.props.partyId));
if (selected) {
this.setState({ partyInput: partyDisplayName(this.props.kind, selected) });
@@ -147,14 +145,14 @@ class ManifestHeader extends PureComponent {
try {
const { kind, onPartyChange } = this.props;
if (kind === 'delivery') {
const row = await supplierAutomat.actions.create({ name: raw });
const row = await companyAutomat.actions.createSupplier({ name: raw });
const displayName = row?.name || raw;
enqueueSnackbar(`Lieferant „${displayName}“ angelegt.`, { variant: 'success' });
this.setState({ creatingParty: false, createdParty: row, partyInput: displayName });
onPartyChange?.(row.id);
} else {
await customergroupAutomat.actions.ensureLoaded();
const groups = customergroupAutomat.state.items ?? [];
await companyAutomat.actions.ensureCustomergroupsLoaded();
const groups = companyAutomat.state.customergroups ?? [];
const targetGroup = getLowestSortNonSupplierCustomerGroup(groups) ?? groups[0];
if (!targetGroup) {
throw new Error('Keine Kundengruppe vorhanden.');
@@ -257,11 +255,15 @@ class ManifestHeader extends PureComponent {
componentDidMount() {
this._cancelled = false;
this.unsubNumber = numberAutomat.subscribe(this, () => {
this.forceUpdate();
});
this.unsubNumber = companyAutomat.subscribe(
this,
() => {
this.forceUpdate();
},
['numbers'],
);
this.subscribeListAutomat(this.props.kind);
void numberAutomat.actions.ensureLoaded().catch(() => {});
void companyAutomat.actions.ensureNumbersLoaded().catch(() => {});
if (!this.props.number && this.props.docId == null) {
void ensureDocumentNumber(this.props.kind)
.then(() => {

View File

@@ -26,7 +26,7 @@ import orderAutomat, {
isOrderPaid,
isOrderDelivered,
} from '../../automats/orderAutomat';
import numberAutomat from '../../automats/numberAutomat';
import companyAutomat from '../../automats/companyAutomat';
import { order as orderApi } from '../../api';
import { backendErrorFrom } from '../../utils/backendError';
import { notifyError } from '../../utils/notify';
@@ -595,11 +595,15 @@ export class OrderList extends PureComponent {
filterKey: orderAutomat.getFilterKey(state),
entityId: state.entityId ?? null,
}));
this.unsubNumber = numberAutomat.subscribe(this, () => {
this.headerItem = createDummyTestOrder();
this.forceUpdate();
});
void numberAutomat.actions.ensureLoaded().catch(() => {});
this.unsubNumber = companyAutomat.subscribe(
this,
() => {
this.headerItem = createDummyTestOrder();
this.forceUpdate();
},
['numbers'],
);
void companyAutomat.actions.ensureNumbersLoaded().catch(() => {});
void this.loadParties();
}

View File

@@ -17,7 +17,7 @@ import FillSpace from 'dashgui/FillSpace';
import { PanelTile, PanelTileGrid } from 'dashgui/panels';
import BackendError from '../BackendError';
import orderAutomat from '../../automats/orderAutomat';
import accountAutomat from '../../automats/accountAutomat';
import companyAutomat from '../../automats/companyAutomat';
import { payment as paymentApi } from '../../api';
import { backendErrorFrom } from '../../utils/backendError';
import { notifyError } from '../../utils/notify';
@@ -184,14 +184,18 @@ export class OrderPaymentList extends PureComponent {
status: state.status,
error: state.error ? backendErrorFrom(state.error) : null,
}));
this.unsubAccount = accountAutomat.subscribe(this, (state) => ({
accountsById: Object.fromEntries((state.items || []).map((a) => [a.id, a.name])),
}));
this.unsubAccount = companyAutomat.subscribe(
this,
(state) => ({
accountsById: Object.fromEntries((state.accounts || []).map((a) => [a.id, a.name])),
}),
['accounts'],
);
if (orderAutomat.state.status === 'idle') {
void orderAutomat.actions.load().catch(() => {});
}
void accountAutomat.actions.ensureLoaded().catch(() => {});
void companyAutomat.actions.ensureAccountsLoaded().catch(() => {});
void this.loadPartiesData();
}

View File

@@ -18,7 +18,7 @@ import { PanelTile, PanelTileGrid } from 'dashgui/panels';
import BackendError from '../BackendError';
import SkeleHashImage from '../settings/SkeleHashImage';
import quoteAutomat, { CHUNK_SIZE } from '../../automats/quoteAutomat';
import numberAutomat from '../../automats/numberAutomat';
import companyAutomat from '../../automats/companyAutomat';
import { quote as quoteApi } from '../../api';
import { backendErrorFrom } from '../../utils/backendError';
import { notifyError } from '../../utils/notify';
@@ -593,11 +593,15 @@ export class QuoteList extends PureComponent {
filterKey: quoteAutomat.getFilterKey(state),
entityId: state.entityId ?? null,
}));
this.unsubNumber = numberAutomat.subscribe(this, () => {
this.headerItem = createDummyTestQuote();
this.forceUpdate();
});
void numberAutomat.actions.ensureLoaded().catch(() => { });
this.unsubNumber = companyAutomat.subscribe(
this,
() => {
this.headerItem = createDummyTestQuote();
this.forceUpdate();
},
['numbers'],
);
void companyAutomat.actions.ensureNumbersLoaded().catch(() => { });
void this.loadParties();
}

View File

@@ -26,7 +26,7 @@ import retoureAutomat, {
isRetourePaid,
isRetoureShipped,
} from '../../automats/retoureAutomat';
import numberAutomat from '../../automats/numberAutomat';
import companyAutomat from '../../automats/companyAutomat';
import { retoure as retoureApi } from '../../api';
import { backendErrorFrom } from '../../utils/backendError';
import { notifyError } from '../../utils/notify';
@@ -600,10 +600,14 @@ export class RetoureList extends PureComponent {
filterKey: retoureAutomat.getFilterKey(state),
entityId: state.entityId ?? null,
}));
this.unsubNumber = numberAutomat.subscribe(this, () => {
this.headerItem = createDummyTestRetoure();
this.forceUpdate();
});
this.unsubNumber = companyAutomat.subscribe(
this,
() => {
this.headerItem = createDummyTestRetoure();
this.forceUpdate();
},
['numbers'],
);
void this.loadParties();
}

View File

@@ -32,14 +32,14 @@ import { notifyError } from '../../utils/notify';
import { formatDate, formatDateTime } from './manifestConfig';
import orderAutomat from '../../automats/orderAutomat';
import shipmentAutomat from '../../automats/shipmentAutomat';
import carrierAutomat from '../../automats/carrierAutomat';
import companyAutomat from '../../automats/companyAutomat';
import { SURFACE_RAISED, WHITE } from '../../colors';
// MARK: <AddPackageDialog/>
class AddPackageDialog extends PureComponent {
constructor(props) {
super(props);
const carriers = (carrierAutomat.state.carriers || []).filter((c) => !c.isReverse);
const carriers = (companyAutomat.state.carriers || []).filter((c) => !c.isReverse);
this.state = {
carriers,
carrierId: carriers[0]?.id ?? '',
@@ -50,17 +50,21 @@ class AddPackageDialog extends PureComponent {
}
componentDidMount() {
this.unsub = carrierAutomat.subscribe(this, (state) => {
const carriers = (state.carriers || []).filter((c) => !c.isReverse);
const currentId = this.state.carrierId;
const valid = carriers.some((c) => c.id === currentId);
return {
carriers,
carrierId: valid ? currentId : (carriers[0]?.id ?? ''),
};
});
if (carrierAutomat.state.status !== 'ready') {
void carrierAutomat.actions.load().catch(() => { });
this.unsub = companyAutomat.subscribe(
this,
(state) => {
const carriers = (state.carriers || []).filter((c) => !c.isReverse);
const currentId = this.state.carrierId;
const valid = carriers.some((c) => c.id === currentId);
return {
carriers,
carrierId: valid ? currentId : (carriers[0]?.id ?? ''),
};
},
['carriers'],
);
if (companyAutomat.state.carriersStatus !== 'ready') {
void companyAutomat.actions.loadCarriers().catch(() => { });
}
}
@@ -414,7 +418,7 @@ export default class ShipmentDetailDialog extends PureComponent {
const shLines = Array.isArray(shipment.lines) ? shipment.lines : [];
const shPackages = Array.isArray(shipment.shippings) ? shipment.shippings : [];
const carriers = carrierAutomat.state.carriers || [];
const carriers = companyAutomat.state.carriers || [];
const isShipmentShipped = Boolean(
shipment.state === 'delivered' ||
shipment.state === 'shipped' ||

View File

@@ -24,7 +24,7 @@ import BackendError from '../BackendError';
import AppDialog from '../AppDialog';
import shipmentAutomat, { CHUNK_SIZE } from '../../automats/shipmentAutomat';
import orderAutomat from '../../automats/orderAutomat';
import numberAutomat from '../../automats/numberAutomat';
import companyAutomat from '../../automats/companyAutomat';
import { shipment as shipmentApi } from '../../api';
import { backendErrorFrom } from '../../utils/backendError';
import { notifyError } from '../../utils/notify';
@@ -949,11 +949,15 @@ export class ShipmentList extends PureComponent {
orders: state.items || [],
}));
this.unsubNumber = numberAutomat.subscribe(this, () => {
this.headerItem = createDummyTestShipment();
this.forceUpdate();
});
void numberAutomat.actions.ensureLoaded().catch(() => {});
this.unsubNumber = companyAutomat.subscribe(
this,
() => {
this.headerItem = createDummyTestShipment();
this.forceUpdate();
},
['numbers'],
);
void companyAutomat.actions.ensureNumbersLoaded().catch(() => {});
void shipmentAutomat.actions.load().catch(() => {});
void orderAutomat.actions.load().catch(() => {});

View File

@@ -4,15 +4,13 @@ import {
order as orderApi,
retoure as retoureApi,
} from '../../api';
import supplierAutomat from '../../automats/supplierAutomat';
import entityAutomat from '../../automats/entityAutomat';
import customergroupAutomat from '../../automats/customergroupAutomat';
import deliveryAutomat from '../../automats/deliveryAutomat';
import quoteAutomat from '../../automats/quoteAutomat';
import orderAutomat from '../../automats/orderAutomat';
import retoureAutomat from '../../automats/retoureAutomat';
import { getArticle } from '../../automats/artikelAutomat';
import { selectCompanyTaxrate } from '../../automats/companyAutomat';
import companyAutomat, { selectCompanyTaxrate } from '../../automats/companyAutomat';
import { netFromGross } from '../../utils/price';
import { ensureDocumentNumber, getNextDocumentNumber } from '../../utils/documentNumber';
import {
@@ -646,18 +644,18 @@ export function apiFor(cfgOrKind) {
export async function loadParties(cfgOrKind) {
const kind = typeof cfgOrKind === 'string' ? cfgOrKind : cfgOrKind?.kind;
if (kind === 'delivery') {
if (supplierAutomat.state.status === 'ready') {
return sortSuppliers(supplierAutomat.state.suppliers);
if (companyAutomat.state.suppliersStatus === 'ready') {
return sortSuppliers(companyAutomat.state.suppliers);
}
const list = await supplierAutomat.actions.load();
const list = await companyAutomat.actions.loadSuppliers();
return sortSuppliers(list);
}
const [entities, groups] = await Promise.all([
entityAutomat.actions.ensureLoaded(),
customergroupAutomat.actions.ensureLoaded(),
companyAutomat.actions.ensureCustomergroupsLoaded(),
]);
const entityList = entities ?? entityAutomat.state.items ?? [];
const groupList = groups ?? customergroupAutomat.state.items ?? [];
const groupList = groups ?? companyAutomat.state.customergroups ?? [];
return filterNonSupplierEntities(entityList, groupList);
}