commit d4ded9f3ca6ec266d1a5a4f13043112c3946b4b0
parent 8a6c2a75208d5fc6d7f994d88299cee5e2c2a6c5
Author: Sebastian <sebasjm@gmail.com>
Date: Tue, 3 Jun 2025 17:29:31 -0300
fix #9677
Diffstat:
5 files changed, 65 insertions(+), 16 deletions(-)
diff --git a/packages/aml-backoffice-ui/src/hooks/decision-request.ts b/packages/aml-backoffice-ui/src/hooks/decision-request.ts
@@ -78,6 +78,10 @@ export interface DecisionRequest {
*/
properties: Record<string, boolean | string> | undefined;
/**
+ * Errors on the properties
+ */
+ properties_errors : object | undefined;
+ /**
* If given all the information, this account need to be investigated
*/
keep_investigating: boolean | undefined;
@@ -130,6 +134,7 @@ export const codecForDecisionRequest = (): Codec<DecisionRequest> =>
.property("rules", codecOptional(codecForList(codecForKycRules())))
.property("deadline", codecOptional(codecForAbsoluteTime))
.property("properties", codecOptional(codecForMap(codecForAny())))
+ .property("properties_errors", codecForAny())
.property("attributes", codecOptional(codecForAccountAttributes()))
.property("custom_properties", codecForAny())
.property("justification", codecOptional(codecForString()))
@@ -153,6 +158,7 @@ const DECISION_REQUEST_EMPTY: DecisionRequest = {
custom_events: undefined,
attributes: undefined,
accountName: undefined,
+ properties_errors: undefined,
triggering_events: undefined,
justification: undefined,
keep_investigating: undefined,
diff --git a/packages/aml-backoffice-ui/src/pages/decision/AmlDecisionRequestWizard.tsx b/packages/aml-backoffice-ui/src/pages/decision/AmlDecisionRequestWizard.tsx
@@ -81,7 +81,7 @@ export function isAttributesCompleted(request: DecisionRequest): boolean {
);
}
export function isPropertiesCompleted(request: DecisionRequest): boolean {
- return request.properties !== undefined;
+ return request.properties !== undefined && request.properties_errors === undefined;
}
export function isEventsCompleted(request: DecisionRequest): boolean {
return request.custom_events !== undefined;
diff --git a/packages/aml-backoffice-ui/src/pages/decision/Properties.tsx b/packages/aml-backoffice-ui/src/pages/decision/Properties.tsx
@@ -7,20 +7,24 @@ import {
PropertiesDerivation_TOPS,
PropertiesDerivationFunctionByPropertyName,
TalerAmlProperties,
- TOPS_AccountProperties
+ TalerFormAttributes,
+ TOPS_AccountProperties,
} from "@gnu-taler/taler-util";
import {
+ ErrorsSummary,
FormDesign,
FormUI,
InternationalizationAPI,
onComponentUnload,
UIFormElementConfig,
UIHandlerId,
+ undefinedIfEmpty,
useExchangeApiContext,
useForm,
- useTranslationContext
+ useTranslationContext,
} from "@gnu-taler/web-util/browser";
import { h, VNode } from "preact";
+import { useState } from "preact/hooks";
import {
DecisionRequest,
useCurrentDecisionRequest,
@@ -34,7 +38,7 @@ import { DEFAULT_LIMITS_WHEN_NEW_ACCOUNT } from "./Rules.js";
* @returns
*/
export function Properties({}: {}): VNode {
- const [request] = useCurrentDecisionRequest();
+ const [request, updateRequest] = useCurrentDecisionRequest();
const { config } = useExchangeApiContext();
const [pref] = usePreferences();
@@ -51,8 +55,8 @@ export function Properties({}: {}): VNode {
const merged = Object.entries(calculatedProps).reduce(
(prev, [key, value]) => {
- if (prev[key] === undefined) {
- prev[key] = !!value;
+ if (prev[key] === undefined && value !== undefined) {
+ prev[key] = value;
}
return prev;
},
@@ -65,18 +69,37 @@ export function Properties({}: {}): VNode {
);
}
+function officerMustCheckInvestigationState(
+ data: Record<keyof typeof TalerFormAttributes, string>,
+): boolean {
+ if (data[TalerFormAttributes.FORM_ID] !== "vqf_902_14") return false;
+ if (data[TalerFormAttributes.INCRISK_RESULT] !== "OTHER") return false;
+ return true;
+}
+
function ReloadForm({ merged }: { merged: any }): VNode {
const { i18n } = useTranslationContext();
const [request, updateRequest] = useCurrentDecisionRequest();
- const design = propertiesForm(i18n, propertiesByDialect(i18n));
+ const design = propertiesForm(
+ i18n,
+ propertiesByDialect(i18n, {
+ MANDATORY_INVESTIGATION_STATE: officerMustCheckInvestigationState(
+ (request.attributes?.data ?? {}) as any,
+ ),
+ }),
+ );
+ // const [id, setId] = useState(new Date().getTime());
+
+ const customProps = Object.entries(request.custom_properties ?? {}).map(
+ ([name, value]) => {
+ return { name, value };
+ },
+ );
const form = useForm<PropertiesForm>(design, {
defined: merged,
- custom: Object.entries(request.custom_properties ?? {}).map(
- ([name, value]) => {
- return { name, value };
- },
- ),
+ custom: customProps,
});
+ const errors = form.status.errors;
onComponentUnload(() => {
updateRequest("unload properties", {
@@ -89,10 +112,25 @@ function ReloadForm({ merged }: { merged: any }): VNode {
},
{} as Record<string, string>,
),
+ properties_errors: errors,
});
});
+
return (
<div>
+ <button
+ onClick={() => {
+ form.update({
+ custom: customProps,
+ defined: merged,
+ });
+ }}
+ class="m-4 rounded-md w-fit border-0 px-3 py-2 text-center text-sm disabled:bg-gray-500 bg-indigo-700 text-white shadow-sm hover:bg-indigo-700"
+ >
+ <i18n.Translate>Reset to default</i18n.Translate>
+ </button>
+
+ {!errors ? undefined : <ErrorsSummary errors={errors.defined as any} />}
<FormUI design={design} model={form.model} />
</div>
);
@@ -144,9 +182,10 @@ export const propertiesForm = (
function propertiesByDialect(
i18n: InternationalizationAPI,
- // dialect: AmlSpaDialect,
+ options: {
+ MANDATORY_INVESTIGATION_STATE?: boolean;
+ } = {},
): UIFormElementConfig[] {
- // if (!dialect) return [];
return [
{
id: TalerAmlProperties.FILE_NOTE,
@@ -198,6 +237,7 @@ function propertiesByDialect(
id: TalerAmlProperties.INVESTIGATION_STATE,
label: i18n.str`The MROS reporting state for the account.`,
type: "choiceStacked",
+ required: options.MANDATORY_INVESTIGATION_STATE,
choices: [
{
label: i18n.str`None`,
@@ -230,7 +270,7 @@ function propertiesByDialect(
id: TalerAmlProperties.SANCTION_LIST_BEST_MATCH,
label: i18n.str`Identifies the sanction list entry that the account matched against`,
type: "text",
- help: i18n.str`best match, does not mean it was a good match`,
+ help: i18n.str`Best match, does not mean it was a good match.`,
},
{
id: TalerAmlProperties.SANCTION_LIST_RATING,
diff --git a/packages/taler-util/src/aml/properties.ts b/packages/taler-util/src/aml/properties.ts
@@ -180,7 +180,7 @@ export const PropertiesDerivation_TOPS: PropertiesDerivationFunctionByPropertyNa
if (
attributes[TalerFormAttributes.INCRISK_RESULT] === "OTHER"
) {
- return "INVESTIGATION_PENDING";
+ return null as any;
}
}
diff --git a/packages/web-util/src/forms/gana/VQF_902_14.ts b/packages/web-util/src/forms/gana/VQF_902_14.ts
@@ -31,6 +31,9 @@ export function VQF_902_14(
help: i18n.str`Description of the circumstances/transactions, which triggered the special clarifications`,
type: "textArea",
required: true,
+ validator(text, form) {
+ return !text ? i18n.str`can't be empty` : undefined
+ },
},
],
},