Skip to content

Commit 4b19753

Browse files
committed
[FIX] xlsx: import data validation rules with formula
Data validations rules with formulas were not correctly imported, ad they are not prefixed by "=" in the xlsx, but should be in o-spreadsheet. closes #7269 Task: 5062253 X-original-commit: d261046 Signed-off-by: Lucas Lefèvre (lul) <lul@odoo.com> Signed-off-by: Adrien Minne (adrm) <adrm@odoo.com>
1 parent 13cf688 commit 4b19753

File tree

5 files changed

+33
-16
lines changed

5 files changed

+33
-16
lines changed

src/xlsx/conversion/cf_conversion.ts

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { ICON_SETS } from "../../components/icons/icons";
2-
import { tokenize } from "../../formulas";
32
import {
43
ColorScaleMidPointThreshold,
54
ColorScaleThreshold,
@@ -8,6 +7,7 @@ import {
87
IconThreshold,
98
} from "../../types";
109
import { ExcelIconSet, XLSXConditionalFormat, XLSXDxf } from "../../types/xlsx";
10+
import { prefixFormulaWithEqual } from "../helpers/misc";
1111
import { WarningTypes, XLSXImportWarningManager } from "../helpers/xlsx_parser_error_manager";
1212
import { convertColor, hexaToInt } from "./color_conversion";
1313
import {
@@ -84,9 +84,9 @@ export function convertConditionalFormats(
8484
case "cellIs":
8585
if (!rule.operator || !rule.formula || rule.formula.length === 0) continue;
8686
operator = convertCFCellIsOperator(rule.operator);
87-
values.push(prefixFormula(rule.formula[0]));
87+
values.push(prefixFormulaWithEqual(rule.formula[0]));
8888
if (rule.formula.length === 2) {
89-
values.push(prefixFormula(rule.formula[1]));
89+
values.push(prefixFormulaWithEqual(rule.formula[1]));
9090
}
9191
break;
9292
}
@@ -269,12 +269,6 @@ function convertIcons(xlsxIconSet: ExcelIconSet, index: number): string {
269269
: ICON_SETS[iconSet].good;
270270
}
271271

272-
/** Prefix the string by "=" if the string looks like a formula */
273-
function prefixFormula(formula: string): string {
274-
const tokens = tokenize(formula);
275-
return tokens.length === 1 && tokens[0].type !== "REFERENCE" ? formula : "=" + formula;
276-
}
277-
278272
// ---------------------------------------------------------------------------
279273
// Warnings
280274
// ---------------------------------------------------------------------------

src/xlsx/conversion/data_validation_conversion.ts

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
DateIsNotBetweenCriterion,
88
} from "../../types";
99
import { XLSXDataValidation } from "../../types/xlsx";
10+
import { prefixFormulaWithEqual } from "../helpers/misc";
1011
import { WarningTypes, XLSXImportWarningManager } from "../helpers/xlsx_parser_error_manager";
1112
import {
1213
XLSX_DV_DATE_OPERATOR_TO_DV_TYPE_MAPPING,
@@ -42,7 +43,7 @@ export function convertDataValidationRules(
4243
dvRules.push(decimalRule);
4344
break;
4445
case "list":
45-
const listRule = convertListrule(dvId++, dv);
46+
const listRule = convertListRule(dvId++, dv);
4647
dvRules.push(listRule);
4748
break;
4849
case "date":
@@ -65,9 +66,9 @@ export function convertDataValidationRules(
6566
}
6667

6768
function convertDecimalRule(id: number, dv: XLSXDataValidation): DataValidationRuleData {
68-
const values = [dv.formula1.toString()];
69+
const values = [prefixFormulaWithEqual(dv.formula1.toString())];
6970
if (dv.formula2) {
70-
values.push(dv.formula2.toString());
71+
values.push(prefixFormulaWithEqual(dv.formula2.toString()));
7172
}
7273
return {
7374
id: id.toString(),
@@ -80,7 +81,7 @@ function convertDecimalRule(id: number, dv: XLSXDataValidation): DataValidationR
8081
};
8182
}
8283

83-
function convertListrule(id: number, dv: XLSXDataValidation): DataValidationRuleData {
84+
function convertListRule(id: number, dv: XLSXDataValidation): DataValidationRuleData {
8485
const formula1 = dv.formula1.toString();
8586
const isRangeRule = rangeReference.test(formula1);
8687
return {
@@ -97,9 +98,9 @@ function convertListrule(id: number, dv: XLSXDataValidation): DataValidationRule
9798

9899
function convertDateRule(id: number, dv: XLSXDataValidation): DataValidationRuleData {
99100
let criterion: DataValidationDateCriterion | DateIsBetweenCriterion | DateIsNotBetweenCriterion;
100-
const values = [dv.formula1.toString()];
101+
const values = [prefixFormulaWithEqual(dv.formula1.toString())];
101102
if (dv.formula2) {
102-
values.push(dv.formula2.toString());
103+
values.push(prefixFormulaWithEqual(dv.formula2.toString()));
103104
criterion = {
104105
type: XLSX_DV_DATE_OPERATOR_TO_DV_TYPE_MAPPING[dv.operator],
105106
values: getDateCriterionFormattedValues(values, DEFAULT_LOCALE),
@@ -126,7 +127,7 @@ function convertCustomRule(id: number, dv: XLSXDataValidation): DataValidationRu
126127
isBlocking: dv.errorStyle !== "warning",
127128
criterion: {
128129
type: "customFormula",
129-
values: [`=${dv.formula1.toString()}`],
130+
values: [prefixFormulaWithEqual(dv.formula1.toString())],
130131
},
131132
};
132133
}

src/xlsx/helpers/misc.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { tokenize } from "../../formulas/tokenizer";
12
import { Dimension, ExcelHeaderData, ExcelSheetData } from "../../types";
23

34
/**
@@ -80,3 +81,12 @@ export function getSheetDataHeader(
8081
}
8182
return sheetData.rows[index];
8283
}
84+
85+
/** Prefix the string by "=" if the string looks like a formula */
86+
export function prefixFormulaWithEqual(formula: string): string {
87+
if (formula[0] === "=") {
88+
return formula;
89+
}
90+
const tokens = tokenize(formula);
91+
return tokens.length === 1 && tokens[0].type !== "REFERENCE" ? formula : "=" + formula;
92+
}

tests/__xlsx__/xlsx_demo_data.xlsx

44 Bytes
Binary file not shown.

tests/xlsx/xlsx_import.test.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,18 @@ describe("Import xlsx data", () => {
408408
});
409409
});
410410

411+
test("Can import a data validation rule with a formula", () => {
412+
const testSheet = getWorkbookSheet("jestDataValidations", convertedData)!;
413+
const dvRule = getDataValidationBeginningAt("J2", testSheet);
414+
expect(dvRule).toMatchObject({
415+
criterion: {
416+
type: "isBetween",
417+
values: ["=$A$2", "=2+10"],
418+
},
419+
ranges: ["J2:J6"],
420+
});
421+
});
422+
411423
test.each([
412424
["2 colors max", "H2"],
413425
["3 colors max", "H3"],

0 commit comments

Comments
 (0)