mirror of
https://github.com/valitydev/control-center.git
synced 2024-11-06 02:25:17 +00:00
FIN-80: New terminals fees view (#384)
This commit is contained in:
parent
ba1960d746
commit
7fa32c653c
4181
package-lock.json
generated
4181
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
34
package.json
34
package.json
@ -16,17 +16,17 @@
|
||||
"fix": "npm run lint:fix && npm run format:fix && npm run spell:fix"
|
||||
},
|
||||
"dependencies": {
|
||||
"@angular/animations": "18.0.5",
|
||||
"@angular/cdk": "18.0.5",
|
||||
"@angular/common": "18.0.5",
|
||||
"@angular/compiler": "18.0.5",
|
||||
"@angular/core": "18.0.5",
|
||||
"@angular/forms": "18.0.5",
|
||||
"@angular/material": "18.0.5",
|
||||
"@angular/platform-browser": "18.0.5",
|
||||
"@angular/platform-browser-dynamic": "18.0.5",
|
||||
"@angular/platform-server": "18.0.5",
|
||||
"@angular/router": "18.0.5",
|
||||
"@angular/animations": "18.2.2",
|
||||
"@angular/cdk": "18.2.2",
|
||||
"@angular/common": "18.2.2",
|
||||
"@angular/compiler": "18.2.2",
|
||||
"@angular/core": "18.2.2",
|
||||
"@angular/forms": "18.2.2",
|
||||
"@angular/material": "18.2.2",
|
||||
"@angular/platform-browser": "18.2.2",
|
||||
"@angular/platform-browser-dynamic": "18.2.2",
|
||||
"@angular/platform-server": "18.2.2",
|
||||
"@angular/router": "18.2.2",
|
||||
"@ngneat/input-mask": "6.0.0",
|
||||
"@vality/deanonimus-proto": "2.0.1-2a02d87.0",
|
||||
"@vality/domain-proto": "2.0.1-e5d3c83.0",
|
||||
@ -34,7 +34,7 @@
|
||||
"@vality/fistful-proto": "2.0.1-88e69a5.0",
|
||||
"@vality/machinegun-proto": "1.0.0",
|
||||
"@vality/magista-proto": "2.0.2-ec1bdb9.0",
|
||||
"@vality/ng-core": "18.2.0",
|
||||
"@vality/ng-core": "18.3.1-pr-67-675080b.0",
|
||||
"@vality/ng-thrift": "18.0.1-pr-13-bdb6d51.0",
|
||||
"@vality/payout-manager-proto": "2.0.1-eb4091a.0",
|
||||
"@vality/repairer-proto": "2.0.2-07b73e9.0",
|
||||
@ -54,14 +54,14 @@
|
||||
"tslib": "2.3.1",
|
||||
"utility-types": "3.10.0",
|
||||
"yaml": "2.4.5",
|
||||
"zone.js": "0.14.2"
|
||||
"zone.js": "0.14.10"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-devkit/build-angular": "18.0.6",
|
||||
"@angular-devkit/build-angular": "18.2.2",
|
||||
"@angular-eslint/builder": "18.0.1",
|
||||
"@angular-eslint/schematics": "18.0.1",
|
||||
"@angular/cli": "18.0.6",
|
||||
"@angular/compiler-cli": "18.0.5",
|
||||
"@angular/cli": "18.2.2",
|
||||
"@angular/compiler-cli": "18.2.2",
|
||||
"@types/inputmask": "5.0.3",
|
||||
"@types/jasmine": "4.0.3",
|
||||
"@types/jwt-decode": "2.2.1",
|
||||
@ -85,4 +85,4 @@
|
||||
"typescript": "~5.4.5",
|
||||
"typescript-memoize": "1.1.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -114,11 +114,6 @@ export class AppComponent {
|
||||
url: '/payments',
|
||||
services: PAYMENTS_ROUTING_CONFIG.services,
|
||||
},
|
||||
{
|
||||
label: 'Old Payments',
|
||||
url: '/old-payments',
|
||||
services: PAYMENTS_ROUTING_CONFIG.services,
|
||||
},
|
||||
{
|
||||
label: 'Chargebacks',
|
||||
url: '/chargebacks',
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { Component, Input, Output, EventEmitter } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { StatPayment } from '@vality/magista-proto/magista';
|
||||
import { LoadOptions, Column2, createMenuColumn } from '@vality/ng-core';
|
||||
import { LoadOptions, Column2, createMenuColumn, TABLE_WRAPPER_STYLE } from '@vality/ng-core';
|
||||
import { getUnionKey } from '@vality/ng-thrift';
|
||||
import startCase from 'lodash-es/startCase';
|
||||
|
||||
@ -18,7 +18,7 @@ import {
|
||||
@Component({
|
||||
selector: 'cc-payments-table',
|
||||
templateUrl: './payments-table.component.html',
|
||||
styles: `:host { height: 100%; }`,
|
||||
host: { style: TABLE_WRAPPER_STYLE },
|
||||
})
|
||||
export class PaymentsTableComponent {
|
||||
@Input() data!: StatPayment[];
|
||||
@ -31,8 +31,15 @@ export class PaymentsTableComponent {
|
||||
@Output() more = new EventEmitter<void>();
|
||||
|
||||
columns: Column2<StatPayment>[] = [
|
||||
{ field: 'id', cell: (d) => ({ click: () => this.toDetails(d) }), sticky: 'start' },
|
||||
{ field: 'invoice_id', sticky: 'start' },
|
||||
{
|
||||
field: 'id',
|
||||
cell: (d) => ({
|
||||
value: `${d.invoice_id}.${d.id}`,
|
||||
click: () => this.toDetails(d),
|
||||
}),
|
||||
sticky: 'start',
|
||||
},
|
||||
{ field: 'external_id' },
|
||||
createCurrencyColumn((d) => ({ amount: d.amount, code: d.currency_symbolic_code }), {
|
||||
field: 'amount',
|
||||
}),
|
||||
@ -66,7 +73,6 @@ export class PaymentsTableComponent {
|
||||
createDomainObjectColumn((d) => ({ ref: { provider: d.provider_id } }), {
|
||||
header: 'Provider',
|
||||
}),
|
||||
{ field: 'external_id' },
|
||||
createFailureColumn2((d) => ({
|
||||
failure: d.status?.failed?.failure?.failure,
|
||||
noFailureMessage:
|
||||
|
@ -6,8 +6,8 @@ import { TableModule, VSelectPipe, Column2 } from '@vality/ng-core';
|
||||
import type { TermSetHistory, ShopTermSet } from '@vality/dominator-proto/internal/dominator';
|
||||
|
||||
import { SidenavInfoModule } from '../../../../shared/components/sidenav-info';
|
||||
import { getDomainObjectDetails } from '../../../../shared/components/thrift-api-crud';
|
||||
import { getInlineDecisions2 } from '../../utils/get-inline-decisions';
|
||||
import { createDomainObjectColumn } from '../../../../shared/utils/table2';
|
||||
import { getFlatDecisions } from '../../utils/get-flat-decisions';
|
||||
import {
|
||||
getShopCashFlowSelectors,
|
||||
isShopTermSetDecision,
|
||||
@ -26,7 +26,7 @@ export class ShopsTermSetHistoryCardComponent {
|
||||
historyData = computed(() =>
|
||||
(this.data()?.term_set_history?.reverse?.() || []).map((t) => ({
|
||||
value: t,
|
||||
children: getInlineDecisions2(getShopCashFlowSelectors(t.term_set)).filter((v) =>
|
||||
children: getFlatDecisions(getShopCashFlowSelectors(t.term_set)).filter((v) =>
|
||||
isShopTermSetDecision(v, {
|
||||
partyId: this.data().owner_id,
|
||||
shopId: this.data().shop_id,
|
||||
@ -38,14 +38,9 @@ export class ShopsTermSetHistoryCardComponent {
|
||||
|
||||
columns: Column2<TermSetHistory>[] = [
|
||||
{ field: 'applied_at', cell: { type: 'datetime' } },
|
||||
{
|
||||
field: 'term_set',
|
||||
cell: (d) => ({
|
||||
value: getDomainObjectDetails({ term_set_hierarchy: d?.term_set })?.label,
|
||||
description: getDomainObjectDetails({ term_set_hierarchy: d?.term_set })
|
||||
?.description,
|
||||
}),
|
||||
},
|
||||
createDomainObjectColumn((d) => ({ ref: { term_set_hierarchy: d?.term_set?.ref } }), {
|
||||
header: 'Term Set',
|
||||
}),
|
||||
...SHOP_FEES_COLUMNS,
|
||||
];
|
||||
}
|
||||
|
@ -40,7 +40,7 @@ import {
|
||||
createContractColumn,
|
||||
createDomainObjectColumn,
|
||||
} from '../../../../shared/utils/table2';
|
||||
import { getInlineDecisions2, InlineDecision2 } from '../../utils/get-inline-decisions';
|
||||
import { getFlatDecisions, FlatDecision } from '../../utils/get-flat-decisions';
|
||||
import { ShopsTermSetHistoryCardComponent } from '../shops-term-set-history-card';
|
||||
|
||||
import { ShopsTermsService } from './shops-terms.service';
|
||||
@ -89,7 +89,7 @@ export class ShopsTermsComponent implements OnInit {
|
||||
map((terms) =>
|
||||
terms.map((t) => ({
|
||||
value: t,
|
||||
children: getInlineDecisions2(getShopCashFlowSelectors(t.current_term_set)).filter(
|
||||
children: getFlatDecisions(getShopCashFlowSelectors(t.current_term_set)).filter(
|
||||
(v) =>
|
||||
isShopTermSetDecision(v, {
|
||||
partyId: t.owner_id,
|
||||
@ -102,7 +102,7 @@ export class ShopsTermsComponent implements OnInit {
|
||||
);
|
||||
hasMore$ = this.shopsTermsService.hasMore$;
|
||||
isLoading$ = this.shopsTermsService.isLoading$;
|
||||
columns: Column2<ShopTermSet, InlineDecision2>[] = [
|
||||
columns: Column2<ShopTermSet, FlatDecision>[] = [
|
||||
createShopColumn(
|
||||
(d) => ({
|
||||
shopId: d.shop_id,
|
||||
|
@ -7,9 +7,9 @@ import {
|
||||
} from '@vality/domain-proto/internal/domain';
|
||||
import { Column2 } from '@vality/ng-core';
|
||||
|
||||
import { getCashVolumeParts, formatCashVolumes } from '../../../../../shared';
|
||||
import { InlineDecision2, formatLevelPredicate } from '../../../utils/get-inline-decisions';
|
||||
import { isOneHundredPercentCashFlowPosting } from '../../../utils/is-one-hundred-percent-cash-flow-posting';
|
||||
import { formatCashVolumes } from '../../../../../shared';
|
||||
import { createFeesColumns } from '../../../utils/create-fees-columns';
|
||||
import { FlatDecision } from '../../../utils/get-flat-decisions';
|
||||
import { isThatCurrency } from '../../../utils/is-that-currency';
|
||||
|
||||
export function getShopCashFlowSelectors(d: TermSetHierarchyObject) {
|
||||
@ -32,7 +32,7 @@ export function isThatShopParty(predicate: Predicate, partyId: PartyID, shopId:
|
||||
}
|
||||
|
||||
export function isShopTermSetDecision(
|
||||
v: InlineDecision2,
|
||||
v: FlatDecision,
|
||||
params: { partyId: PartyID; shopId: ShopID; currency: string },
|
||||
) {
|
||||
return (
|
||||
@ -42,39 +42,13 @@ export function isShopTermSetDecision(
|
||||
);
|
||||
}
|
||||
|
||||
const BASE_SHOP_FEES_COLUMNS = createFeesColumns({
|
||||
feeFilter: isShopFee,
|
||||
otherFilter: (v) => !isShopRreserve(v),
|
||||
});
|
||||
|
||||
export const SHOP_FEES_COLUMNS = [
|
||||
{
|
||||
field: 'condition',
|
||||
child: (d) => ({ value: formatLevelPredicate(d) }),
|
||||
},
|
||||
{
|
||||
field: 'feeShare',
|
||||
header: 'Fee, %',
|
||||
child: (d) => ({
|
||||
value: getCashVolumeParts(d.value.filter(isShopFee).map((v) => v.volume))?.share,
|
||||
}),
|
||||
},
|
||||
{
|
||||
field: 'feeFixed',
|
||||
header: 'Fee, fix',
|
||||
child: (d) => ({
|
||||
value: getCashVolumeParts(d.value.filter(isShopFee).map((v) => v.volume))?.fixed,
|
||||
}),
|
||||
},
|
||||
{
|
||||
field: 'feeMin',
|
||||
header: 'Fee, min',
|
||||
child: (d) => ({
|
||||
value: getCashVolumeParts(d.value.filter(isShopFee).map((v) => v.volume))?.max,
|
||||
}),
|
||||
},
|
||||
{
|
||||
field: 'feeMax',
|
||||
header: 'Fee, max',
|
||||
child: (d) => ({
|
||||
value: getCashVolumeParts(d.value.filter(isShopFee).map((v) => v.volume))?.min,
|
||||
}),
|
||||
},
|
||||
...BASE_SHOP_FEES_COLUMNS.slice(0, -1),
|
||||
{
|
||||
field: 'rreserve',
|
||||
header: 'RReserve',
|
||||
@ -82,19 +56,5 @@ export const SHOP_FEES_COLUMNS = [
|
||||
value: formatCashVolumes(d.value.filter(isShopRreserve).map((v) => v.volume)),
|
||||
}),
|
||||
},
|
||||
{
|
||||
field: 'other',
|
||||
child: (d) => ({
|
||||
value: formatCashVolumes(
|
||||
d.value
|
||||
.filter(
|
||||
(v) =>
|
||||
!isShopFee(v) &&
|
||||
!isShopRreserve(v) &&
|
||||
!isOneHundredPercentCashFlowPosting(v),
|
||||
)
|
||||
.map((v) => v.volume),
|
||||
),
|
||||
}),
|
||||
},
|
||||
] satisfies Column2<object, InlineDecision2>[];
|
||||
BASE_SHOP_FEES_COLUMNS.at(-1),
|
||||
] satisfies Column2<object, FlatDecision>[];
|
||||
|
@ -1,25 +1,3 @@
|
||||
<cc-card [title]="'Term Sets History'">
|
||||
<v-table
|
||||
[cellTemplate]="{
|
||||
payments_condition: arrayColumnTemplate,
|
||||
payments: arrayColumnTemplate,
|
||||
wallets_condition: arrayColumnTemplate,
|
||||
wallets: arrayColumnTemplate
|
||||
}"
|
||||
[columns]="columns"
|
||||
[data]="data()"
|
||||
></v-table>
|
||||
|
||||
<ng-template #arrayColumnTemplate let-colDef="colDef" let-rowData="rowData" let-value="value">
|
||||
<ng-container *ngIf="(rowData | vSelect: colDef.tooltip : '' : [colDef]) || ' ' as tooltip">
|
||||
<div
|
||||
*ngFor="let item of value; let index = index"
|
||||
[matTooltip]="tooltip[index]"
|
||||
matTooltipPosition="right"
|
||||
style="white-space: nowrap; cursor: default"
|
||||
>
|
||||
{{ value?.length > 1 ? item || '-' : item }}
|
||||
</div>
|
||||
</ng-container>
|
||||
</ng-template>
|
||||
<v-table2 [columns]="columns" [treeData]="historyData()"></v-table2>
|
||||
</cc-card>
|
||||
|
@ -1,12 +1,18 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { Component, input } from '@angular/core';
|
||||
import { Component, input, computed } from '@angular/core';
|
||||
import { MatTooltip } from '@angular/material/tooltip';
|
||||
import { TableModule, type Column, VSelectPipe } from '@vality/ng-core';
|
||||
import { TableModule, VSelectPipe, Column2 } from '@vality/ng-core';
|
||||
|
||||
import type { ProvisionTermSetHistory } from '@vality/dominator-proto/internal/dominator';
|
||||
import type {
|
||||
TerminalTermSet,
|
||||
ProvisionTermSetHistory,
|
||||
} from '@vality/dominator-proto/internal/dominator';
|
||||
|
||||
import { SidenavInfoModule } from '../../../../shared/components/sidenav-info';
|
||||
import { createTerminalFeesColumn } from '../terminals-terms/utils/create-terminal-fees-column';
|
||||
import {
|
||||
TERMINAL_FEES_COLUMNS,
|
||||
getTerminalTreeDataItem,
|
||||
} from '../terminals-terms/utils/terminal-fees-columns';
|
||||
|
||||
@Component({
|
||||
selector: 'cc-shops-term-set-history-card',
|
||||
@ -16,9 +22,15 @@ import { createTerminalFeesColumn } from '../terminals-terms/utils/create-termin
|
||||
styles: ``,
|
||||
})
|
||||
export class TerminalsTermSetHistoryCardComponent {
|
||||
data = input<ProvisionTermSetHistory[]>();
|
||||
columns: Column<ProvisionTermSetHistory>[] = [
|
||||
{ field: 'applied_at', type: 'datetime' },
|
||||
...createTerminalFeesColumn<ProvisionTermSetHistory>((d) => d.term_set),
|
||||
data = input<TerminalTermSet>();
|
||||
historyData = computed(() =>
|
||||
(this.data()?.term_set_history?.reverse?.() || []).map(
|
||||
getTerminalTreeDataItem((d) => d.term_set),
|
||||
),
|
||||
);
|
||||
|
||||
columns: Column2<ProvisionTermSetHistory>[] = [
|
||||
{ field: 'applied_at', cell: { type: 'datetime' } },
|
||||
...TERMINAL_FEES_COLUMNS,
|
||||
];
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
<cc-page-layout title="Terminals terms">
|
||||
<cc-page-layout fullHeight title="Terminals terms">
|
||||
<cc-page-layout-actions>
|
||||
<v-more-filters-button [filters]="filters"></v-more-filters-button>
|
||||
</cc-page-layout-actions>
|
||||
@ -10,38 +10,12 @@
|
||||
</ng-template>
|
||||
</v-filters>
|
||||
|
||||
<v-table
|
||||
[cellTemplate]="{
|
||||
payments_condition: arrayColumnTemplate,
|
||||
payments: arrayColumnTemplate,
|
||||
wallets_condition: arrayColumnTemplate,
|
||||
wallets: arrayColumnTemplate
|
||||
}"
|
||||
<v-table2
|
||||
[columns]="columns"
|
||||
[data]="terms$ | async"
|
||||
[hasMore]="hasMore$ | async"
|
||||
[progress]="isLoading$ | async"
|
||||
[treeData]="terms$ | async"
|
||||
(more)="more()"
|
||||
(update)="update($event)"
|
||||
></v-table>
|
||||
|
||||
<ng-template #arrayColumnTemplate let-colDef="colDef" let-rowData="rowData" let-value="value">
|
||||
<ng-container *ngIf="(rowData | vSelect: colDef.tooltip : '' : [colDef]) || ' ' as tooltip">
|
||||
<div
|
||||
*ngFor="let item of value; let index = index"
|
||||
[matTooltip]="tooltip[index]"
|
||||
[title]="item"
|
||||
matTooltipPosition="right"
|
||||
style="
|
||||
white-space: nowrap;
|
||||
cursor: default;
|
||||
max-width: 50vw;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
"
|
||||
>
|
||||
{{ value?.length > 1 ? item || '-' : item }}
|
||||
</div>
|
||||
</ng-container>
|
||||
</ng-template>
|
||||
></v-table2>
|
||||
</cc-page-layout>
|
||||
|
@ -10,7 +10,7 @@ import {
|
||||
} from '@vality/dominator-proto/internal/dominator';
|
||||
import {
|
||||
clean,
|
||||
Column,
|
||||
Column2,
|
||||
countChanged,
|
||||
createControls,
|
||||
debounceTimeWithFirst,
|
||||
@ -32,14 +32,14 @@ import type { ProviderRef, TerminalRef } from '@vality/dominator-proto/internal/
|
||||
import { PageLayoutModule } from '@cc/app/shared';
|
||||
import { CurrencyFieldComponent } from '@cc/app/shared/components/currency-field';
|
||||
import { MerchantFieldModule } from '@cc/app/shared/components/merchant-field';
|
||||
import { createDomainObjectColumn } from '@cc/app/shared/utils/table/create-domain-object-column';
|
||||
import { createDomainObjectColumn } from '@cc/app/shared/utils/table2/create-domain-object-column';
|
||||
import { DEBOUNCE_TIME_MS } from '@cc/app/tokens';
|
||||
|
||||
import { SidenavInfoService } from '../../../../shared/components/sidenav-info';
|
||||
import { TerminalsTermSetHistoryCardComponent } from '../terminals-term-set-history-card';
|
||||
|
||||
import { TerminalsTermsService } from './terminals-terms.service';
|
||||
import { createTerminalFeesColumn } from './utils/create-terminal-fees-column';
|
||||
import { TERMINAL_FEES_COLUMNS, getTerminalTreeDataItem } from './utils/terminal-fees-columns';
|
||||
|
||||
type Params = Pick<CommonSearchQueryParams, 'currencies'> &
|
||||
Overwrite<
|
||||
@ -73,21 +73,28 @@ export class TerminalsTermsComponent implements OnInit {
|
||||
terminal_ids: null,
|
||||
}),
|
||||
);
|
||||
terms$ = this.terminalsTermsService.result$;
|
||||
terms$ = this.terminalsTermsService.result$.pipe(
|
||||
map((terms) => terms.map(getTerminalTreeDataItem((d) => d.current_term_set))),
|
||||
);
|
||||
hasMore$ = this.terminalsTermsService.hasMore$;
|
||||
isLoading$ = this.terminalsTermsService.isLoading$;
|
||||
columns: Column<TerminalTermSet>[] = [
|
||||
createDomainObjectColumn<TerminalTermSet>('terminal', (d) => d.terminal_id),
|
||||
createDomainObjectColumn<TerminalTermSet>('provider', (d) => d.provider_id),
|
||||
{ field: 'currencies', formatter: (d) => d.currencies.join(', ') },
|
||||
...createTerminalFeesColumn<TerminalTermSet>((d) => d.current_term_set),
|
||||
columns: Column2<TerminalTermSet>[] = [
|
||||
createDomainObjectColumn((d) => ({ ref: { terminal: d.terminal_id } }), {
|
||||
header: 'Terminal',
|
||||
sticky: 'start',
|
||||
}),
|
||||
createDomainObjectColumn((d) => ({ ref: { provider: d.provider_id } }), {
|
||||
header: 'Provider',
|
||||
}),
|
||||
{ field: 'currencies', cell: (d) => ({ value: d.currencies.join(', ') }) },
|
||||
...TERMINAL_FEES_COLUMNS,
|
||||
{
|
||||
field: 'term_set_history',
|
||||
formatter: (d) => d.term_set_history?.length || '',
|
||||
click: (d) =>
|
||||
this.sidenavInfoService.open(TerminalsTermSetHistoryCardComponent, {
|
||||
data: d?.term_set_history?.reverse(),
|
||||
}),
|
||||
cell: (d) => ({
|
||||
value: d.term_set_history?.length || '',
|
||||
click: () =>
|
||||
this.sidenavInfoService.open(TerminalsTermSetHistoryCardComponent, { data: d }),
|
||||
}),
|
||||
},
|
||||
];
|
||||
active$ = getValueChanges(this.filtersForm).pipe(
|
||||
|
@ -1,53 +0,0 @@
|
||||
import type { ProvisionTermSet } from '@vality/dominator-proto/internal/proto/domain';
|
||||
import type { Column } from '@vality/ng-core';
|
||||
|
||||
import { getInlineDecisions, formatLevelPredicate } from '../../../utils/get-inline-decisions';
|
||||
|
||||
export function createTerminalFeesColumn<T extends object>(
|
||||
fn: (d: T) => ProvisionTermSet = (d) => d as never,
|
||||
): Column<T>[] {
|
||||
return [
|
||||
{
|
||||
field: 'payments_condition',
|
||||
formatter: (d) =>
|
||||
getInlineDecisions(
|
||||
[fn(d)?.payments?.cash_flow].filter(Boolean),
|
||||
(d) =>
|
||||
!(
|
||||
d.source.provider === 0 &&
|
||||
d.destination.merchant === 0 &&
|
||||
d.volume?.share?.parts?.p === 1 &&
|
||||
d.volume?.share?.parts?.q === 1
|
||||
),
|
||||
).map((v) => formatLevelPredicate(v)),
|
||||
},
|
||||
{
|
||||
field: 'payments',
|
||||
formatter: (d) =>
|
||||
getInlineDecisions(
|
||||
[fn(d)?.payments?.cash_flow].filter(Boolean),
|
||||
(d) =>
|
||||
!(
|
||||
d.source.provider === 0 &&
|
||||
d.destination.merchant === 0 &&
|
||||
d.volume?.share?.parts?.p === 1 &&
|
||||
d.volume?.share?.parts?.q === 1
|
||||
),
|
||||
).map((v) => v?.value),
|
||||
},
|
||||
{
|
||||
field: 'wallets_condition',
|
||||
formatter: (d) =>
|
||||
getInlineDecisions([fn(d)?.wallet?.withdrawals?.cash_flow].filter(Boolean)).map(
|
||||
(v) => formatLevelPredicate(v),
|
||||
),
|
||||
},
|
||||
{
|
||||
field: 'wallets',
|
||||
formatter: (d) =>
|
||||
getInlineDecisions([fn(d)?.wallet?.withdrawals?.cash_flow].filter(Boolean)).map(
|
||||
(v) => v?.value,
|
||||
),
|
||||
},
|
||||
];
|
||||
}
|
@ -0,0 +1,58 @@
|
||||
import { ProvisionTermSet, CashFlowPosting } from '@vality/domain-proto/internal/domain';
|
||||
import { Column2, TreeDataItem } from '@vality/ng-core';
|
||||
|
||||
import { createFeesColumns } from '../../../utils/create-fees-columns';
|
||||
import { FlatDecision, getFlatDecisions } from '../../../utils/get-flat-decisions';
|
||||
|
||||
export interface TerminalChild {
|
||||
payment: FlatDecision;
|
||||
withdrawal: FlatDecision;
|
||||
}
|
||||
|
||||
export function getTerminalPaymentsCashFlowSelectors(d: ProvisionTermSet) {
|
||||
return [d?.payments?.cash_flow].filter(Boolean);
|
||||
}
|
||||
|
||||
export function getTerminalWalletsCashFlowSelectors(d: ProvisionTermSet) {
|
||||
return [d?.wallet?.withdrawals?.cash_flow].filter(Boolean);
|
||||
}
|
||||
|
||||
export function isPaymentFee(v: CashFlowPosting) {
|
||||
return v?.source?.system === 0 && v?.destination?.provider === 0;
|
||||
}
|
||||
|
||||
export function isWithdrawalFee(v: CashFlowPosting) {
|
||||
return v?.source?.system === 0 && v?.destination?.provider === 0;
|
||||
}
|
||||
|
||||
export function getTerminalTreeDataItem<T extends object>(
|
||||
selectTermSet: (d: T) => ProvisionTermSet,
|
||||
) {
|
||||
return (d: T): TreeDataItem<T, TerminalChild> => {
|
||||
const termSet = selectTermSet(d);
|
||||
const paymentsDecisions = getFlatDecisions(getTerminalPaymentsCashFlowSelectors(termSet));
|
||||
const withdrawalsDecisions = getFlatDecisions(getTerminalWalletsCashFlowSelectors(termSet));
|
||||
return {
|
||||
value: d,
|
||||
children: new Array(Math.max(paymentsDecisions.length, withdrawalsDecisions.length))
|
||||
.fill(null)
|
||||
.map((_, idx) => ({
|
||||
payment: paymentsDecisions[idx],
|
||||
withdrawal: withdrawalsDecisions[idx],
|
||||
})),
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export const TERMINAL_FEES_COLUMNS = [
|
||||
...createFeesColumns<TerminalChild>({
|
||||
conditionLabel: 'Payment Condition',
|
||||
feeFilter: isPaymentFee,
|
||||
selectFlatDecision: (d) => d.payment,
|
||||
}),
|
||||
...createFeesColumns<TerminalChild>({
|
||||
conditionLabel: 'Withdrawal Condition',
|
||||
feeFilter: isWithdrawalFee,
|
||||
selectFlatDecision: (d) => d.withdrawal,
|
||||
}),
|
||||
] satisfies Column2<object, TerminalChild>[];
|
@ -6,8 +6,8 @@ import { TableModule, VSelectPipe, Column2 } from '@vality/ng-core';
|
||||
import type { TermSetHistory, WalletTermSet } from '@vality/dominator-proto/internal/dominator';
|
||||
|
||||
import { SidenavInfoModule } from '../../../../shared/components/sidenav-info';
|
||||
import { getDomainObjectDetails } from '../../../../shared/components/thrift-api-crud';
|
||||
import { getInlineDecisions2 } from '../../utils/get-inline-decisions';
|
||||
import { createDomainObjectColumn } from '../../../../shared/utils/table2';
|
||||
import { getFlatDecisions } from '../../utils/get-flat-decisions';
|
||||
import {
|
||||
WALLET_FEES_COLUMNS,
|
||||
isWalletTermSetDecision,
|
||||
@ -26,7 +26,7 @@ export class WalletsTermSetHistoryCardComponent {
|
||||
historyData = computed(() =>
|
||||
(this.data()?.term_set_history?.reverse?.() || []).map((t) => ({
|
||||
value: t,
|
||||
children: getInlineDecisions2(getWalletCashFlowSelectors(t.term_set)).filter((v) =>
|
||||
children: getFlatDecisions(getWalletCashFlowSelectors(t.term_set)).filter((v) =>
|
||||
isWalletTermSetDecision(v, {
|
||||
partyId: this.data().owner_id,
|
||||
walletId: this.data().wallet_id,
|
||||
@ -38,14 +38,9 @@ export class WalletsTermSetHistoryCardComponent {
|
||||
|
||||
columns: Column2<TermSetHistory>[] = [
|
||||
{ field: 'applied_at', cell: { type: 'datetime' } },
|
||||
{
|
||||
field: 'term_set',
|
||||
cell: (d) => ({
|
||||
value: getDomainObjectDetails({ term_set_hierarchy: d?.term_set })?.label,
|
||||
description: getDomainObjectDetails({ term_set_hierarchy: d?.term_set })
|
||||
?.description,
|
||||
}),
|
||||
},
|
||||
createDomainObjectColumn((d) => ({ ref: { term_set_hierarchy: d?.term_set?.ref } }), {
|
||||
header: 'Term Set',
|
||||
}),
|
||||
...WALLET_FEES_COLUMNS,
|
||||
];
|
||||
}
|
||||
|
@ -4,13 +4,11 @@ import {
|
||||
Predicate,
|
||||
WalletID,
|
||||
} from '@vality/domain-proto/internal/domain';
|
||||
import { Column2 } from '@vality/ng-core';
|
||||
|
||||
import type { TermSetHierarchyObject } from '@vality/dominator-proto/internal/proto/domain';
|
||||
|
||||
import { getCashVolumeParts, formatCashVolumes } from '../../../../../shared';
|
||||
import { InlineDecision2, formatLevelPredicate } from '../../../utils/get-inline-decisions';
|
||||
import { isOneHundredPercentCashFlowPosting } from '../../../utils/is-one-hundred-percent-cash-flow-posting';
|
||||
import { createFeesColumns } from '../../../utils/create-fees-columns';
|
||||
import { FlatDecision } from '../../../utils/get-flat-decisions';
|
||||
import { isThatCurrency } from '../../../utils/is-that-currency';
|
||||
|
||||
export function getWalletCashFlowSelectors(d: TermSetHierarchyObject) {
|
||||
@ -33,7 +31,7 @@ export function isThatWalletParty(predicate: Predicate, partyId: PartyID, wallet
|
||||
}
|
||||
|
||||
export function isWalletTermSetDecision(
|
||||
v: InlineDecision2,
|
||||
v: FlatDecision,
|
||||
params: { partyId: PartyID; walletId: WalletID; currency: string },
|
||||
) {
|
||||
return (
|
||||
@ -43,47 +41,6 @@ export function isWalletTermSetDecision(
|
||||
);
|
||||
}
|
||||
|
||||
export const WALLET_FEES_COLUMNS = [
|
||||
{
|
||||
field: 'condition',
|
||||
child: (d) => ({ value: formatLevelPredicate(d) }),
|
||||
},
|
||||
{
|
||||
field: 'feeShare',
|
||||
header: 'Fee, %',
|
||||
child: (d) => ({
|
||||
value: getCashVolumeParts(d.value.filter(isWalletFee).map((v) => v.volume))?.share,
|
||||
}),
|
||||
},
|
||||
{
|
||||
field: 'feeFixed',
|
||||
header: 'Fee, fix',
|
||||
child: (d) => ({
|
||||
value: getCashVolumeParts(d.value.filter(isWalletFee).map((v) => v.volume))?.fixed,
|
||||
}),
|
||||
},
|
||||
{
|
||||
field: 'feeMin',
|
||||
header: 'Fee, min',
|
||||
child: (d) => ({
|
||||
value: getCashVolumeParts(d.value.filter(isWalletFee).map((v) => v.volume))?.max,
|
||||
}),
|
||||
},
|
||||
{
|
||||
field: 'feeMax',
|
||||
header: 'Fee, max',
|
||||
child: (d) => ({
|
||||
value: getCashVolumeParts(d.value.filter(isWalletFee).map((v) => v.volume))?.min,
|
||||
}),
|
||||
},
|
||||
{
|
||||
field: 'other',
|
||||
child: (d) => ({
|
||||
value: formatCashVolumes(
|
||||
d.value
|
||||
.filter((v) => !isWalletFee(v) && !isOneHundredPercentCashFlowPosting(v))
|
||||
.map((v) => v.volume),
|
||||
),
|
||||
}),
|
||||
},
|
||||
] satisfies Column2<object, InlineDecision2>[];
|
||||
export const WALLET_FEES_COLUMNS = createFeesColumns({
|
||||
feeFilter: isWalletFee,
|
||||
});
|
||||
|
@ -42,7 +42,7 @@ import {
|
||||
} from '@cc/app/shared/utils/table2';
|
||||
import { DEBOUNCE_TIME_MS } from '@cc/app/tokens';
|
||||
|
||||
import { InlineDecision2, getInlineDecisions2 } from '../../utils/get-inline-decisions';
|
||||
import { FlatDecision, getFlatDecisions } from '../../utils/get-flat-decisions';
|
||||
import { WalletsTermSetHistoryCardComponent } from '../wallets-term-set-history-card';
|
||||
|
||||
import {
|
||||
@ -92,21 +92,20 @@ export class WalletsTermsComponent implements OnInit {
|
||||
map((terms) =>
|
||||
terms.map((t) => ({
|
||||
value: t,
|
||||
children: getInlineDecisions2(
|
||||
getWalletCashFlowSelectors(t.current_term_set),
|
||||
).filter((v) =>
|
||||
isWalletTermSetDecision(v, {
|
||||
partyId: t.owner_id,
|
||||
walletId: t.wallet_id,
|
||||
currency: t.currency,
|
||||
}),
|
||||
children: getFlatDecisions(getWalletCashFlowSelectors(t.current_term_set)).filter(
|
||||
(v) =>
|
||||
isWalletTermSetDecision(v, {
|
||||
partyId: t.owner_id,
|
||||
walletId: t.wallet_id,
|
||||
currency: t.currency,
|
||||
}),
|
||||
),
|
||||
})),
|
||||
),
|
||||
);
|
||||
hasMore$ = this.walletsTermsService.hasMore$;
|
||||
isLoading$ = this.walletsTermsService.isLoading$;
|
||||
columns: Column2<WalletTermSet, InlineDecision2>[] = [
|
||||
columns: Column2<WalletTermSet, FlatDecision>[] = [
|
||||
createWalletColumn((d) => ({ id: d.wallet_id, name: d.wallet_name, partyId: d.owner_id }), {
|
||||
sticky: 'start',
|
||||
}),
|
||||
|
85
src/app/sections/terms/utils/create-fees-columns.ts
Normal file
85
src/app/sections/terms/utils/create-fees-columns.ts
Normal file
@ -0,0 +1,85 @@
|
||||
import { CashFlowPosting } from '@vality/domain-proto/internal/domain';
|
||||
import { Column2 } from '@vality/ng-core';
|
||||
|
||||
import { getCashVolumeParts, formatCashVolumes } from '../../../shared';
|
||||
|
||||
import {
|
||||
formatLevelPredicate,
|
||||
formatCashFlowSourceDestination,
|
||||
FlatDecision,
|
||||
} from './get-flat-decisions';
|
||||
import { isOneHundredPercentCashFlowPosting } from './is-one-hundred-percent-cash-flow-posting';
|
||||
|
||||
export function createFeesColumns<T extends object>({
|
||||
selectFlatDecision = (d) => d as never,
|
||||
conditionLabel = 'Condition',
|
||||
feeFilter = () => true,
|
||||
otherFilter = () => true,
|
||||
}: {
|
||||
selectFlatDecision?: (d: T) => FlatDecision;
|
||||
conditionLabel?: string;
|
||||
feeFilter?: (v: CashFlowPosting) => boolean;
|
||||
otherFilter?: (v: CashFlowPosting) => boolean;
|
||||
} = {}): Column2<object, T>[] {
|
||||
function getFeeCashVolumeParts(d: T) {
|
||||
const decision = selectFlatDecision(d);
|
||||
return decision
|
||||
? getCashVolumeParts(decision.value.filter(feeFilter).map((v) => v.volume))
|
||||
: null;
|
||||
}
|
||||
return [
|
||||
{
|
||||
field: conditionLabel,
|
||||
header: conditionLabel,
|
||||
child: (d) => ({
|
||||
value: selectFlatDecision(d) ? formatLevelPredicate(selectFlatDecision(d)) : null,
|
||||
}),
|
||||
},
|
||||
{
|
||||
field: `${conditionLabel}_feeShare`,
|
||||
header: 'Fee, %',
|
||||
child: (d) => ({
|
||||
value: getFeeCashVolumeParts(d)?.share,
|
||||
}),
|
||||
},
|
||||
{
|
||||
field: `${conditionLabel}_feeFixed`,
|
||||
header: 'Fee, fix',
|
||||
child: (d) => ({
|
||||
value: getFeeCashVolumeParts(d)?.fixed,
|
||||
}),
|
||||
},
|
||||
{
|
||||
field: `${conditionLabel}_feeMin`,
|
||||
header: 'Fee, min',
|
||||
child: (d) => ({
|
||||
value: getFeeCashVolumeParts(d)?.max,
|
||||
}),
|
||||
},
|
||||
{
|
||||
field: `${conditionLabel}_feeMax`,
|
||||
header: 'Fee, max',
|
||||
child: (d) => ({
|
||||
value: getFeeCashVolumeParts(d)?.min,
|
||||
}),
|
||||
},
|
||||
{
|
||||
field: `${conditionLabel}_other`,
|
||||
header: 'Other',
|
||||
child: (d) => {
|
||||
const decision = selectFlatDecision(d);
|
||||
if (!decision) {
|
||||
return null;
|
||||
}
|
||||
const cashFlow = decision.value.filter(
|
||||
(v) =>
|
||||
otherFilter(v) && !feeFilter(v) && !isOneHundredPercentCashFlowPosting(v),
|
||||
);
|
||||
return {
|
||||
value: formatCashVolumes(cashFlow.map((v) => v.volume)),
|
||||
tooltip: formatCashFlowSourceDestination(cashFlow),
|
||||
};
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
101
src/app/sections/terms/utils/get-flat-decisions.ts
Normal file
101
src/app/sections/terms/utils/get-flat-decisions.ts
Normal file
@ -0,0 +1,101 @@
|
||||
import { CashFlow } from '@vality/domain-proto/internal/domain';
|
||||
import { getUnionKey } from '@vality/ng-thrift';
|
||||
|
||||
import type {
|
||||
CashFlowSelector,
|
||||
CashFlowAccount,
|
||||
Predicate,
|
||||
} from '@vality/dominator-proto/internal/proto/domain';
|
||||
|
||||
import { formatPredicate, compareCashVolumes } from '@cc/app/shared';
|
||||
|
||||
// TODO: use enums
|
||||
function formatCashFlowAccount(acc: CashFlowAccount) {
|
||||
return (
|
||||
getUnionKey(acc) +
|
||||
':' +
|
||||
(() => {
|
||||
switch (getUnionKey(acc)) {
|
||||
case 'system':
|
||||
return {
|
||||
0: 'settlement',
|
||||
1: 'subagent',
|
||||
}[acc.system];
|
||||
case 'merchant':
|
||||
return {
|
||||
0: 'settlement',
|
||||
1: 'guarantee',
|
||||
2: 'payout',
|
||||
}[acc.merchant];
|
||||
case 'wallet':
|
||||
return {
|
||||
0: 'sender_source',
|
||||
1: 'sender_settlement',
|
||||
2: 'receiver_settlement',
|
||||
3: 'receiver_destination',
|
||||
}[acc.wallet];
|
||||
case 'external':
|
||||
return {
|
||||
0: 'income',
|
||||
1: 'outcome',
|
||||
}[acc.external];
|
||||
case 'provider':
|
||||
return {
|
||||
0: 'settlement',
|
||||
}[acc.provider];
|
||||
}
|
||||
})()
|
||||
);
|
||||
}
|
||||
|
||||
export function formatLevelPredicate(v: { level: number; if?: Predicate }) {
|
||||
return `${'\xa0'.repeat(Math.max(v.level - 1, 0))}${v.level > 0 ? '↳' : ''} ${formatPredicate(
|
||||
v.if,
|
||||
)}`;
|
||||
}
|
||||
|
||||
export function formatCashFlowSourceDestination(value: CashFlow): string {
|
||||
return value
|
||||
.sort((a, b) => compareCashVolumes(a.volume, b.volume))
|
||||
.map(
|
||||
(v) =>
|
||||
`${formatCashFlowAccount(v.source)} → ${formatCashFlowAccount(v.destination)}` +
|
||||
(v.details ? ` (${v.details})` : ''),
|
||||
)
|
||||
.join(', ');
|
||||
}
|
||||
|
||||
export interface FlatDecision {
|
||||
value: CashFlow;
|
||||
level: number;
|
||||
if?: Predicate;
|
||||
}
|
||||
|
||||
export function getFlatDecisions(d: CashFlowSelector[], level = 0) {
|
||||
return d.reduce<FlatDecision[]>((acc, c) => {
|
||||
if (c.value) {
|
||||
acc.push({
|
||||
value: c.value.sort((a, b) => compareCashVolumes(a.volume, b.volume)),
|
||||
level,
|
||||
});
|
||||
}
|
||||
if (c.decisions?.length) {
|
||||
acc.push(
|
||||
...c.decisions.flatMap((d) => {
|
||||
const thenFlatDecisions = getFlatDecisions([d.then_], level + 1);
|
||||
if (d.if_) {
|
||||
const ifFlatDecision = {
|
||||
if: d.if_,
|
||||
level,
|
||||
};
|
||||
return thenFlatDecisions.length > 1
|
||||
? [{ ...ifFlatDecision, value: [] }, ...thenFlatDecisions]
|
||||
: [{ ...thenFlatDecisions[0], ...ifFlatDecision }];
|
||||
}
|
||||
return thenFlatDecisions;
|
||||
}),
|
||||
);
|
||||
}
|
||||
return acc;
|
||||
}, []);
|
||||
}
|
@ -1,156 +0,0 @@
|
||||
import { CashFlow } from '@vality/domain-proto/internal/domain';
|
||||
import { getUnionKey } from '@vality/ng-thrift';
|
||||
|
||||
import type {
|
||||
CashFlowPosting,
|
||||
CashFlowSelector,
|
||||
CashFlowAccount,
|
||||
Predicate,
|
||||
} from '@vality/dominator-proto/internal/proto/domain';
|
||||
|
||||
import {
|
||||
formatPredicate,
|
||||
formatCashVolumes,
|
||||
compareCashVolumes,
|
||||
getCashVolumeParts,
|
||||
CashVolumeParts,
|
||||
} from '@cc/app/shared';
|
||||
|
||||
export interface InlineCashFlowSelector {
|
||||
if?: Predicate;
|
||||
value?: string;
|
||||
parts?: CashVolumeParts;
|
||||
parent?: InlineCashFlowSelector;
|
||||
description?: string;
|
||||
level: number;
|
||||
}
|
||||
|
||||
// TODO: use enums
|
||||
function formatCashFlowAccount(acc: CashFlowAccount) {
|
||||
return (
|
||||
getUnionKey(acc) +
|
||||
':' +
|
||||
(() => {
|
||||
switch (getUnionKey(acc)) {
|
||||
case 'system':
|
||||
return {
|
||||
0: 'settlement',
|
||||
1: 'subagent',
|
||||
}[acc.system];
|
||||
case 'merchant':
|
||||
return {
|
||||
0: 'settlement',
|
||||
1: 'guarantee',
|
||||
2: 'payout',
|
||||
}[acc.merchant];
|
||||
case 'wallet':
|
||||
return {
|
||||
0: 'sender_source',
|
||||
1: 'sender_settlement',
|
||||
2: 'receiver_settlement',
|
||||
3: 'receiver_destination',
|
||||
}[acc.wallet];
|
||||
case 'external':
|
||||
return {
|
||||
0: 'income',
|
||||
1: 'outcome',
|
||||
}[acc.external];
|
||||
case 'provider':
|
||||
return {
|
||||
0: 'settlement',
|
||||
}[acc.provider];
|
||||
}
|
||||
})()
|
||||
);
|
||||
}
|
||||
|
||||
export function formatLevelPredicate(v: { level: number; if?: Predicate }) {
|
||||
return `${'\xa0'.repeat(Math.max(v.level - 1, 0))}${v.level > 0 ? '↳' : ''} ${formatPredicate(
|
||||
v.if,
|
||||
)}`;
|
||||
}
|
||||
|
||||
export function getInlineDecisions(
|
||||
d: CashFlowSelector[],
|
||||
filterValue: (v: CashFlowPosting) => boolean = Boolean,
|
||||
level = 0,
|
||||
): InlineCashFlowSelector[] {
|
||||
return d.reduce((acc, c) => {
|
||||
if (c.value) {
|
||||
const value = c.value.filter(filterValue);
|
||||
acc.push({
|
||||
value: formatCashVolumes(value.map((v) => v.volume)),
|
||||
parts: getCashVolumeParts(value.map((v) => v.volume)),
|
||||
level,
|
||||
description: value
|
||||
.sort((a, b) => compareCashVolumes(a.volume, b.volume))
|
||||
.map(
|
||||
(v) =>
|
||||
`${formatCashFlowAccount(v.source)} → ${formatCashFlowAccount(
|
||||
v.destination,
|
||||
)}` + (v.details ? ` (${v.details})` : ''),
|
||||
)
|
||||
.join(', '),
|
||||
});
|
||||
}
|
||||
if (c.decisions?.length) {
|
||||
acc.push(
|
||||
...c.decisions
|
||||
.map((d) => {
|
||||
const thenInlineDecisions = getInlineDecisions(
|
||||
[d.then_],
|
||||
filterValue,
|
||||
level + 1,
|
||||
);
|
||||
if (d.if_) {
|
||||
const ifInlineDecision = {
|
||||
if: d.if_,
|
||||
level,
|
||||
};
|
||||
return thenInlineDecisions.length > 1
|
||||
? [ifInlineDecision, ...thenInlineDecisions]
|
||||
: [{ ...thenInlineDecisions[0], ...ifInlineDecision }];
|
||||
}
|
||||
return thenInlineDecisions;
|
||||
})
|
||||
.flat(),
|
||||
);
|
||||
}
|
||||
return acc;
|
||||
}, [] as InlineCashFlowSelector[]);
|
||||
}
|
||||
|
||||
export interface InlineDecision2 {
|
||||
value: CashFlow;
|
||||
level: number;
|
||||
if?: Predicate;
|
||||
}
|
||||
|
||||
export function getInlineDecisions2(d: CashFlowSelector[], level = 0) {
|
||||
return d.reduce<InlineDecision2[]>((acc, c) => {
|
||||
if (c.value) {
|
||||
acc.push({
|
||||
value: c.value.sort((a, b) => compareCashVolumes(a.volume, b.volume)),
|
||||
level,
|
||||
});
|
||||
}
|
||||
if (c.decisions?.length) {
|
||||
acc.push(
|
||||
...c.decisions.flatMap((d) => {
|
||||
const thenInlineDecisions = getInlineDecisions2([d.then_], level + 1);
|
||||
if (d.if_) {
|
||||
const ifInlineDecision = {
|
||||
if: d.if_,
|
||||
level,
|
||||
};
|
||||
return thenInlineDecisions.length > 1
|
||||
? [{ ...ifInlineDecision, value: [] }, ...thenInlineDecisions]
|
||||
: [{ ...thenInlineDecisions[0], ...ifInlineDecision }];
|
||||
}
|
||||
return thenInlineDecisions;
|
||||
}),
|
||||
);
|
||||
}
|
||||
return acc;
|
||||
}, []);
|
||||
}
|
Loading…
Reference in New Issue
Block a user