# `companyAutomat` > **Source File**: [`src/automats/companyAutomat.js`](file:///home/seb/src/dashfront/src/automats/companyAutomat.js) > **Registration Key**: `'company'` (`Automat.get('company')` / `window.__AUTOMATS__.get('company')`) --- ## 1. Overview & Purpose `companyAutomat` stores the active company configuration and metadata for the authenticated user's selected tenant. It provides essential company-wide parameters needed throughout Dashfront, such as default tax rates (standard and reduced), legal company details, default language, and the root category ID of the catalog hierarchy. ### Core Responsibilities - **Company Configuration**: Caches legal details, tax rates (`taxrate`, `reducedtaxrate`), and catalog root category ID (`rootCategoryId`). - **Data Normalization**: Normalizes backend company payloads via `normalizeCompany()` for predictable shape in forms and calculations. - **Cross-Automat Triggering**: Changes in `companyAutomat` drive `categoryAutomat` to fetch the company's category tree. - **Autonomous Bootstrap**: Automatically loads whenever `authAutomat` has an active `selectedCompanyId` and resets on logout. --- ## 2. State Structure ```ts interface NormalizedCompany { id: number | string; name: string; rootCategoryId: number | string | null; taxrate: number; // Standard VAT rate (e.g. 19.00) reducedtaxrate: number; // Reduced VAT rate (e.g. 7.00) iso639: string; // Default language code (e.g. 'de') street?: string; zip?: string; city?: string; country?: string; iban?: string; bic?: string; taxId?: string; vatId?: string; [key: string]: any; } interface CompanyState { /** Normalized details of currently selected company. */ current: NormalizedCompany | null; /** Async lifecycle status. */ status: 'idle' | 'loading' | 'succeeded' | 'failed'; /** Last error message if load/update failed. */ error: string | null; } ``` ### Initial State ```js const initialState = { current: null, status: 'idle', error: null, }; ``` --- ## 3. Configuration & Options ```js new Automat(initialState, actions, { name: 'company' }); ``` - **`name`**: `'company'` - **`persist`**: `false` --- ## 4. Actions & Methods Access actions via `companyAutomat.actions.()`. ### `load(): Promise` Determines the selected company ID from `authAutomat.state.user?.selectedCompanyId`. If none is selected, returns `null`. Otherwise, queries `GET /api/company/:id`, normalizes the data, updates `state.current`, and sets status to `'succeeded'`. ### `update(payload: object): Promise` Persists updated company settings via `PUT /api/company/:id`, re-fetches authoritative data, normalizes it, updates `state.current`, and returns the updated company object. ### `reset(): void` Resets state back to `initialState`. --- ## 5. Exported Standalone Selectors Exported plain helper functions for querying company state without requiring a React component: | Selector | Return Type | Description | |---|---|---| | **`selectCurrentCompany()`** | `NormalizedCompany \| null` | Returns the entire current company object. | | **`selectCompanyId()`** | `string \| number \| null` | The ID of the currently selected company. | | **`selectCompanyStatus()`** | `'idle'\|'loading'\|'succeeded'\|'failed'` | Current status of the company store. | | **`selectCompanyName()`** | `string \| undefined` | Company legal or trade name. | | **`selectCompanyIso639()`** | `string \| undefined` | ISO language code (e.g. `'de'`). | | **`selectCompanyTaxrate()`** | `number \| null` | Standard VAT rate (e.g. `19.0`). | | **`selectCompanyReducedTaxrate()`** | `number \| null` | Reduced VAT rate (e.g. `7.0`). | | **`selectCompanyRootCategoryId()`** | `number \| string \| null` | ID of the root category node. | --- ## 6. Cross-Automat Subscriptions `companyAutomat` automatically tracks authentication changes: ```js authAutomat.subscribe((auth) => { const companyId = auth.user?.selectedCompanyId; if (auth.status === 'authed' && companyId) { void companyAutomat.actions.load(); } else if (auth.status === 'anon') { companyAutomat.actions.reset(); } }); ``` --- ## 7. Usage Examples ### A. React `PureComponent` Tax Rate Calculation ```jsx import { PureComponent } from 'react'; import companyAutomat, { selectCompanyTaxrate } from '../automats/companyAutomat'; export class PriceDisplay extends PureComponent { constructor(props) { super(props); this.state = { taxrate: selectCompanyTaxrate() ?? 19.0, }; } componentDidMount() { this.unsub = companyAutomat.subscribe(this, (state) => ({ taxrate: state.current?.taxrate ?? 19.0, })); } componentWillUnmount() { this.unsub?.(); } render() { const { netPrice } = this.props; const grossPrice = netPrice * (1 + this.state.taxrate / 100); return (
Netto: {netPrice.toFixed(2)} € Brutto (inkl. {this.state.taxrate}% MwSt): {grossPrice.toFixed(2)} €
); } } ``` ### B. Pure Function / Utility Usage ```js import { selectCompanyId, selectCompanyRootCategoryId } from '../automats/companyAutomat'; export function getCompanyUploadUrl() { const companyId = selectCompanyId(); if (!companyId) throw new Error('Kein Unternehmen aktiv.'); return `/api/company/${companyId}/upload`; } ``` --- ## 8. Best Practices & Gotchas 1. **Tax Calculations**: Always query `selectCompanyTaxrate()` or `selectCompanyReducedTaxrate()` instead of hardcoding `19%` or `7%`. 2. **Catalog Roots**: Don't assume root category is `1` or `null`; always use `selectCompanyRootCategoryId()`.