@agridea/suibi-module 0.1.0-preview.21 → 0.1.0-preview.277fb90

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (110) hide show
  1. package/README.md +10 -10
  2. package/dist/elements/browser/main.js +75 -64
  3. package/dist/elements/browser/styles.css +1 -1
  4. package/dist/elements/browser/suibi-module-latest.css +1 -1
  5. package/dist/elements/browser/suibi-module-latest.js +75 -64
  6. package/dist/elements/browser/{suibi-module.v0.1.0-preview.21.css → suibi-module.v0.1.0-preview.277fb90.css} +1 -1
  7. package/dist/elements/browser/suibi-module.v0.1.0-preview.277fb90.js +78 -0
  8. package/dist/elements/browser/suibi-theme-dark.css +1 -1
  9. package/dist/elements/browser/version.txt +1 -1
  10. package/dist/elements/browser/wc-global-utilities.css +1 -0
  11. package/dist/types/app/app.d.ts +6 -2
  12. package/dist/types/app/components/add-dashed-button/add-dashed-button.component.d.ts +9 -0
  13. package/dist/types/app/components/data-preview/data-preview.component.d.ts +4 -2
  14. package/dist/types/app/components/empty-state/empty-state.component.d.ts +12 -0
  15. package/dist/types/app/components/gauge-arc/gauge-arc.component.d.ts +49 -0
  16. package/dist/types/app/{header-bar.d.ts → components/header-bar/header-bar.component.d.ts} +4 -6
  17. package/dist/types/app/components/inline-table/inline-table.component.d.ts +137 -0
  18. package/dist/types/app/components/inline-table/inline-table.types.d.ts +203 -0
  19. package/dist/types/app/components/module-placeholder-page/module-placeholder-page.component.d.ts +6 -0
  20. package/dist/types/app/components/planning-result/planning-result.component.d.ts +46 -0
  21. package/dist/types/app/components/planning-result-row/planning-result-row.component.d.ts +34 -0
  22. package/dist/types/app/components/planning-trigger/planning-trigger.component.d.ts +13 -0
  23. package/dist/types/app/components/results-page/results-page.component.d.ts +13 -0
  24. package/dist/types/app/components/suissebilanz-dashboard/suissebilanz-dashboard.component.d.ts +32 -0
  25. package/dist/types/app/components/suissebilanz-dashboard/suissebilanz-metrics.service.d.ts +21 -0
  26. package/dist/types/app/components/suissebilanz-minibar/suissebilanz-minibar.component.d.ts +19 -0
  27. package/dist/types/app/components/validation-page/validation-page.component.d.ts +18 -0
  28. package/dist/types/app/components/welcome-page/metadata.types.d.ts +1 -1
  29. package/dist/types/app/components/welcome-page/welcome-page.component.d.ts +5 -3
  30. package/dist/types/app/components/workflow-stepper/workflow-stepper.component.d.ts +49 -0
  31. package/dist/types/app/core/data/naebi-data.service.d.ts +43 -28
  32. package/dist/types/app/core/error/global-error-handler.d.ts +5 -0
  33. package/dist/types/app/core/i18n/i18n.service.d.ts +5 -3
  34. package/dist/types/app/core/i18n/locales/fr.d.ts +2 -0
  35. package/dist/types/app/core/i18n/locales/it.d.ts +2 -0
  36. package/dist/types/app/core/master-data/master-data.service.d.ts +8 -1
  37. package/dist/types/app/core/metadata/suibi-metadata.types.d.ts +11 -1
  38. package/dist/types/app/core/navigation/navigation.service.d.ts +29 -1
  39. package/dist/types/app/core/planning/planning-balance.service.d.ts +38 -0
  40. package/dist/types/app/core/planning/planning-balance.types.d.ts +206 -0
  41. package/dist/types/app/core/planning/planning-balance.utils.d.ts +10 -0
  42. package/dist/types/app/core/telemetry/telemetry.service.d.ts +12 -0
  43. package/dist/types/app/core/utils/object.util.d.ts +26 -0
  44. package/dist/types/app/core/validation/capabilities.d.ts +5 -5
  45. package/dist/types/app/core/validation/global-validation.service.d.ts +19 -4
  46. package/dist/types/app/jsonforms/filters/code-list-filter-resolvers.d.ts +3 -0
  47. package/dist/types/app/jsonforms/registry/renderers.registry.d.ts +8 -0
  48. package/dist/types/app/jsonforms/renderers/controls/selects/animal-category/animal-category-select.renderer.d.ts +1 -1
  49. package/dist/types/app/jsonforms/renderers/controls/selects/code-list/code-list-select.renderer.d.ts +10 -4
  50. package/dist/types/app/jsonforms/renderers/layout/array/array-layout.renderer.d.ts +43 -0
  51. package/dist/types/app/jsonforms/renderers/layout/categorization/selected-category-categorization.renderer.d.ts +3 -0
  52. package/dist/types/app/jsonforms/renderers/layout/constraint/constraint-layout.renderer.d.ts +1 -0
  53. package/dist/types/app/jsonforms/renderers/layout/group/base-group.renderer.d.ts +2 -0
  54. package/dist/types/app/jsonforms/renderers/layout/group/module-toggle-group.renderer.d.ts +38 -0
  55. package/dist/types/app/nutrient-cycle/animal-stock/animal-stock-detail/animal-stock-detail.component.d.ts +21 -0
  56. package/dist/types/app/nutrient-cycle/animal-stock/{animal-stock-list.component.d.ts → animal-stock-list/animal-stock-list.component.d.ts} +6 -9
  57. package/dist/types/app/nutrient-cycle/animal-stock/{animal-stock-master-detail.component.d.ts → animal-stock-master-detail/animal-stock-master-detail.component.d.ts} +2 -3
  58. package/dist/types/app/nutrient-cycle/animal-stock/index.d.ts +3 -3
  59. package/dist/types/app/nutrient-cycle/farm-manure-trading/farm-manure-trading-master-detail/farm-manure-trading-master-detail.component.d.ts +19 -0
  60. package/dist/types/app/nutrient-cycle/farm-manure-trading/farm-manure-trading-table/farm-manure-trading-table.component.d.ts +34 -0
  61. package/dist/types/app/nutrient-cycle/farm-manure-trading/farm-manure-trading-table/farm-manure-trading-table.config.d.ts +24 -0
  62. package/dist/types/app/nutrient-cycle/farm-manure-trading/index.d.ts +3 -3
  63. package/dist/types/app/nutrient-cycle/farm-manure-trading/transaction-unit.util.d.ts +2 -0
  64. package/dist/types/app/nutrient-cycle/field-cultivation/arable-land-table/arable-land-table.component.d.ts +22 -0
  65. package/dist/types/app/nutrient-cycle/field-cultivation/arable-land-table/arable-land-table.config.d.ts +9 -0
  66. package/dist/types/app/nutrient-cycle/field-cultivation/crop-harvest-table/crop-harvest-table.component.d.ts +21 -0
  67. package/dist/types/app/nutrient-cycle/field-cultivation/crop-harvest-table/crop-harvest-table.config.d.ts +13 -0
  68. package/dist/types/app/nutrient-cycle/field-cultivation/field-cultivation-detail/field-cultivation-detail.component.d.ts +22 -0
  69. package/dist/types/app/nutrient-cycle/field-cultivation/field-cultivation-general/field-cultivation-general.component.d.ts +20 -0
  70. package/dist/types/app/nutrient-cycle/field-cultivation/field-cultivation-list/field-cultivation-list.component.d.ts +17 -0
  71. package/dist/types/app/nutrient-cycle/field-cultivation/field-cultivation-master-detail/field-cultivation-master-detail.component.d.ts +29 -0
  72. package/dist/types/app/nutrient-cycle/field-cultivation/field-cultivation.types.d.ts +41 -0
  73. package/dist/types/app/nutrient-cycle/field-cultivation/field-cultivation.util.d.ts +6 -0
  74. package/dist/types/app/nutrient-cycle/field-cultivation/fodder-cropland-table/fodder-cropland-table.component.d.ts +28 -0
  75. package/dist/types/app/nutrient-cycle/field-cultivation/fodder-cropland-table/fodder-cropland-table.config.d.ts +16 -0
  76. package/dist/types/app/nutrient-cycle/field-cultivation/index.d.ts +9 -0
  77. package/dist/types/app/nutrient-cycle/field-cultivation/special-crops-table/special-crops-table.component.d.ts +29 -0
  78. package/dist/types/app/nutrient-cycle/field-cultivation/special-crops-table/special-crops-table.config.d.ts +50 -0
  79. package/dist/types/app/nutrient-cycle/field-spreading/fertiliser-table/fertiliser-table.component.d.ts +43 -0
  80. package/dist/types/app/nutrient-cycle/field-spreading/fertiliser-table/fertiliser-table.config.d.ts +20 -0
  81. package/dist/types/app/nutrient-cycle/field-spreading/field-spreading.component.d.ts +16 -4
  82. package/dist/types/app/nutrient-cycle/field-spreading/field-spreading.types.d.ts +1 -0
  83. package/dist/types/app/nutrient-cycle/field-spreading/ingredient.util.d.ts +8 -0
  84. package/dist/types/app/nutrient-cycle/field-spreading/recycling-table/recycling-table.component.d.ts +31 -0
  85. package/dist/types/app/nutrient-cycle/field-spreading/recycling-table/recycling-table.config.d.ts +17 -0
  86. package/dist/types/app/nutrient-cycle/field-spreading/recycling-table/recycling-transaction-unit.util.d.ts +4 -0
  87. package/dist/types/app/nutrient-cycle/fodder/fodder-master-detail/fodder-master-detail.component.d.ts +25 -0
  88. package/dist/types/app/nutrient-cycle/fodder/fodder-table/fodder-table.component.d.ts +26 -0
  89. package/dist/types/app/nutrient-cycle/fodder/fodder-table/fodder-table.config.d.ts +9 -0
  90. package/dist/types/app/nutrient-cycle/fodder/fodder.types.d.ts +34 -0
  91. package/dist/types/app/nutrient-cycle/fodder/index.d.ts +3 -0
  92. package/dist/types/app/nutrient-cycle/fodder/ingredient.util.d.ts +8 -0
  93. package/dist/types/app/nutrient-cycle/fodder/transaction-unit.util.d.ts +2 -0
  94. package/dist/types/app/nutrient-cycle/lifetime-performance/index.d.ts +2 -0
  95. package/dist/types/app/nutrient-cycle/lifetime-performance/lifetime-performance-form.component.d.ts +1 -1
  96. package/dist/types/app/nutrient-cycle/storage/index.d.ts +4 -0
  97. package/dist/types/app/nutrient-cycle/storage/storage-detail/storage-detail.component.d.ts +30 -0
  98. package/dist/types/app/nutrient-cycle/storage/storage-general/storage-general.component.d.ts +29 -0
  99. package/dist/types/app/nutrient-cycle/storage/storage-list/storage-list.component.d.ts +23 -0
  100. package/dist/types/app/nutrient-cycle/storage/storage-master-detail/storage-master-detail.component.d.ts +32 -0
  101. package/dist/types/app/nutrient-cycle/storage/storage.types.d.ts +40 -0
  102. package/dist/types/environments/environment.d.ts +11 -0
  103. package/dist/types/shared/material-icons.d.ts +3 -3
  104. package/package.json +69 -17
  105. package/dist/elements/browser/suibi-module.v0.1.0-preview.21.js +0 -67
  106. package/dist/types/app/nutrient-cycle/animal-stock/animal-stock-detail.component.d.ts +0 -22
  107. package/dist/types/app/nutrient-cycle/farm-manure-trading/farm-manure-trading-detail.component.d.ts +0 -27
  108. package/dist/types/app/nutrient-cycle/farm-manure-trading/farm-manure-trading-list.component.d.ts +0 -22
  109. package/dist/types/app/nutrient-cycle/farm-manure-trading/farm-manure-trading-master-detail.component.d.ts +0 -26
  110. /package/dist/types/app/{core/validation/validation-errors-panel.d.ts → components/validation-errors-panel/validation-errors-panel.component.d.ts} +0 -0
@@ -0,0 +1,34 @@
1
+ import type { InlineTableConfig } from '../../../components/inline-table/inline-table.types';
2
+ import { FarmManureTradingMode } from '../../../core/navigation/navigation.service';
3
+ import { FarmManureTradingSupply, FarmManureTradingDispense } from '../farm-manure-trading.types';
4
+ type TradingRow = FarmManureTradingSupply | FarmManureTradingDispense;
5
+ /**
6
+ * FarmManureTradingTableComponent — thin wrapper around InlineTableComponent.
7
+ *
8
+ * Responsibilities:
9
+ * 1. Provides the per-mode column/section config (the "uischema").
10
+ * 2. Bridges typed `FarmManureTradingSupply[]`/`Dispense[]` to/from the generic
11
+ * `Record<string, unknown>[]` API of InlineTableComponent.
12
+ * 3. Supplies `deriveUnits` as a `rowTransform` — `transactionUnit` ('kg'/'m3') and
13
+ * every ingredient's `unit` ('kg/t'/'kg/m3') are fully derived from the selected
14
+ * product's matterState (never user-entered) — two independent mappings, NOT a
15
+ * concatenation of one into the other.
16
+ */
17
+ export declare class FarmManureTradingTableComponent {
18
+ readonly mode: import("@angular/core").InputSignal<FarmManureTradingMode>;
19
+ readonly entries: import("@angular/core").InputSignal<TradingRow[]>;
20
+ readonly entriesChange: import("@angular/core").OutputEmitterRef<TradingRow[]>;
21
+ protected readonly config: import("@angular/core").Signal<InlineTableConfig>;
22
+ /** Cast typed entries to generic Record[] for InlineTableComponent. */
23
+ readonly rowsForTable: import("@angular/core").Signal<Record<string, unknown>[]>;
24
+ /** Cast generic output back to typed trading rows. */
25
+ onRowsChange(rows: Record<string, unknown>[]): void;
26
+ /**
27
+ * Row transform re-deriving `transactionUnit` and every ingredient's `unit` from the
28
+ * product's matterState on each edit — runs unconditionally (not just when
29
+ * `typeOfManureRecyclingProduct` changes) so an edit made before the product is picked
30
+ * still resolves once it is.
31
+ */
32
+ readonly deriveUnits: (_changedKey: string, _newValue: unknown, row: Record<string, unknown>) => Record<string, unknown>;
33
+ }
34
+ export {};
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Column and section configuration for the Farm Manure Trading inline tables.
3
+ *
4
+ * This is the "uischema" for the supply ("Reprises") and dispense ("Cessions")
5
+ * tables — one InlineTableConfig per mode, mirroring recycling-table.config.ts.
6
+ * Columns:
7
+ * - Product: typeOfManureRecyclingProduct (code list filtered per mode)
8
+ * - Quantity: quantity (number)
9
+ * - Unit: transactionUnit (readonly — derived from the product's
10
+ * matterState, never user-editable, per the API spec)
11
+ * - Origin: manureDerivation[] (expandable key/share pair editor,
12
+ * expected total 100 %)
13
+ * - Nutrients: Ntot, Nsol (molecularFormula 'Nlos'), P₂O₅, K₂O, Mg read/written
14
+ * via the ingredient[] sub-array (same 5 nutrients as recycling).
15
+ * - Nutrient unit: readonly, derived from the product's matterState (kg/t | kg/m³).
16
+ */
17
+ import type { InlineTableConfig } from '../../../components/inline-table/inline-table.types';
18
+ import type { FarmManureTradingMode } from '../../../core/navigation/navigation.service';
19
+ /** Nutrient formulas tracked per trading entry, in display order. 'Nlos' = soluble nitrogen
20
+ * (matches the `molecularFormula` enum from assets/master-data/substances.json — there is no 'NSol'). */
21
+ export declare const TRADING_NUTRIENT_COLUMNS: readonly ["Ntot", "Nlos", "P2O5", "K2O", "Mg"];
22
+ export type TradingNutrientFormula = (typeof TRADING_NUTRIENT_COLUMNS)[number];
23
+ /** Builds the inline-table config for one mode ('supply' | 'dispense'). */
24
+ export declare function createTradingTableConfig(mode: FarmManureTradingMode): InlineTableConfig;
@@ -1,4 +1,4 @@
1
- export * from './farm-manure-trading-list.component';
2
- export * from './farm-manure-trading-detail.component';
3
- export * from './farm-manure-trading-master-detail.component';
1
+ export * from './farm-manure-trading-table/farm-manure-trading-table.component';
2
+ export * from './farm-manure-trading-table/farm-manure-trading-table.config';
3
+ export * from './farm-manure-trading-master-detail/farm-manure-trading-master-detail.component';
4
4
  export * from './farm-manure-trading.types';
@@ -1 +1,3 @@
1
1
  export declare function deriveTransactionUnit(productCode: string | null | undefined): string | undefined;
2
+ /** Derives the mandatory ingredient unit ('kg/t' or 'kg/m3') from the product's matterState. */
3
+ export declare function deriveTradingIngredientUnit(productCode: string | null | undefined): string | undefined;
@@ -0,0 +1,22 @@
1
+ import { FieldCultivationArableLand } from '../field-cultivation.types';
2
+ /**
3
+ * ArableLandTableComponent — thin wrapper around InlineTableComponent for the
4
+ * "Grandes cultures" tab: arable-land entries are edited directly in the table
5
+ * (no detail pane). The config provides the columns; the rowTransform clears the
6
+ * yield-related fields when the newly selected crop does not permit yield input.
7
+ */
8
+ export declare class ArableLandTableComponent {
9
+ readonly entries: import("@angular/core").InputSignal<FieldCultivationArableLand[]>;
10
+ readonly entriesChange: import("@angular/core").OutputEmitterRef<FieldCultivationArableLand[]>;
11
+ /** Column/section config (constant — no signal needed). */
12
+ protected readonly config: import("../../../components/inline-table/inline-table.types").InlineTableConfig;
13
+ /** Cast typed entries to the generic Record[] expected by InlineTableComponent. */
14
+ readonly rowsForTable: import("@angular/core").Signal<Record<string, unknown>[]>;
15
+ onRowsChange(rows: Record<string, unknown>[]): void;
16
+ /**
17
+ * Crop change: clear yield + divergence when the new crop forbids yield input,
18
+ * so no stale values linger under the now-disabled cells. Requirement corrections
19
+ * are special-crops-only (SUIBIL-1143): strip them so they never reach the emitted JSON.
20
+ */
21
+ readonly enforceArableRules: (changedKey: string, newValue: unknown, row: Record<string, unknown>) => Record<string, unknown>;
22
+ }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Column and section configuration for the arable-land inline table ("Grandes cultures").
3
+ *
4
+ * Replaces the former list + JSONForms detail pane for arable land: the main entry
5
+ * fields are edited directly in the table. The crop dropdown reuses the
6
+ * `agronomicCropCategoryArableLand` code list as-is, keeping its existing order.
7
+ */
8
+ import type { InlineTableConfig } from '../../../components/inline-table/inline-table.types';
9
+ export declare const ARABLE_LAND_TABLE_CONFIG: InlineTableConfig;
@@ -0,0 +1,21 @@
1
+ import { FieldCultivationCropHarvest } from '../field-cultivation.types';
2
+ import { CropHarvestTableKind } from './crop-harvest-table.config';
3
+ /**
4
+ * CropHarvestTableComponent — thin wrapper around InlineTableComponent for one of the
5
+ * two crop-harvest tables of the "Général" tab (fed / dispensed).
6
+ *
7
+ * Rows without a selected crop (freshly added) exist only in the local `uiRows`
8
+ * state and are emitted upstream once a crop is picked, so no empty rows ever
9
+ * reach the data store (fodder `uiRows` pattern).
10
+ */
11
+ export declare class CropHarvestTableComponent {
12
+ readonly entries: import("@angular/core").InputSignal<FieldCultivationCropHarvest[]>;
13
+ readonly kind: import("@angular/core").InputSignal<CropHarvestTableKind>;
14
+ readonly entriesChange: import("@angular/core").OutputEmitterRef<FieldCultivationCropHarvest[]>;
15
+ readonly config: import("@angular/core").Signal<import("../../../components/inline-table/inline-table.types").InlineTableConfig>;
16
+ /** Rows as last edited locally (may contain not-yet-committed empty rows); null = follow data. */
17
+ private readonly uiRows;
18
+ readonly rowsForTable: import("@angular/core").Signal<Record<string, unknown>[]>;
19
+ constructor();
20
+ onRowsChange(rows: Record<string, unknown>[]): void;
21
+ }
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Column and section configuration for the two crop-harvest inline tables of the
3
+ * "Général" tab (fed crop harvest / dispensed crop harvest).
4
+ *
5
+ * Both tables share the same columns — the same three fields the JSONForms array
6
+ * detail exposed before (crop, plant name, effective yield) — and differ only by
7
+ * their labels. The crop dropdown reuses the full `agronomicCropCategory` code
8
+ * list, exactly like the former JSONForms control.
9
+ */
10
+ import type { InlineTableConfig } from '../../../components/inline-table/inline-table.types';
11
+ export type CropHarvestTableKind = 'feeding' | 'dispense';
12
+ export declare const FEEDING_TABLE_CONFIG: InlineTableConfig;
13
+ export declare const DISPENSE_TABLE_CONFIG: InlineTableConfig;
@@ -0,0 +1,22 @@
1
+ import { JsonSchema, UISchemaElement } from '@jsonforms/core';
2
+ import { FieldCultivationDetailEntry, FieldCultivationDetailMode } from '../field-cultivation.types';
3
+ export declare class FieldCultivationDetailComponent {
4
+ private readonly i18n;
5
+ readonly row: import("@angular/core").InputSignal<FieldCultivationDetailEntry | null>;
6
+ readonly index: import("@angular/core").InputSignal<number | null>;
7
+ readonly mode: import("@angular/core").InputSignal<FieldCultivationDetailMode>;
8
+ readonly rowChange: import("@angular/core").OutputEmitterRef<FieldCultivationDetailEntry>;
9
+ readonly close: import("@angular/core").OutputEmitterRef<void>;
10
+ readonly renderers: {
11
+ tester: import("@jsonforms/core").RankedTester;
12
+ renderer: any;
13
+ }[];
14
+ readonly suibiAjv: import("ajv").Ajv;
15
+ private readonly baseSchemas;
16
+ private readonly baseUis;
17
+ readonly itemSchema: import("@angular/core").Signal<JsonSchema>;
18
+ readonly localizedUi: import("@angular/core").Signal<UISchemaElement>;
19
+ readonly detailTitle: import("@angular/core").Signal<string>;
20
+ readonly jsonFormsData: import("@angular/core").Signal<(import("..").FieldCultivationSpecial & import("../../../core/schemas/ui-helper-registry").UiHelperDefinitions) | null>;
21
+ onDataChange(event: unknown): void;
22
+ }
@@ -0,0 +1,20 @@
1
+ import { JsonSchema } from '@jsonforms/core';
2
+ import { FieldCultivationData } from '../field-cultivation.types';
3
+ export declare class FieldCultivationGeneralComponent {
4
+ private readonly i18n;
5
+ readonly value: import("@angular/core").InputSignal<FieldCultivationData>;
6
+ readonly valueChange: import("@angular/core").OutputEmitterRef<FieldCultivationData>;
7
+ readonly renderers: {
8
+ tester: import("@jsonforms/core").RankedTester;
9
+ renderer: any;
10
+ }[];
11
+ readonly ajv: import("ajv").Ajv;
12
+ readonly schema: import("@angular/core").Signal<JsonSchema>;
13
+ readonly localizedUi: import("@angular/core").Signal<import("@jsonforms/core").UISchemaElement>;
14
+ readonly jsonFormsData: import("@angular/core").Signal<({
15
+ buildingZoneAreaSize: number | null | undefined;
16
+ outdoorVegetableMainCropAreaSize: number | null | undefined;
17
+ indoorVegetableMainCropAreaSize: number | null | undefined;
18
+ } & import("../../../core/schemas/ui-helper-registry").UiHelperDefinitions) | null>;
19
+ onDataChange(event: unknown): void;
20
+ }
@@ -0,0 +1,17 @@
1
+ import { FieldCultivationDetailEntry, FieldCultivationDetailMode } from '../field-cultivation.types';
2
+ export declare class FieldCultivationListComponent {
3
+ private readonly masterData;
4
+ private readonly i18n;
5
+ readonly rows: import("@angular/core").InputSignal<FieldCultivationDetailEntry[]>;
6
+ readonly selectedIndex: import("@angular/core").InputSignal<number | null>;
7
+ readonly mode: import("@angular/core").InputSignal<FieldCultivationDetailMode>;
8
+ readonly select: import("@angular/core").OutputEmitterRef<number>;
9
+ readonly add: import("@angular/core").OutputEmitterRef<void>;
10
+ readonly delete: import("@angular/core").OutputEmitterRef<number>;
11
+ readonly displayedColumns: string[];
12
+ resolveCrop(code: string | null | undefined): string;
13
+ emptyLabel(): string;
14
+ emptyHintLabel(): string;
15
+ addLabel(): string;
16
+ onDelete(index: number, event: Event): void;
17
+ }
@@ -0,0 +1,29 @@
1
+ import { FieldCultivationTab } from '../../../core/navigation/navigation.service';
2
+ import { CropHarvestTableKind } from '../crop-harvest-table/crop-harvest-table.config';
3
+ import { FieldCultivationArableLand, FieldCultivationCropHarvest, FieldCultivationData, FieldCultivationFodderCropland, FieldCultivationSpecial } from '../field-cultivation.types';
4
+ export declare class FieldCultivationMasterDetailComponent {
5
+ private readonly dataSvc;
6
+ private readonly navigationSvc;
7
+ constructor();
8
+ readonly fieldCultivation: import("@angular/core").Signal<FieldCultivationData>;
9
+ readonly fodderCroplandRows: import("@angular/core").Signal<FieldCultivationFodderCropland[]>;
10
+ readonly arableLandRows: import("@angular/core").Signal<FieldCultivationArableLand[]>;
11
+ readonly specialRows: import("@angular/core").Signal<FieldCultivationSpecial[]>;
12
+ readonly feedingRows: import("@angular/core").Signal<FieldCultivationCropHarvest[]>;
13
+ readonly dispenseRows: import("@angular/core").Signal<FieldCultivationCropHarvest[]>;
14
+ readonly activeTab: import("@angular/core").WritableSignal<FieldCultivationTab>;
15
+ readonly activeTabIndex: import("@angular/core").Signal<0 | 1 | 2 | 3>;
16
+ onTabChange(index: number): void;
17
+ onGeneralChange(value: FieldCultivationData): void;
18
+ /** Persists one crop-harvest table's rows (fed / dispensed harvests of the general tab). */
19
+ onCropHarvestRowsChange(kind: CropHarvestTableKind, rows: FieldCultivationCropHarvest[]): void;
20
+ /** Persists the fodder-cropland rows produced by the inline table (edit / add / delete). */
21
+ onFodderCroplandRowsChange(rows: FieldCultivationFodderCropland[]): void;
22
+ /** Persists the arable-land rows produced by the inline table (edit / add / delete). */
23
+ onArableRowsChange(rows: FieldCultivationArableLand[]): void;
24
+ /** Persists the special-crops rows produced by the inline table (edit / add / delete). */
25
+ onSpecialRowsChange(rows: FieldCultivationSpecial[]): void;
26
+ private patchRows;
27
+ private patchFieldCultivation;
28
+ private parseTab;
29
+ }
@@ -0,0 +1,41 @@
1
+ export interface FieldCultivationRequirementCorrection {
2
+ quantity?: number | null;
3
+ molecularFormula?: string | null;
4
+ unit?: string | null;
5
+ }
6
+ export interface FieldCultivationCropHarvest {
7
+ agronomicCropCategory?: string | null;
8
+ userSpecificPlantName?: string | null;
9
+ effectiveYield?: number | null;
10
+ }
11
+ export interface FieldCultivationBaseEntry {
12
+ agronomicCropCategory?: string | null;
13
+ userSpecificPlantName?: string | null;
14
+ isMainCrop?: boolean;
15
+ areaSize?: number | null;
16
+ yieldPerSquareMeasure?: number | null;
17
+ }
18
+ export interface FieldCultivationFodderCropland extends FieldCultivationBaseEntry {
19
+ fieldName?: string | null;
20
+ calculateYieldThroughFodderBalance?: boolean;
21
+ requirementCorrection?: FieldCultivationRequirementCorrection[];
22
+ }
23
+ export interface FieldCultivationArableLand extends FieldCultivationBaseEntry {
24
+ hasLongTermYieldDivergence?: boolean;
25
+ requirementCorrection?: FieldCultivationRequirementCorrection[];
26
+ }
27
+ export interface FieldCultivationSpecial extends FieldCultivationBaseEntry {
28
+ requirementCorrection?: FieldCultivationRequirementCorrection[];
29
+ }
30
+ export interface FieldCultivationData {
31
+ buildingZoneAreaSize?: number | null;
32
+ outdoorVegetableMainCropAreaSize?: number | null;
33
+ indoorVegetableMainCropAreaSize?: number | null;
34
+ feedingOfCropHarvest?: FieldCultivationCropHarvest[];
35
+ dispenseOfCropHarvest?: FieldCultivationCropHarvest[];
36
+ fodderCropland?: FieldCultivationFodderCropland[];
37
+ arableLand?: FieldCultivationArableLand[];
38
+ special?: FieldCultivationSpecial[];
39
+ }
40
+ export type FieldCultivationDetailMode = 'fodderCropland' | 'arableLand' | 'special';
41
+ export type FieldCultivationDetailEntry = FieldCultivationFodderCropland | FieldCultivationArableLand | FieldCultivationSpecial;
@@ -0,0 +1,6 @@
1
+ import { FieldCultivationCropHarvest, FieldCultivationData, FieldCultivationDetailEntry, FieldCultivationDetailMode, FieldCultivationRequirementCorrection } from './field-cultivation.types';
2
+ export declare function normalizeRequirementCorrection(source: Partial<FieldCultivationRequirementCorrection> | undefined): FieldCultivationRequirementCorrection;
3
+ export declare function normalizeCropHarvestEntry(source: Partial<FieldCultivationCropHarvest> | undefined): FieldCultivationCropHarvest;
4
+ export declare function normalizeFieldCultivationDetailEntry(mode: FieldCultivationDetailMode, source: Partial<FieldCultivationDetailEntry> | undefined): FieldCultivationDetailEntry;
5
+ export declare function createEmptyFieldCultivationDetailEntry(mode: FieldCultivationDetailMode): FieldCultivationDetailEntry;
6
+ export declare function normalizeFieldCultivation(source: Partial<FieldCultivationData> | undefined): FieldCultivationData;
@@ -0,0 +1,28 @@
1
+ import { FieldCultivationFodderCropland } from '../field-cultivation.types';
2
+ /**
3
+ * FodderCroplandTableComponent — thin wrapper around InlineTableComponent for the
4
+ * "Surface fourragère" tab: entries are edited directly in the table (no detail pane).
5
+ *
6
+ * Rows without a selected crop (freshly added) exist only in the local `uiRows`
7
+ * state and are emitted upstream once a crop is picked, so no empty rows ever
8
+ * reach the data store (fodder `uiRows` pattern). The rowTransform clears the
9
+ * yield whenever it is not user-editable for the row.
10
+ */
11
+ export declare class FodderCroplandTableComponent {
12
+ readonly entries: import("@angular/core").InputSignal<FieldCultivationFodderCropland[]>;
13
+ readonly entriesChange: import("@angular/core").OutputEmitterRef<FieldCultivationFodderCropland[]>;
14
+ /** Column/section config (constant — no signal needed). */
15
+ protected readonly config: import("../../../components/inline-table/inline-table.types").InlineTableConfig;
16
+ /** Rows as last edited locally (may contain not-yet-committed empty rows); null = follow data. */
17
+ private readonly uiRows;
18
+ readonly rowsForTable: import("@angular/core").Signal<Record<string, unknown>[]>;
19
+ constructor();
20
+ onRowsChange(rows: Record<string, unknown>[]): void;
21
+ /**
22
+ * Clears the yield whenever it stops being user-editable for the row (fodder-balance
23
+ * calculation switched on, or new crop without yield input), so no stale value
24
+ * lingers under the now-disabled cell. Requirement corrections are special-crops-only
25
+ * (SUIBIL-1143): strip them so they never reach the emitted JSON.
26
+ */
27
+ readonly enforceFodderCroplandRules: (changedKey: string, newValue: unknown, row: Record<string, unknown>) => Record<string, unknown>;
28
+ }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Column and section configuration for the fodder-cropland inline table
3
+ * ("Surface fourragère" tab).
4
+ *
5
+ * Replaces the former list + JSONForms detail pane: entries are edited directly
6
+ * in the table. `userSpecificPlantName` and `fieldName` stay in the data model
7
+ * (filled by imports/API) but are no longer editable in the UI.
8
+ */
9
+ import type { InlineTableConfig } from '../../../components/inline-table/inline-table.types';
10
+ /**
11
+ * Yield is user-editable only when the selected crop permits yield input AND the
12
+ * yield is not calculated through the fodder balance — mirrors the former
13
+ * `fieldCultivation_shouldShowYieldInput` constraint of the detail form.
14
+ */
15
+ export declare function yieldNotEditable(row: Record<string, unknown>): boolean;
16
+ export declare const FODDER_CROPLAND_TABLE_CONFIG: InlineTableConfig;
@@ -0,0 +1,9 @@
1
+ export * from './field-cultivation-list/field-cultivation-list.component';
2
+ export * from './field-cultivation-detail/field-cultivation-detail.component';
3
+ export * from './field-cultivation-general/field-cultivation-general.component';
4
+ export * from './field-cultivation-master-detail/field-cultivation-master-detail.component';
5
+ export * from './crop-harvest-table/crop-harvest-table.component';
6
+ export * from './fodder-cropland-table/fodder-cropland-table.component';
7
+ export * from './arable-land-table/arable-land-table.component';
8
+ export * from './special-crops-table/special-crops-table.component';
9
+ export * from './field-cultivation.types';
@@ -0,0 +1,29 @@
1
+ import { FieldCultivationSpecial } from '../field-cultivation.types';
2
+ /**
3
+ * SpecialCropsTableComponent — thin wrapper around InlineTableComponent for the
4
+ * "Cultures spéciales" tab: one table for the whole CULT_SPECIAL category.
5
+ *
6
+ * Rows without a selected crop (freshly added) exist only in the local `uiRows`
7
+ * state and are emitted upstream once a crop is picked, so no empty rows ever
8
+ * reach the data store (fodder `uiRows` pattern).
9
+ */
10
+ export declare class SpecialCropsTableComponent {
11
+ readonly entries: import("@angular/core").InputSignal<FieldCultivationSpecial[]>;
12
+ readonly entriesChange: import("@angular/core").OutputEmitterRef<FieldCultivationSpecial[]>;
13
+ /** Column/section config (constant — no signal needed). */
14
+ protected readonly config: import("../../../components/inline-table/inline-table.types").InlineTableConfig;
15
+ /** Rows as last edited locally (may contain not-yet-committed empty rows); null = follow data. */
16
+ private readonly uiRows;
17
+ readonly rowsForTable: import("@angular/core").Signal<Record<string, unknown>[]>;
18
+ constructor();
19
+ onRowsChange(rows: Record<string, unknown>[]): void;
20
+ /**
21
+ * Domain rules applied on every edit:
22
+ * - units of the managed nutrient slots are fixed (N2 in kg, corrections in %),
23
+ * - managed slots left empty are dropped (the API rejects null quantities),
24
+ * - selecting a crop pre-fills Nmin from its standard N2 requirement and resets the
25
+ * corrections to 100 %; clearing the crop (or picking one that forbids corrections)
26
+ * removes the managed slots.
27
+ */
28
+ readonly enforceSpecialCropRules: (changedKey: string, newValue: unknown, row: Record<string, unknown>) => Record<string, unknown>;
29
+ }
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Column and section configuration for the special-crops inline table
3
+ * ("Cultures spéciales" tab).
4
+ *
5
+ * ONE table for the whole CULT_SPECIAL category: the crop dropdown reuses the
6
+ * `agronomicCropCategorySpecial` code list, which is already filtered on
7
+ * cultivationCategory === 'CULT_SPECIAL'. Nutrient columns live in the row's
8
+ * `requirementCorrection[]` sub-array: Nmin is the N2 slot in kg, the three
9
+ * corrections are the P2O5/K2O/Mg slots in %.
10
+ */
11
+ import type { InlineTableConfig } from '../../../components/inline-table/inline-table.types';
12
+ /** Nmin maps to the N2 requirement-correction slot, always expressed in kg. */
13
+ export declare const NMIN_FORMULA = "N2";
14
+ export declare const NMIN_UNIT = "kg";
15
+ /** Correction slots managed by the table, always expressed in % (100 % = no correction). */
16
+ export declare const CORRECTION_FORMULAS: readonly ["P2O5", "K2O", "Mg"];
17
+ export declare const CORRECTION_UNIT = "%";
18
+ export declare const CORRECTION_DEFAULT = 100;
19
+ /** Code list feeding the crop dropdown — the whole CULT_SPECIAL category. */
20
+ export declare const SPECIAL_CROPS_CODE_LIST = "agronomicCropCategorySpecial";
21
+ /** Crop ids permitted in the table — every CULT_SPECIAL entry of the master data. */
22
+ export declare const SPECIAL_CROPS_IDS: Set<string>;
23
+ /** Looks up a crop entry in the table's code list. */
24
+ export declare function specialCropEntry(id: unknown): Record<string, unknown> | undefined;
25
+ /**
26
+ * Nutrient columns are read-only unless the selected crop has the
27
+ * `isPermittedForRequirementCorrection` flag: without it, the pre-filled Nmin and
28
+ * correction values are fixed defaults from master data and must not be user-editable.
29
+ */
30
+ export declare function nutrientColumnsLocked(crop: Record<string, unknown> | undefined): boolean;
31
+ /**
32
+ * Applies the crop's defaults to the requirement-correction slots.
33
+ * - If the crop does NOT permit requirement corrections (or none is selected): the
34
+ * managed slots are removed entirely — nothing is editable and nothing is sent to the API.
35
+ * - If the crop DOES permit them: the managed slots are pre-filled from the crop's
36
+ * master-data `requirement` (N2 in kg; P2O5/K2O/Mg in %) and stay user-editable.
37
+ */
38
+ export declare function applyCropDefaults(row: Record<string, unknown>, crop: Record<string, unknown> | undefined): Record<string, unknown>;
39
+ /**
40
+ * Normalizes the managed requirement-correction slots on every edit: fixed units
41
+ * (N2 → kg, corrections → %) and removal of managed entries left without a quantity
42
+ * (the API rejects present-but-null quantities).
43
+ */
44
+ export declare function normalizeManagedCorrections(row: Record<string, unknown>): Record<string, unknown>;
45
+ /**
46
+ * Shared column definitions for the requirement-correction sub-array (Nmin + P2O5/K2O/Mg),
47
+ * reusable across fodder, arable and special tables. `lockRow` disables editing per row.
48
+ */
49
+ export declare function requirementCorrectionColumns(lockRow: (row: Record<string, unknown>) => boolean): InlineTableConfig['columns'];
50
+ export declare const SPECIAL_CROPS_TABLE_CONFIG: InlineTableConfig;
@@ -0,0 +1,43 @@
1
+ import { FieldSpreadingFertiliserEntry } from '../field-spreading.types';
2
+ /**
3
+ * FertiliserTableComponent — thin wrapper around InlineTableComponent.
4
+ *
5
+ * Responsibilities:
6
+ * 1. Provides `FERTILISER_TABLE_CONFIG` (the column/section "uischema") to the
7
+ * generic table component.
8
+ * 2. Bridges the typed `FieldSpreadingFertiliserEntry[]` inputs/outputs to the
9
+ * generic `Record<string, unknown>[]` API expected by InlineTableComponent.
10
+ * 3. Supplies `autoPopulateNutrients` as a `rowTransform` — domain logic that
11
+ * pre-fills Ntot/P₂O₅/K₂O/Mg from the product's max values on product selection.
12
+ *
13
+ * To create a similar table for another domain:
14
+ * 1. Copy `fertiliser-table.config.ts` and define new columns there.
15
+ * 2. Create a new thin wrapper component (like this one) that wires the config
16
+ * and an optional rowTransform.
17
+ * 3. The generic InlineTableComponent requires no changes.
18
+ */
19
+ export declare class FertiliserTableComponent {
20
+ readonly entries: import("@angular/core").InputSignal<FieldSpreadingFertiliserEntry[]>;
21
+ readonly entriesChange: import("@angular/core").OutputEmitterRef<FieldSpreadingFertiliserEntry[]>;
22
+ /** Column/section config exposed to the template (constant — no signal needed). */
23
+ protected readonly config: import("../../../components/inline-table/inline-table.types").InlineTableConfig;
24
+ /** Cast typed entries to the generic Record[] expected by InlineTableComponent. */
25
+ readonly rowsForTable: import("@angular/core").Signal<Record<string, unknown>[]>;
26
+ /** Cast the generic output back to the typed FieldSpreadingFertiliserEntry[], stripping any
27
+ * ingredient with a 0 quantity so it never reaches the final JSON. */
28
+ onRowsChange(rows: Record<string, unknown>[]): void;
29
+ /**
30
+ * Row transform for auto-populating nutrient columns when a product is selected.
31
+ *
32
+ * Also imposes `transactionUnit = 'kg'` on every edit (not just product changes) so
33
+ * stale/imported rows with a different or null unit get corrected once touched —
34
+ * `createRow` already defaults new rows to 'kg', this is only a safety net.
35
+ *
36
+ * Defined as an arrow-function property so `this` is never needed and the function
37
+ * can be passed as a value to InlineTableComponent without losing its context.
38
+ *
39
+ * Only reacts to changes on the `fertiliserProductCategory` column key; all other
40
+ * edits pass through unchanged.
41
+ */
42
+ readonly autoPopulateNutrients: (changedKey: string, newValue: unknown, row: Record<string, unknown>) => Record<string, unknown>;
43
+ }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Column and section configuration for the Mineral Fertiliser inline table.
3
+ *
4
+ * This is the "uischema" for the Mineral fertilisers tab — it is the ONLY file
5
+ * that needs to be created/modified when adapting the inline table pattern for
6
+ * a different domain (e.g. recycling entries).
7
+ *
8
+ * Relationship to InlineTableComponent:
9
+ * - `columns` → drives header labels, cell widgets, grid widths, and code-list sources
10
+ * - `createRow` → produces a blank row with the ingredient sub-array pre-initialised
11
+ * - Labels reference i18n keys; chemical formula headers use `labelLiteral: true`
12
+ *
13
+ * Auto-population of nutrient columns on product selection is NOT configured here —
14
+ * that business logic lives in FertiliserTableComponent as a `rowTransform` function.
15
+ */
16
+ import type { InlineTableConfig } from '../../../components/inline-table/inline-table.types';
17
+ /** The four nutrient formulas tracked per fertiliser entry, in display order. */
18
+ export declare const NUTRIENT_COLUMNS: readonly ["Ntot", "P2O5", "K2O", "Mg"];
19
+ export type NutrientFormula = (typeof NUTRIENT_COLUMNS)[number];
20
+ export declare const FERTILISER_TABLE_CONFIG: InlineTableConfig;
@@ -1,13 +1,12 @@
1
- import { JsonSchema, UISchemaElement } from '@jsonforms/core';
2
- import { FieldSpreadingData } from './field-spreading.types';
1
+ import { JsonSchema } from '@jsonforms/core';
2
+ import { FieldSpreadingData, FieldSpreadingFertiliserEntry, FieldSpreadingRecyclingEntry } from './field-spreading.types';
3
3
  export declare class FieldSpreadingComponent {
4
4
  private readonly dataSvc;
5
5
  private readonly navigationSvc;
6
6
  private readonly i18n;
7
- private readonly rootData;
8
7
  constructor();
9
8
  readonly schema: import("@angular/core").Signal<JsonSchema>;
10
- readonly localizedUi: import("@angular/core").Signal<UISchemaElement>;
9
+ readonly localizedGeneralUi: import("@angular/core").Signal<import("@jsonforms/core").UISchemaElement>;
11
10
  readonly renderers: {
12
11
  tester: import("@jsonforms/core").RankedTester;
13
12
  renderer: any;
@@ -15,7 +14,20 @@ export declare class FieldSpreadingComponent {
15
14
  readonly ajv: import("ajv").Ajv;
16
15
  private readonly normalizedFieldSpreading;
17
16
  readonly jsonFormsData: import("@angular/core").Signal<(FieldSpreadingData & import("../../core/schemas/ui-helper-registry").UiHelperDefinitions) | null>;
17
+ /** Fertiliser entries exposed to the custom table component. */
18
+ readonly fertiliserEntries: import("@angular/core").Signal<FieldSpreadingFertiliserEntry[]>;
19
+ /** Recycling entries exposed to the custom table component. */
20
+ readonly recyclingEntries: import("@angular/core").Signal<FieldSpreadingRecyclingEntry[]>;
21
+ /** Drives mat-tab-group [selectedIndex] from NavigationService state. */
22
+ readonly activeTabIndex: import("@angular/core").Signal<number>;
23
+ onTabChange(index: number): void;
24
+ /** Called by both general JSONForms instances on data change.
25
+ * Preserves fertiliser and recycling entries managed by their custom table components. */
18
26
  onDataChange(event: unknown): void;
27
+ /** Called by FertiliserTableComponent when entries are added/edited/removed. */
28
+ onFertiliserChange(fertiliser: FieldSpreadingFertiliserEntry[]): void;
29
+ /** Called by RecyclingTableComponent when entries are added/edited/removed. */
30
+ onRecyclingChange(recycling: FieldSpreadingRecyclingEntry[]): void;
19
31
  private patchFieldSpreading;
20
32
  private normalizeFieldSpreading;
21
33
  private areFieldSpreadingEqual;
@@ -23,6 +23,7 @@ export interface FieldSpreadingIngredient {
23
23
  unit?: string | null;
24
24
  }
25
25
  export interface FieldSpreadingFertiliserEntry {
26
+ descriptor?: string | null;
26
27
  fertiliserProductCategory?: string | null;
27
28
  quantity?: number | null;
28
29
  transactionUnit?: string | null;
@@ -0,0 +1,8 @@
1
+ import { FieldSpreadingIngredient } from './field-spreading.types';
2
+ /**
3
+ * Ensures all ingredients are present in the output, converting `null` quantities to `0`
4
+ * to satisfy API requirements while still filtering out explicitly zeroed entries.
5
+ */
6
+ export declare function stripZeroQuantityIngredients<T extends {
7
+ ingredient?: FieldSpreadingIngredient[];
8
+ }>(entries: T[]): T[];
@@ -0,0 +1,31 @@
1
+ import { FieldSpreadingRecyclingEntry } from '../field-spreading.types';
2
+ /**
3
+ * RecyclingTableComponent — thin wrapper around InlineTableComponent.
4
+ *
5
+ * Responsibilities:
6
+ * 1. Provides `RECYCLING_TABLE_CONFIG` (the column/section "uischema").
7
+ * 2. Bridges typed `FieldSpreadingRecyclingEntry[]` to/from the generic
8
+ * `Record<string, unknown>[]` API of InlineTableComponent.
9
+ * 3. Supplies `deriveUnits` as a `rowTransform` — `transactionUnit` ('kg'/'m3') and every
10
+ * ingredient's `unit` ('kg/t'/'kg/m3') are fully derived from the selected product's
11
+ * matterState (never user-entered) — they are separate mappings, NOT a concatenation of
12
+ * one into the other (kg/kg would be wrong for solid products).
13
+ */
14
+ export declare class RecyclingTableComponent {
15
+ readonly entries: import("@angular/core").InputSignal<FieldSpreadingRecyclingEntry[]>;
16
+ readonly entriesChange: import("@angular/core").OutputEmitterRef<FieldSpreadingRecyclingEntry[]>;
17
+ /** Column/section config (constant — no signal needed). */
18
+ protected readonly config: import("../../../components/inline-table/inline-table.types").InlineTableConfig;
19
+ /** Cast typed entries to generic Record[] for InlineTableComponent. */
20
+ readonly rowsForTable: import("@angular/core").Signal<Record<string, unknown>[]>;
21
+ /** Cast generic output back to typed FieldSpreadingRecyclingEntry[], stripping any
22
+ * ingredient with a 0 quantity so it never reaches the final JSON. */
23
+ onRowsChange(rows: Record<string, unknown>[]): void;
24
+ /**
25
+ * Row transform re-deriving `transactionUnit` and every ingredient's `unit` from the
26
+ * product's matterState on each edit — runs unconditionally (not just when
27
+ * `typeOfManureRecyclingProduct` changes) so an edit made before the product is picked still
28
+ * resolves once it is.
29
+ */
30
+ readonly deriveUnits: (_changedKey: string, _newValue: unknown, row: Record<string, unknown>) => Record<string, unknown>;
31
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Column and section configuration for the Recycling Fertiliser inline table.
3
+ *
4
+ * This is the "uischema" for the Recycling fertilisers tab.
5
+ * The structure mirrors fertiliser-table.config.ts — only the columns differ:
6
+ * - Product field: typeOfManureRecyclingProduct (different code list)
7
+ * - Nutrient columns: Ntot, Nlos, P₂O₅, K₂O, Mg expressed in kg/unit (not %)
8
+ * — 5 nutrients vs 4 for mineral fertilisers, no auto-population on product select.
9
+ *
10
+ * To adapt again for a new domain, copy this file and adjust columns + i18n keys.
11
+ */
12
+ import type { InlineTableConfig } from '../../../components/inline-table/inline-table.types';
13
+ /** Nutrient formulas tracked per recycling entry, in display order. 'Nlos' = soluble nitrogen (matches the
14
+ * `molecularFormula` enum from assets/master-data/substances.json — NOT 'NSol', which the API rejects). */
15
+ export declare const RECYCLING_NUTRIENT_COLUMNS: readonly ["Ntot", "Nlos", "P2O5", "K2O", "Mg"];
16
+ export type RecyclingNutrientFormula = (typeof RECYCLING_NUTRIENT_COLUMNS)[number];
17
+ export declare const RECYCLING_TABLE_CONFIG: InlineTableConfig;
@@ -0,0 +1,4 @@
1
+ /** Derives the mandatory transaction unit ('kg' or 'm3') from the product's matterState. */
2
+ export declare function deriveRecyclingTransactionUnit(productCode: string | null | undefined): string | null;
3
+ /** Derives the mandatory ingredient unit ('kg/t' or 'kg/m3') from the product's matterState. */
4
+ export declare function deriveRecyclingIngredientUnit(productCode: string | null | undefined): string | null;