@roomwise/calc-engine 0.6.0 → 0.7.0
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/dist/index.cjs +118 -23
- package/dist/index.d.cts +24 -3
- package/dist/index.d.ts +24 -3
- package/dist/index.js +112 -24
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -51,13 +51,10 @@ function toCents(dollars) {
|
|
|
51
51
|
return cents;
|
|
52
52
|
}
|
|
53
53
|
//#endregion
|
|
54
|
-
//#region src/variables/putty.ts
|
|
55
|
-
function puttyRequiredOn(room, surface, categories) {
|
|
56
|
-
const selected = categories.filter((category) => category.surface === surface && room.selections.some((selection) => selection.categoryId === category.id));
|
|
57
|
-
return selected.length === 0 || selected.some((category) => category.requiresPutty);
|
|
58
|
-
}
|
|
59
|
-
//#endregion
|
|
60
54
|
//#region src/variables/room.ts
|
|
55
|
+
function surfaceAreaOf(variables, surface) {
|
|
56
|
+
return surface === "WALLS" ? variables.wallArea : variables.floorArea;
|
|
57
|
+
}
|
|
61
58
|
function roomVariables(room) {
|
|
62
59
|
const perimeter = 2 * (room.lengthM + room.widthM);
|
|
63
60
|
return {
|
|
@@ -72,6 +69,63 @@ function roomVariables(room) {
|
|
|
72
69
|
};
|
|
73
70
|
}
|
|
74
71
|
//#endregion
|
|
72
|
+
//#region src/variables/putty.ts
|
|
73
|
+
function puttyRequiredOn(room, surface, categories) {
|
|
74
|
+
const selected = categories.filter((category) => category.surface === surface && room.selections.some((selection) => selection.categoryId === category.id));
|
|
75
|
+
return selected.length === 0 || selected.some((category) => category.requiresPutty);
|
|
76
|
+
}
|
|
77
|
+
//#endregion
|
|
78
|
+
//#region src/variables/share.ts
|
|
79
|
+
function isShareSurface(surface) {
|
|
80
|
+
return surface === "WALLS" || surface === "FLOOR";
|
|
81
|
+
}
|
|
82
|
+
function surfaceShares(room, surface, categories) {
|
|
83
|
+
const selections = room.selections.filter((selection) => selection.productId !== null && categories.some((category) => category.id === selection.categoryId && category.surface === surface));
|
|
84
|
+
return {
|
|
85
|
+
selections,
|
|
86
|
+
shared: selections.some((selection) => selection.areaShare !== void 0),
|
|
87
|
+
complete: selections.every((selection) => selection.areaShare !== void 0),
|
|
88
|
+
totalPercent: selections.reduce((sum, selection) => sum + (selection.areaShare ?? 0), 0)
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
function areaShareOf(selection) {
|
|
92
|
+
return selection.areaShare === void 0 ? 1 : selection.areaShare / 100;
|
|
93
|
+
}
|
|
94
|
+
function areaShareError(room, selection, categories) {
|
|
95
|
+
const category = categories.find((item) => item.id === selection.categoryId);
|
|
96
|
+
if (category === void 0) return null;
|
|
97
|
+
if (!isShareSurface(category.surface)) return selection.areaShare === void 0 ? null : {
|
|
98
|
+
code: "AREA_SHARE_NOT_ALLOWED",
|
|
99
|
+
params: {
|
|
100
|
+
categoryId: category.id,
|
|
101
|
+
surface: category.surface
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
const shares = surfaceShares(room, category.surface, categories);
|
|
105
|
+
const params = {
|
|
106
|
+
roomClientId: room.clientId,
|
|
107
|
+
surface: category.surface
|
|
108
|
+
};
|
|
109
|
+
if (shares.shared && !shares.complete) return {
|
|
110
|
+
code: "AREA_SHARE_MISSING",
|
|
111
|
+
params
|
|
112
|
+
};
|
|
113
|
+
if (shares.totalPercent > 100) return {
|
|
114
|
+
code: "AREA_SHARE_EXCEEDS_SURFACE",
|
|
115
|
+
params: {
|
|
116
|
+
...params,
|
|
117
|
+
percent: shares.totalPercent
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
function puttyShareOn(room, surface, categories) {
|
|
123
|
+
const shares = surface === "WALLS" ? surfaceShares(room, surface, categories) : null;
|
|
124
|
+
if (shares === null || !shares.shared) return puttyRequiredOn(room, surface, categories) ? 1 : 0;
|
|
125
|
+
const needing = shares.selections.filter((selection) => categories.find((category) => category.id === selection.categoryId)?.requiresPutty);
|
|
126
|
+
return Math.min(1, needing.reduce((sum, selection) => sum + areaShareOf(selection), 0));
|
|
127
|
+
}
|
|
128
|
+
//#endregion
|
|
75
129
|
//#region src/variables/object.ts
|
|
76
130
|
const COUNTED_AS_ROOMS = [
|
|
77
131
|
"LIVING_ROOM",
|
|
@@ -100,7 +154,7 @@ function objectVariables(configuration, categories) {
|
|
|
100
154
|
bathroomsCount: configuration.rooms.filter((room) => room.roomTypeCode === "BATHROOM").length,
|
|
101
155
|
roomsFloorArea,
|
|
102
156
|
roomsWallArea: sum((room) => room.wallArea),
|
|
103
|
-
roomsPuttyWallArea: configuration.rooms.reduce((total, room) =>
|
|
157
|
+
roomsPuttyWallArea: configuration.rooms.reduce((total, room) => total + roomVariables(room).wallArea * puttyShareOn(room, "WALLS", categories), 0),
|
|
104
158
|
roomsPerimeter: sum((room) => room.perimeter),
|
|
105
159
|
wetRoomsCount: rooms.filter((room) => WET_ROOMS.includes(room.roomType)).length
|
|
106
160
|
};
|
|
@@ -733,11 +787,6 @@ function applySurfacePrep(data, room, lines, objectScope) {
|
|
|
733
787
|
...roomVariables(room),
|
|
734
788
|
...objectScope
|
|
735
789
|
};
|
|
736
|
-
const areas = {
|
|
737
|
-
FLOOR: variables.floorArea,
|
|
738
|
-
CEILING: variables.floorArea,
|
|
739
|
-
WALLS: variables.wallArea
|
|
740
|
-
};
|
|
741
790
|
const surfaces = /* @__PURE__ */ new Map();
|
|
742
791
|
lines.forEach((line, index) => {
|
|
743
792
|
const category = data.categories.find((item) => item.id === line.categoryId);
|
|
@@ -749,11 +798,14 @@ function applySurfacePrep(data, room, lines, objectScope) {
|
|
|
749
798
|
for (const [surface, indexes] of surfaces) {
|
|
750
799
|
const rule = surfaceRuleOf(data, surface);
|
|
751
800
|
if (rule === void 0) continue;
|
|
801
|
+
const surfaceArea = surfaceAreaOf(variables, surface);
|
|
802
|
+
const puttyShare = puttyShareOn(room, surface, data.categories);
|
|
752
803
|
const outcome = runNumericFormula(rule.costFormula, {
|
|
753
804
|
variables: {
|
|
754
805
|
...variables,
|
|
755
|
-
surfaceArea
|
|
756
|
-
puttyRequired:
|
|
806
|
+
surfaceArea,
|
|
807
|
+
puttyRequired: puttyShare > 0,
|
|
808
|
+
puttyArea: surfaceArea * puttyShare
|
|
757
809
|
},
|
|
758
810
|
coefficients: data.coefficients
|
|
759
811
|
});
|
|
@@ -786,7 +838,9 @@ function selectRule(data, categoryId, materialTypeId) {
|
|
|
786
838
|
const rules = data.rules.filter(isMaterialRule);
|
|
787
839
|
return rules.find((rule) => rule.level === "MATERIAL_TYPE" && rule.categoryId === categoryId && rule.materialTypeId === materialTypeId) ?? rules.find((rule) => rule.level === "CATEGORY" && rule.categoryId === categoryId);
|
|
788
840
|
}
|
|
789
|
-
function materialLine(configuration, data, room,
|
|
841
|
+
function materialLine(configuration, data, room, selection, objectScope) {
|
|
842
|
+
const { categoryId } = selection;
|
|
843
|
+
const productId = selection.productId;
|
|
790
844
|
const init = {
|
|
791
845
|
id: lineId("MATERIALS", room.clientId, categoryId),
|
|
792
846
|
section: "MATERIALS",
|
|
@@ -794,6 +848,8 @@ function materialLine(configuration, data, room, categoryId, productId, objectSc
|
|
|
794
848
|
categoryId,
|
|
795
849
|
productId
|
|
796
850
|
};
|
|
851
|
+
const shareError = areaShareError(room, selection, data.categories);
|
|
852
|
+
if (shareError !== null) return failedLine(init, "ERROR", shareError);
|
|
797
853
|
const category = data.categories.find((item) => item.id === categoryId);
|
|
798
854
|
const product = data.products.find((item) => item.id === productId && item.categoryId === categoryId);
|
|
799
855
|
if (product === void 0 || category === void 0 || !product.available) return failedLine(init, "UNAVAILABLE", {
|
|
@@ -815,8 +871,12 @@ function materialLine(configuration, data, room, categoryId, productId, objectSc
|
|
|
815
871
|
materialTypeId: product.materialTypeId
|
|
816
872
|
}
|
|
817
873
|
});
|
|
874
|
+
const base = roomVariables(room);
|
|
875
|
+
const share = areaShareOf(selection);
|
|
818
876
|
const variables = {
|
|
819
|
-
...
|
|
877
|
+
...base,
|
|
878
|
+
wallArea: category.surface === "WALLS" ? base.wallArea * share : base.wallArea,
|
|
879
|
+
floorArea: category.surface === "FLOOR" ? base.floorArea * share : base.floorArea,
|
|
820
880
|
...productVariables(product, category),
|
|
821
881
|
...objectScope
|
|
822
882
|
};
|
|
@@ -886,7 +946,7 @@ function materialLine(configuration, data, room, categoryId, productId, objectSc
|
|
|
886
946
|
}
|
|
887
947
|
function materialLines(configuration, data, objectScope) {
|
|
888
948
|
return configuration.rooms.flatMap((room) => {
|
|
889
|
-
const lines = room.selections.flatMap((
|
|
949
|
+
const lines = room.selections.flatMap((selection) => selection.productId === null ? [] : [materialLine(configuration, data, room, selection, objectScope)]);
|
|
890
950
|
return configuration.scope === "PARTIAL" ? applySurfacePrep(data, room, lines, objectScope) : lines;
|
|
891
951
|
});
|
|
892
952
|
}
|
|
@@ -984,7 +1044,8 @@ const RangeSchema = zod.z.object({
|
|
|
984
1044
|
//#region src/schemas/configuration.ts
|
|
985
1045
|
const RoomSelectionSchema = zod.z.object({
|
|
986
1046
|
categoryId: zod.z.string(),
|
|
987
|
-
productId: zod.z.string().nullable()
|
|
1047
|
+
productId: zod.z.string().nullable(),
|
|
1048
|
+
areaShare: zod.z.int().min(1).max(100).optional()
|
|
988
1049
|
});
|
|
989
1050
|
const RoomConfigurationSchema = zod.z.object({
|
|
990
1051
|
clientId: zod.z.string(),
|
|
@@ -1224,6 +1285,7 @@ const RuleSampleSchema = zod.z.object({
|
|
|
1224
1285
|
}).optional(),
|
|
1225
1286
|
surfaceArea: zod.z.number().min(0).optional(),
|
|
1226
1287
|
puttyRequired: zod.z.boolean().optional(),
|
|
1288
|
+
puttyArea: zod.z.number().min(0).optional(),
|
|
1227
1289
|
object: zod.z.object({
|
|
1228
1290
|
scope: ScopeSchema,
|
|
1229
1291
|
totalAreaSqm: zod.z.number().positive().nullable(),
|
|
@@ -1302,10 +1364,32 @@ function roomsAreaWarnings(configuration, limits) {
|
|
|
1302
1364
|
params: { missingSqm }
|
|
1303
1365
|
}] : [];
|
|
1304
1366
|
}
|
|
1305
|
-
|
|
1367
|
+
const SHARE_SURFACES = ["WALLS", "FLOOR"];
|
|
1368
|
+
function areaShareWarnings(configuration, categories) {
|
|
1369
|
+
return configuration.rooms.flatMap((room) => {
|
|
1370
|
+
const variables = roomVariables(room);
|
|
1371
|
+
return SHARE_SURFACES.flatMap((surface) => {
|
|
1372
|
+
const shares = surfaceShares(room, surface, categories);
|
|
1373
|
+
if (!shares.shared || !shares.complete || shares.totalPercent >= 100) return [];
|
|
1374
|
+
const percent = 100 - shares.totalPercent;
|
|
1375
|
+
const area = surfaceAreaOf(variables, surface);
|
|
1376
|
+
return [{
|
|
1377
|
+
code: "AREA_SHARE_UNALLOCATED",
|
|
1378
|
+
params: {
|
|
1379
|
+
roomClientId: room.clientId,
|
|
1380
|
+
surface,
|
|
1381
|
+
percent,
|
|
1382
|
+
sqm: roundArea(area * percent / 100)
|
|
1383
|
+
}
|
|
1384
|
+
}];
|
|
1385
|
+
});
|
|
1386
|
+
});
|
|
1387
|
+
}
|
|
1388
|
+
function estimateWarnings(lines, configuration, rate, data) {
|
|
1306
1389
|
return [
|
|
1307
1390
|
...collectWarnings(lines),
|
|
1308
|
-
...roomsAreaWarnings(configuration, limits),
|
|
1391
|
+
...roomsAreaWarnings(configuration, data.limits),
|
|
1392
|
+
...areaShareWarnings(configuration, data.categories),
|
|
1309
1393
|
...configuration.currency === "UAH" && rate === null ? [{ code: "EXCHANGE_RATE_UNAVAILABLE" }] : []
|
|
1310
1394
|
];
|
|
1311
1395
|
}
|
|
@@ -1333,7 +1417,7 @@ function estimate(configuration, data) {
|
|
|
1333
1417
|
exchangeRate: data.exchangeRate,
|
|
1334
1418
|
lines,
|
|
1335
1419
|
totals: computeTotals(lines, rate !== null),
|
|
1336
|
-
warnings: estimateWarnings(lines, configuration, rate, data
|
|
1420
|
+
warnings: estimateWarnings(lines, configuration, rate, data),
|
|
1337
1421
|
incomplete: isIncomplete(lines)
|
|
1338
1422
|
};
|
|
1339
1423
|
}
|
|
@@ -1428,11 +1512,13 @@ function scopeOf(level, sample) {
|
|
|
1428
1512
|
code: "SAMPLE_INCOMPLETE",
|
|
1429
1513
|
params: { missing: room === void 0 ? "room" : "surfaceArea" }
|
|
1430
1514
|
} };
|
|
1515
|
+
const puttyRequired = sample.puttyRequired ?? true;
|
|
1431
1516
|
return { scope: {
|
|
1432
1517
|
...roomVariables(room),
|
|
1433
1518
|
...objectScope(sample),
|
|
1434
1519
|
surfaceArea,
|
|
1435
|
-
puttyRequired
|
|
1520
|
+
puttyRequired,
|
|
1521
|
+
puttyArea: sample.puttyArea ?? (puttyRequired ? surfaceArea : 0)
|
|
1436
1522
|
} };
|
|
1437
1523
|
}
|
|
1438
1524
|
if (room === void 0 || product === void 0) return { error: {
|
|
@@ -1581,6 +1667,7 @@ const FORMULA_SCOPE_VARIABLES = {
|
|
|
1581
1667
|
};
|
|
1582
1668
|
const FORMULA_QUANTITY_VARIABLE = number("quantity");
|
|
1583
1669
|
const FORMULA_SURFACE_AREA_VARIABLE = number("surfaceArea");
|
|
1670
|
+
const FORMULA_PUTTY_AREA_VARIABLE = number("puttyArea");
|
|
1584
1671
|
const FORMULA_PUTTY_REQUIRED_VARIABLE = boolean("puttyRequired");
|
|
1585
1672
|
const FORMULA_VARIABLES = {
|
|
1586
1673
|
OBJECT: FORMULA_SCOPE_VARIABLES.object,
|
|
@@ -1598,7 +1685,8 @@ const FORMULA_VARIABLES = {
|
|
|
1598
1685
|
...FORMULA_SCOPE_VARIABLES.room,
|
|
1599
1686
|
...FORMULA_SCOPE_VARIABLES.object,
|
|
1600
1687
|
FORMULA_SURFACE_AREA_VARIABLE,
|
|
1601
|
-
FORMULA_PUTTY_REQUIRED_VARIABLE
|
|
1688
|
+
FORMULA_PUTTY_REQUIRED_VARIABLE,
|
|
1689
|
+
FORMULA_PUTTY_AREA_VARIABLE
|
|
1602
1690
|
]
|
|
1603
1691
|
};
|
|
1604
1692
|
const ALL_VARIABLE_NAMES = new Set([...FORMULA_VARIABLES.CATEGORY, ...FORMULA_VARIABLES.SURFACE].map((variable) => variable.name));
|
|
@@ -1826,6 +1914,7 @@ exports.ExchangeRateSchema = ExchangeRateSchema;
|
|
|
1826
1914
|
exports.FORMULA_FUNCTIONS = FORMULA_FUNCTIONS;
|
|
1827
1915
|
exports.FORMULA_FUNCTION_TABLE = FORMULA_FUNCTION_TABLE;
|
|
1828
1916
|
exports.FORMULA_LIMITS = FORMULA_LIMITS;
|
|
1917
|
+
exports.FORMULA_PUTTY_AREA_VARIABLE = FORMULA_PUTTY_AREA_VARIABLE;
|
|
1829
1918
|
exports.FORMULA_PUTTY_REQUIRED_VARIABLE = FORMULA_PUTTY_REQUIRED_VARIABLE;
|
|
1830
1919
|
exports.FORMULA_QUANTITY_VARIABLE = FORMULA_QUANTITY_VARIABLE;
|
|
1831
1920
|
exports.FORMULA_SCOPE_VARIABLES = FORMULA_SCOPE_VARIABLES;
|
|
@@ -1862,11 +1951,14 @@ exports.ScopeSchema = ScopeSchema;
|
|
|
1862
1951
|
exports.SectionSchema = SectionSchema;
|
|
1863
1952
|
exports.SectionTotalSchema = SectionTotalSchema;
|
|
1864
1953
|
exports.SurfaceKindSchema = SurfaceKindSchema;
|
|
1954
|
+
exports.areaShareError = areaShareError;
|
|
1955
|
+
exports.areaShareOf = areaShareOf;
|
|
1865
1956
|
exports.checkLimits = checkLimits;
|
|
1866
1957
|
exports.convertCentsToKopecks = convertCentsToKopecks;
|
|
1867
1958
|
exports.estimate = estimate;
|
|
1868
1959
|
exports.evaluate = evaluate;
|
|
1869
1960
|
exports.findOptionPriceSourceViolation = findOptionPriceSourceViolation;
|
|
1961
|
+
exports.isShareSurface = isShareSurface;
|
|
1870
1962
|
exports.levenshtein = levenshtein;
|
|
1871
1963
|
exports.objectVariables = objectVariables;
|
|
1872
1964
|
exports.parse = parse;
|
|
@@ -1874,8 +1966,11 @@ exports.previewRule = previewRule;
|
|
|
1874
1966
|
exports.productVariables = productVariables;
|
|
1875
1967
|
exports.productVariablesOf = productVariablesOf;
|
|
1876
1968
|
exports.puttyRequiredOn = puttyRequiredOn;
|
|
1969
|
+
exports.puttyShareOn = puttyShareOn;
|
|
1877
1970
|
exports.roomVariables = roomVariables;
|
|
1878
1971
|
exports.suggestNearest = suggestNearest;
|
|
1972
|
+
exports.surfaceAreaOf = surfaceAreaOf;
|
|
1973
|
+
exports.surfaceShares = surfaceShares;
|
|
1879
1974
|
exports.toCents = toCents;
|
|
1880
1975
|
exports.totalAreaOf = totalAreaOf;
|
|
1881
1976
|
exports.validateFormula = validateFormula;
|
package/dist/index.d.cts
CHANGED
|
@@ -29,10 +29,10 @@ export declare const RateSourceSchema: z.ZodEnum<{
|
|
|
29
29
|
}>;
|
|
30
30
|
export type RateSource = z.infer<typeof RateSourceSchema>;
|
|
31
31
|
export declare const SurfaceKindSchema: z.ZodEnum<{
|
|
32
|
+
NONE: "NONE";
|
|
32
33
|
FLOOR: "FLOOR";
|
|
33
34
|
WALLS: "WALLS";
|
|
34
35
|
CEILING: "CEILING";
|
|
35
|
-
NONE: "NONE";
|
|
36
36
|
}>;
|
|
37
37
|
export type SurfaceKind = z.infer<typeof SurfaceKindSchema>;
|
|
38
38
|
export declare const ProductUnitSchema: z.ZodEnum<{
|
|
@@ -106,6 +106,7 @@ export type Range = z.infer<typeof RangeSchema>;
|
|
|
106
106
|
export declare const RoomSelectionSchema: z.ZodObject<{
|
|
107
107
|
categoryId: z.ZodString;
|
|
108
108
|
productId: z.ZodNullable<z.ZodString>;
|
|
109
|
+
areaShare: z.ZodOptional<z.ZodInt>;
|
|
109
110
|
}, z.core.$strip>;
|
|
110
111
|
export type RoomSelection = z.infer<typeof RoomSelectionSchema>;
|
|
111
112
|
export declare const RoomConfigurationSchema: z.ZodObject<{
|
|
@@ -127,6 +128,7 @@ export declare const RoomConfigurationSchema: z.ZodObject<{
|
|
|
127
128
|
selections: z.ZodArray<z.ZodObject<{
|
|
128
129
|
categoryId: z.ZodString;
|
|
129
130
|
productId: z.ZodNullable<z.ZodString>;
|
|
131
|
+
areaShare: z.ZodOptional<z.ZodInt>;
|
|
130
132
|
}, z.core.$strip>>;
|
|
131
133
|
}, z.core.$strip>;
|
|
132
134
|
export type RoomConfiguration = z.infer<typeof RoomConfigurationSchema>;
|
|
@@ -168,6 +170,7 @@ export declare const ConfigurationSchema: z.ZodObject<{
|
|
|
168
170
|
selections: z.ZodArray<z.ZodObject<{
|
|
169
171
|
categoryId: z.ZodString;
|
|
170
172
|
productId: z.ZodNullable<z.ZodString>;
|
|
173
|
+
areaShare: z.ZodOptional<z.ZodInt>;
|
|
171
174
|
}, z.core.$strip>>;
|
|
172
175
|
}, z.core.$strip>>;
|
|
173
176
|
options: z.ZodArray<z.ZodObject<{
|
|
@@ -383,6 +386,7 @@ export declare const RuleSampleSchema: z.ZodObject<{
|
|
|
383
386
|
}, z.core.$strip>>;
|
|
384
387
|
surfaceArea: z.ZodOptional<z.ZodNumber>;
|
|
385
388
|
puttyRequired: z.ZodOptional<z.ZodBoolean>;
|
|
389
|
+
puttyArea: z.ZodOptional<z.ZodNumber>;
|
|
386
390
|
object: z.ZodObject<{
|
|
387
391
|
scope: z.ZodEnum<{
|
|
388
392
|
FULL: "FULL";
|
|
@@ -484,10 +488,10 @@ export declare const PricingCategorySchema: z.ZodObject<{
|
|
|
484
488
|
id: z.ZodString;
|
|
485
489
|
wastePercent: z.ZodNumber;
|
|
486
490
|
surface: z.ZodEnum<{
|
|
491
|
+
NONE: "NONE";
|
|
487
492
|
FLOOR: "FLOOR";
|
|
488
493
|
WALLS: "WALLS";
|
|
489
494
|
CEILING: "CEILING";
|
|
490
|
-
NONE: "NONE";
|
|
491
495
|
}>;
|
|
492
496
|
requiresPutty: z.ZodDefault<z.ZodBoolean>;
|
|
493
497
|
}, z.core.$strip>;
|
|
@@ -618,10 +622,10 @@ export declare const PricingDataSchema: z.ZodObject<{
|
|
|
618
622
|
id: z.ZodString;
|
|
619
623
|
wastePercent: z.ZodNumber;
|
|
620
624
|
surface: z.ZodEnum<{
|
|
625
|
+
NONE: "NONE";
|
|
621
626
|
FLOOR: "FLOOR";
|
|
622
627
|
WALLS: "WALLS";
|
|
623
628
|
CEILING: "CEILING";
|
|
624
|
-
NONE: "NONE";
|
|
625
629
|
}>;
|
|
626
630
|
requiresPutty: z.ZodDefault<z.ZodBoolean>;
|
|
627
631
|
}, z.core.$strip>>;
|
|
@@ -820,6 +824,7 @@ export interface FormulaVariable {
|
|
|
820
824
|
export declare const FORMULA_SCOPE_VARIABLES: Record<FormulaScope, readonly FormulaVariable[]>;
|
|
821
825
|
export declare const FORMULA_QUANTITY_VARIABLE: FormulaVariable;
|
|
822
826
|
export declare const FORMULA_SURFACE_AREA_VARIABLE: FormulaVariable;
|
|
827
|
+
export declare const FORMULA_PUTTY_AREA_VARIABLE: FormulaVariable;
|
|
823
828
|
export declare const FORMULA_PUTTY_REQUIRED_VARIABLE: FormulaVariable;
|
|
824
829
|
export declare const FORMULA_VARIABLES: Record<RuleLevel, readonly FormulaVariable[]>;
|
|
825
830
|
export interface ValidateFormulaInput {
|
|
@@ -882,6 +887,22 @@ export interface RoomVariables {
|
|
|
882
887
|
readonly heatedFloor: boolean;
|
|
883
888
|
readonly roomType: RoomTypeCode;
|
|
884
889
|
}
|
|
890
|
+
export type MeasuredSurface = 'FLOOR' | 'WALLS' | 'CEILING';
|
|
891
|
+
export declare function surfaceAreaOf(variables: Pick<RoomVariables, 'floorArea' | 'wallArea'>, surface: MeasuredSurface): number;
|
|
885
892
|
export type RoomDimensions = Pick<RoomConfiguration, 'roomTypeCode' | 'lengthM' | 'widthM' | 'heightM' | 'heatedFloor'>;
|
|
886
893
|
export declare function roomVariables(room: RoomDimensions): RoomVariables;
|
|
894
|
+
//#endregion
|
|
895
|
+
//#region src/variables/share.d.ts
|
|
896
|
+
export type ShareSurface = 'WALLS' | 'FLOOR';
|
|
897
|
+
export interface SurfaceShares {
|
|
898
|
+
readonly selections: readonly RoomSelection[];
|
|
899
|
+
readonly shared: boolean;
|
|
900
|
+
readonly complete: boolean;
|
|
901
|
+
readonly totalPercent: number;
|
|
902
|
+
}
|
|
903
|
+
export declare function isShareSurface(surface: PricingCategory['surface']): surface is ShareSurface;
|
|
904
|
+
export declare function surfaceShares(room: RoomConfiguration, surface: ShareSurface, categories: readonly PricingCategory[]): SurfaceShares;
|
|
905
|
+
export declare function areaShareOf(selection: RoomSelection): number;
|
|
906
|
+
export declare function areaShareError(room: RoomConfiguration, selection: RoomSelection, categories: readonly PricingCategory[]): EstimateMessage | null;
|
|
907
|
+
export declare function puttyShareOn(room: RoomConfiguration, surface: MeasuredSurface, categories: readonly PricingCategory[]): number;
|
|
887
908
|
//#endregion
|
package/dist/index.d.ts
CHANGED
|
@@ -29,10 +29,10 @@ export declare const RateSourceSchema: z.ZodEnum<{
|
|
|
29
29
|
}>;
|
|
30
30
|
export type RateSource = z.infer<typeof RateSourceSchema>;
|
|
31
31
|
export declare const SurfaceKindSchema: z.ZodEnum<{
|
|
32
|
+
NONE: "NONE";
|
|
32
33
|
FLOOR: "FLOOR";
|
|
33
34
|
WALLS: "WALLS";
|
|
34
35
|
CEILING: "CEILING";
|
|
35
|
-
NONE: "NONE";
|
|
36
36
|
}>;
|
|
37
37
|
export type SurfaceKind = z.infer<typeof SurfaceKindSchema>;
|
|
38
38
|
export declare const ProductUnitSchema: z.ZodEnum<{
|
|
@@ -106,6 +106,7 @@ export type Range = z.infer<typeof RangeSchema>;
|
|
|
106
106
|
export declare const RoomSelectionSchema: z.ZodObject<{
|
|
107
107
|
categoryId: z.ZodString;
|
|
108
108
|
productId: z.ZodNullable<z.ZodString>;
|
|
109
|
+
areaShare: z.ZodOptional<z.ZodInt>;
|
|
109
110
|
}, z.core.$strip>;
|
|
110
111
|
export type RoomSelection = z.infer<typeof RoomSelectionSchema>;
|
|
111
112
|
export declare const RoomConfigurationSchema: z.ZodObject<{
|
|
@@ -127,6 +128,7 @@ export declare const RoomConfigurationSchema: z.ZodObject<{
|
|
|
127
128
|
selections: z.ZodArray<z.ZodObject<{
|
|
128
129
|
categoryId: z.ZodString;
|
|
129
130
|
productId: z.ZodNullable<z.ZodString>;
|
|
131
|
+
areaShare: z.ZodOptional<z.ZodInt>;
|
|
130
132
|
}, z.core.$strip>>;
|
|
131
133
|
}, z.core.$strip>;
|
|
132
134
|
export type RoomConfiguration = z.infer<typeof RoomConfigurationSchema>;
|
|
@@ -168,6 +170,7 @@ export declare const ConfigurationSchema: z.ZodObject<{
|
|
|
168
170
|
selections: z.ZodArray<z.ZodObject<{
|
|
169
171
|
categoryId: z.ZodString;
|
|
170
172
|
productId: z.ZodNullable<z.ZodString>;
|
|
173
|
+
areaShare: z.ZodOptional<z.ZodInt>;
|
|
171
174
|
}, z.core.$strip>>;
|
|
172
175
|
}, z.core.$strip>>;
|
|
173
176
|
options: z.ZodArray<z.ZodObject<{
|
|
@@ -383,6 +386,7 @@ export declare const RuleSampleSchema: z.ZodObject<{
|
|
|
383
386
|
}, z.core.$strip>>;
|
|
384
387
|
surfaceArea: z.ZodOptional<z.ZodNumber>;
|
|
385
388
|
puttyRequired: z.ZodOptional<z.ZodBoolean>;
|
|
389
|
+
puttyArea: z.ZodOptional<z.ZodNumber>;
|
|
386
390
|
object: z.ZodObject<{
|
|
387
391
|
scope: z.ZodEnum<{
|
|
388
392
|
FULL: "FULL";
|
|
@@ -484,10 +488,10 @@ export declare const PricingCategorySchema: z.ZodObject<{
|
|
|
484
488
|
id: z.ZodString;
|
|
485
489
|
wastePercent: z.ZodNumber;
|
|
486
490
|
surface: z.ZodEnum<{
|
|
491
|
+
NONE: "NONE";
|
|
487
492
|
FLOOR: "FLOOR";
|
|
488
493
|
WALLS: "WALLS";
|
|
489
494
|
CEILING: "CEILING";
|
|
490
|
-
NONE: "NONE";
|
|
491
495
|
}>;
|
|
492
496
|
requiresPutty: z.ZodDefault<z.ZodBoolean>;
|
|
493
497
|
}, z.core.$strip>;
|
|
@@ -618,10 +622,10 @@ export declare const PricingDataSchema: z.ZodObject<{
|
|
|
618
622
|
id: z.ZodString;
|
|
619
623
|
wastePercent: z.ZodNumber;
|
|
620
624
|
surface: z.ZodEnum<{
|
|
625
|
+
NONE: "NONE";
|
|
621
626
|
FLOOR: "FLOOR";
|
|
622
627
|
WALLS: "WALLS";
|
|
623
628
|
CEILING: "CEILING";
|
|
624
|
-
NONE: "NONE";
|
|
625
629
|
}>;
|
|
626
630
|
requiresPutty: z.ZodDefault<z.ZodBoolean>;
|
|
627
631
|
}, z.core.$strip>>;
|
|
@@ -820,6 +824,7 @@ export interface FormulaVariable {
|
|
|
820
824
|
export declare const FORMULA_SCOPE_VARIABLES: Record<FormulaScope, readonly FormulaVariable[]>;
|
|
821
825
|
export declare const FORMULA_QUANTITY_VARIABLE: FormulaVariable;
|
|
822
826
|
export declare const FORMULA_SURFACE_AREA_VARIABLE: FormulaVariable;
|
|
827
|
+
export declare const FORMULA_PUTTY_AREA_VARIABLE: FormulaVariable;
|
|
823
828
|
export declare const FORMULA_PUTTY_REQUIRED_VARIABLE: FormulaVariable;
|
|
824
829
|
export declare const FORMULA_VARIABLES: Record<RuleLevel, readonly FormulaVariable[]>;
|
|
825
830
|
export interface ValidateFormulaInput {
|
|
@@ -882,6 +887,22 @@ export interface RoomVariables {
|
|
|
882
887
|
readonly heatedFloor: boolean;
|
|
883
888
|
readonly roomType: RoomTypeCode;
|
|
884
889
|
}
|
|
890
|
+
export type MeasuredSurface = 'FLOOR' | 'WALLS' | 'CEILING';
|
|
891
|
+
export declare function surfaceAreaOf(variables: Pick<RoomVariables, 'floorArea' | 'wallArea'>, surface: MeasuredSurface): number;
|
|
885
892
|
export type RoomDimensions = Pick<RoomConfiguration, 'roomTypeCode' | 'lengthM' | 'widthM' | 'heightM' | 'heatedFloor'>;
|
|
886
893
|
export declare function roomVariables(room: RoomDimensions): RoomVariables;
|
|
894
|
+
//#endregion
|
|
895
|
+
//#region src/variables/share.d.ts
|
|
896
|
+
export type ShareSurface = 'WALLS' | 'FLOOR';
|
|
897
|
+
export interface SurfaceShares {
|
|
898
|
+
readonly selections: readonly RoomSelection[];
|
|
899
|
+
readonly shared: boolean;
|
|
900
|
+
readonly complete: boolean;
|
|
901
|
+
readonly totalPercent: number;
|
|
902
|
+
}
|
|
903
|
+
export declare function isShareSurface(surface: PricingCategory['surface']): surface is ShareSurface;
|
|
904
|
+
export declare function surfaceShares(room: RoomConfiguration, surface: ShareSurface, categories: readonly PricingCategory[]): SurfaceShares;
|
|
905
|
+
export declare function areaShareOf(selection: RoomSelection): number;
|
|
906
|
+
export declare function areaShareError(room: RoomConfiguration, selection: RoomSelection, categories: readonly PricingCategory[]): EstimateMessage | null;
|
|
907
|
+
export declare function puttyShareOn(room: RoomConfiguration, surface: MeasuredSurface, categories: readonly PricingCategory[]): number;
|
|
887
908
|
//#endregion
|
package/dist/index.js
CHANGED
|
@@ -26,13 +26,10 @@ function toCents(dollars) {
|
|
|
26
26
|
return cents;
|
|
27
27
|
}
|
|
28
28
|
//#endregion
|
|
29
|
-
//#region src/variables/putty.ts
|
|
30
|
-
function puttyRequiredOn(room, surface, categories) {
|
|
31
|
-
const selected = categories.filter((category) => category.surface === surface && room.selections.some((selection) => selection.categoryId === category.id));
|
|
32
|
-
return selected.length === 0 || selected.some((category) => category.requiresPutty);
|
|
33
|
-
}
|
|
34
|
-
//#endregion
|
|
35
29
|
//#region src/variables/room.ts
|
|
30
|
+
function surfaceAreaOf(variables, surface) {
|
|
31
|
+
return surface === "WALLS" ? variables.wallArea : variables.floorArea;
|
|
32
|
+
}
|
|
36
33
|
function roomVariables(room) {
|
|
37
34
|
const perimeter = 2 * (room.lengthM + room.widthM);
|
|
38
35
|
return {
|
|
@@ -47,6 +44,63 @@ function roomVariables(room) {
|
|
|
47
44
|
};
|
|
48
45
|
}
|
|
49
46
|
//#endregion
|
|
47
|
+
//#region src/variables/putty.ts
|
|
48
|
+
function puttyRequiredOn(room, surface, categories) {
|
|
49
|
+
const selected = categories.filter((category) => category.surface === surface && room.selections.some((selection) => selection.categoryId === category.id));
|
|
50
|
+
return selected.length === 0 || selected.some((category) => category.requiresPutty);
|
|
51
|
+
}
|
|
52
|
+
//#endregion
|
|
53
|
+
//#region src/variables/share.ts
|
|
54
|
+
function isShareSurface(surface) {
|
|
55
|
+
return surface === "WALLS" || surface === "FLOOR";
|
|
56
|
+
}
|
|
57
|
+
function surfaceShares(room, surface, categories) {
|
|
58
|
+
const selections = room.selections.filter((selection) => selection.productId !== null && categories.some((category) => category.id === selection.categoryId && category.surface === surface));
|
|
59
|
+
return {
|
|
60
|
+
selections,
|
|
61
|
+
shared: selections.some((selection) => selection.areaShare !== void 0),
|
|
62
|
+
complete: selections.every((selection) => selection.areaShare !== void 0),
|
|
63
|
+
totalPercent: selections.reduce((sum, selection) => sum + (selection.areaShare ?? 0), 0)
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
function areaShareOf(selection) {
|
|
67
|
+
return selection.areaShare === void 0 ? 1 : selection.areaShare / 100;
|
|
68
|
+
}
|
|
69
|
+
function areaShareError(room, selection, categories) {
|
|
70
|
+
const category = categories.find((item) => item.id === selection.categoryId);
|
|
71
|
+
if (category === void 0) return null;
|
|
72
|
+
if (!isShareSurface(category.surface)) return selection.areaShare === void 0 ? null : {
|
|
73
|
+
code: "AREA_SHARE_NOT_ALLOWED",
|
|
74
|
+
params: {
|
|
75
|
+
categoryId: category.id,
|
|
76
|
+
surface: category.surface
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
const shares = surfaceShares(room, category.surface, categories);
|
|
80
|
+
const params = {
|
|
81
|
+
roomClientId: room.clientId,
|
|
82
|
+
surface: category.surface
|
|
83
|
+
};
|
|
84
|
+
if (shares.shared && !shares.complete) return {
|
|
85
|
+
code: "AREA_SHARE_MISSING",
|
|
86
|
+
params
|
|
87
|
+
};
|
|
88
|
+
if (shares.totalPercent > 100) return {
|
|
89
|
+
code: "AREA_SHARE_EXCEEDS_SURFACE",
|
|
90
|
+
params: {
|
|
91
|
+
...params,
|
|
92
|
+
percent: shares.totalPercent
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
function puttyShareOn(room, surface, categories) {
|
|
98
|
+
const shares = surface === "WALLS" ? surfaceShares(room, surface, categories) : null;
|
|
99
|
+
if (shares === null || !shares.shared) return puttyRequiredOn(room, surface, categories) ? 1 : 0;
|
|
100
|
+
const needing = shares.selections.filter((selection) => categories.find((category) => category.id === selection.categoryId)?.requiresPutty);
|
|
101
|
+
return Math.min(1, needing.reduce((sum, selection) => sum + areaShareOf(selection), 0));
|
|
102
|
+
}
|
|
103
|
+
//#endregion
|
|
50
104
|
//#region src/variables/object.ts
|
|
51
105
|
const COUNTED_AS_ROOMS = [
|
|
52
106
|
"LIVING_ROOM",
|
|
@@ -75,7 +129,7 @@ function objectVariables(configuration, categories) {
|
|
|
75
129
|
bathroomsCount: configuration.rooms.filter((room) => room.roomTypeCode === "BATHROOM").length,
|
|
76
130
|
roomsFloorArea,
|
|
77
131
|
roomsWallArea: sum((room) => room.wallArea),
|
|
78
|
-
roomsPuttyWallArea: configuration.rooms.reduce((total, room) =>
|
|
132
|
+
roomsPuttyWallArea: configuration.rooms.reduce((total, room) => total + roomVariables(room).wallArea * puttyShareOn(room, "WALLS", categories), 0),
|
|
79
133
|
roomsPerimeter: sum((room) => room.perimeter),
|
|
80
134
|
wetRoomsCount: rooms.filter((room) => WET_ROOMS.includes(room.roomType)).length
|
|
81
135
|
};
|
|
@@ -708,11 +762,6 @@ function applySurfacePrep(data, room, lines, objectScope) {
|
|
|
708
762
|
...roomVariables(room),
|
|
709
763
|
...objectScope
|
|
710
764
|
};
|
|
711
|
-
const areas = {
|
|
712
|
-
FLOOR: variables.floorArea,
|
|
713
|
-
CEILING: variables.floorArea,
|
|
714
|
-
WALLS: variables.wallArea
|
|
715
|
-
};
|
|
716
765
|
const surfaces = /* @__PURE__ */ new Map();
|
|
717
766
|
lines.forEach((line, index) => {
|
|
718
767
|
const category = data.categories.find((item) => item.id === line.categoryId);
|
|
@@ -724,11 +773,14 @@ function applySurfacePrep(data, room, lines, objectScope) {
|
|
|
724
773
|
for (const [surface, indexes] of surfaces) {
|
|
725
774
|
const rule = surfaceRuleOf(data, surface);
|
|
726
775
|
if (rule === void 0) continue;
|
|
776
|
+
const surfaceArea = surfaceAreaOf(variables, surface);
|
|
777
|
+
const puttyShare = puttyShareOn(room, surface, data.categories);
|
|
727
778
|
const outcome = runNumericFormula(rule.costFormula, {
|
|
728
779
|
variables: {
|
|
729
780
|
...variables,
|
|
730
|
-
surfaceArea
|
|
731
|
-
puttyRequired:
|
|
781
|
+
surfaceArea,
|
|
782
|
+
puttyRequired: puttyShare > 0,
|
|
783
|
+
puttyArea: surfaceArea * puttyShare
|
|
732
784
|
},
|
|
733
785
|
coefficients: data.coefficients
|
|
734
786
|
});
|
|
@@ -761,7 +813,9 @@ function selectRule(data, categoryId, materialTypeId) {
|
|
|
761
813
|
const rules = data.rules.filter(isMaterialRule);
|
|
762
814
|
return rules.find((rule) => rule.level === "MATERIAL_TYPE" && rule.categoryId === categoryId && rule.materialTypeId === materialTypeId) ?? rules.find((rule) => rule.level === "CATEGORY" && rule.categoryId === categoryId);
|
|
763
815
|
}
|
|
764
|
-
function materialLine(configuration, data, room,
|
|
816
|
+
function materialLine(configuration, data, room, selection, objectScope) {
|
|
817
|
+
const { categoryId } = selection;
|
|
818
|
+
const productId = selection.productId;
|
|
765
819
|
const init = {
|
|
766
820
|
id: lineId("MATERIALS", room.clientId, categoryId),
|
|
767
821
|
section: "MATERIALS",
|
|
@@ -769,6 +823,8 @@ function materialLine(configuration, data, room, categoryId, productId, objectSc
|
|
|
769
823
|
categoryId,
|
|
770
824
|
productId
|
|
771
825
|
};
|
|
826
|
+
const shareError = areaShareError(room, selection, data.categories);
|
|
827
|
+
if (shareError !== null) return failedLine(init, "ERROR", shareError);
|
|
772
828
|
const category = data.categories.find((item) => item.id === categoryId);
|
|
773
829
|
const product = data.products.find((item) => item.id === productId && item.categoryId === categoryId);
|
|
774
830
|
if (product === void 0 || category === void 0 || !product.available) return failedLine(init, "UNAVAILABLE", {
|
|
@@ -790,8 +846,12 @@ function materialLine(configuration, data, room, categoryId, productId, objectSc
|
|
|
790
846
|
materialTypeId: product.materialTypeId
|
|
791
847
|
}
|
|
792
848
|
});
|
|
849
|
+
const base = roomVariables(room);
|
|
850
|
+
const share = areaShareOf(selection);
|
|
793
851
|
const variables = {
|
|
794
|
-
...
|
|
852
|
+
...base,
|
|
853
|
+
wallArea: category.surface === "WALLS" ? base.wallArea * share : base.wallArea,
|
|
854
|
+
floorArea: category.surface === "FLOOR" ? base.floorArea * share : base.floorArea,
|
|
795
855
|
...productVariables(product, category),
|
|
796
856
|
...objectScope
|
|
797
857
|
};
|
|
@@ -861,7 +921,7 @@ function materialLine(configuration, data, room, categoryId, productId, objectSc
|
|
|
861
921
|
}
|
|
862
922
|
function materialLines(configuration, data, objectScope) {
|
|
863
923
|
return configuration.rooms.flatMap((room) => {
|
|
864
|
-
const lines = room.selections.flatMap((
|
|
924
|
+
const lines = room.selections.flatMap((selection) => selection.productId === null ? [] : [materialLine(configuration, data, room, selection, objectScope)]);
|
|
865
925
|
return configuration.scope === "PARTIAL" ? applySurfacePrep(data, room, lines, objectScope) : lines;
|
|
866
926
|
});
|
|
867
927
|
}
|
|
@@ -959,7 +1019,8 @@ const RangeSchema = z.object({
|
|
|
959
1019
|
//#region src/schemas/configuration.ts
|
|
960
1020
|
const RoomSelectionSchema = z.object({
|
|
961
1021
|
categoryId: z.string(),
|
|
962
|
-
productId: z.string().nullable()
|
|
1022
|
+
productId: z.string().nullable(),
|
|
1023
|
+
areaShare: z.int().min(1).max(100).optional()
|
|
963
1024
|
});
|
|
964
1025
|
const RoomConfigurationSchema = z.object({
|
|
965
1026
|
clientId: z.string(),
|
|
@@ -1199,6 +1260,7 @@ const RuleSampleSchema = z.object({
|
|
|
1199
1260
|
}).optional(),
|
|
1200
1261
|
surfaceArea: z.number().min(0).optional(),
|
|
1201
1262
|
puttyRequired: z.boolean().optional(),
|
|
1263
|
+
puttyArea: z.number().min(0).optional(),
|
|
1202
1264
|
object: z.object({
|
|
1203
1265
|
scope: ScopeSchema,
|
|
1204
1266
|
totalAreaSqm: z.number().positive().nullable(),
|
|
@@ -1277,10 +1339,32 @@ function roomsAreaWarnings(configuration, limits) {
|
|
|
1277
1339
|
params: { missingSqm }
|
|
1278
1340
|
}] : [];
|
|
1279
1341
|
}
|
|
1280
|
-
|
|
1342
|
+
const SHARE_SURFACES = ["WALLS", "FLOOR"];
|
|
1343
|
+
function areaShareWarnings(configuration, categories) {
|
|
1344
|
+
return configuration.rooms.flatMap((room) => {
|
|
1345
|
+
const variables = roomVariables(room);
|
|
1346
|
+
return SHARE_SURFACES.flatMap((surface) => {
|
|
1347
|
+
const shares = surfaceShares(room, surface, categories);
|
|
1348
|
+
if (!shares.shared || !shares.complete || shares.totalPercent >= 100) return [];
|
|
1349
|
+
const percent = 100 - shares.totalPercent;
|
|
1350
|
+
const area = surfaceAreaOf(variables, surface);
|
|
1351
|
+
return [{
|
|
1352
|
+
code: "AREA_SHARE_UNALLOCATED",
|
|
1353
|
+
params: {
|
|
1354
|
+
roomClientId: room.clientId,
|
|
1355
|
+
surface,
|
|
1356
|
+
percent,
|
|
1357
|
+
sqm: roundArea(area * percent / 100)
|
|
1358
|
+
}
|
|
1359
|
+
}];
|
|
1360
|
+
});
|
|
1361
|
+
});
|
|
1362
|
+
}
|
|
1363
|
+
function estimateWarnings(lines, configuration, rate, data) {
|
|
1281
1364
|
return [
|
|
1282
1365
|
...collectWarnings(lines),
|
|
1283
|
-
...roomsAreaWarnings(configuration, limits),
|
|
1366
|
+
...roomsAreaWarnings(configuration, data.limits),
|
|
1367
|
+
...areaShareWarnings(configuration, data.categories),
|
|
1284
1368
|
...configuration.currency === "UAH" && rate === null ? [{ code: "EXCHANGE_RATE_UNAVAILABLE" }] : []
|
|
1285
1369
|
];
|
|
1286
1370
|
}
|
|
@@ -1308,7 +1392,7 @@ function estimate(configuration, data) {
|
|
|
1308
1392
|
exchangeRate: data.exchangeRate,
|
|
1309
1393
|
lines,
|
|
1310
1394
|
totals: computeTotals(lines, rate !== null),
|
|
1311
|
-
warnings: estimateWarnings(lines, configuration, rate, data
|
|
1395
|
+
warnings: estimateWarnings(lines, configuration, rate, data),
|
|
1312
1396
|
incomplete: isIncomplete(lines)
|
|
1313
1397
|
};
|
|
1314
1398
|
}
|
|
@@ -1403,11 +1487,13 @@ function scopeOf(level, sample) {
|
|
|
1403
1487
|
code: "SAMPLE_INCOMPLETE",
|
|
1404
1488
|
params: { missing: room === void 0 ? "room" : "surfaceArea" }
|
|
1405
1489
|
} };
|
|
1490
|
+
const puttyRequired = sample.puttyRequired ?? true;
|
|
1406
1491
|
return { scope: {
|
|
1407
1492
|
...roomVariables(room),
|
|
1408
1493
|
...objectScope(sample),
|
|
1409
1494
|
surfaceArea,
|
|
1410
|
-
puttyRequired
|
|
1495
|
+
puttyRequired,
|
|
1496
|
+
puttyArea: sample.puttyArea ?? (puttyRequired ? surfaceArea : 0)
|
|
1411
1497
|
} };
|
|
1412
1498
|
}
|
|
1413
1499
|
if (room === void 0 || product === void 0) return { error: {
|
|
@@ -1556,6 +1642,7 @@ const FORMULA_SCOPE_VARIABLES = {
|
|
|
1556
1642
|
};
|
|
1557
1643
|
const FORMULA_QUANTITY_VARIABLE = number("quantity");
|
|
1558
1644
|
const FORMULA_SURFACE_AREA_VARIABLE = number("surfaceArea");
|
|
1645
|
+
const FORMULA_PUTTY_AREA_VARIABLE = number("puttyArea");
|
|
1559
1646
|
const FORMULA_PUTTY_REQUIRED_VARIABLE = boolean("puttyRequired");
|
|
1560
1647
|
const FORMULA_VARIABLES = {
|
|
1561
1648
|
OBJECT: FORMULA_SCOPE_VARIABLES.object,
|
|
@@ -1573,7 +1660,8 @@ const FORMULA_VARIABLES = {
|
|
|
1573
1660
|
...FORMULA_SCOPE_VARIABLES.room,
|
|
1574
1661
|
...FORMULA_SCOPE_VARIABLES.object,
|
|
1575
1662
|
FORMULA_SURFACE_AREA_VARIABLE,
|
|
1576
|
-
FORMULA_PUTTY_REQUIRED_VARIABLE
|
|
1663
|
+
FORMULA_PUTTY_REQUIRED_VARIABLE,
|
|
1664
|
+
FORMULA_PUTTY_AREA_VARIABLE
|
|
1577
1665
|
]
|
|
1578
1666
|
};
|
|
1579
1667
|
const ALL_VARIABLE_NAMES = new Set([...FORMULA_VARIABLES.CATEGORY, ...FORMULA_VARIABLES.SURFACE].map((variable) => variable.name));
|
|
@@ -1788,4 +1876,4 @@ function validateFormula(input) {
|
|
|
1788
1876
|
};
|
|
1789
1877
|
}
|
|
1790
1878
|
//#endregion
|
|
1791
|
-
export { COEFFICIENT_NAMESPACE, CentsSchema, ConfigurationSchema, CurrencySchema, EstimateLineSchema, EstimateMessageSchema, EstimateSchema, EstimateTotalsSchema, EstimateWarningSchema, ExchangeRateSchema, FORMULA_FUNCTIONS, FORMULA_FUNCTION_TABLE, FORMULA_LIMITS, FORMULA_PUTTY_REQUIRED_VARIABLE, FORMULA_QUANTITY_VARIABLE, FORMULA_SCOPE_VARIABLES, FORMULA_SURFACE_AREA_VARIABLE, FORMULA_VARIABLES, FinishLevelSchema, LineComponentKindSchema, LineComponentSchema, LineStatusSchema, LocalizedTextSchema, OptionCodeSchema, OptionKindSchema, OptionSelectionSchema, OptionUnitSchema, PricingCategorySchema, PricingDataSchema, PricingLimitsSchema, PricingMaterialTypeSchema, PricingOptionSchema, PricingPackageItemSchema, PricingProductSchema, PricingRoomTypeSchema, PricingRuleSchema, ProductUnitSchema, RangeSchema, RateSourceSchema, RoomConfigurationSchema, RoomSelectionSchema, RoomTypeCodeSchema, RuleLevelSchema, RulePreviewSchema, RuleSampleSchema, ScopeSchema, SectionSchema, SectionTotalSchema, SurfaceKindSchema, checkLimits, convertCentsToKopecks, estimate, evaluate, findOptionPriceSourceViolation, levenshtein, objectVariables, parse, previewRule, productVariables, productVariablesOf, puttyRequiredOn, roomVariables, suggestNearest, toCents, totalAreaOf, validateFormula };
|
|
1879
|
+
export { COEFFICIENT_NAMESPACE, CentsSchema, ConfigurationSchema, CurrencySchema, EstimateLineSchema, EstimateMessageSchema, EstimateSchema, EstimateTotalsSchema, EstimateWarningSchema, ExchangeRateSchema, FORMULA_FUNCTIONS, FORMULA_FUNCTION_TABLE, FORMULA_LIMITS, FORMULA_PUTTY_AREA_VARIABLE, FORMULA_PUTTY_REQUIRED_VARIABLE, FORMULA_QUANTITY_VARIABLE, FORMULA_SCOPE_VARIABLES, FORMULA_SURFACE_AREA_VARIABLE, FORMULA_VARIABLES, FinishLevelSchema, LineComponentKindSchema, LineComponentSchema, LineStatusSchema, LocalizedTextSchema, OptionCodeSchema, OptionKindSchema, OptionSelectionSchema, OptionUnitSchema, PricingCategorySchema, PricingDataSchema, PricingLimitsSchema, PricingMaterialTypeSchema, PricingOptionSchema, PricingPackageItemSchema, PricingProductSchema, PricingRoomTypeSchema, PricingRuleSchema, ProductUnitSchema, RangeSchema, RateSourceSchema, RoomConfigurationSchema, RoomSelectionSchema, RoomTypeCodeSchema, RuleLevelSchema, RulePreviewSchema, RuleSampleSchema, ScopeSchema, SectionSchema, SectionTotalSchema, SurfaceKindSchema, areaShareError, areaShareOf, checkLimits, convertCentsToKopecks, estimate, evaluate, findOptionPriceSourceViolation, isShareSurface, levenshtein, objectVariables, parse, previewRule, productVariables, productVariablesOf, puttyRequiredOn, puttyShareOn, roomVariables, suggestNearest, surfaceAreaOf, surfaceShares, toCents, totalAreaOf, validateFormula };
|