@litusarchieve18/agricore-utils 1.0.25 → 1.0.27

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.
package/README.md CHANGED
@@ -183,6 +183,14 @@ Run the publish command:
183
183
  Bash
184
184
  npm publish --access public
185
185
  📝 Version History
186
+ V1.0.29 —
187
+
188
+ V1.0.28 —
189
+
190
+ V1.0.27 — adding get price helper, and adding adapter pattern to handle the conflicting price
191
+
192
+ V1.0.26 — updating evaluatebaseAccess to try look up the parent scope given the current scope is not
193
+
186
194
  V1.0.25 — adding privileges and changing RESOURCE_PATHS
187
195
 
188
196
  V1.0.24 — splitting role dependency into a new file
@@ -17,7 +17,8 @@ var CAT = {
17
17
  SUBSCRIPTION: "1",
18
18
  PERMISSION: "2",
19
19
  VALIDATION: "3",
20
- INTEGRITY: "4"
20
+ INTEGRITY: "4",
21
+ DATABASE: "5"
21
22
  };
22
23
  var ACT = {
23
24
  GENERIC: "00",
@@ -63,7 +64,8 @@ var ERROR_DICTIONARY = {
63
64
  "400": { title: "Data Conflict", text: "A conflict occurred with an existing record. Please review and try again." },
64
65
  "402": { title: "Duplicate Entry", text: "A record with this name or identifier already exists." },
65
66
  "403": { title: "Edit Conflict", text: "This record was recently updated by someone else. Please refresh and try again." },
66
- "404": { title: "Record In Use", text: "This record cannot be deleted because it is referenced by other data." }
67
+ "404": { title: "Record In Use", text: "This record cannot be deleted because it is referenced by other data." },
68
+ "405": { title: "Pricing Conflict", text: "Multiple active prices were found for this product. An administrator must resolve the conflict before this price can be used." }
67
69
  };
68
70
  var UserRole = {
69
71
  OWNER: "owner",
@@ -206,6 +206,66 @@ type ProductUnitType = typeof ProductUnit[keyof typeof ProductUnit];
206
206
  type CatalogSyncStatusType = typeof CatalogSyncStatus[keyof typeof CatalogSyncStatus];
207
207
  type StorageType = typeof StoragePhases[keyof typeof StoragePhases];
208
208
  type StockPolicyTierType = typeof StockPolicyTier[keyof typeof StockPolicyTier];
209
+ interface PricingContext {
210
+ productId: string;
211
+ companyId: string;
212
+ facilityId?: string;
213
+ accountCode?: string | null;
214
+ contractReferenceNumber?: string | null;
215
+ evaluationDate?: Date;
216
+ }
217
+ interface PriceResolutionResult {
218
+ unitPriceCents: number;
219
+ minimumOrderQuantity: number;
220
+ leadTimeDays: number | null;
221
+ priceSource: 'EXPLICIT_CONTRACT' | 'ACCOUNT_MATRIX' | 'INTERNAL_DEFAULT' | 'PRODUCT_FALLBACK';
222
+ sourceRecordId: string;
223
+ }
224
+ interface PricingDataSource {
225
+ findContractPrice(args: {
226
+ productId: string;
227
+ contractReferenceNumber: string;
228
+ targetDate: Date;
229
+ }): Promise<MatrixRow | null>;
230
+ findAccountPrice(args: {
231
+ productId: string;
232
+ accountCode: string;
233
+ targetDate: Date;
234
+ }): Promise<MatrixRow | null>;
235
+ findDefaultPrice(args: {
236
+ productId: string;
237
+ targetDate: Date;
238
+ }): Promise<MatrixRow | null>;
239
+ findBaseProduct(args: {
240
+ productId: string;
241
+ }): Promise<BaseProductRow | null>;
242
+ }
243
+ interface MatrixRow {
244
+ canonicalId: string;
245
+ matrixUnitPrice: number;
246
+ minimumOrderQuantity: number;
247
+ leadTimeDays: number | null;
248
+ }
249
+ interface BaseProductRow {
250
+ canonicalId: string;
251
+ unitPriceCents: number;
252
+ }
253
+ type Tier = 'EXPLICIT_CONTRACT' | 'ACCOUNT_MATRIX' | 'INTERNAL_DEFAULT';
254
+ interface PriceConflictCandidate {
255
+ sourceRecordId: string;
256
+ unitPriceCents: number;
257
+ validFrom: string;
258
+ validTo: string | null;
259
+ }
260
+ interface ShadowedCleanMatch {
261
+ tier: Tier;
262
+ unitPriceCents: number;
263
+ sourceRecordId: string;
264
+ matchedOn: {
265
+ accountCode?: string;
266
+ contractReferenceNumber?: string;
267
+ };
268
+ }
209
269
 
210
270
  declare const MOD: {
211
271
  readonly OPERATIONS: "OPR";
@@ -227,6 +287,7 @@ declare const CAT: {
227
287
  readonly PERMISSION: "2";
228
288
  readonly VALIDATION: "3";
229
289
  readonly INTEGRITY: "4";
290
+ readonly DATABASE: "5";
230
291
  };
231
292
  declare const ACT: {
232
293
  readonly GENERIC: "00";
@@ -685,4 +746,4 @@ declare const StockPolicyTier: {
685
746
  readonly BY_LOCATION: 3;
686
747
  };
687
748
 
688
- export { NettingType as $, ACCESS_RANK as A, BarcodeNamespace as B, CAR_SUPPORTED_EVIDENCE_MIME_TYPES as C, type CorrectiveActionCompileTaskMetadata as D, type CorrectiveActionGenerationSource as E, type CorrectiveActionStatus as F, CropCycleStatus as G, DOCUMENT_DISPLAY_INFO as H, DOCUMENT_MENU_MAP as I, DocumentCategory as J, DocumentType as K, ERROR_DICTIONARY as L, EVERYONE as M, EmitterType as N, EnabledModule as O, FORM_REGISTRY as P, FacilityType as Q, type FileUploadTaskType as R, type FormMeta as S, HarvestMethod as T, type InfrastructureFields as U, LinkedStatus as V, MOD as W, MODULE_LABELS as X, MicroclimateZone as Y, MimeType as Z, type ModCode as _, ACT as a, type NormalizedSignatureValue as a0, NotificationMode as a1, OrderStatus as a2, type PermissionLevel as a3, PhysicalState as a4, PlantingMethod as a5, ProductType as a6, type ProductTypeType as a7, ProductUnit as a8, type ProductUnitType as a9, TaskStatus as aA, TaskType as aB, type TaskTypeConfig as aC, type TemplateScopeLevel as aD, TransactionType as aE, TrellisType as aF, UserPrivilege as aG, type UserPrivilegeType as aH, UserRole as aI, type UserRoleAssignment as aJ, type UserRoleType as aK, VigorRating as aL, WaterSource as aM, type WireSession as aN, RESOURCE_MODULE_MAP as aa, RESOURCE_PATHS as ab, RESOURCE_REQUIREMENTS as ac, ROLE_SECTIONS_BY_KEY as ad, RelationshipType as ae, type ResolvedError as af, type ResourceOverrides as ag, type ResourceRequirement as ah, type RoleAssignment as ai, RowOrientation as aj, SENTINEL_UUID as ak, SESSION_SCHEMA as al, SIGNATURE_MODES as am, type SchemaField as an, type ScopeType as ao, type SignatureInput as ap, type SignatureMode as aq, SoilTexture as ar, StockPolicyTier as as, type StockPolicyTierType as at, StoragePhases as au, type StorageType as av, TASK_TYPE_REGISTRY as aw, TEMPLATE_SCOPE_LEVELS as ax, type TabConfig as ay, TargetEntityType as az, AccessLevel as b, type AccessLevelType as c, type AgriCoreSession as d, ApprovalStatus as e, ApprovalType as f, AuditStatus as g, AuditType as h, type AuthScopeFields as i, type AvailableScope as j, type BarcodeNamespaceType as k, BarcodeType as l, type BarcodeTypeType as m, type Base44Id as n, CAR_SUPPORTED_SIGNATURE_MIME_TYPES as o, CAT as p, CATEGORY_TABS as q, CORRECTIVE_ACTION_GENERATION_SOURCES as r, CORRECTIVE_ACTION_STATUSES as s, type CanonicalId as t, type CarSupportedEvidenceMimeType as u, type CarSupportedSignatureMimeType as v, type CarTemplateFileMetadata as w, CatalogSyncStatus as x, type CatalogSyncStatusType as y, type CompanyConfig as z };
749
+ export { MimeType as $, ACCESS_RANK as A, BarcodeNamespace as B, CAR_SUPPORTED_EVIDENCE_MIME_TYPES as C, type CompanyConfig as D, type CorrectiveActionCompileTaskMetadata as E, type CorrectiveActionGenerationSource as F, type CorrectiveActionStatus as G, CropCycleStatus as H, DOCUMENT_DISPLAY_INFO as I, DOCUMENT_MENU_MAP as J, DocumentCategory as K, DocumentType as L, ERROR_DICTIONARY as M, EVERYONE as N, EmitterType as O, EnabledModule as P, FORM_REGISTRY as Q, FacilityType as R, type FileUploadTaskType as S, type FormMeta as T, HarvestMethod as U, type InfrastructureFields as V, LinkedStatus as W, MOD as X, MODULE_LABELS as Y, type MatrixRow as Z, MicroclimateZone as _, ACT as a, type ModCode as a0, NettingType as a1, type NormalizedSignatureValue as a2, NotificationMode as a3, OrderStatus as a4, type PermissionLevel as a5, PhysicalState as a6, PlantingMethod as a7, type PriceConflictCandidate as a8, type PriceResolutionResult as a9, type StockPolicyTierType as aA, StoragePhases as aB, type StorageType as aC, TASK_TYPE_REGISTRY as aD, TEMPLATE_SCOPE_LEVELS as aE, type TabConfig as aF, TargetEntityType as aG, TaskStatus as aH, TaskType as aI, type TaskTypeConfig as aJ, type TemplateScopeLevel as aK, type Tier as aL, TransactionType as aM, TrellisType as aN, UserPrivilege as aO, type UserPrivilegeType as aP, UserRole as aQ, type UserRoleAssignment as aR, type UserRoleType as aS, VigorRating as aT, WaterSource as aU, type WireSession as aV, type PricingContext as aa, type PricingDataSource as ab, ProductType as ac, type ProductTypeType as ad, ProductUnit as ae, type ProductUnitType as af, RESOURCE_MODULE_MAP as ag, RESOURCE_PATHS as ah, RESOURCE_REQUIREMENTS as ai, ROLE_SECTIONS_BY_KEY as aj, RelationshipType as ak, type ResolvedError as al, type ResourceOverrides as am, type ResourceRequirement as an, type RoleAssignment as ao, RowOrientation as ap, SENTINEL_UUID as aq, SESSION_SCHEMA as ar, SIGNATURE_MODES as as, type SchemaField as at, type ScopeType as au, type ShadowedCleanMatch as av, type SignatureInput as aw, type SignatureMode as ax, SoilTexture as ay, StockPolicyTier as az, AccessLevel as b, type AccessLevelType as c, type AgriCoreSession as d, ApprovalStatus as e, ApprovalType as f, AuditStatus as g, AuditType as h, type AuthScopeFields as i, type AvailableScope as j, type BarcodeNamespaceType as k, BarcodeType as l, type BarcodeTypeType as m, type Base44Id as n, type BaseProductRow as o, CAR_SUPPORTED_SIGNATURE_MIME_TYPES as p, CAT as q, CATEGORY_TABS as r, CORRECTIVE_ACTION_GENERATION_SOURCES as s, CORRECTIVE_ACTION_STATUSES as t, type CanonicalId as u, type CarSupportedEvidenceMimeType as v, type CarSupportedSignatureMimeType as w, type CarTemplateFileMetadata as x, CatalogSyncStatus as y, type CatalogSyncStatusType as z };
@@ -206,6 +206,66 @@ type ProductUnitType = typeof ProductUnit[keyof typeof ProductUnit];
206
206
  type CatalogSyncStatusType = typeof CatalogSyncStatus[keyof typeof CatalogSyncStatus];
207
207
  type StorageType = typeof StoragePhases[keyof typeof StoragePhases];
208
208
  type StockPolicyTierType = typeof StockPolicyTier[keyof typeof StockPolicyTier];
209
+ interface PricingContext {
210
+ productId: string;
211
+ companyId: string;
212
+ facilityId?: string;
213
+ accountCode?: string | null;
214
+ contractReferenceNumber?: string | null;
215
+ evaluationDate?: Date;
216
+ }
217
+ interface PriceResolutionResult {
218
+ unitPriceCents: number;
219
+ minimumOrderQuantity: number;
220
+ leadTimeDays: number | null;
221
+ priceSource: 'EXPLICIT_CONTRACT' | 'ACCOUNT_MATRIX' | 'INTERNAL_DEFAULT' | 'PRODUCT_FALLBACK';
222
+ sourceRecordId: string;
223
+ }
224
+ interface PricingDataSource {
225
+ findContractPrice(args: {
226
+ productId: string;
227
+ contractReferenceNumber: string;
228
+ targetDate: Date;
229
+ }): Promise<MatrixRow | null>;
230
+ findAccountPrice(args: {
231
+ productId: string;
232
+ accountCode: string;
233
+ targetDate: Date;
234
+ }): Promise<MatrixRow | null>;
235
+ findDefaultPrice(args: {
236
+ productId: string;
237
+ targetDate: Date;
238
+ }): Promise<MatrixRow | null>;
239
+ findBaseProduct(args: {
240
+ productId: string;
241
+ }): Promise<BaseProductRow | null>;
242
+ }
243
+ interface MatrixRow {
244
+ canonicalId: string;
245
+ matrixUnitPrice: number;
246
+ minimumOrderQuantity: number;
247
+ leadTimeDays: number | null;
248
+ }
249
+ interface BaseProductRow {
250
+ canonicalId: string;
251
+ unitPriceCents: number;
252
+ }
253
+ type Tier = 'EXPLICIT_CONTRACT' | 'ACCOUNT_MATRIX' | 'INTERNAL_DEFAULT';
254
+ interface PriceConflictCandidate {
255
+ sourceRecordId: string;
256
+ unitPriceCents: number;
257
+ validFrom: string;
258
+ validTo: string | null;
259
+ }
260
+ interface ShadowedCleanMatch {
261
+ tier: Tier;
262
+ unitPriceCents: number;
263
+ sourceRecordId: string;
264
+ matchedOn: {
265
+ accountCode?: string;
266
+ contractReferenceNumber?: string;
267
+ };
268
+ }
209
269
 
210
270
  declare const MOD: {
211
271
  readonly OPERATIONS: "OPR";
@@ -227,6 +287,7 @@ declare const CAT: {
227
287
  readonly PERMISSION: "2";
228
288
  readonly VALIDATION: "3";
229
289
  readonly INTEGRITY: "4";
290
+ readonly DATABASE: "5";
230
291
  };
231
292
  declare const ACT: {
232
293
  readonly GENERIC: "00";
@@ -685,4 +746,4 @@ declare const StockPolicyTier: {
685
746
  readonly BY_LOCATION: 3;
686
747
  };
687
748
 
688
- export { NettingType as $, ACCESS_RANK as A, BarcodeNamespace as B, CAR_SUPPORTED_EVIDENCE_MIME_TYPES as C, type CorrectiveActionCompileTaskMetadata as D, type CorrectiveActionGenerationSource as E, type CorrectiveActionStatus as F, CropCycleStatus as G, DOCUMENT_DISPLAY_INFO as H, DOCUMENT_MENU_MAP as I, DocumentCategory as J, DocumentType as K, ERROR_DICTIONARY as L, EVERYONE as M, EmitterType as N, EnabledModule as O, FORM_REGISTRY as P, FacilityType as Q, type FileUploadTaskType as R, type FormMeta as S, HarvestMethod as T, type InfrastructureFields as U, LinkedStatus as V, MOD as W, MODULE_LABELS as X, MicroclimateZone as Y, MimeType as Z, type ModCode as _, ACT as a, type NormalizedSignatureValue as a0, NotificationMode as a1, OrderStatus as a2, type PermissionLevel as a3, PhysicalState as a4, PlantingMethod as a5, ProductType as a6, type ProductTypeType as a7, ProductUnit as a8, type ProductUnitType as a9, TaskStatus as aA, TaskType as aB, type TaskTypeConfig as aC, type TemplateScopeLevel as aD, TransactionType as aE, TrellisType as aF, UserPrivilege as aG, type UserPrivilegeType as aH, UserRole as aI, type UserRoleAssignment as aJ, type UserRoleType as aK, VigorRating as aL, WaterSource as aM, type WireSession as aN, RESOURCE_MODULE_MAP as aa, RESOURCE_PATHS as ab, RESOURCE_REQUIREMENTS as ac, ROLE_SECTIONS_BY_KEY as ad, RelationshipType as ae, type ResolvedError as af, type ResourceOverrides as ag, type ResourceRequirement as ah, type RoleAssignment as ai, RowOrientation as aj, SENTINEL_UUID as ak, SESSION_SCHEMA as al, SIGNATURE_MODES as am, type SchemaField as an, type ScopeType as ao, type SignatureInput as ap, type SignatureMode as aq, SoilTexture as ar, StockPolicyTier as as, type StockPolicyTierType as at, StoragePhases as au, type StorageType as av, TASK_TYPE_REGISTRY as aw, TEMPLATE_SCOPE_LEVELS as ax, type TabConfig as ay, TargetEntityType as az, AccessLevel as b, type AccessLevelType as c, type AgriCoreSession as d, ApprovalStatus as e, ApprovalType as f, AuditStatus as g, AuditType as h, type AuthScopeFields as i, type AvailableScope as j, type BarcodeNamespaceType as k, BarcodeType as l, type BarcodeTypeType as m, type Base44Id as n, CAR_SUPPORTED_SIGNATURE_MIME_TYPES as o, CAT as p, CATEGORY_TABS as q, CORRECTIVE_ACTION_GENERATION_SOURCES as r, CORRECTIVE_ACTION_STATUSES as s, type CanonicalId as t, type CarSupportedEvidenceMimeType as u, type CarSupportedSignatureMimeType as v, type CarTemplateFileMetadata as w, CatalogSyncStatus as x, type CatalogSyncStatusType as y, type CompanyConfig as z };
749
+ export { MimeType as $, ACCESS_RANK as A, BarcodeNamespace as B, CAR_SUPPORTED_EVIDENCE_MIME_TYPES as C, type CompanyConfig as D, type CorrectiveActionCompileTaskMetadata as E, type CorrectiveActionGenerationSource as F, type CorrectiveActionStatus as G, CropCycleStatus as H, DOCUMENT_DISPLAY_INFO as I, DOCUMENT_MENU_MAP as J, DocumentCategory as K, DocumentType as L, ERROR_DICTIONARY as M, EVERYONE as N, EmitterType as O, EnabledModule as P, FORM_REGISTRY as Q, FacilityType as R, type FileUploadTaskType as S, type FormMeta as T, HarvestMethod as U, type InfrastructureFields as V, LinkedStatus as W, MOD as X, MODULE_LABELS as Y, type MatrixRow as Z, MicroclimateZone as _, ACT as a, type ModCode as a0, NettingType as a1, type NormalizedSignatureValue as a2, NotificationMode as a3, OrderStatus as a4, type PermissionLevel as a5, PhysicalState as a6, PlantingMethod as a7, type PriceConflictCandidate as a8, type PriceResolutionResult as a9, type StockPolicyTierType as aA, StoragePhases as aB, type StorageType as aC, TASK_TYPE_REGISTRY as aD, TEMPLATE_SCOPE_LEVELS as aE, type TabConfig as aF, TargetEntityType as aG, TaskStatus as aH, TaskType as aI, type TaskTypeConfig as aJ, type TemplateScopeLevel as aK, type Tier as aL, TransactionType as aM, TrellisType as aN, UserPrivilege as aO, type UserPrivilegeType as aP, UserRole as aQ, type UserRoleAssignment as aR, type UserRoleType as aS, VigorRating as aT, WaterSource as aU, type WireSession as aV, type PricingContext as aa, type PricingDataSource as ab, ProductType as ac, type ProductTypeType as ad, ProductUnit as ae, type ProductUnitType as af, RESOURCE_MODULE_MAP as ag, RESOURCE_PATHS as ah, RESOURCE_REQUIREMENTS as ai, ROLE_SECTIONS_BY_KEY as aj, RelationshipType as ak, type ResolvedError as al, type ResourceOverrides as am, type ResourceRequirement as an, type RoleAssignment as ao, RowOrientation as ap, SENTINEL_UUID as aq, SESSION_SCHEMA as ar, SIGNATURE_MODES as as, type SchemaField as at, type ScopeType as au, type ShadowedCleanMatch as av, type SignatureInput as aw, type SignatureMode as ax, SoilTexture as ay, StockPolicyTier as az, AccessLevel as b, type AccessLevelType as c, type AgriCoreSession as d, ApprovalStatus as e, ApprovalType as f, AuditStatus as g, AuditType as h, type AuthScopeFields as i, type AvailableScope as j, type BarcodeNamespaceType as k, BarcodeType as l, type BarcodeTypeType as m, type Base44Id as n, type BaseProductRow as o, CAR_SUPPORTED_SIGNATURE_MIME_TYPES as p, CAT as q, CATEGORY_TABS as r, CORRECTIVE_ACTION_GENERATION_SOURCES as s, CORRECTIVE_ACTION_STATUSES as t, type CanonicalId as u, type CarSupportedEvidenceMimeType as v, type CarSupportedSignatureMimeType as w, type CarTemplateFileMetadata as x, CatalogSyncStatus as y, type CatalogSyncStatusType as z };
@@ -1 +1 @@
1
- export { A as ACCESS_RANK, a as ACT, b as AccessLevel, e as ApprovalStatus, f as ApprovalType, g as AuditStatus, h as AuditType, B as BarcodeNamespace, l as BarcodeType, C as CAR_SUPPORTED_EVIDENCE_MIME_TYPES, o as CAR_SUPPORTED_SIGNATURE_MIME_TYPES, p as CAT, q as CATEGORY_TABS, r as CORRECTIVE_ACTION_GENERATION_SOURCES, s as CORRECTIVE_ACTION_STATUSES, x as CatalogSyncStatus, G as CropCycleStatus, H as DOCUMENT_DISPLAY_INFO, I as DOCUMENT_MENU_MAP, J as DocumentCategory, K as DocumentType, L as ERROR_DICTIONARY, M as EVERYONE, N as EmitterType, O as EnabledModule, P as FORM_REGISTRY, Q as FacilityType, T as HarvestMethod, V as LinkedStatus, W as MOD, X as MODULE_LABELS, Y as MicroclimateZone, Z as MimeType, _ as ModCode, $ as NettingType, a1 as NotificationMode, a2 as OrderStatus, a4 as PhysicalState, a5 as PlantingMethod, a6 as ProductType, a8 as ProductUnit, aa as RESOURCE_MODULE_MAP, ab as RESOURCE_PATHS, ac as RESOURCE_REQUIREMENTS, ad as ROLE_SECTIONS_BY_KEY, ae as RelationshipType, ah as ResourceRequirement, aj as RowOrientation, ak as SENTINEL_UUID, al as SESSION_SCHEMA, am as SIGNATURE_MODES, ar as SoilTexture, as as StockPolicyTier, au as StoragePhases, aw as TASK_TYPE_REGISTRY, ax as TEMPLATE_SCOPE_LEVELS, az as TargetEntityType, aA as TaskStatus, aB as TaskType, aE as TransactionType, aF as TrellisType, aG as UserPrivilege, aI as UserRole, aL as VigorRating, aM as WaterSource } from './constants-D5sndLi7.mjs';
1
+ export { A as ACCESS_RANK, a as ACT, b as AccessLevel, e as ApprovalStatus, f as ApprovalType, g as AuditStatus, h as AuditType, B as BarcodeNamespace, l as BarcodeType, C as CAR_SUPPORTED_EVIDENCE_MIME_TYPES, p as CAR_SUPPORTED_SIGNATURE_MIME_TYPES, q as CAT, r as CATEGORY_TABS, s as CORRECTIVE_ACTION_GENERATION_SOURCES, t as CORRECTIVE_ACTION_STATUSES, y as CatalogSyncStatus, H as CropCycleStatus, I as DOCUMENT_DISPLAY_INFO, J as DOCUMENT_MENU_MAP, K as DocumentCategory, L as DocumentType, M as ERROR_DICTIONARY, N as EVERYONE, O as EmitterType, P as EnabledModule, Q as FORM_REGISTRY, R as FacilityType, U as HarvestMethod, W as LinkedStatus, X as MOD, Y as MODULE_LABELS, _ as MicroclimateZone, $ as MimeType, a0 as ModCode, a1 as NettingType, a3 as NotificationMode, a4 as OrderStatus, a6 as PhysicalState, a7 as PlantingMethod, ac as ProductType, ae as ProductUnit, ag as RESOURCE_MODULE_MAP, ah as RESOURCE_PATHS, ai as RESOURCE_REQUIREMENTS, aj as ROLE_SECTIONS_BY_KEY, ak as RelationshipType, an as ResourceRequirement, ap as RowOrientation, aq as SENTINEL_UUID, ar as SESSION_SCHEMA, as as SIGNATURE_MODES, ay as SoilTexture, az as StockPolicyTier, aB as StoragePhases, aD as TASK_TYPE_REGISTRY, aE as TEMPLATE_SCOPE_LEVELS, aG as TargetEntityType, aH as TaskStatus, aI as TaskType, aM as TransactionType, aN as TrellisType, aO as UserPrivilege, aQ as UserRole, aT as VigorRating, aU as WaterSource } from './constants-dvGSNAt_.mjs';
@@ -1 +1 @@
1
- export { A as ACCESS_RANK, a as ACT, b as AccessLevel, e as ApprovalStatus, f as ApprovalType, g as AuditStatus, h as AuditType, B as BarcodeNamespace, l as BarcodeType, C as CAR_SUPPORTED_EVIDENCE_MIME_TYPES, o as CAR_SUPPORTED_SIGNATURE_MIME_TYPES, p as CAT, q as CATEGORY_TABS, r as CORRECTIVE_ACTION_GENERATION_SOURCES, s as CORRECTIVE_ACTION_STATUSES, x as CatalogSyncStatus, G as CropCycleStatus, H as DOCUMENT_DISPLAY_INFO, I as DOCUMENT_MENU_MAP, J as DocumentCategory, K as DocumentType, L as ERROR_DICTIONARY, M as EVERYONE, N as EmitterType, O as EnabledModule, P as FORM_REGISTRY, Q as FacilityType, T as HarvestMethod, V as LinkedStatus, W as MOD, X as MODULE_LABELS, Y as MicroclimateZone, Z as MimeType, _ as ModCode, $ as NettingType, a1 as NotificationMode, a2 as OrderStatus, a4 as PhysicalState, a5 as PlantingMethod, a6 as ProductType, a8 as ProductUnit, aa as RESOURCE_MODULE_MAP, ab as RESOURCE_PATHS, ac as RESOURCE_REQUIREMENTS, ad as ROLE_SECTIONS_BY_KEY, ae as RelationshipType, ah as ResourceRequirement, aj as RowOrientation, ak as SENTINEL_UUID, al as SESSION_SCHEMA, am as SIGNATURE_MODES, ar as SoilTexture, as as StockPolicyTier, au as StoragePhases, aw as TASK_TYPE_REGISTRY, ax as TEMPLATE_SCOPE_LEVELS, az as TargetEntityType, aA as TaskStatus, aB as TaskType, aE as TransactionType, aF as TrellisType, aG as UserPrivilege, aI as UserRole, aL as VigorRating, aM as WaterSource } from './constants-D5sndLi7.js';
1
+ export { A as ACCESS_RANK, a as ACT, b as AccessLevel, e as ApprovalStatus, f as ApprovalType, g as AuditStatus, h as AuditType, B as BarcodeNamespace, l as BarcodeType, C as CAR_SUPPORTED_EVIDENCE_MIME_TYPES, p as CAR_SUPPORTED_SIGNATURE_MIME_TYPES, q as CAT, r as CATEGORY_TABS, s as CORRECTIVE_ACTION_GENERATION_SOURCES, t as CORRECTIVE_ACTION_STATUSES, y as CatalogSyncStatus, H as CropCycleStatus, I as DOCUMENT_DISPLAY_INFO, J as DOCUMENT_MENU_MAP, K as DocumentCategory, L as DocumentType, M as ERROR_DICTIONARY, N as EVERYONE, O as EmitterType, P as EnabledModule, Q as FORM_REGISTRY, R as FacilityType, U as HarvestMethod, W as LinkedStatus, X as MOD, Y as MODULE_LABELS, _ as MicroclimateZone, $ as MimeType, a0 as ModCode, a1 as NettingType, a3 as NotificationMode, a4 as OrderStatus, a6 as PhysicalState, a7 as PlantingMethod, ac as ProductType, ae as ProductUnit, ag as RESOURCE_MODULE_MAP, ah as RESOURCE_PATHS, ai as RESOURCE_REQUIREMENTS, aj as ROLE_SECTIONS_BY_KEY, ak as RelationshipType, an as ResourceRequirement, ap as RowOrientation, aq as SENTINEL_UUID, ar as SESSION_SCHEMA, as as SIGNATURE_MODES, ay as SoilTexture, az as StockPolicyTier, aB as StoragePhases, aD as TASK_TYPE_REGISTRY, aE as TEMPLATE_SCOPE_LEVELS, aG as TargetEntityType, aH as TaskStatus, aI as TaskType, aM as TransactionType, aN as TrellisType, aO as UserPrivilege, aQ as UserRole, aT as VigorRating, aU as WaterSource } from './constants-dvGSNAt_.js';
package/dist/constants.js CHANGED
@@ -103,7 +103,8 @@ var CAT = {
103
103
  SUBSCRIPTION: "1",
104
104
  PERMISSION: "2",
105
105
  VALIDATION: "3",
106
- INTEGRITY: "4"
106
+ INTEGRITY: "4",
107
+ DATABASE: "5"
107
108
  };
108
109
  var ACT = {
109
110
  GENERIC: "00",
@@ -149,7 +150,8 @@ var ERROR_DICTIONARY = {
149
150
  "400": { title: "Data Conflict", text: "A conflict occurred with an existing record. Please review and try again." },
150
151
  "402": { title: "Duplicate Entry", text: "A record with this name or identifier already exists." },
151
152
  "403": { title: "Edit Conflict", text: "This record was recently updated by someone else. Please refresh and try again." },
152
- "404": { title: "Record In Use", text: "This record cannot be deleted because it is referenced by other data." }
153
+ "404": { title: "Record In Use", text: "This record cannot be deleted because it is referenced by other data." },
154
+ "405": { title: "Pricing Conflict", text: "Multiple active prices were found for this product. An administrator must resolve the conflict before this price can be used." }
153
155
  };
154
156
  var UserRole = {
155
157
  OWNER: "owner",
@@ -62,7 +62,7 @@ import {
62
62
  UserRole,
63
63
  VigorRating,
64
64
  WaterSource
65
- } from "./chunk-OFNQBQP4.mjs";
65
+ } from "./chunk-Y5KVDVNY.mjs";
66
66
  export {
67
67
  ACCESS_RANK,
68
68
  ACT,
package/dist/index.d.mts CHANGED
@@ -1,5 +1,5 @@
1
- import { d as AgriCoreSession, aJ as UserRoleAssignment, ao as ScopeType, aN as WireSession, ah as ResourceRequirement, c as AccessLevelType, j as AvailableScope, U as InfrastructureFields, S as FormMeta, ay as TabConfig, af as ResolvedError } from './constants-D5sndLi7.mjs';
2
- export { A as ACCESS_RANK, a as ACT, b as AccessLevel, e as ApprovalStatus, f as ApprovalType, g as AuditStatus, h as AuditType, i as AuthScopeFields, B as BarcodeNamespace, k as BarcodeNamespaceType, l as BarcodeType, m as BarcodeTypeType, n as Base44Id, C as CAR_SUPPORTED_EVIDENCE_MIME_TYPES, o as CAR_SUPPORTED_SIGNATURE_MIME_TYPES, p as CAT, q as CATEGORY_TABS, r as CORRECTIVE_ACTION_GENERATION_SOURCES, s as CORRECTIVE_ACTION_STATUSES, t as CanonicalId, u as CarSupportedEvidenceMimeType, v as CarSupportedSignatureMimeType, w as CarTemplateFileMetadata, x as CatalogSyncStatus, y as CatalogSyncStatusType, z as CompanyConfig, D as CorrectiveActionCompileTaskMetadata, E as CorrectiveActionGenerationSource, F as CorrectiveActionStatus, G as CropCycleStatus, H as DOCUMENT_DISPLAY_INFO, I as DOCUMENT_MENU_MAP, J as DocumentCategory, K as DocumentType, L as ERROR_DICTIONARY, M as EVERYONE, N as EmitterType, O as EnabledModule, P as FORM_REGISTRY, Q as FacilityType, R as FileUploadTaskType, T as HarvestMethod, V as LinkedStatus, W as MOD, X as MODULE_LABELS, Y as MicroclimateZone, Z as MimeType, _ as ModCode, $ as NettingType, a0 as NormalizedSignatureValue, a1 as NotificationMode, a2 as OrderStatus, a3 as PermissionLevel, a4 as PhysicalState, a5 as PlantingMethod, a6 as ProductType, a7 as ProductTypeType, a8 as ProductUnit, a9 as ProductUnitType, aa as RESOURCE_MODULE_MAP, ab as RESOURCE_PATHS, ac as RESOURCE_REQUIREMENTS, ad as ROLE_SECTIONS_BY_KEY, ae as RelationshipType, ag as ResourceOverrides, ai as RoleAssignment, aj as RowOrientation, ak as SENTINEL_UUID, al as SESSION_SCHEMA, am as SIGNATURE_MODES, an as SchemaField, ap as SignatureInput, aq as SignatureMode, ar as SoilTexture, as as StockPolicyTier, at as StockPolicyTierType, au as StoragePhases, av as StorageType, aw as TASK_TYPE_REGISTRY, ax as TEMPLATE_SCOPE_LEVELS, az as TargetEntityType, aA as TaskStatus, aB as TaskType, aC as TaskTypeConfig, aD as TemplateScopeLevel, aE as TransactionType, aF as TrellisType, aG as UserPrivilege, aH as UserPrivilegeType, aI as UserRole, aK as UserRoleType, aL as VigorRating, aM as WaterSource } from './constants-D5sndLi7.mjs';
1
+ import { d as AgriCoreSession, aR as UserRoleAssignment, aL as Tier, a8 as PriceConflictCandidate, av as ShadowedCleanMatch, ab as PricingDataSource, aa as PricingContext, a9 as PriceResolutionResult, au as ScopeType, aV as WireSession, an as ResourceRequirement, c as AccessLevelType, j as AvailableScope, V as InfrastructureFields, T as FormMeta, aF as TabConfig, al as ResolvedError } from './constants-dvGSNAt_.mjs';
2
+ export { A as ACCESS_RANK, a as ACT, b as AccessLevel, e as ApprovalStatus, f as ApprovalType, g as AuditStatus, h as AuditType, i as AuthScopeFields, B as BarcodeNamespace, k as BarcodeNamespaceType, l as BarcodeType, m as BarcodeTypeType, n as Base44Id, o as BaseProductRow, C as CAR_SUPPORTED_EVIDENCE_MIME_TYPES, p as CAR_SUPPORTED_SIGNATURE_MIME_TYPES, q as CAT, r as CATEGORY_TABS, s as CORRECTIVE_ACTION_GENERATION_SOURCES, t as CORRECTIVE_ACTION_STATUSES, u as CanonicalId, v as CarSupportedEvidenceMimeType, w as CarSupportedSignatureMimeType, x as CarTemplateFileMetadata, y as CatalogSyncStatus, z as CatalogSyncStatusType, D as CompanyConfig, E as CorrectiveActionCompileTaskMetadata, F as CorrectiveActionGenerationSource, G as CorrectiveActionStatus, H as CropCycleStatus, I as DOCUMENT_DISPLAY_INFO, J as DOCUMENT_MENU_MAP, K as DocumentCategory, L as DocumentType, M as ERROR_DICTIONARY, N as EVERYONE, O as EmitterType, P as EnabledModule, Q as FORM_REGISTRY, R as FacilityType, S as FileUploadTaskType, U as HarvestMethod, W as LinkedStatus, X as MOD, Y as MODULE_LABELS, Z as MatrixRow, _ as MicroclimateZone, $ as MimeType, a0 as ModCode, a1 as NettingType, a2 as NormalizedSignatureValue, a3 as NotificationMode, a4 as OrderStatus, a5 as PermissionLevel, a6 as PhysicalState, a7 as PlantingMethod, ac as ProductType, ad as ProductTypeType, ae as ProductUnit, af as ProductUnitType, ag as RESOURCE_MODULE_MAP, ah as RESOURCE_PATHS, ai as RESOURCE_REQUIREMENTS, aj as ROLE_SECTIONS_BY_KEY, ak as RelationshipType, am as ResourceOverrides, ao as RoleAssignment, ap as RowOrientation, aq as SENTINEL_UUID, ar as SESSION_SCHEMA, as as SIGNATURE_MODES, at as SchemaField, aw as SignatureInput, ax as SignatureMode, ay as SoilTexture, az as StockPolicyTier, aA as StockPolicyTierType, aB as StoragePhases, aC as StorageType, aD as TASK_TYPE_REGISTRY, aE as TEMPLATE_SCOPE_LEVELS, aG as TargetEntityType, aH as TaskStatus, aI as TaskType, aJ as TaskTypeConfig, aK as TemplateScopeLevel, aM as TransactionType, aN as TrellisType, aO as UserPrivilege, aP as UserPrivilegeType, aQ as UserRole, aS as UserRoleType, aT as VigorRating, aU as WaterSource } from './constants-dvGSNAt_.mjs';
3
3
 
4
4
  declare const AgriLogger: {
5
5
  log(level: "INFO" | "WARN" | "ERROR", message: string, meta: any): void;
@@ -18,6 +18,28 @@ declare function transformRoleAssignments(assignments: UserRoleAssignment[]): Re
18
18
  privileges: string[];
19
19
  }>;
20
20
 
21
+ declare class PriceAmbiguityError extends Error {
22
+ readonly productId: string;
23
+ readonly tier: Tier;
24
+ readonly candidates: PriceConflictCandidate[];
25
+ readonly matchedOn: {
26
+ accountCode?: string;
27
+ contractReferenceNumber?: string;
28
+ };
29
+ constructor(productId: string, tier: Tier, candidates: PriceConflictCandidate[], matchedOn?: {
30
+ accountCode?: string;
31
+ contractReferenceNumber?: string;
32
+ });
33
+ }
34
+ declare class AggregatePriceAmbiguityError extends Error {
35
+ readonly productId: string;
36
+ readonly conflicts: PriceAmbiguityError[];
37
+ readonly shadowedCleanMatches: ShadowedCleanMatch[];
38
+ constructor(productId: string, conflicts: PriceAmbiguityError[], shadowedCleanMatches?: ShadowedCleanMatch[]);
39
+ }
40
+ declare function resolvePrice(dataSource: PricingDataSource, context: PricingContext): Promise<PriceResolutionResult>;
41
+ declare function createBase44PricingAdapter(db: any): PricingDataSource;
42
+
21
43
  declare const Validator: {
22
44
  /** * 1. Email: The classic. Uses a standard RFC 5322 regex.
23
45
  */
@@ -84,15 +106,16 @@ declare class AppError extends Error {
84
106
  status: number;
85
107
  appCode: string;
86
108
  isOperational: boolean;
87
- constructor(status: number, mod: string, cat: string, act: string, message: string);
109
+ details?: unknown;
110
+ constructor(status: number, mod: string, cat: string, act: string, message: string, details?: unknown);
88
111
  }
89
112
  declare const ErrorFactory: {
90
113
  unauthorized: (mod: string, msg?: string) => AppError;
91
114
  forbidden: (mod: string, act: string, msg?: string) => AppError;
92
115
  badRequest: (mod: string, act: string, msg?: string) => AppError;
93
116
  notFound: (mod: string, act?: "00", msg?: string) => AppError;
94
- conflict: (mod: string, act: string, msg?: string) => AppError;
95
- integrity: (mod: string, act?: "00", msg?: string) => AppError;
117
+ conflict: (mod: string, act: string, msg?: string, details?: unknown) => AppError;
118
+ integrity: (mod: string, act?: "00", msg?: string, details?: unknown) => AppError;
96
119
  subscription: (mod: string, msg?: string) => AppError;
97
120
  internal: (mod: string, msg?: string) => AppError;
98
121
  };
@@ -178,4 +201,4 @@ declare function calculateFileMetadataMatch(criteria: {
178
201
  contextMatch?: string[];
179
202
  }, fileMetadata: Record<string, any>, auditContext: Record<string, any>): number;
180
203
 
181
- export { AccessLevelType, AgriCoreSession, AgriLogger, AppError, AvailableScope, Converter, ErrorFactory, FormMeta, InfrastructureFields, ResolvedError, ResourceRequirement, ScopeType, TabConfig, UserRoleAssignment, Validator, WireSession, assertTenantBoundary, calculateFileMetadataMatch, decodeSession, encodeSession, evaluateBaseAccess, extractAppCode, findSpecificOverride, generateCanonicalId, generateDocumentPath, generateInfrastructureFields, getAcceptedMimeTypes, getApproveAction, getFormMeta, getFormsGroupedByModule, getPrivilegesAt, getRoleAt, getScopeAncestry, getTaskTypeOptions, handleAppErrorResponse, hasPrivilegeAt, hasRoleAt, isTabVisible, isTabWritable, resolveAccess, resolveAppError, resolveEffectiveAccess, resolveError, transformRoleAssignments, verifyAndExtractSession, withAgriLogging };
204
+ export { AccessLevelType, AggregatePriceAmbiguityError, AgriCoreSession, AgriLogger, AppError, AvailableScope, Converter, ErrorFactory, FormMeta, InfrastructureFields, PriceAmbiguityError, PriceConflictCandidate, PriceResolutionResult, PricingContext, PricingDataSource, ResolvedError, ResourceRequirement, ScopeType, ShadowedCleanMatch, TabConfig, Tier, UserRoleAssignment, Validator, WireSession, assertTenantBoundary, calculateFileMetadataMatch, createBase44PricingAdapter, decodeSession, encodeSession, evaluateBaseAccess, extractAppCode, findSpecificOverride, generateCanonicalId, generateDocumentPath, generateInfrastructureFields, getAcceptedMimeTypes, getApproveAction, getFormMeta, getFormsGroupedByModule, getPrivilegesAt, getRoleAt, getScopeAncestry, getTaskTypeOptions, handleAppErrorResponse, hasPrivilegeAt, hasRoleAt, isTabVisible, isTabWritable, resolveAccess, resolveAppError, resolveEffectiveAccess, resolveError, resolvePrice, transformRoleAssignments, verifyAndExtractSession, withAgriLogging };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { d as AgriCoreSession, aJ as UserRoleAssignment, ao as ScopeType, aN as WireSession, ah as ResourceRequirement, c as AccessLevelType, j as AvailableScope, U as InfrastructureFields, S as FormMeta, ay as TabConfig, af as ResolvedError } from './constants-D5sndLi7.js';
2
- export { A as ACCESS_RANK, a as ACT, b as AccessLevel, e as ApprovalStatus, f as ApprovalType, g as AuditStatus, h as AuditType, i as AuthScopeFields, B as BarcodeNamespace, k as BarcodeNamespaceType, l as BarcodeType, m as BarcodeTypeType, n as Base44Id, C as CAR_SUPPORTED_EVIDENCE_MIME_TYPES, o as CAR_SUPPORTED_SIGNATURE_MIME_TYPES, p as CAT, q as CATEGORY_TABS, r as CORRECTIVE_ACTION_GENERATION_SOURCES, s as CORRECTIVE_ACTION_STATUSES, t as CanonicalId, u as CarSupportedEvidenceMimeType, v as CarSupportedSignatureMimeType, w as CarTemplateFileMetadata, x as CatalogSyncStatus, y as CatalogSyncStatusType, z as CompanyConfig, D as CorrectiveActionCompileTaskMetadata, E as CorrectiveActionGenerationSource, F as CorrectiveActionStatus, G as CropCycleStatus, H as DOCUMENT_DISPLAY_INFO, I as DOCUMENT_MENU_MAP, J as DocumentCategory, K as DocumentType, L as ERROR_DICTIONARY, M as EVERYONE, N as EmitterType, O as EnabledModule, P as FORM_REGISTRY, Q as FacilityType, R as FileUploadTaskType, T as HarvestMethod, V as LinkedStatus, W as MOD, X as MODULE_LABELS, Y as MicroclimateZone, Z as MimeType, _ as ModCode, $ as NettingType, a0 as NormalizedSignatureValue, a1 as NotificationMode, a2 as OrderStatus, a3 as PermissionLevel, a4 as PhysicalState, a5 as PlantingMethod, a6 as ProductType, a7 as ProductTypeType, a8 as ProductUnit, a9 as ProductUnitType, aa as RESOURCE_MODULE_MAP, ab as RESOURCE_PATHS, ac as RESOURCE_REQUIREMENTS, ad as ROLE_SECTIONS_BY_KEY, ae as RelationshipType, ag as ResourceOverrides, ai as RoleAssignment, aj as RowOrientation, ak as SENTINEL_UUID, al as SESSION_SCHEMA, am as SIGNATURE_MODES, an as SchemaField, ap as SignatureInput, aq as SignatureMode, ar as SoilTexture, as as StockPolicyTier, at as StockPolicyTierType, au as StoragePhases, av as StorageType, aw as TASK_TYPE_REGISTRY, ax as TEMPLATE_SCOPE_LEVELS, az as TargetEntityType, aA as TaskStatus, aB as TaskType, aC as TaskTypeConfig, aD as TemplateScopeLevel, aE as TransactionType, aF as TrellisType, aG as UserPrivilege, aH as UserPrivilegeType, aI as UserRole, aK as UserRoleType, aL as VigorRating, aM as WaterSource } from './constants-D5sndLi7.js';
1
+ import { d as AgriCoreSession, aR as UserRoleAssignment, aL as Tier, a8 as PriceConflictCandidate, av as ShadowedCleanMatch, ab as PricingDataSource, aa as PricingContext, a9 as PriceResolutionResult, au as ScopeType, aV as WireSession, an as ResourceRequirement, c as AccessLevelType, j as AvailableScope, V as InfrastructureFields, T as FormMeta, aF as TabConfig, al as ResolvedError } from './constants-dvGSNAt_.js';
2
+ export { A as ACCESS_RANK, a as ACT, b as AccessLevel, e as ApprovalStatus, f as ApprovalType, g as AuditStatus, h as AuditType, i as AuthScopeFields, B as BarcodeNamespace, k as BarcodeNamespaceType, l as BarcodeType, m as BarcodeTypeType, n as Base44Id, o as BaseProductRow, C as CAR_SUPPORTED_EVIDENCE_MIME_TYPES, p as CAR_SUPPORTED_SIGNATURE_MIME_TYPES, q as CAT, r as CATEGORY_TABS, s as CORRECTIVE_ACTION_GENERATION_SOURCES, t as CORRECTIVE_ACTION_STATUSES, u as CanonicalId, v as CarSupportedEvidenceMimeType, w as CarSupportedSignatureMimeType, x as CarTemplateFileMetadata, y as CatalogSyncStatus, z as CatalogSyncStatusType, D as CompanyConfig, E as CorrectiveActionCompileTaskMetadata, F as CorrectiveActionGenerationSource, G as CorrectiveActionStatus, H as CropCycleStatus, I as DOCUMENT_DISPLAY_INFO, J as DOCUMENT_MENU_MAP, K as DocumentCategory, L as DocumentType, M as ERROR_DICTIONARY, N as EVERYONE, O as EmitterType, P as EnabledModule, Q as FORM_REGISTRY, R as FacilityType, S as FileUploadTaskType, U as HarvestMethod, W as LinkedStatus, X as MOD, Y as MODULE_LABELS, Z as MatrixRow, _ as MicroclimateZone, $ as MimeType, a0 as ModCode, a1 as NettingType, a2 as NormalizedSignatureValue, a3 as NotificationMode, a4 as OrderStatus, a5 as PermissionLevel, a6 as PhysicalState, a7 as PlantingMethod, ac as ProductType, ad as ProductTypeType, ae as ProductUnit, af as ProductUnitType, ag as RESOURCE_MODULE_MAP, ah as RESOURCE_PATHS, ai as RESOURCE_REQUIREMENTS, aj as ROLE_SECTIONS_BY_KEY, ak as RelationshipType, am as ResourceOverrides, ao as RoleAssignment, ap as RowOrientation, aq as SENTINEL_UUID, ar as SESSION_SCHEMA, as as SIGNATURE_MODES, at as SchemaField, aw as SignatureInput, ax as SignatureMode, ay as SoilTexture, az as StockPolicyTier, aA as StockPolicyTierType, aB as StoragePhases, aC as StorageType, aD as TASK_TYPE_REGISTRY, aE as TEMPLATE_SCOPE_LEVELS, aG as TargetEntityType, aH as TaskStatus, aI as TaskType, aJ as TaskTypeConfig, aK as TemplateScopeLevel, aM as TransactionType, aN as TrellisType, aO as UserPrivilege, aP as UserPrivilegeType, aQ as UserRole, aS as UserRoleType, aT as VigorRating, aU as WaterSource } from './constants-dvGSNAt_.js';
3
3
 
4
4
  declare const AgriLogger: {
5
5
  log(level: "INFO" | "WARN" | "ERROR", message: string, meta: any): void;
@@ -18,6 +18,28 @@ declare function transformRoleAssignments(assignments: UserRoleAssignment[]): Re
18
18
  privileges: string[];
19
19
  }>;
20
20
 
21
+ declare class PriceAmbiguityError extends Error {
22
+ readonly productId: string;
23
+ readonly tier: Tier;
24
+ readonly candidates: PriceConflictCandidate[];
25
+ readonly matchedOn: {
26
+ accountCode?: string;
27
+ contractReferenceNumber?: string;
28
+ };
29
+ constructor(productId: string, tier: Tier, candidates: PriceConflictCandidate[], matchedOn?: {
30
+ accountCode?: string;
31
+ contractReferenceNumber?: string;
32
+ });
33
+ }
34
+ declare class AggregatePriceAmbiguityError extends Error {
35
+ readonly productId: string;
36
+ readonly conflicts: PriceAmbiguityError[];
37
+ readonly shadowedCleanMatches: ShadowedCleanMatch[];
38
+ constructor(productId: string, conflicts: PriceAmbiguityError[], shadowedCleanMatches?: ShadowedCleanMatch[]);
39
+ }
40
+ declare function resolvePrice(dataSource: PricingDataSource, context: PricingContext): Promise<PriceResolutionResult>;
41
+ declare function createBase44PricingAdapter(db: any): PricingDataSource;
42
+
21
43
  declare const Validator: {
22
44
  /** * 1. Email: The classic. Uses a standard RFC 5322 regex.
23
45
  */
@@ -84,15 +106,16 @@ declare class AppError extends Error {
84
106
  status: number;
85
107
  appCode: string;
86
108
  isOperational: boolean;
87
- constructor(status: number, mod: string, cat: string, act: string, message: string);
109
+ details?: unknown;
110
+ constructor(status: number, mod: string, cat: string, act: string, message: string, details?: unknown);
88
111
  }
89
112
  declare const ErrorFactory: {
90
113
  unauthorized: (mod: string, msg?: string) => AppError;
91
114
  forbidden: (mod: string, act: string, msg?: string) => AppError;
92
115
  badRequest: (mod: string, act: string, msg?: string) => AppError;
93
116
  notFound: (mod: string, act?: "00", msg?: string) => AppError;
94
- conflict: (mod: string, act: string, msg?: string) => AppError;
95
- integrity: (mod: string, act?: "00", msg?: string) => AppError;
117
+ conflict: (mod: string, act: string, msg?: string, details?: unknown) => AppError;
118
+ integrity: (mod: string, act?: "00", msg?: string, details?: unknown) => AppError;
96
119
  subscription: (mod: string, msg?: string) => AppError;
97
120
  internal: (mod: string, msg?: string) => AppError;
98
121
  };
@@ -178,4 +201,4 @@ declare function calculateFileMetadataMatch(criteria: {
178
201
  contextMatch?: string[];
179
202
  }, fileMetadata: Record<string, any>, auditContext: Record<string, any>): number;
180
203
 
181
- export { AccessLevelType, AgriCoreSession, AgriLogger, AppError, AvailableScope, Converter, ErrorFactory, FormMeta, InfrastructureFields, ResolvedError, ResourceRequirement, ScopeType, TabConfig, UserRoleAssignment, Validator, WireSession, assertTenantBoundary, calculateFileMetadataMatch, decodeSession, encodeSession, evaluateBaseAccess, extractAppCode, findSpecificOverride, generateCanonicalId, generateDocumentPath, generateInfrastructureFields, getAcceptedMimeTypes, getApproveAction, getFormMeta, getFormsGroupedByModule, getPrivilegesAt, getRoleAt, getScopeAncestry, getTaskTypeOptions, handleAppErrorResponse, hasPrivilegeAt, hasRoleAt, isTabVisible, isTabWritable, resolveAccess, resolveAppError, resolveEffectiveAccess, resolveError, transformRoleAssignments, verifyAndExtractSession, withAgriLogging };
204
+ export { AccessLevelType, AggregatePriceAmbiguityError, AgriCoreSession, AgriLogger, AppError, AvailableScope, Converter, ErrorFactory, FormMeta, InfrastructureFields, PriceAmbiguityError, PriceConflictCandidate, PriceResolutionResult, PricingContext, PricingDataSource, ResolvedError, ResourceRequirement, ScopeType, ShadowedCleanMatch, TabConfig, Tier, UserRoleAssignment, Validator, WireSession, assertTenantBoundary, calculateFileMetadataMatch, createBase44PricingAdapter, decodeSession, encodeSession, evaluateBaseAccess, extractAppCode, findSpecificOverride, generateCanonicalId, generateDocumentPath, generateInfrastructureFields, getAcceptedMimeTypes, getApproveAction, getFormMeta, getFormsGroupedByModule, getPrivilegesAt, getRoleAt, getScopeAncestry, getTaskTypeOptions, handleAppErrorResponse, hasPrivilegeAt, hasRoleAt, isTabVisible, isTabWritable, resolveAccess, resolveAppError, resolveEffectiveAccess, resolveError, resolvePrice, transformRoleAssignments, verifyAndExtractSession, withAgriLogging };
package/dist/index.js CHANGED
@@ -23,6 +23,7 @@ __export(index_exports, {
23
23
  ACCESS_RANK: () => ACCESS_RANK,
24
24
  ACT: () => ACT,
25
25
  AccessLevel: () => AccessLevel,
26
+ AggregatePriceAmbiguityError: () => AggregatePriceAmbiguityError,
26
27
  AgriLogger: () => AgriLogger,
27
28
  AppError: () => AppError,
28
29
  ApprovalStatus: () => ApprovalStatus,
@@ -62,6 +63,7 @@ __export(index_exports, {
62
63
  OrderStatus: () => OrderStatus,
63
64
  PhysicalState: () => PhysicalState,
64
65
  PlantingMethod: () => PlantingMethod,
66
+ PriceAmbiguityError: () => PriceAmbiguityError,
65
67
  ProductType: () => ProductType,
66
68
  ProductUnit: () => ProductUnit,
67
69
  RESOURCE_MODULE_MAP: () => RESOURCE_MODULE_MAP,
@@ -90,6 +92,7 @@ __export(index_exports, {
90
92
  WaterSource: () => WaterSource,
91
93
  assertTenantBoundary: () => assertTenantBoundary,
92
94
  calculateFileMetadataMatch: () => calculateFileMetadataMatch,
95
+ createBase44PricingAdapter: () => createBase44PricingAdapter,
93
96
  decodeSession: () => decodeSession,
94
97
  encodeSession: () => encodeSession,
95
98
  evaluateBaseAccess: () => evaluateBaseAccess,
@@ -115,6 +118,7 @@ __export(index_exports, {
115
118
  resolveAppError: () => resolveAppError,
116
119
  resolveEffectiveAccess: () => resolveEffectiveAccess,
117
120
  resolveError: () => resolveError,
121
+ resolvePrice: () => resolvePrice,
118
122
  transformRoleAssignments: () => transformRoleAssignments,
119
123
  verifyAndExtractSession: () => verifyAndExtractSession,
120
124
  withAgriLogging: () => withAgriLogging
@@ -247,6 +251,182 @@ function transformRoleAssignments(assignments) {
247
251
  return result;
248
252
  }
249
253
 
254
+ // src/priceHelpers.ts
255
+ var PriceAmbiguityError = class extends Error {
256
+ constructor(productId, tier, candidates, matchedOn = {}) {
257
+ const keyDescription = matchedOn.contractReferenceNumber ? `contract ${matchedOn.contractReferenceNumber}` : matchedOn.accountCode ? `account ${matchedOn.accountCode}` : "the system default";
258
+ super(
259
+ `Ambiguous pricing for product ${productId} at tier ${tier} (${keyDescription}): ${candidates.length} overlapping active prices found (${candidates.map((c) => `$${(c.unitPriceCents / 100).toFixed(2)}`).join(", ")}).`
260
+ );
261
+ this.productId = productId;
262
+ this.tier = tier;
263
+ this.candidates = candidates;
264
+ this.matchedOn = matchedOn;
265
+ this.name = "PriceAmbiguityError";
266
+ }
267
+ productId;
268
+ tier;
269
+ candidates;
270
+ matchedOn;
271
+ };
272
+ var AggregatePriceAmbiguityError = class extends Error {
273
+ constructor(productId, conflicts, shadowedCleanMatches = []) {
274
+ const tierList = conflicts.map((c) => c.tier).join(", ");
275
+ const note = shadowedCleanMatches.length > 0 ? ` Note: ${shadowedCleanMatches.length} other tier(s) had a clean price available but were not used, since a higher-priority tier must be resolved first.` : "";
276
+ super(
277
+ `Pricing for product ${productId} could not be resolved: ambiguous prices found at ${conflicts.length} tier(s) [${tierList}].${note}`
278
+ );
279
+ this.productId = productId;
280
+ this.conflicts = conflicts;
281
+ this.shadowedCleanMatches = shadowedCleanMatches;
282
+ this.name = "AggregatePriceAmbiguityError";
283
+ }
284
+ productId;
285
+ conflicts;
286
+ shadowedCleanMatches;
287
+ };
288
+ function fromMatrixRow(row, priceSource) {
289
+ return {
290
+ unitPriceCents: row.matrixUnitPrice,
291
+ minimumOrderQuantity: row.minimumOrderQuantity,
292
+ leadTimeDays: row.leadTimeDays,
293
+ priceSource,
294
+ sourceRecordId: row.canonicalId
295
+ };
296
+ }
297
+ async function resolvePrice(dataSource, context) {
298
+ const targetDate = context.evaluationDate ?? /* @__PURE__ */ new Date();
299
+ const conflicts = [];
300
+ const shadowedCleanMatches = [];
301
+ async function tryTier(lookup) {
302
+ try {
303
+ return await lookup();
304
+ } catch (err) {
305
+ if (err instanceof PriceAmbiguityError) {
306
+ conflicts.push(err);
307
+ return null;
308
+ }
309
+ throw err;
310
+ }
311
+ }
312
+ function handleCleanRow(row, tier, matchedOn) {
313
+ if (!row) return null;
314
+ if (conflicts.length === 0) return fromMatrixRow(row, tier);
315
+ shadowedCleanMatches.push({
316
+ tier,
317
+ unitPriceCents: row.matrixUnitPrice,
318
+ sourceRecordId: row.canonicalId,
319
+ matchedOn
320
+ });
321
+ return null;
322
+ }
323
+ if (context.contractReferenceNumber) {
324
+ const row = await tryTier(
325
+ () => dataSource.findContractPrice({
326
+ productId: context.productId,
327
+ contractReferenceNumber: context.contractReferenceNumber,
328
+ targetDate
329
+ })
330
+ );
331
+ const result = handleCleanRow(row, "EXPLICIT_CONTRACT", {
332
+ contractReferenceNumber: context.contractReferenceNumber
333
+ });
334
+ if (result) return result;
335
+ }
336
+ if (context.accountCode && context.accountCode !== "INTERNAL_DEFAULT") {
337
+ const row = await tryTier(
338
+ () => dataSource.findAccountPrice({
339
+ productId: context.productId,
340
+ accountCode: context.accountCode,
341
+ targetDate
342
+ })
343
+ );
344
+ const result = handleCleanRow(row, "ACCOUNT_MATRIX", { accountCode: context.accountCode });
345
+ if (result) return result;
346
+ }
347
+ const defaultRow = await tryTier(
348
+ () => dataSource.findDefaultPrice({ productId: context.productId, targetDate })
349
+ );
350
+ const defaultResult = handleCleanRow(defaultRow, "INTERNAL_DEFAULT", {});
351
+ if (defaultResult) return defaultResult;
352
+ if (conflicts.length > 0) {
353
+ throw new AggregatePriceAmbiguityError(context.productId, conflicts, shadowedCleanMatches);
354
+ }
355
+ const baseProduct = await dataSource.findBaseProduct({ productId: context.productId });
356
+ if (baseProduct) {
357
+ return {
358
+ unitPriceCents: baseProduct.unitPriceCents,
359
+ minimumOrderQuantity: 1,
360
+ leadTimeDays: null,
361
+ priceSource: "PRODUCT_FALLBACK",
362
+ sourceRecordId: baseProduct.canonicalId
363
+ };
364
+ }
365
+ throw new Error(`Critical Architecture Error: Product ${context.productId} not found in system catalog.`);
366
+ }
367
+ var ACTIVE_ROW_LOOKBACK = 5;
368
+ var SORT_MOST_RECENT_FIRST = "-validFrom";
369
+ function pickActiveRow(rows, targetIso, productId, tier, matchedOn) {
370
+ const activeMatches = rows.filter(
371
+ (r) => r.validTo === null || new Date(r.validTo).toISOString() >= targetIso
372
+ );
373
+ if (activeMatches.length > 1) {
374
+ throw new PriceAmbiguityError(
375
+ productId,
376
+ tier,
377
+ activeMatches.map((r) => ({
378
+ sourceRecordId: r.canonicalId,
379
+ unitPriceCents: r.matrixUnitPrice,
380
+ validFrom: r.validFrom,
381
+ validTo: r.validTo
382
+ })),
383
+ matchedOn
384
+ );
385
+ }
386
+ return activeMatches[0] ?? null;
387
+ }
388
+ function createBase44PricingAdapter(db) {
389
+ return {
390
+ async findContractPrice({ productId, contractReferenceNumber, targetDate }) {
391
+ const targetIso = targetDate.toISOString();
392
+ const rows = await db.ProductPriceMatrix.filter(
393
+ {
394
+ productId,
395
+ contractReferenceNumber,
396
+ matrixType: "procurement_buy",
397
+ validFrom_lte: targetIso
398
+ },
399
+ SORT_MOST_RECENT_FIRST,
400
+ ACTIVE_ROW_LOOKBACK
401
+ );
402
+ return pickActiveRow(rows, targetIso, productId, "EXPLICIT_CONTRACT", {
403
+ contractReferenceNumber
404
+ });
405
+ },
406
+ async findAccountPrice({ productId, accountCode, targetDate }) {
407
+ const targetIso = targetDate.toISOString();
408
+ const rows = await db.ProductPriceMatrix.filter(
409
+ { productId, accountCode, validFrom_lte: targetIso },
410
+ SORT_MOST_RECENT_FIRST,
411
+ ACTIVE_ROW_LOOKBACK
412
+ );
413
+ return pickActiveRow(rows, targetIso, productId, "ACCOUNT_MATRIX", { accountCode });
414
+ },
415
+ async findDefaultPrice({ productId, targetDate }) {
416
+ const targetIso = targetDate.toISOString();
417
+ const rows = await db.ProductPriceMatrix.filter(
418
+ { productId, accountCode: "INTERNAL_DEFAULT", validFrom_lte: targetIso },
419
+ SORT_MOST_RECENT_FIRST,
420
+ ACTIVE_ROW_LOOKBACK
421
+ );
422
+ return pickActiveRow(rows, targetIso, productId, "INTERNAL_DEFAULT", {});
423
+ },
424
+ async findBaseProduct({ productId }) {
425
+ return await db.CompanyProduct.get(productId) ?? null;
426
+ }
427
+ };
428
+ }
429
+
250
430
  // src/validators.ts
251
431
  var Validator = {
252
432
  /** * 1. Email: The classic. Uses a standard RFC 5322 regex.
@@ -389,7 +569,8 @@ var CAT = {
389
569
  SUBSCRIPTION: "1",
390
570
  PERMISSION: "2",
391
571
  VALIDATION: "3",
392
- INTEGRITY: "4"
572
+ INTEGRITY: "4",
573
+ DATABASE: "5"
393
574
  };
394
575
  var ACT = {
395
576
  GENERIC: "00",
@@ -435,7 +616,8 @@ var ERROR_DICTIONARY = {
435
616
  "400": { title: "Data Conflict", text: "A conflict occurred with an existing record. Please review and try again." },
436
617
  "402": { title: "Duplicate Entry", text: "A record with this name or identifier already exists." },
437
618
  "403": { title: "Edit Conflict", text: "This record was recently updated by someone else. Please refresh and try again." },
438
- "404": { title: "Record In Use", text: "This record cannot be deleted because it is referenced by other data." }
619
+ "404": { title: "Record In Use", text: "This record cannot be deleted because it is referenced by other data." },
620
+ "405": { title: "Pricing Conflict", text: "Multiple active prices were found for this product. An administrator must resolve the conflict before this price can be used." }
439
621
  };
440
622
  var UserRole = {
441
623
  OWNER: "owner",
@@ -1332,11 +1514,14 @@ var AppError = class extends Error {
1332
1514
  status;
1333
1515
  appCode;
1334
1516
  isOperational;
1335
- constructor(status, mod, cat, act, message) {
1517
+ details;
1518
+ // optional structured payload, e.g. conflicting price candidates
1519
+ constructor(status, mod, cat, act, message, details) {
1336
1520
  super(message);
1337
1521
  this.status = status;
1338
1522
  this.appCode = `${mod}-${status}-${cat}${act}`;
1339
1523
  this.isOperational = true;
1524
+ this.details = details;
1340
1525
  Object.setPrototypeOf(this, new.target.prototype);
1341
1526
  }
1342
1527
  };
@@ -1345,15 +1530,21 @@ var ErrorFactory = {
1345
1530
  forbidden: (mod, act, msg = "Access denied") => new AppError(403, mod, CAT.PERMISSION, act, msg),
1346
1531
  badRequest: (mod, act, msg = "Bad request") => new AppError(400, mod, CAT.VALIDATION, act, msg),
1347
1532
  notFound: (mod, act = ACT.GENERIC, msg = "Record not found") => new AppError(404, mod, CAT.VALIDATION, act, msg),
1348
- conflict: (mod, act, msg = "Record already exists") => new AppError(409, mod, CAT.INTEGRITY, act, msg),
1349
- integrity: (mod, act = ACT.GENERIC, msg = "Data integrity violation") => new AppError(409, mod, CAT.INTEGRITY, act, msg),
1533
+ conflict: (mod, act, msg = "Record already exists", details) => new AppError(409, mod, CAT.INTEGRITY, act, msg, details),
1534
+ integrity: (mod, act = ACT.GENERIC, msg = "Data integrity violation", details) => new AppError(409, mod, CAT.INTEGRITY, act, msg, details),
1350
1535
  subscription: (mod, msg = "Module locked or subscription required") => new AppError(403, mod, CAT.SUBSCRIPTION, ACT.GENERIC, msg),
1351
1536
  internal: (mod, msg = "Internal server error") => new AppError(500, mod, CAT.INTEGRITY, ACT.GENERIC, msg)
1352
1537
  };
1353
1538
  var handleAppErrorResponse = (error, mod = MOD.ADMIN) => {
1354
1539
  if (error instanceof AppError && error.isOperational) {
1355
1540
  return Response.json(
1356
- { error: { appCode: error.appCode, message: error.message } },
1541
+ {
1542
+ error: {
1543
+ appCode: error.appCode,
1544
+ message: error.message,
1545
+ ...error.details ? { details: error.details } : {}
1546
+ }
1547
+ },
1357
1548
  { status: error.status }
1358
1549
  );
1359
1550
  }
@@ -1565,10 +1756,18 @@ function isTabWritable(session, activeScopeId, tabConfig) {
1565
1756
  return resolveAccess(session, activeScopeId, tabConfig) === "WRITE";
1566
1757
  }
1567
1758
  function evaluateBaseAccess(resourcePath, session, activeScopeId, requirements = {}) {
1568
- const role = getRoleAt(session, activeScopeId);
1759
+ const ancestry = getScopeAncestry(activeScopeId, session.availableScopes);
1760
+ const directRole = getRoleAt(session, activeScopeId);
1761
+ const inheritedRole = !directRole ? ancestry.slice(1).reduce(
1762
+ (found, scopeId) => found ?? getRoleAt(session, scopeId),
1763
+ null
1764
+ ) : null;
1765
+ const role = directRole ?? inheritedRole;
1766
+ const isInherited = !directRole && !!inheritedRole;
1569
1767
  const privileges = getPrivilegesAt(session, activeScopeId);
1570
1768
  if (!role) return "NONE";
1571
- if (role === UserRole.OWNER) return "WRITE";
1769
+ if (role === UserRole.OWNER) return isInherited ? "READ" : "WRITE";
1770
+ if (role === UserRole.MANAGER) return isInherited ? "READ" : "WRITE";
1572
1771
  const requiredModules = RESOURCE_MODULE_MAP[resourcePath] || [];
1573
1772
  if (requiredModules.length > 0) {
1574
1773
  const hasModule = requiredModules.some((m) => session.enabledModules?.includes(m));
@@ -1582,7 +1781,7 @@ function evaluateBaseAccess(resourcePath, session, activeScopeId, requirements =
1582
1781
  const hasPrivilege = requirements.requiredPrivileges.some((p) => privileges.includes(p));
1583
1782
  if (!hasPrivilege) return "NONE";
1584
1783
  }
1585
- return role === UserRole.MANAGER ? "WRITE" : "READ";
1784
+ return "READ";
1586
1785
  }
1587
1786
  function resolveEffectiveAccess(base, override) {
1588
1787
  return override === void 0 || override === null ? base : override;
@@ -1709,6 +1908,7 @@ function calculateFileMetadataMatch(criteria, fileMetadata, auditContext) {
1709
1908
  ACCESS_RANK,
1710
1909
  ACT,
1711
1910
  AccessLevel,
1911
+ AggregatePriceAmbiguityError,
1712
1912
  AgriLogger,
1713
1913
  AppError,
1714
1914
  ApprovalStatus,
@@ -1748,6 +1948,7 @@ function calculateFileMetadataMatch(criteria, fileMetadata, auditContext) {
1748
1948
  OrderStatus,
1749
1949
  PhysicalState,
1750
1950
  PlantingMethod,
1951
+ PriceAmbiguityError,
1751
1952
  ProductType,
1752
1953
  ProductUnit,
1753
1954
  RESOURCE_MODULE_MAP,
@@ -1776,6 +1977,7 @@ function calculateFileMetadataMatch(criteria, fileMetadata, auditContext) {
1776
1977
  WaterSource,
1777
1978
  assertTenantBoundary,
1778
1979
  calculateFileMetadataMatch,
1980
+ createBase44PricingAdapter,
1779
1981
  decodeSession,
1780
1982
  encodeSession,
1781
1983
  evaluateBaseAccess,
@@ -1801,6 +2003,7 @@ function calculateFileMetadataMatch(criteria, fileMetadata, auditContext) {
1801
2003
  resolveAppError,
1802
2004
  resolveEffectiveAccess,
1803
2005
  resolveError,
2006
+ resolvePrice,
1804
2007
  transformRoleAssignments,
1805
2008
  verifyAndExtractSession,
1806
2009
  withAgriLogging
package/dist/index.mjs CHANGED
@@ -62,7 +62,7 @@ import {
62
62
  UserRole,
63
63
  VigorRating,
64
64
  WaterSource
65
- } from "./chunk-OFNQBQP4.mjs";
65
+ } from "./chunk-Y5KVDVNY.mjs";
66
66
 
67
67
  // src/index.ts
68
68
  import { jwtVerify } from "jose";
@@ -192,6 +192,182 @@ function transformRoleAssignments(assignments) {
192
192
  return result;
193
193
  }
194
194
 
195
+ // src/priceHelpers.ts
196
+ var PriceAmbiguityError = class extends Error {
197
+ constructor(productId, tier, candidates, matchedOn = {}) {
198
+ const keyDescription = matchedOn.contractReferenceNumber ? `contract ${matchedOn.contractReferenceNumber}` : matchedOn.accountCode ? `account ${matchedOn.accountCode}` : "the system default";
199
+ super(
200
+ `Ambiguous pricing for product ${productId} at tier ${tier} (${keyDescription}): ${candidates.length} overlapping active prices found (${candidates.map((c) => `$${(c.unitPriceCents / 100).toFixed(2)}`).join(", ")}).`
201
+ );
202
+ this.productId = productId;
203
+ this.tier = tier;
204
+ this.candidates = candidates;
205
+ this.matchedOn = matchedOn;
206
+ this.name = "PriceAmbiguityError";
207
+ }
208
+ productId;
209
+ tier;
210
+ candidates;
211
+ matchedOn;
212
+ };
213
+ var AggregatePriceAmbiguityError = class extends Error {
214
+ constructor(productId, conflicts, shadowedCleanMatches = []) {
215
+ const tierList = conflicts.map((c) => c.tier).join(", ");
216
+ const note = shadowedCleanMatches.length > 0 ? ` Note: ${shadowedCleanMatches.length} other tier(s) had a clean price available but were not used, since a higher-priority tier must be resolved first.` : "";
217
+ super(
218
+ `Pricing for product ${productId} could not be resolved: ambiguous prices found at ${conflicts.length} tier(s) [${tierList}].${note}`
219
+ );
220
+ this.productId = productId;
221
+ this.conflicts = conflicts;
222
+ this.shadowedCleanMatches = shadowedCleanMatches;
223
+ this.name = "AggregatePriceAmbiguityError";
224
+ }
225
+ productId;
226
+ conflicts;
227
+ shadowedCleanMatches;
228
+ };
229
+ function fromMatrixRow(row, priceSource) {
230
+ return {
231
+ unitPriceCents: row.matrixUnitPrice,
232
+ minimumOrderQuantity: row.minimumOrderQuantity,
233
+ leadTimeDays: row.leadTimeDays,
234
+ priceSource,
235
+ sourceRecordId: row.canonicalId
236
+ };
237
+ }
238
+ async function resolvePrice(dataSource, context) {
239
+ const targetDate = context.evaluationDate ?? /* @__PURE__ */ new Date();
240
+ const conflicts = [];
241
+ const shadowedCleanMatches = [];
242
+ async function tryTier(lookup) {
243
+ try {
244
+ return await lookup();
245
+ } catch (err) {
246
+ if (err instanceof PriceAmbiguityError) {
247
+ conflicts.push(err);
248
+ return null;
249
+ }
250
+ throw err;
251
+ }
252
+ }
253
+ function handleCleanRow(row, tier, matchedOn) {
254
+ if (!row) return null;
255
+ if (conflicts.length === 0) return fromMatrixRow(row, tier);
256
+ shadowedCleanMatches.push({
257
+ tier,
258
+ unitPriceCents: row.matrixUnitPrice,
259
+ sourceRecordId: row.canonicalId,
260
+ matchedOn
261
+ });
262
+ return null;
263
+ }
264
+ if (context.contractReferenceNumber) {
265
+ const row = await tryTier(
266
+ () => dataSource.findContractPrice({
267
+ productId: context.productId,
268
+ contractReferenceNumber: context.contractReferenceNumber,
269
+ targetDate
270
+ })
271
+ );
272
+ const result = handleCleanRow(row, "EXPLICIT_CONTRACT", {
273
+ contractReferenceNumber: context.contractReferenceNumber
274
+ });
275
+ if (result) return result;
276
+ }
277
+ if (context.accountCode && context.accountCode !== "INTERNAL_DEFAULT") {
278
+ const row = await tryTier(
279
+ () => dataSource.findAccountPrice({
280
+ productId: context.productId,
281
+ accountCode: context.accountCode,
282
+ targetDate
283
+ })
284
+ );
285
+ const result = handleCleanRow(row, "ACCOUNT_MATRIX", { accountCode: context.accountCode });
286
+ if (result) return result;
287
+ }
288
+ const defaultRow = await tryTier(
289
+ () => dataSource.findDefaultPrice({ productId: context.productId, targetDate })
290
+ );
291
+ const defaultResult = handleCleanRow(defaultRow, "INTERNAL_DEFAULT", {});
292
+ if (defaultResult) return defaultResult;
293
+ if (conflicts.length > 0) {
294
+ throw new AggregatePriceAmbiguityError(context.productId, conflicts, shadowedCleanMatches);
295
+ }
296
+ const baseProduct = await dataSource.findBaseProduct({ productId: context.productId });
297
+ if (baseProduct) {
298
+ return {
299
+ unitPriceCents: baseProduct.unitPriceCents,
300
+ minimumOrderQuantity: 1,
301
+ leadTimeDays: null,
302
+ priceSource: "PRODUCT_FALLBACK",
303
+ sourceRecordId: baseProduct.canonicalId
304
+ };
305
+ }
306
+ throw new Error(`Critical Architecture Error: Product ${context.productId} not found in system catalog.`);
307
+ }
308
+ var ACTIVE_ROW_LOOKBACK = 5;
309
+ var SORT_MOST_RECENT_FIRST = "-validFrom";
310
+ function pickActiveRow(rows, targetIso, productId, tier, matchedOn) {
311
+ const activeMatches = rows.filter(
312
+ (r) => r.validTo === null || new Date(r.validTo).toISOString() >= targetIso
313
+ );
314
+ if (activeMatches.length > 1) {
315
+ throw new PriceAmbiguityError(
316
+ productId,
317
+ tier,
318
+ activeMatches.map((r) => ({
319
+ sourceRecordId: r.canonicalId,
320
+ unitPriceCents: r.matrixUnitPrice,
321
+ validFrom: r.validFrom,
322
+ validTo: r.validTo
323
+ })),
324
+ matchedOn
325
+ );
326
+ }
327
+ return activeMatches[0] ?? null;
328
+ }
329
+ function createBase44PricingAdapter(db) {
330
+ return {
331
+ async findContractPrice({ productId, contractReferenceNumber, targetDate }) {
332
+ const targetIso = targetDate.toISOString();
333
+ const rows = await db.ProductPriceMatrix.filter(
334
+ {
335
+ productId,
336
+ contractReferenceNumber,
337
+ matrixType: "procurement_buy",
338
+ validFrom_lte: targetIso
339
+ },
340
+ SORT_MOST_RECENT_FIRST,
341
+ ACTIVE_ROW_LOOKBACK
342
+ );
343
+ return pickActiveRow(rows, targetIso, productId, "EXPLICIT_CONTRACT", {
344
+ contractReferenceNumber
345
+ });
346
+ },
347
+ async findAccountPrice({ productId, accountCode, targetDate }) {
348
+ const targetIso = targetDate.toISOString();
349
+ const rows = await db.ProductPriceMatrix.filter(
350
+ { productId, accountCode, validFrom_lte: targetIso },
351
+ SORT_MOST_RECENT_FIRST,
352
+ ACTIVE_ROW_LOOKBACK
353
+ );
354
+ return pickActiveRow(rows, targetIso, productId, "ACCOUNT_MATRIX", { accountCode });
355
+ },
356
+ async findDefaultPrice({ productId, targetDate }) {
357
+ const targetIso = targetDate.toISOString();
358
+ const rows = await db.ProductPriceMatrix.filter(
359
+ { productId, accountCode: "INTERNAL_DEFAULT", validFrom_lte: targetIso },
360
+ SORT_MOST_RECENT_FIRST,
361
+ ACTIVE_ROW_LOOKBACK
362
+ );
363
+ return pickActiveRow(rows, targetIso, productId, "INTERNAL_DEFAULT", {});
364
+ },
365
+ async findBaseProduct({ productId }) {
366
+ return await db.CompanyProduct.get(productId) ?? null;
367
+ }
368
+ };
369
+ }
370
+
195
371
  // src/validators.ts
196
372
  var Validator = {
197
373
  /** * 1. Email: The classic. Uses a standard RFC 5322 regex.
@@ -320,11 +496,14 @@ var AppError = class extends Error {
320
496
  status;
321
497
  appCode;
322
498
  isOperational;
323
- constructor(status, mod, cat, act, message) {
499
+ details;
500
+ // optional structured payload, e.g. conflicting price candidates
501
+ constructor(status, mod, cat, act, message, details) {
324
502
  super(message);
325
503
  this.status = status;
326
504
  this.appCode = `${mod}-${status}-${cat}${act}`;
327
505
  this.isOperational = true;
506
+ this.details = details;
328
507
  Object.setPrototypeOf(this, new.target.prototype);
329
508
  }
330
509
  };
@@ -333,15 +512,21 @@ var ErrorFactory = {
333
512
  forbidden: (mod, act, msg = "Access denied") => new AppError(403, mod, CAT.PERMISSION, act, msg),
334
513
  badRequest: (mod, act, msg = "Bad request") => new AppError(400, mod, CAT.VALIDATION, act, msg),
335
514
  notFound: (mod, act = ACT.GENERIC, msg = "Record not found") => new AppError(404, mod, CAT.VALIDATION, act, msg),
336
- conflict: (mod, act, msg = "Record already exists") => new AppError(409, mod, CAT.INTEGRITY, act, msg),
337
- integrity: (mod, act = ACT.GENERIC, msg = "Data integrity violation") => new AppError(409, mod, CAT.INTEGRITY, act, msg),
515
+ conflict: (mod, act, msg = "Record already exists", details) => new AppError(409, mod, CAT.INTEGRITY, act, msg, details),
516
+ integrity: (mod, act = ACT.GENERIC, msg = "Data integrity violation", details) => new AppError(409, mod, CAT.INTEGRITY, act, msg, details),
338
517
  subscription: (mod, msg = "Module locked or subscription required") => new AppError(403, mod, CAT.SUBSCRIPTION, ACT.GENERIC, msg),
339
518
  internal: (mod, msg = "Internal server error") => new AppError(500, mod, CAT.INTEGRITY, ACT.GENERIC, msg)
340
519
  };
341
520
  var handleAppErrorResponse = (error, mod = MOD.ADMIN) => {
342
521
  if (error instanceof AppError && error.isOperational) {
343
522
  return Response.json(
344
- { error: { appCode: error.appCode, message: error.message } },
523
+ {
524
+ error: {
525
+ appCode: error.appCode,
526
+ message: error.message,
527
+ ...error.details ? { details: error.details } : {}
528
+ }
529
+ },
345
530
  { status: error.status }
346
531
  );
347
532
  }
@@ -553,10 +738,18 @@ function isTabWritable(session, activeScopeId, tabConfig) {
553
738
  return resolveAccess(session, activeScopeId, tabConfig) === "WRITE";
554
739
  }
555
740
  function evaluateBaseAccess(resourcePath, session, activeScopeId, requirements = {}) {
556
- const role = getRoleAt(session, activeScopeId);
741
+ const ancestry = getScopeAncestry(activeScopeId, session.availableScopes);
742
+ const directRole = getRoleAt(session, activeScopeId);
743
+ const inheritedRole = !directRole ? ancestry.slice(1).reduce(
744
+ (found, scopeId) => found ?? getRoleAt(session, scopeId),
745
+ null
746
+ ) : null;
747
+ const role = directRole ?? inheritedRole;
748
+ const isInherited = !directRole && !!inheritedRole;
557
749
  const privileges = getPrivilegesAt(session, activeScopeId);
558
750
  if (!role) return "NONE";
559
- if (role === UserRole.OWNER) return "WRITE";
751
+ if (role === UserRole.OWNER) return isInherited ? "READ" : "WRITE";
752
+ if (role === UserRole.MANAGER) return isInherited ? "READ" : "WRITE";
560
753
  const requiredModules = RESOURCE_MODULE_MAP[resourcePath] || [];
561
754
  if (requiredModules.length > 0) {
562
755
  const hasModule = requiredModules.some((m) => session.enabledModules?.includes(m));
@@ -570,7 +763,7 @@ function evaluateBaseAccess(resourcePath, session, activeScopeId, requirements =
570
763
  const hasPrivilege = requirements.requiredPrivileges.some((p) => privileges.includes(p));
571
764
  if (!hasPrivilege) return "NONE";
572
765
  }
573
- return role === UserRole.MANAGER ? "WRITE" : "READ";
766
+ return "READ";
574
767
  }
575
768
  function resolveEffectiveAccess(base, override) {
576
769
  return override === void 0 || override === null ? base : override;
@@ -696,6 +889,7 @@ export {
696
889
  ACCESS_RANK,
697
890
  ACT,
698
891
  AccessLevel,
892
+ AggregatePriceAmbiguityError,
699
893
  AgriLogger,
700
894
  AppError,
701
895
  ApprovalStatus,
@@ -735,6 +929,7 @@ export {
735
929
  OrderStatus,
736
930
  PhysicalState,
737
931
  PlantingMethod,
932
+ PriceAmbiguityError,
738
933
  ProductType,
739
934
  ProductUnit,
740
935
  RESOURCE_MODULE_MAP,
@@ -763,6 +958,7 @@ export {
763
958
  WaterSource,
764
959
  assertTenantBoundary,
765
960
  calculateFileMetadataMatch,
961
+ createBase44PricingAdapter,
766
962
  decodeSession,
767
963
  encodeSession,
768
964
  evaluateBaseAccess,
@@ -788,6 +984,7 @@ export {
788
984
  resolveAppError,
789
985
  resolveEffectiveAccess,
790
986
  resolveError,
987
+ resolvePrice,
791
988
  transformRoleAssignments,
792
989
  verifyAndExtractSession,
793
990
  withAgriLogging
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@litusarchieve18/agricore-utils",
3
- "version": "1.0.25",
3
+ "version": "1.0.27",
4
4
  "description": "Canonical Backend Utility Library for AgriCore",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",