Skip to content

Commit

Permalink
[AAE-20769] Fix precision for incoming values in bigdecimal field (#9434
Browse files Browse the repository at this point in the history
)

* [AAE-20769] Fix precision for incoming values in bigdecimal field

* CR
  • Loading branch information
BSekula authored Mar 18, 2024
1 parent b4f27d1 commit 69de85a
Show file tree
Hide file tree
Showing 9 changed files with 260 additions and 14 deletions.
14 changes: 13 additions & 1 deletion lib/core/src/lib/form/components/form-renderer.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ import {
checkboxWidgetFormVisibilityMock,
dateWidgetFormVisibilityMock,
multilineWidgetFormVisibilityMock,
displayTextWidgetFormVisibilityMock
displayTextWidgetFormVisibilityMock,
displayBigDecimalWidgetMock
} from './mock/form-renderer.component.mock';
import { FormService } from '../services/form.service';
import { CoreTestingModule } from '../../testing';
Expand Down Expand Up @@ -849,4 +850,15 @@ describe('Form Renderer Component', () => {
expectElementToBeHidden(displayTextContainer);
});
});

describe('Display Bigdecimal Widget', () => {
it('should round decimal field value to correct precision', async () => {
formRendererComponent.formDefinition = formService.parseForm(displayBigDecimalWidgetMock.formRepresentation.formDefinition);
fixture.detectChanges();
await fixture.whenStable();

const decimalInputElement = fixture.nativeElement.querySelector('#Decimal0tzu53');
expect(decimalInputElement.value).toBeTruthy('10.12');
});
});
});
29 changes: 26 additions & 3 deletions lib/core/src/lib/form/components/form-renderer.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,12 @@
* limitations under the License.
*/

import { Component, ViewEncapsulation, Input, OnDestroy, Injector, OnChanges } from '@angular/core';
import { Component, ViewEncapsulation, Input, OnDestroy, Injector, OnChanges, OnInit, Inject } from '@angular/core';
import { FormRulesManager, formRulesManagerFactory } from '../models/form-rules.model';
import { FormModel } from './widgets/core/form.model';
import { ContainerModel, FormFieldModel, TabModel } from './widgets';
import { FormService } from '../services/form.service';
import { FORM_FIELD_MODEL_RENDER_MIDDLEWARE, FormFieldModelRenderMiddleware } from './middlewares/middleware';

@Component({
selector: 'adf-form-renderer',
Expand All @@ -31,10 +32,11 @@ import { FormService } from '../services/form.service';
useFactory: formRulesManagerFactory,
deps: [Injector]
}

],
encapsulation: ViewEncapsulation.None
})
export class FormRendererComponent<T> implements OnChanges, OnDestroy {
export class FormRendererComponent<T> implements OnInit, OnChanges, OnDestroy {
/** Toggle debug options. */
@Input()
showDebugButton: boolean = false;
Expand All @@ -46,7 +48,16 @@ export class FormRendererComponent<T> implements OnChanges, OnDestroy {

fields: FormFieldModel[];

constructor(public formService: FormService, private formRulesManager: FormRulesManager<T>) {}
constructor(
public formService: FormService,
private formRulesManager: FormRulesManager<T>,
@Inject(FORM_FIELD_MODEL_RENDER_MIDDLEWARE)
private middlewareServices: FormFieldModelRenderMiddleware[]
) {}

ngOnInit(): void {
this.runMiddlewareServices();
}

ngOnChanges(): void {
this.formRulesManager.initialize(this.formDefinition);
Expand Down Expand Up @@ -123,4 +134,16 @@ export class FormRendererComponent<T> implements OnChanges, OnDestroy {
const colspan = container ? container.field.colspan : 1;
return (100 / container.field.numberOfColumns) * colspan + '';
}

private runMiddlewareServices(): void {
const formFields = this.formDefinition.getFormFields();

formFields.forEach(field => {
this.middlewareServices.forEach((middlewareService) => {
if (middlewareService.type === field.type) {
field = middlewareService.getParsedField(field);
}
});
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/*!
* @license
* Copyright © 2005-2023 Hyland Software, Inc. and its affiliates. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { FormFieldModel, FormFieldTypes, FormModel } from '../widgets';
import { DecimalRenderMiddlewareService } from './decimal-middleware.service';

describe('DecimalRenderMiddlewareService', () => {
let decimalMiddlewareService: DecimalRenderMiddlewareService;
let formFieldModel: FormFieldModel;

beforeEach(() => {
decimalMiddlewareService = new DecimalRenderMiddlewareService();

const form = new FormModel();
formFieldModel = new FormFieldModel(form, {
type: FormFieldTypes.DECIMAL,
id: 'id',
precision: 3,
value: '10.1060'
});
});

it('should return field with proper precisison', () => {
formFieldModel.value = '10.1000000000000';
formFieldModel.precision = 3;
const parsedField = decimalMiddlewareService.getParsedField(formFieldModel);
expect(parsedField.value).toBe('10.100');
});

it('should round up number with correct precisison', () => {
formFieldModel.value = '10.1039999';
formFieldModel.precision = 3;
const parsedField = decimalMiddlewareService.getParsedField(formFieldModel);
expect(parsedField.value).toBe('10.104');
});

it('should round up number, when removed fraction part starts with number larger or equal 5', () => {
formFieldModel.value = '10.1035000';
formFieldModel.precision = 3;
const parsedField = decimalMiddlewareService.getParsedField(formFieldModel);
expect(parsedField.value).toBe('10.104');
});

it('should NOT round up number, when removed fraction part starts with number smaller than 5', () => {
formFieldModel.value = '10.1034999';
formFieldModel.precision = 3;
const parsedField = decimalMiddlewareService.getParsedField(formFieldModel);
expect(parsedField.value).toBe('10.103');
});

it('should return the same value when precision is correct', () => {
formFieldModel.value = '10.123';
formFieldModel.precision = 3;
const parsedField = decimalMiddlewareService.getParsedField(formFieldModel);
expect(parsedField.value).toBe('10.123');
});

it('should work when value is not defined', () => {
formFieldModel.value = null;
const parsedField = decimalMiddlewareService.getParsedField(formFieldModel);
expect(parsedField.value).toBe(null);
});

it('should work when value is number', () => {
formFieldModel.value = 3.333;
const parsedField = decimalMiddlewareService.getParsedField(formFieldModel);
expect(parsedField.value).toBe(3.333);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*!
* @license
* Copyright © 2005-2023 Hyland Software, Inc. and its affiliates. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { Injectable } from '@angular/core';
import { FormFieldModelRenderMiddleware } from './middleware';
import { FormFieldModel, FormFieldTypes } from '../widgets';

@Injectable()
export class DecimalRenderMiddlewareService implements FormFieldModelRenderMiddleware {
type = FormFieldTypes.DECIMAL;

getParsedField(field: FormFieldModel): FormFieldModel {
const allowedMaxPrecision = field.precision;
const value = field.value;

field.value = this.forceMaxPrecisionIfNeeded(value, allowedMaxPrecision);

return field;
}

private forceMaxPrecisionIfNeeded(value: string | number, allowedMaxPrecision): string | number {
let numberOfDecimalDigits = 0;
const stringValue = typeof value === 'string' ? value : `${value}`;
const numberChunks = stringValue.split('.');

if (numberChunks.length === 2) {
numberOfDecimalDigits = numberChunks[1].length;
}

if (numberOfDecimalDigits > allowedMaxPrecision) {
const valueWithCorrectPrecision = parseFloat(value.toString())
.toFixed(allowedMaxPrecision);

return valueWithCorrectPrecision;
}

return value;
}
};
26 changes: 26 additions & 0 deletions lib/core/src/lib/form/components/middlewares/middleware.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*!
* @license
* Copyright © 2005-2023 Hyland Software, Inc. and its affiliates. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { InjectionToken } from '@angular/core';
import { FormFieldModel } from '../../components/widgets';

export interface FormFieldModelRenderMiddleware {
type: string;
getParsedField(field: FormFieldModel): FormFieldModel;
}

export const FORM_FIELD_MODEL_RENDER_MIDDLEWARE = new InjectionToken('RENDER_FORM_FIELD_MODEL_MIDDLEWARE');
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
* limitations under the License.
*/

import { FormFieldTypes } from '../widgets';

export const formDisplayValueVisibility = {
formRepresentation: {
id: 'form-3175b074-53c6-4b5b-92df-246b62108db3',
Expand Down Expand Up @@ -2086,3 +2088,50 @@ export const displayTextWidgetFormVisibilityMock = {
}
}
};

export const displayBigDecimalWidgetMock = {
formRepresentation: {
id: 'form-098756a5-2222-4c3a-1111-81dabc9a88b6',
name: 'displayBigdecimalForm',
description: '',
version: 0,
standAlone: true,
formDefinition: {
tabs: [],
fields: [
{
id: '45269202-5f2a-438e-b14c-fe13eb4b2aa1',
name: 'Label',
type: 'container',
tab: null,
numberOfColumns: 2,
fields: {
1: [
{
id: 'Decimal0tzu53',
name: 'Bigdecimal',
type: FormFieldTypes.DECIMAL,
required: false,
colspan: 1,
placeholder: null,
minLength: 0,
maxLength: 0,
regexPattern: null,
visibilityCondition: null,
precision: 2,
value: '10.12345678',
params: {
existingColspan: 1,
maxColspan: 2
}
}
]
}
}
],
outcomes: [],
metadata: {},
variables: []
}
}
};
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
pattern="-?[0-9]*(\.[0-9]*)?"
[id]="field.id"
[required]="isRequired()"
[value]="displayValue"
[(ngModel)]="field.value"
(ngModelChange)="onFieldChanged(field)"
[disabled]="field.readOnly"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
* limitations under the License.
*/

import { Component, OnInit, ViewEncapsulation } from '@angular/core';
import { Component, ViewEncapsulation } from '@angular/core';
import { FormService } from '../../../services/form.service';
import { WidgetComponent } from '../widget.component';

Expand All @@ -36,14 +36,8 @@ import { WidgetComponent } from '../widget.component';
},
encapsulation: ViewEncapsulation.None
})
export class DecimalWidgetComponent extends WidgetComponent implements OnInit {
displayValue: number;

export class DecimalWidgetComponent extends WidgetComponent {
constructor(public formService: FormService) {
super(formService);
}

ngOnInit(): void {
this.displayValue = this.field.value;
}
}
9 changes: 8 additions & 1 deletion lib/core/src/lib/form/form-base.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ import { EditJsonDialogModule } from '../dialogs/edit-json/edit-json.dialog.modu
import { A11yModule } from '@angular/cdk/a11y';
import { ViewerModule } from '../viewer/viewer.module';
import { InplaceFormInputComponent } from './components/inplace-form-input/inplace-form-input.component';
import { FORM_FIELD_MODEL_RENDER_MIDDLEWARE } from './components/middlewares/middleware';
import { DecimalRenderMiddlewareService } from './components/middlewares/decimal-middleware.service';

@NgModule({
imports: [
Expand Down Expand Up @@ -70,7 +72,12 @@ import { InplaceFormInputComponent } from './components/inplace-form-input/inpla
...WIDGET_DIRECTIVES,
InplaceFormInputComponent,
WidgetComponent
]
],
providers: [{
provide: FORM_FIELD_MODEL_RENDER_MIDDLEWARE,
useClass: DecimalRenderMiddlewareService,
multi: true
}]
})
export class FormBaseModule {
}

0 comments on commit 69de85a

Please sign in to comment.