@agridea/suibi-module 0.1.0-preview.7 → 0.1.0-preview.87cac2d

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 (112) hide show
  1. package/README.md +10 -10
  2. package/dist/elements/browser/main.js +75 -72
  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 -72
  6. package/dist/elements/browser/{suibi-module.v0.1.0-preview.7.css → suibi-module.v0.1.0-preview.87cac2d.css} +1 -1
  7. package/dist/elements/browser/suibi-module.v0.1.0-preview.87cac2d.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 -1
  11. package/dist/types/app/app.d.ts +1 -3
  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 +226 -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} +3 -4
  17. package/dist/types/app/components/inline-table/inline-table.component.d.ts +159 -0
  18. package/dist/types/app/components/inline-table/inline-table.types.d.ts +212 -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 +38 -28
  32. package/dist/types/app/core/error/global-error-handler.d.ts +2 -3
  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 +36 -1
  39. package/dist/types/app/core/planning/planning-balance.service.d.ts +46 -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/utils/custom-unit.util.d.ts +39 -0
  43. package/dist/types/app/core/utils/object.util.d.ts +22 -0
  44. package/dist/types/app/core/validation/ajv-custom.d.ts +1 -0
  45. package/dist/types/app/core/validation/capabilities.d.ts +11 -5
  46. package/dist/types/app/core/validation/global-validation.service.d.ts +21 -4
  47. package/dist/types/app/jsonforms/filters/code-list-filter-resolvers.d.ts +3 -0
  48. package/dist/types/app/jsonforms/registry/renderers.registry.d.ts +8 -0
  49. package/dist/types/app/jsonforms/renderers/controls/selects/animal-category/animal-category-select.renderer.d.ts +1 -1
  50. package/dist/types/app/jsonforms/renderers/controls/selects/code-list/code-list-select.renderer.d.ts +10 -4
  51. package/dist/types/app/jsonforms/renderers/layout/array/array-layout.renderer.d.ts +43 -0
  52. package/dist/types/app/jsonforms/renderers/layout/categorization/selected-category-categorization.renderer.d.ts +3 -0
  53. package/dist/types/app/jsonforms/renderers/layout/constraint/constraint-layout.renderer.d.ts +1 -0
  54. package/dist/types/app/jsonforms/renderers/layout/group/base-group.renderer.d.ts +2 -0
  55. package/dist/types/app/jsonforms/renderers/layout/group/module-toggle-group.renderer.d.ts +38 -0
  56. package/dist/types/app/nutrient-cycle/animal-stock/animal-stock-detail/animal-stock-detail.component.d.ts +21 -0
  57. 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
  58. 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
  59. package/dist/types/app/nutrient-cycle/animal-stock/index.d.ts +3 -3
  60. package/dist/types/app/nutrient-cycle/farm-manure-trading/farm-manure-trading-master-detail/farm-manure-trading-master-detail.component.d.ts +19 -0
  61. package/dist/types/app/nutrient-cycle/farm-manure-trading/farm-manure-trading-table/farm-manure-trading-table.component.d.ts +37 -0
  62. package/dist/types/app/nutrient-cycle/farm-manure-trading/farm-manure-trading-table/farm-manure-trading-table.config.d.ts +24 -0
  63. package/dist/types/app/nutrient-cycle/farm-manure-trading/farm-manure-trading.types.d.ts +4 -0
  64. package/dist/types/app/nutrient-cycle/farm-manure-trading/index.d.ts +3 -3
  65. package/dist/types/app/nutrient-cycle/farm-manure-trading/transaction-unit.util.d.ts +2 -0
  66. package/dist/types/app/nutrient-cycle/field-cultivation/arable-land-table/arable-land-table.component.d.ts +23 -0
  67. package/dist/types/app/nutrient-cycle/field-cultivation/arable-land-table/arable-land-table.config.d.ts +16 -0
  68. package/dist/types/app/nutrient-cycle/field-cultivation/crop-harvest-table/crop-harvest-table.component.d.ts +21 -0
  69. package/dist/types/app/nutrient-cycle/field-cultivation/crop-harvest-table/crop-harvest-table.config.d.ts +13 -0
  70. package/dist/types/app/nutrient-cycle/field-cultivation/field-cultivation-detail/field-cultivation-detail.component.d.ts +22 -0
  71. package/dist/types/app/nutrient-cycle/field-cultivation/field-cultivation-general/field-cultivation-general.component.d.ts +20 -0
  72. package/dist/types/app/nutrient-cycle/field-cultivation/field-cultivation-list/field-cultivation-list.component.d.ts +17 -0
  73. package/dist/types/app/nutrient-cycle/field-cultivation/field-cultivation-master-detail/field-cultivation-master-detail.component.d.ts +29 -0
  74. package/dist/types/app/nutrient-cycle/field-cultivation/field-cultivation.types.d.ts +45 -0
  75. package/dist/types/app/nutrient-cycle/field-cultivation/field-cultivation.util.d.ts +10 -0
  76. package/dist/types/app/nutrient-cycle/field-cultivation/fodder-cropland-table/fodder-cropland-table.component.d.ts +29 -0
  77. package/dist/types/app/nutrient-cycle/field-cultivation/fodder-cropland-table/fodder-cropland-table.config.d.ts +21 -0
  78. package/dist/types/app/nutrient-cycle/field-cultivation/index.d.ts +9 -0
  79. package/dist/types/app/nutrient-cycle/field-cultivation/special-crops-table/special-crops-table.component.d.ts +29 -0
  80. package/dist/types/app/nutrient-cycle/field-cultivation/special-crops-table/special-crops-table.config.d.ts +54 -0
  81. package/dist/types/app/nutrient-cycle/field-spreading/fertiliser-table/fertiliser-table.component.d.ts +52 -0
  82. package/dist/types/app/nutrient-cycle/field-spreading/fertiliser-table/fertiliser-table.config.d.ts +20 -0
  83. package/dist/types/app/nutrient-cycle/field-spreading/field-spreading.component.d.ts +18 -4
  84. package/dist/types/app/nutrient-cycle/field-spreading/field-spreading.types.d.ts +1 -0
  85. package/dist/types/app/nutrient-cycle/field-spreading/ingredient.util.d.ts +8 -0
  86. package/dist/types/app/nutrient-cycle/field-spreading/recycling-table/recycling-table.component.d.ts +32 -0
  87. package/dist/types/app/nutrient-cycle/field-spreading/recycling-table/recycling-table.config.d.ts +17 -0
  88. package/dist/types/app/nutrient-cycle/field-spreading/recycling-table/recycling-transaction-unit.util.d.ts +4 -0
  89. package/dist/types/app/nutrient-cycle/fodder/fodder-master-detail/fodder-master-detail.component.d.ts +25 -0
  90. package/dist/types/app/nutrient-cycle/fodder/fodder-table/fodder-table.component.d.ts +28 -0
  91. package/dist/types/app/nutrient-cycle/fodder/fodder-table/fodder-table.config.d.ts +9 -0
  92. package/dist/types/app/nutrient-cycle/fodder/fodder.types.d.ts +34 -0
  93. package/dist/types/app/nutrient-cycle/fodder/index.d.ts +3 -0
  94. package/dist/types/app/nutrient-cycle/fodder/ingredient.util.d.ts +8 -0
  95. package/dist/types/app/nutrient-cycle/fodder/transaction-unit.util.d.ts +2 -0
  96. package/dist/types/app/nutrient-cycle/lifetime-performance/index.d.ts +2 -0
  97. package/dist/types/app/nutrient-cycle/lifetime-performance/lifetime-performance-form.component.d.ts +1 -1
  98. package/dist/types/app/nutrient-cycle/storage/index.d.ts +4 -0
  99. package/dist/types/app/nutrient-cycle/storage/storage-detail/storage-detail.component.d.ts +30 -0
  100. package/dist/types/app/nutrient-cycle/storage/storage-general/storage-general.component.d.ts +29 -0
  101. package/dist/types/app/nutrient-cycle/storage/storage-list/storage-list.component.d.ts +23 -0
  102. package/dist/types/app/nutrient-cycle/storage/storage-master-detail/storage-master-detail.component.d.ts +32 -0
  103. package/dist/types/app/nutrient-cycle/storage/storage.types.d.ts +40 -0
  104. package/dist/types/environments/environment.d.ts +5 -0
  105. package/dist/types/shared/material-icons.d.ts +3 -3
  106. package/package.json +68 -17
  107. package/dist/elements/browser/suibi-module.v0.1.0-preview.7.js +0 -75
  108. package/dist/types/app/nutrient-cycle/animal-stock/animal-stock-detail.component.d.ts +0 -22
  109. package/dist/types/app/nutrient-cycle/farm-manure-trading/farm-manure-trading-detail.component.d.ts +0 -27
  110. package/dist/types/app/nutrient-cycle/farm-manure-trading/farm-manure-trading-list.component.d.ts +0 -22
  111. package/dist/types/app/nutrient-cycle/farm-manure-trading/farm-manure-trading-master-detail.component.d.ts +0 -26
  112. /package/dist/types/app/{core/validation/validation-errors-panel.d.ts → components/validation-errors-panel/validation-errors-panel.component.d.ts} +0 -0
@@ -29,10 +29,8 @@ export declare class NaebiDataService {
29
29
  hoursPerDay: number;
30
30
  };
31
31
  stall: {
32
- stableSystem: number;
33
- stableCapacity: number;
32
+ stableSystem: string;
34
33
  stableVentilationType: number;
35
- stableAirPurification: number;
36
34
  hasStableDeepLitter: boolean;
37
35
  hasStableManureBeltDrying: boolean;
38
36
  stableManureRemovalFrequency: number;
@@ -41,10 +39,6 @@ export declare class NaebiDataService {
41
39
  hasStableFeedingStationElevated: boolean;
42
40
  hasStableFloorSlopedUrineDrainage: boolean;
43
41
  hasYard: boolean;
44
- yardFeeding: number;
45
- yardFloorType: number;
46
- yardDays: number;
47
- yardHoursPerDay: number;
48
42
  };
49
43
  };
50
44
  hasImpexDerivedExcretion: boolean;
@@ -52,6 +46,7 @@ export declare class NaebiDataService {
52
46
  feeding: {
53
47
  fodderConsumption: number;
54
48
  concentratedFeedstuffConsumption: number;
49
+ concentratedFeedStuffConsumption: number;
55
50
  winterFeeding: {
56
51
  feedingRoutine: {
57
52
  typeOfFeedstuffProduct: string;
@@ -76,19 +71,14 @@ export declare class NaebiDataService {
76
71
  }[];
77
72
  storage: {
78
73
  stableStrawLitter: number;
79
- manureSupplyProportionStored: number;
80
74
  slurrySupplyProportionStored: number;
81
75
  createFacilitySpecificManureProduct: boolean;
82
76
  createFacilitySpecificSlurryProduct: boolean;
77
+ slurryTankQuantity: number;
83
78
  dilutionRatio: number;
84
- manurePit: {
85
- cover: number;
86
- manureFromAnimalStockStored: {
87
- manureDerivation: string;
88
- proportionStored: number;
89
- }[];
90
- }[];
79
+ manurePit: never[];
91
80
  slurryTank: {
81
+ descriptor: string;
92
82
  volumeInM3: number;
93
83
  depthInM: number;
94
84
  cover: number;
@@ -97,16 +87,7 @@ export declare class NaebiDataService {
97
87
  }[];
98
88
  };
99
89
  farmManureTrading: {
100
- supply: {
101
- quantity: number;
102
- typeOfManureRecyclingProduct: string;
103
- transactionUnit: string;
104
- ingredient: {
105
- quantity: number;
106
- molecularFormula: string;
107
- unit: string;
108
- }[];
109
- }[];
90
+ supply: never[];
110
91
  dispense: {
111
92
  quantity: number;
112
93
  typeOfManureRecyclingProduct: string;
@@ -115,6 +96,11 @@ export declare class NaebiDataService {
115
96
  zoologicalAnimal: string;
116
97
  percentageAllocation: number;
117
98
  }[];
99
+ ingredient: {
100
+ quantity: number;
101
+ molecularFormula: string;
102
+ unit: string;
103
+ }[];
118
104
  }[];
119
105
  };
120
106
  fieldSpreading: {
@@ -138,6 +124,7 @@ export declare class NaebiDataService {
138
124
  proportionAppliedOtherMonths: number;
139
125
  };
140
126
  fertiliser: {
127
+ descriptor: string;
141
128
  fertiliserProductCategory: string;
142
129
  quantity: number;
143
130
  transactionUnit: string;
@@ -159,8 +146,6 @@ export declare class NaebiDataService {
159
146
  }[];
160
147
  };
161
148
  lifetimePerformance: {
162
- dailyGain: number;
163
- liveWeight: number;
164
149
  milkProductionReport: number;
165
150
  };
166
151
  fodder: {
@@ -175,6 +160,12 @@ export declare class NaebiDataService {
175
160
  unit: string;
176
161
  }[];
177
162
  }[];
163
+ dispense: {
164
+ typeOfFeedstuffProduct: string;
165
+ quantity: number;
166
+ transactionUnit: string;
167
+ ingredient: never[];
168
+ }[];
178
169
  };
179
170
  cropFromNonFodderCropland: {
180
171
  typeOfFeedstuffProduct: string;
@@ -190,6 +181,17 @@ export declare class NaebiDataService {
190
181
  totalBalanceErrorMargin: number;
191
182
  };
192
183
  fieldCultivation: {
184
+ buildingZoneAreaSize: number;
185
+ outdoorVegetableMainCropAreaSize: number;
186
+ indoorVegetableMainCropAreaSize: number;
187
+ feedingOfCropHarvest: {
188
+ agronomicCropCategory: string;
189
+ effectiveYield: number;
190
+ }[];
191
+ dispenseOfCropHarvest: {
192
+ agronomicCropCategory: string;
193
+ effectiveYield: number;
194
+ }[];
193
195
  fodderCropland: ({
194
196
  agronomicCropCategory: string;
195
197
  isMainCrop: boolean;
@@ -208,17 +210,25 @@ export declare class NaebiDataService {
208
210
  isMainCrop: boolean;
209
211
  areaSize: number;
210
212
  yieldPerSquareMeasure: number;
213
+ hasLongTermYieldDivergence: boolean;
211
214
  }[];
212
215
  special: {
213
216
  agronomicCropCategory: string;
214
217
  userSpecificPlantName: string;
215
218
  isMainCrop: boolean;
216
219
  areaSize: number;
217
- yieldPerSquareMeasure: number;
220
+ requirementCorrection: {
221
+ quantity: number;
222
+ molecularFormula: string;
223
+ unit: string;
224
+ }[];
218
225
  }[];
219
226
  };
220
227
  generateReport: boolean;
221
228
  };
229
+ calculationVersion: {
230
+ version: string;
231
+ };
222
232
  }>;
223
233
  private readonly _lastEmitted;
224
234
  private readonly _dirty;
@@ -1,6 +1,5 @@
1
- import { ErrorHandler, Injector } from '@angular/core';
1
+ import { ErrorHandler } from '@angular/core';
2
2
  export declare class GlobalErrorHandler implements ErrorHandler {
3
- private injector;
4
- constructor(injector: Injector);
3
+ private readonly injector;
5
4
  handleError(error: any): void;
6
5
  }
@@ -1,5 +1,5 @@
1
1
  import { PipeTransform, Signal } from '@angular/core';
2
- export type Locale = 'en' | 'de';
2
+ export type Locale = 'en' | 'de' | 'fr' | 'it';
3
3
  export type JsonFormsTranslator = (key: string, defaultMessage: string | undefined, context: unknown) => string;
4
4
  export declare class I18nService {
5
5
  private readonly _locale;
@@ -8,13 +8,15 @@ export declare class I18nService {
8
8
  readonly jsonFormsI18n: Signal<{
9
9
  locale: Locale;
10
10
  translate: JsonFormsTranslator;
11
+ translateError: (error: unknown, translate: JsonFormsTranslator) => string;
11
12
  }>;
12
13
  setLocale(locale: Locale): void;
14
+ /** Returns true if the given string is a supported locale key. */
15
+ isValidLocale(value: string): value is Locale;
13
16
  t(key: string, defaultMessage?: string): string;
14
17
  }
15
18
  export declare class TranslatePipe implements PipeTransform {
16
- private readonly i18n;
17
19
  private readonly cache;
18
- constructor(i18n: I18nService);
20
+ private readonly i18n;
19
21
  transform(key: string, defaultMessage?: string): Signal<string>;
20
22
  }
@@ -0,0 +1,2 @@
1
+ export declare const frTranslations: Record<string, string>;
2
+ export type FrTranslationKeys = keyof typeof frTranslations;
@@ -0,0 +1,2 @@
1
+ export declare const itTranslations: Record<string, string>;
2
+ export type ItTranslationKeys = keyof typeof itTranslations;
@@ -1,7 +1,9 @@
1
1
  import { Locale } from '../i18n/i18n.service';
2
- type MasterDataKeyField = 'id' | 'code';
2
+ /** The property name of the primary key in a master-data catalog entry. */
3
+ type MasterDataKeyField = string;
3
4
  interface MasterDataCatalog {
4
5
  entries: any[];
6
+ /** Property name to use as the lookup key; 'id' entries are coerced to Number. */
5
7
  key: MasterDataKeyField;
6
8
  }
7
9
  declare const MASTER_DATA: Record<string, MasterDataCatalog>;
@@ -21,5 +23,10 @@ export declare class MasterDataService {
21
23
  resolveUtilisation(id: number | string | null | undefined, locale?: Locale): string;
22
24
  resolveManureProduct(code: string | null | undefined, locale?: Locale): string;
23
25
  resolveZoologicalAnimal(code: string | null | undefined, locale?: Locale): string;
26
+ resolveCultivationCategory(code: string | null | undefined, locale?: Locale): string;
27
+ resolveAgronomicCropCategory(code: string | null | undefined, locale?: Locale): string;
28
+ resolveFeedstuffProduct(code: string | null | undefined, locale?: Locale): string;
29
+ resolveCover(id: number | string | null | undefined, locale?: Locale): string;
30
+ resolveMixingFrequency(id: number | string | null | undefined, locale?: Locale): string;
24
31
  }
25
32
  export {};
@@ -1,8 +1,18 @@
1
- export type SuibiVersion = '1.19' | '1.20';
1
+ export type SuibiVersion = 'v2.0';
2
2
  export type SubmissionStatus = 'draft' | 'submitted' | 'final';
3
+ /** Which computation modules are active for this dossier. */
4
+ export interface ComputationModules {
5
+ suisseBilanz: boolean;
6
+ gmf: boolean;
7
+ nh3: boolean;
8
+ impex: boolean;
9
+ linear: boolean;
10
+ }
11
+ export declare const DEFAULT_COMPUTATION_MODULES: ComputationModules;
3
12
  export interface SuibiMetadata {
4
13
  title: string;
5
14
  suibiVersion: SuibiVersion;
6
15
  status: SubmissionStatus;
16
+ modules: ComputationModules;
7
17
  }
8
18
  export declare const DEFAULT_SUIBI_METADATA: SuibiMetadata;
@@ -1,8 +1,13 @@
1
- export type PageId = 'welcome' | 'animal_stock' | 'data_preview' | 'storage' | 'field_spreading' | 'farm_manure_trading';
1
+ export type PageId = 'welcome' | 'animal_stock' | 'data_preview' | 'storage' | 'field_spreading' | 'farm_manure_trading' | 'fodder' | 'field_cultivation' | 'validation' | 'results';
2
2
  export type AnimalStockCategory = 'base' | 'formOfDetention' | 'feeding';
3
3
  export type FarmManureTradingMode = 'supply' | 'dispense';
4
4
  export type FarmManureTradingCategory = 'general' | 'derivation' | 'ingredients';
5
+ export type FodderMode = 'supply' | 'dispense' | 'non_fodder_cropland';
6
+ export type FodderCategory = 'general' | 'ingredients';
5
7
  export type FieldSpreadingCategory = 'general' | 'fertiliser' | 'recycling';
8
+ export type FieldCultivationTab = 'general' | 'fodderCropland' | 'arableLand' | 'special';
9
+ export type StorageTab = 'manure' | 'slurry';
10
+ export type StorageEntryType = 'manure_pit' | 'slurry_tank';
6
11
  /**
7
12
  * NavigationService
8
13
  * Global reactive store for application routing and deep-link state.
@@ -38,6 +43,26 @@ export declare class NavigationService {
38
43
  mode: FarmManureTradingMode;
39
44
  index: number;
40
45
  } | null>;
46
+ /** Selected fodder detail context (mode + index) */
47
+ readonly selectedFodderDetail: import("@angular/core").WritableSignal<{
48
+ mode: FodderMode;
49
+ index: number;
50
+ } | null>;
51
+ /** Selected field cultivation detail context (tab + index) */
52
+ readonly selectedFieldCultivationDetail: import("@angular/core").WritableSignal<{
53
+ tab: Exclude<FieldCultivationTab, "general">;
54
+ index: number;
55
+ } | null>;
56
+ /** Selected storage detail context (type + index) */
57
+ readonly selectedStorageDetail: import("@angular/core").WritableSignal<{
58
+ type: StorageEntryType;
59
+ index: number;
60
+ } | null>;
61
+ /** Selected field spreading row context (category/tab + row index) — used by validation deep-links */
62
+ readonly selectedFieldSpreadingDetail: import("@angular/core").WritableSignal<{
63
+ category: FieldSpreadingCategory;
64
+ index: number;
65
+ } | null>;
41
66
  /** True if currently viewing animal stock detail (not list) */
42
67
  readonly isAnimalStockDetailView: import("@angular/core").Signal<boolean>;
43
68
  /** True if currently on animal stock page (list or detail) */
@@ -58,10 +83,20 @@ export declare class NavigationService {
58
83
  navigateToAnimalStockDetail(index: number, category?: AnimalStockCategory): void;
59
84
  navigateToFarmManureTradingDetail(mode: FarmManureTradingMode, index: number, category?: FarmManureTradingCategory): void;
60
85
  navigateToFarmManureTradingList(): void;
86
+ navigateToFodderDetail(mode: FodderMode, index: number, category?: FodderCategory): void;
87
+ navigateToFodderList(): void;
61
88
  navigateToFieldSpreading(category?: FieldSpreadingCategory): void;
89
+ /** Deep-link to a specific row of a field spreading tab (e.g. from a validation error). */
90
+ navigateToFieldSpreadingDetail(category: FieldSpreadingCategory, index: number): void;
91
+ navigateToFieldCultivationDetail(tab: Exclude<FieldCultivationTab, 'general'>, index: number): void;
92
+ navigateToFieldCultivationList(tab?: FieldCultivationTab): void;
93
+ navigateToStorageDetail(type: StorageEntryType, index: number): void;
94
+ navigateToStorageList(tab?: StorageTab): void;
62
95
  /**
63
96
  * Set active category/tab for current page (without changing page/entry).
64
97
  * Generic method supporting any page's categorization navigation.
98
+ * No-op when page and category are already the same values to prevent
99
+ * unnecessary signal emissions that re-trigger the tab index computed.
65
100
  */
66
101
  setCategory(page: PageId, category: string): void;
67
102
  /**
@@ -0,0 +1,46 @@
1
+ import { NaebiData } from '../data/naebi-data.service';
2
+ import type { PlanningBalanceResponse } from './planning-balance.types';
3
+ export type { PlanningBalanceResponse } from './planning-balance.types';
4
+ /** Which backend to target for planning requests. */
5
+ export type PlanningEndpoint = 'ebilanz' | 'blw';
6
+ /**
7
+ * Sends NAEBI data to a planning endpoint and exposes the result as a
8
+ * signal-based resource. Call `runPlanning(data, endpoint)` to trigger a request.
9
+ *
10
+ * The ID counter ensures each call re-fetches even if the payload hasn't changed.
11
+ */
12
+ export declare class PlanningBalanceService {
13
+ private readonly http;
14
+ private readonly metadataSvc;
15
+ private readonly _value;
16
+ private readonly _error;
17
+ private readonly _isLoading;
18
+ private readonly _selectedEndpoint;
19
+ private readonly _lastStartedRequestId;
20
+ private readonly _lastCompletedRequestId;
21
+ private readonly _lastSuccessfulRequestId;
22
+ private _nextId;
23
+ private activeRequestId;
24
+ private activeRequestSub;
25
+ readonly planningResource: {
26
+ value: import("@angular/core").Signal<PlanningBalanceResponse | undefined>;
27
+ error: import("@angular/core").Signal<unknown>;
28
+ isLoading: import("@angular/core").Signal<boolean>;
29
+ hasValue: import("@angular/core").Signal<boolean>;
30
+ lastStartedRequestId: import("@angular/core").Signal<number>;
31
+ lastCompletedRequestId: import("@angular/core").Signal<number>;
32
+ lastSuccessfulRequestId: import("@angular/core").Signal<number>;
33
+ };
34
+ readonly selectedEndpoint: import("@angular/core").Signal<PlanningEndpoint>;
35
+ setSelectedEndpoint(endpoint: PlanningEndpoint): void;
36
+ /**
37
+ * Builds the exact payload posted to the planning API: calculationVersion stamped from
38
+ * the current metadata, `nutrientCycle.generateReport` forced to true (the PDF report
39
+ * must always be requested on submission), empty ingredient/routine slots stripped,
40
+ * null optional fields and host-only fields removed, custom display units converted
41
+ * to base units.
42
+ */
43
+ buildApiPayload(data: NaebiData): NaebiData;
44
+ /** Fire a new planning-balance request with the current NAEBI data payload. */
45
+ runPlanning(data: NaebiData, endpoint?: PlanningEndpoint): void;
46
+ }
@@ -0,0 +1,206 @@
1
+ /**
2
+ * TypeScript interfaces for the planning-balance API response.
3
+ * These match the eBilanz / BLW response shape observed in the example data.
4
+ */
5
+ /** A single nutrient quantity entry (kg or % unit). */
6
+ export interface NutrientEntry {
7
+ molecularFormula: string;
8
+ quantity: number;
9
+ quantityCorrected?: number;
10
+ unit: string;
11
+ productFamilyType?: string;
12
+ typeOfManureRecyclingProduct?: string;
13
+ fertiliserProductCategory?: string;
14
+ }
15
+ export interface CalculationVersion {
16
+ version: string;
17
+ validFrom: string;
18
+ validTo: string;
19
+ }
20
+ export interface AreaAndYieldPerAgronomicCropCategory {
21
+ agronomicCropCategory: string;
22
+ areaSize: number;
23
+ effectiveYield: number;
24
+ isMainCrop: boolean;
25
+ isNutrientPoorFodder: boolean;
26
+ yieldPerSquareMeasure?: number;
27
+ }
28
+ export interface AreaPerCultivationType {
29
+ areaSize: number;
30
+ isMainCrop: boolean;
31
+ }
32
+ export interface AreaAndYieldPerCultivationCategory {
33
+ cultivationCategory: string;
34
+ areaAndYieldPerAgronomicCropCategory: AreaAndYieldPerAgronomicCropCategory[];
35
+ areaPerCultivationType: AreaPerCultivationType[];
36
+ }
37
+ export interface AreaPerSubCategory {
38
+ cultivationSubCategory: string;
39
+ areaSize: number;
40
+ isMainCrop: boolean;
41
+ }
42
+ export interface FieldCultivation {
43
+ areaAndYieldPerCultivationCategory: AreaAndYieldPerCultivationCategory[];
44
+ areaPerSubCategory: AreaPerSubCategory[];
45
+ fertilizableAreaSize: number;
46
+ slurrySpreadingAreaSize: number;
47
+ totalAgriculturalLandAreaSize: number;
48
+ }
49
+ export interface FodderQuantity {
50
+ quantity: number;
51
+ unit: string;
52
+ proportionNutrientPoorFodder?: number;
53
+ }
54
+ export interface FodderProduct {
55
+ typeOfFeedstuffProduct: string;
56
+ quantity: number;
57
+ unit: string;
58
+ isNutrientPoorFodder: boolean;
59
+ }
60
+ export interface ConsumptionAnimalStock {
61
+ animalCategoryPRIF: number;
62
+ averageQuantity: number;
63
+ order: string;
64
+ quantity: number;
65
+ unit: string;
66
+ }
67
+ export interface RequiredEffectiveYieldFromFodderCropland {
68
+ consumptionAnimalStock: ConsumptionAnimalStock[];
69
+ cropFromNonFodderCroplandPerProduct: FodderProduct[];
70
+ dispensePerProduct: FodderProduct[];
71
+ supplyPerProduct: FodderProduct[];
72
+ totalBalance: FodderQuantity;
73
+ totalConsumptionAnimalStock: FodderQuantity;
74
+ totalCropFromNonFodderCropland: FodderQuantity;
75
+ totalDispense: FodderQuantity;
76
+ totalSupply: FodderQuantity;
77
+ }
78
+ export interface FodderBalance {
79
+ requiredEffectiveYieldFromFodderCropland: RequiredEffectiveYieldFromFodderCropland;
80
+ totalBalance: FodderQuantity;
81
+ totalEffectiveYieldFromFodderCropland: FodderQuantity;
82
+ totalNutrientPoorFodder: FodderQuantity;
83
+ }
84
+ export interface EmissionAndAccumulationEntry {
85
+ animalCategoryPRIF: number;
86
+ order: string;
87
+ accumulation: NutrientEntry[];
88
+ emission: NutrientEntry[];
89
+ manureExcretion?: unknown[];
90
+ }
91
+ export interface AccumulationEntireExcretion {
92
+ animalCategoryPRIF: number;
93
+ order: string;
94
+ durationSumTotalCorrectedNutrientBalance: number;
95
+ accumulation: NutrientEntry[];
96
+ }
97
+ export interface TotalNutrientSet {
98
+ accumulation: NutrientEntry[];
99
+ emission?: NutrientEntry[];
100
+ }
101
+ export interface AnimalStock {
102
+ accumulationEntireExcretion: AccumulationEntireExcretion[];
103
+ emissionAndAccumulationPasture: EmissionAndAccumulationEntry[];
104
+ emissionAndAccumulationStall: EmissionAndAccumulationEntry[];
105
+ emissionAndAccumulationYard: EmissionAndAccumulationEntry[];
106
+ totalAccumulationEntireExcretion: TotalNutrientSet;
107
+ totalEmissionAndAccumulationAnimalStock: TotalNutrientSet;
108
+ totalEmissionAndAccumulationPasture: TotalNutrientSet;
109
+ totalEmissionAndAccumulationStall: TotalNutrientSet;
110
+ totalEmissionAndAccumulationYard: TotalNutrientSet;
111
+ }
112
+ export interface ManureTradingProduct {
113
+ typeOfManureRecyclingProduct: string;
114
+ quantity: number;
115
+ unit: string;
116
+ ingredient: NutrientEntry[];
117
+ }
118
+ export interface FarmManureTrading {
119
+ balancePerProduct: ManureTradingProduct[];
120
+ dispensePerProduct: ManureTradingProduct[];
121
+ supplyPerProduct: ManureTradingProduct[];
122
+ totalBalance: {
123
+ ingredient: NutrientEntry[];
124
+ };
125
+ }
126
+ export interface NutrientRequirementEntry {
127
+ agronomicCropCategory?: string;
128
+ cultivationCategory?: string;
129
+ isMainCrop?: boolean;
130
+ requirement: NutrientEntry[];
131
+ }
132
+ export interface FieldCultivationNutrients {
133
+ nutrientTransferUnfertilizedCultivation: NutrientEntry[];
134
+ requirementPerAgronomicCropCategory: NutrientRequirementEntry[];
135
+ requirementPerCultivationCategory: NutrientRequirementEntry[];
136
+ totalRequirement: NutrientEntry[];
137
+ }
138
+ export interface FieldSpreading {
139
+ emissionAndAccumulationFieldSpreading: TotalNutrientSet;
140
+ totalEmissionAndAccumulationFieldSpreading: TotalNutrientSet;
141
+ }
142
+ export interface StorageBalance {
143
+ emissionAndAccumulationManureStorage: TotalNutrientSet;
144
+ totalEmissionAndAccumulationManureStorage: TotalNutrientSet;
145
+ }
146
+ export interface NutrientBalance {
147
+ animalStock: AnimalStock;
148
+ farmManureTrading: FarmManureTrading;
149
+ fieldCultivation: FieldCultivationNutrients;
150
+ fieldSpreading: FieldSpreading;
151
+ storage: StorageBalance;
152
+ /** Final per-nutrient balance figures: kg lines + % lines interleaved. */
153
+ totalBalance: NutrientEntry[];
154
+ /** Farm-wide gas emissions (NH3, NO, N2O, N2). */
155
+ totalEmissionFarm: NutrientEntry[];
156
+ nutrientBalanceTMP?: unknown[];
157
+ }
158
+ export interface NutrientCycle {
159
+ creationDateTime: string;
160
+ facilitySpecificProducts: {
161
+ manureRecyclingProduct: unknown[];
162
+ };
163
+ fieldCultivation: FieldCultivation;
164
+ fodderBalance: FodderBalance;
165
+ nutrientBalance: NutrientBalance;
166
+ version: string;
167
+ /** Base64-encoded PDF report, if returned by the endpoint. */
168
+ report?: string;
169
+ }
170
+ export interface ValidationMessageDetail {
171
+ designation_deu: string;
172
+ designation_eng: string;
173
+ designation_fra: string;
174
+ designation_ita: string;
175
+ }
176
+ export interface ValidationMessage {
177
+ field: string;
178
+ type: string;
179
+ detail: ValidationMessageDetail;
180
+ }
181
+ /** Full response from the planning-balance endpoint. */
182
+ export interface PlanningBalanceResponse {
183
+ calculationVersion: CalculationVersion;
184
+ nutrientCycle: NutrientCycle;
185
+ validationMessage: ValidationMessage[];
186
+ }
187
+ /** Merged kg + % row for the final balance table (Section D). */
188
+ export interface BalanceRow {
189
+ molecularFormula: string;
190
+ quantity: number;
191
+ quantityCorrected: number;
192
+ quantityPct: number | null;
193
+ quantityCorrectedPct: number | null;
194
+ unit: 'kg';
195
+ }
196
+ /** Crop requirement row enriched with area and yield for display (Section C). */
197
+ export interface CropRequirementRow {
198
+ cropCode: string;
199
+ cultivationCategory: string;
200
+ isMainCrop: boolean;
201
+ areaHa: number;
202
+ effectiveYield: number;
203
+ /** kg/ha yield per square measure field (m² basis), converted to dt/ha for display. */
204
+ yieldDtHa: number | null;
205
+ requirement: NutrientEntry[];
206
+ }
@@ -0,0 +1,10 @@
1
+ import type { BalanceRow, NutrientEntry } from './planning-balance.types';
2
+ /**
3
+ * Merges the interleaved kg / % rows from `totalBalance` into one `BalanceRow`
4
+ * per nutrient formula, preserving the canonical KEY_NUTRIENTS display order.
5
+ *
6
+ * The planning-balance API returns two `NutrientEntry` objects per formula
7
+ * (one with `unit === 'kg'`, one with `unit === '%'`). This function coalesces
8
+ * them so callers work with a single, normalised row.
9
+ */
10
+ export declare function mergeBalanceRows(totalBalance: NutrientEntry[]): BalanceRow[];
@@ -0,0 +1,39 @@
1
+ export interface CustomUnit {
2
+ /** Unit code stored on the row (e.g. 'ha', 't', 'dt'). */
3
+ code: string;
4
+ /** API base unit this custom unit converts to (e.g. 'm2', 'kg'). */
5
+ baseUnit: string;
6
+ /** Multiplier from the custom unit to its base unit (1 ha = 10'000 m2 → 10000). */
7
+ factor: number;
8
+ descriptor?: Record<string, unknown>;
9
+ }
10
+ export declare const CUSTOM_UNITS: readonly CustomUnit[];
11
+ /** True when the unit code is a custom display unit (not an API base unit). */
12
+ export declare function isCustomUnit(unit: unknown): boolean;
13
+ /** Base unit a quantity can be converted to: the custom unit's `baseUnit`, or the unit
14
+ * itself when it already is a base (or unknown) unit. */
15
+ export declare function baseUnitOf(unit: string | null | undefined): string | null | undefined;
16
+ /** Custom units convertible to the given base unit (e.g. 'kg' → [t, dt]). */
17
+ export declare function customUnitsForBaseUnit(baseUnit: string): CustomUnit[];
18
+ /**
19
+ * Builds a filter (compatible with the inline table's `optionsFilter`) keeping only the
20
+ * units compatible with the given context base unit(s) — i.e. each base unit plus its
21
+ * custom units. Pass a nullable base (e.g. derived from a product's matterState): `null`
22
+ * keeps the full list (nothing derived yet); pass an array of bases (e.g. ['kg', 'm3'])
23
+ * to pre-filter to their union before the exact base is known.
24
+ *
25
+ * Works on any entry shape exposing `id` (and `baseUnit` for custom units).
26
+ */
27
+ export declare function unitOptionsForBaseUnit<T extends {
28
+ id: string | number;
29
+ }>(contextBaseUnit: string | readonly string[] | null | undefined): (entry: T) => boolean;
30
+ /** Converts a quantity expressed in a custom unit to its base unit; pass-through for
31
+ * base/unknown units and null quantities. */
32
+ export declare function convertToBaseUnit(quantity: number | null | undefined, unit: string | null | undefined): {
33
+ quantity: number | null | undefined;
34
+ unit: string | null | undefined;
35
+ };
36
+ /** Converts a quantity between two units sharing the same base unit (kg ↔ t ↔ dt,
37
+ * m2 ↔ ha). Returns the quantity unchanged when either unit is missing or the units
38
+ * are incompatible (different base units). */
39
+ export declare function convertQuantityBetween(quantity: number | null | undefined, fromUnit: string | null | undefined, toUnit: string | null | undefined): number | null | undefined;
@@ -22,3 +22,25 @@ export declare function deepEqual(a: unknown, b: unknown): boolean;
22
22
  * @returns A deep copy of the value
23
23
  */
24
24
  export declare function deepClone<T>(value: T): T;
25
+ export declare function stripIncompleteIngredients<T>(value: T): T;
26
+ /**
27
+ * Sanitizes the planning payload: the calculation API (OpenAPI, no `nullable: true`
28
+ * anywhere) accepts an optional field as *absent* but rejects it when present with a
29
+ * null value ("must be string/number"). The working data model normalizes optional
30
+ * fields to null, so strip them at the submission boundary — mirroring what
31
+ * `stripIncompleteIngredients` does for ingredient slots.
32
+ *
33
+ * - inside `fieldCultivation` entry collections (fodderCropland, arableLand, special,
34
+ * feedingOfCropHarvest, dispenseOfCropHarvest): any null property is dropped
35
+ * (fieldName, userSpecificPlantName, yieldPerSquareMeasure, effectiveYield, …)
36
+ * - `nutrientCycle.fodder.trading.<collection>[].quantity`: null → dropped
37
+ * - `nutrientCycle.animalStock[].feeding.(winter|summer)Feeding`: never-filled routine
38
+ * slots (`{}` rows pre-created by the inline tables) and null fields are dropped;
39
+ * a season — and `feeding` itself — is removed when nothing filled-in remains
40
+ * - `nutrientCycle.fieldSpreading`: null fields dropped (`soilPh`, `slurry.*`,
41
+ * `manure.*`); `slurry`/`manure` removed when nothing filled-in remains
42
+ */
43
+ export declare function sanitizePlanningPayload(data: NaebiDataLike): NaebiDataLike;
44
+ /** Structural type so object.util stays free of a NaebiData import (circular-safe). */
45
+ type NaebiDataLike = Record<string, unknown>;
46
+ export {};
@@ -9,6 +9,7 @@ import Ajv from 'ajv';
9
9
  *
10
10
  * Custom keywords:
11
11
  * - `permittedStableSystem`: Validates stable system against animal category constraints
12
+ * - `proportionSum`: Validates the sum of one numeric field across array items
12
13
  *
13
14
  * @param options - Additional AJV options to merge with defaults
14
15
  */
@@ -5,14 +5,20 @@
5
5
  * All master data is embedded statically at compile time - no runtime HTTP calls.
6
6
  */
7
7
  /**
8
- * Derives permitted stable systems (husbandry type IDs) for a given animal category.
8
+ * Derives permitted stable systems (stableSystem enum strings) for a given animal category.
9
9
  *
10
10
  * @param animalCategoryPRIF - The PRIF animal category ID
11
- * @returns Array of permitted husbandry type IDs (stable systems)
11
+ * @returns Array of permitted stableSystem enum strings (e.g. 'HUS_TETHER')
12
12
  */
13
- export declare function derivePermittedStableSystems(animalCategoryPRIF: number | null | undefined): number[];
13
+ export declare function derivePermittedStableSystems(animalCategoryPRIF: number | null | undefined): string[];
14
14
  /**
15
15
  * Pre-computed map for performance (memoized at module load).
16
- * Maps animalCategoryPRIF -> array of permitted stableSystem values.
16
+ * Maps animalCategoryPRIF -> array of permitted stableSystem enum strings.
17
17
  */
18
- export declare const PERMITTED_STABLE_SYSTEMS: Record<number, number[]>;
18
+ export declare const PERMITTED_STABLE_SYSTEMS: Record<number, string[]>;
19
+ /**
20
+ * Pre-computed map of non-zero per-category minimum yields (yieldPerSquareMeasure).
21
+ * Only 8 of the 314 crop categories declare a minimum > 0 (e.g. cereals, peas);
22
+ * all others fall back to the schema-level `minimum: 0`.
23
+ */
24
+ export declare const CROP_MINIMUM_YIELD_PER_SQUARE_MEASURE: Record<string, number>;