Skip to content

Commit

Permalink
FIO-9357 fixed calculation based on DataSource component (#202)
Browse files Browse the repository at this point in the history
* FIO-9357 fixed calculation based on DataSource component

* FIO-9357 fixed typo
  • Loading branch information
HannaKurban authored Dec 16, 2024
1 parent 0a627a7 commit 9e9ce40
Show file tree
Hide file tree
Showing 3 changed files with 223 additions and 3 deletions.
215 changes: 215 additions & 0 deletions src/process/__tests__/process.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4750,6 +4750,221 @@ describe('Process Tests', function () {
assert.deepEqual(context.scope.errors.length, 0);
});

it('Should calculate value on server for calculations based on dataSource component', async function () {
const form = {
_id: '6752ad48eda1569ebc9aaead',
title: 'cart',
name: 'Cart',
path: '9357cart',
type: 'form',
display: 'form',
components: [
{
label: 'Products',
persistent: 'client-only',
trigger: {
init: true,
server: true
},
dataSrc: 'url',
fetch: {
url: '{{ config.appUrl }}/product/submission',
method: 'get',
headers: [
{
key: '',
value: ''
}
],
mapFunction: '',
forwardHeaders: false,
},
allowCaching: true,
key: 'products',
type: 'datasource',
input: true,
tableView: false
},
{
label: 'Cart',
reorder: false,
addAnotherPosition: 'bottom',
layoutFixed: false,
enableRowGroups: false,
initEmpty: false,
tableView: false,
key: 'cart',
type: 'datagrid',
input: true,
components: [
{
label: 'Product',
widget: 'choicesjs',
tableView: true,
dataSrc: 'custom',
data: {
custom: 'values = data.products;'
},
valueProperty: '_id',
template: '\u003Cspan\u003E{{ item.data.name }}\u003C/span\u003E',
refreshOn: 'products',
key: 'product',
type: 'select',
input: true
},
{
label: 'Quantity',
applyMaskOn: 'change',
mask: false,
tableView: false,
delimiter: false,
requireDecimal: false,
inputFormat: 'plain',
truncateMultipleSpaces: false,
key: 'quantity',
type: 'number',
input: true,
defaultValue: 1
},
{
label: 'Price',
applyMaskOn: 'change',
mask: false,
tableView: false,
delimiter: false,
requireDecimal: false,
inputFormat: 'plain',
truncateMultipleSpaces: false,
redrawOn: 'cart.product',
calculateValue: 'var productId = row.product;\nvalue = 0;\nif (productId && data.products && data.products.length) {\n data.products.forEach(function(product) {\n if (product._id === productId) {\n value = product.data.price * (row.quantity || 1);\n }\n });\n}',
calculateServer: true,
key: 'price',
type: 'number',
input: true
}
]
},
{
label: 'Total',
applyMaskOn: 'change',
mask: false,
tableView: false,
delimiter: false,
requireDecimal: false,
inputFormat: 'plain',
truncateMultipleSpaces: false,
redrawOn: 'cart',
calculateValue: 'if (data.cart && data.cart.length) {\n value = data.cart.reduce(function(total, cartItem) {\n return total + cartItem.price;\n }, 0);\n}',
calculateServer: true,
key: 'total',
type: 'number',
input: true
},
{
type: 'button',
label: 'Submit',
key: 'submit',
disableOnInvalid: true,
input: true,
tableView: false
}
],
created: '2024-12-06T07:52:40.891Z',
modified: '2024-12-06T08:33:40.971Z',
config: {
appUrl: 'http://localhost:3000/idwqwhclwioyqbw'
},
};

const resource = [
{
_id: '6752adf3eda1569ebc9ab0cd',
data: {
name: 'Cream',
price: 30
},
},
{
_id: '6752adf4eda1569ebc9ab0df',
data: {
name: 'Perfume',
price: 100
},
},
{
_id: '6752adf4eda1569ebc9ab0f1',
data: {
name: 'Soap',
price: 5
},
},
{
_id: '6752adf4eda1569ebc9ab103',
data: {
name: 'Toothpaste',
price: 10
},
},
{
_id: '6752adf4eda1569ebc9ab115',
data: {
name: 'Shampoo',
price: 20
},
}
];

const submission = {
data: {
cart: [
{
product: '6752adf4eda1569ebc9ab115',
quantity: 5,
price: 100
},
{
product: '6752adf4eda1569ebc9ab103',
quantity: 3,
price: 30
},
{
product: '6752adf4eda1569ebc9ab0df',
quantity: 2,
price: 200
}
],
total: 330,
submit: true
},
state: 'submitted'
};

const context = {
form,
submission,
data: submission.data,
components: form.components,
processors: ProcessTargets.submission,
scope: {},
fetch: (): Promise<Response> => {
return Promise.resolve({
ok: true,
json: () => {
return Promise.resolve(resource);
}
} as Response);
},
config: {
server: true,
},
};
await process(context);
submission.data = context.data;
context.processors = ProcessTargets.evaluator;
await process(context);
assert.deepEqual(context.data, submission.data);
});

describe('Required component validation in nested form in DataGrid/EditGrid', function () {
const nestedForm = {
key: 'form',
Expand Down
9 changes: 7 additions & 2 deletions src/process/calculation/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
CalculationScope,
CalculationContext,
ProcessorInfo,
FetchScope,
} from 'types';
import { set } from 'lodash';
import { normalizeContext } from 'utils/formUtil';
Expand All @@ -24,9 +25,13 @@ export const calculateProcessSync: ProcessorFnSync<CalculationScope> = (
if (!shouldCalculate(context)) {
return;
}

const calculationContext = (scope as FetchScope).fetched
? {...context, data: {...data, ...(scope as FetchScope).fetched}}
: context;
const evalContextValue = evalContext
? evalContext(normalizeContext(context))
: normalizeContext(context);
? evalContext(normalizeContext(calculationContext))
: normalizeContext(calculationContext);
evalContextValue.value = value || null;
if (!scope.calculated) scope.calculated = [];
const newValue = JSONLogicEvaluator.evaluate(component.calculateValue, evalContextValue, 'value');
Expand Down
2 changes: 1 addition & 1 deletion src/process/fetch/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ export const fetchProcess: ProcessorFn<FetchScope> = async (context: FetchContex
// Make sure the value does not get filtered for now...
if (!(scope as FilterContext).filter) (scope as FilterContext).filter = {};
(scope as FilterContext).filter[path] = true;
scope.fetched[path] = true;
scope.fetched[path] = get(row, key);
} catch (err: any) {
console.log(err.message);
}
Expand Down

0 comments on commit 9e9ce40

Please sign in to comment.