Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 7 additions & 5 deletions src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import Keycloak from 'keycloak-js';
import { debounceTime, map, of, shareReplay, switchMap, tap } from 'rxjs';

import { CommonModule } from '@angular/common';
import { Component, DestroyRef, inject, signal } from '@angular/core';
import { Component, DestroyRef, inject, isDevMode, signal } from '@angular/core';
import { takeUntilDestroyed, toObservable } from '@angular/core/rxjs-interop';
import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon';
Expand Down Expand Up @@ -118,24 +118,26 @@ const createNavLinks = (): Link[] => [
url: `${partyPath}/wallet-webhooks`,
},
{
label: 'Payment RR (old)',
label: 'Payment RR',
url: `${partyPath}/routing-rules/payment/main`,
checkUrl: `${partyPath}/routing-rules/payment`,
},
{
label: 'Withdrawal RR (old)',
label: 'Withdrawal RR',
url: `${partyPath}/routing-rules/withdrawal/main`,
checkUrl: `${partyPath}/routing-rules/withdrawal`,
},
{
label: 'Payment RR',
label: 'Payment RR (in dev)',
url: `${partyPath}/rr/payment/main`,
checkUrl: `${partyPath}/rr/payment`,
isHidden: !isDevMode,
},
{
label: 'Withdrawal RR',
label: 'Withdrawal RR (in dev)',
url: `${partyPath}/rr/withdrawal/main`,
checkUrl: `${partyPath}/rr/withdrawal`,
isHidden: !isDevMode,
},
]
: [],
Expand Down
15 changes: 9 additions & 6 deletions src/app/parties/party/party-store.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { EMPTY, of } from 'rxjs';
import {
catchError,
distinctUntilChanged,
map,
shareReplay,
startWith,
switchMap,
Expand All @@ -19,9 +20,15 @@ export class PartyStoreService {
private route = inject(ActivatedRoute);
private partiesStoreService = inject(PartiesStoreService);
private log = inject(NotifyLogService);
party$ = this.route.params.pipe(

id$ = this.route.params.pipe(
startWith(this.route.snapshot.params),
switchMap(({ partyID }) =>
map(({ partyID }) => partyID),
distinctUntilChanged(),
shareReplay({ refCount: true, bufferSize: 1 }),
);
party$ = this.id$.pipe(
switchMap((partyID) =>
partyID
? this.partiesStoreService.getParty(partyID).value$.pipe(
catchError((err) => {
Expand All @@ -34,8 +41,4 @@ export class PartyStoreService {
distinctUntilChanged(),
shareReplay({ refCount: true, bufferSize: 1 }),
);

private get partyId() {
return this.route.snapshot.params['partyID'] as string;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ export class PartyRoutingRulesetComponent {
refID,
shops: shops
.filter((s) =>
ruleset.data.decisions.delegates.every(
(ruleset.data.decisions.delegates || []).every(
(d) =>
d?.allowed?.condition?.party?.definition?.shop_is !==
s.ref.id,
Expand All @@ -217,7 +217,7 @@ export class PartyRoutingRulesetComponent {
.sort((a, b) => compareDifferentTypes(a.data.name, b.data.name)),
wallets: wallets
.filter((w) =>
ruleset.data.decisions.delegates.every(
(ruleset.data.decisions.delegates || []).every(
(d) =>
d?.allowed?.condition?.party?.definition?.wallet_is !==
w.ref.id,
Expand Down
7 changes: 2 additions & 5 deletions src/app/wallets/wallets.component.html
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
<cc-page-layout fullHeight title="Wallets">
<v-table
[columns]="columns"
[data]="wallets$ | async"
[progress]="isLoading$ | async"
externalFilter
[data]="wallets.value()"
[progress]="wallets.isLoading()"
name="ftsWallets"
standaloneFilter
(filterChange)="search($event)"
(more)="more()"
(update)="reload($event)"
></v-table>
</cc-page-layout>
43 changes: 17 additions & 26 deletions src/app/wallets/wallets.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,17 @@ import { map, shareReplay } from 'rxjs/operators';
import { MemoizeExpiring } from 'typescript-memoize';

import { CommonModule } from '@angular/common';
import { Component, OnInit, inject } from '@angular/core';
import { Component, inject } from '@angular/core';
import { ReactiveFormsModule } from '@angular/forms';
import { MatButtonModule } from '@angular/material/button';
import { MatCardModule } from '@angular/material/card';
import { MatIconModule } from '@angular/material/icon';
import { MatInputModule } from '@angular/material/input';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';

import { DomainObjectType } from '@vality/domain-proto/domain';
import { VersionedObject } from '@vality/domain-proto/domain_config_v2';
import {
Column,
DebounceTime,
FiltersModule,
ListFieldModule,
SwitchButtonModule,
Expand All @@ -24,7 +22,7 @@ import {
} from '@vality/matez';
import { ThriftFormModule, getUnionKey } from '@vality/ng-thrift';

import { FetchFullDomainObjectsService } from '~/api/domain-config';
import { DomainObjectsStoreService, FetchFullDomainObjectsService } from '~/api/domain-config';
import { ThriftPartyManagementService } from '~/api/services';
import { MerchantFieldModule } from '~/components/merchant-field';
import { PageLayoutModule } from '~/components/page-layout';
Expand Down Expand Up @@ -53,13 +51,22 @@ import { PartyStoreService } from '../parties/party';
SwitchButtonModule,
],
})
export class WalletsComponent implements OnInit {
private fetchFullDomainObjectsService = inject(FetchFullDomainObjectsService);
export class WalletsComponent {
private domainObjectsStoreService = inject(DomainObjectsStoreService);
private partyStoreService = inject(PartyStoreService);
private partyManagementService = inject(ThriftPartyManagementService);

wallets$ = this.fetchFullDomainObjectsService.result$;
isLoading$ = this.fetchFullDomainObjectsService.isLoading$;
wallets = this.domainObjectsStoreService
.getObjects('wallet_config')
.map((wallets) =>
this.partyStoreService.id$.pipe(
map((id) =>
id
? wallets.filter((w) => w.object.wallet_config.data.party_ref.id === id)
: wallets,
),
),
);

columns: Column<VersionedObject>[] = [
{ field: 'id', cell: (d) => ({ value: d.object.wallet_config.ref.id }) },
Expand Down Expand Up @@ -128,24 +135,8 @@ export class WalletsComponent implements OnInit {
];
party$ = this.partyStoreService.party$;

ngOnInit() {
this.fetchFullDomainObjectsService.load({
type: DomainObjectType.wallet_config,
query: '',
});
}

@DebounceTime()
search(query: string) {
this.fetchFullDomainObjectsService.load({ query, type: DomainObjectType.wallet_config });
}

reload(options: UpdateOptions) {
this.fetchFullDomainObjectsService.reload(options);
}

more() {
this.fetchFullDomainObjectsService.more();
reload(_options: UpdateOptions) {
this.wallets.reload();
}

@MemoizeExpiring(5 * 60_000)
Expand Down
149 changes: 89 additions & 60 deletions src/components/shops-table/shops-table.component.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { isNil } from 'lodash-es';
import startCase from 'lodash-es/startCase';
import { combineLatest, map, of, switchMap } from 'rxjs';
import { filter, shareReplay, startWith } from 'rxjs/operators';
Expand All @@ -18,7 +17,8 @@ import { toObservable } from '@angular/core/rxjs-interop';
import { MatCardModule } from '@angular/material/card';
import { Router } from '@angular/router';

import { RoutingRulesetRef, ShopConfigObject } from '@vality/domain-proto/domain';
import { ShopConfigObject } from '@vality/domain-proto/domain';
import { VersionedObject } from '@vality/domain-proto/domain_config_v2';
import {
Column,
ConfirmDialogComponent,
Expand Down Expand Up @@ -173,21 +173,97 @@ export class ShopsTableComponent {
),
createMenuColumn((d) =>
this.getDelegatesByParty().pipe(
map((delegatesByParty) => ({
items: [
...delegatesByParty.rulesetIds.map((id) => {
const rulesetId =
map((delegatesByParty) =>
delegatesByParty.rulesetIds
.map(
(id) =>
delegatesByParty.delegatesWithPaymentInstitutionByParty
?.get?.(d.data.party_ref.id)
?.find?.((v) => v?.partyDelegate?.ruleset?.id === id)
?.partyDelegate?.ruleset?.id;
return {
label: `Routing rules #${id}`,
?.partyDelegate?.ruleset,
)
.filter(Boolean),
),
switchMap((rulesets) =>
rulesets?.length
? combineLatest(
rulesets.map(
(ruleset) =>
this.domainStoreService.getObject({
routing_rules: { id: ruleset.id },
}).value$,
),
)
: of([] as VersionedObject[]),
),
map((rulesetObjects) => {
const partyId = d.data.party_ref.id;
const shopId = d.ref.id;
const delegates = rulesetObjects.map(
(ruleset) =>
ruleset?.object?.routing_rules?.data?.decisions?.delegates?.filter?.(
(delegate) =>
delegate?.allowed?.condition?.party?.party_ref?.id ===
partyId &&
delegate?.allowed?.condition?.party?.definition?.shop_is ===
shopId,
) || [],
);
const noShopRuleset = {
label: 'No routing rule',
disabled: true,
};
if (rulesetObjects.length === 0) {
return [
{
label: 'No party RR',
disabled: true,
},
noShopRuleset,
];
}
return rulesetObjects.flatMap((ruleset, idx) => {
const rr = ruleset.object.routing_rules;
return [
{
label:
'Party RR' +
(rulesetObjects.length > 1 ? ` #${rr.ref.id}` : ''),
click: () =>
this.openRoutingRules(rulesetId, d.ref.id, d.data.party_ref.id),
disabled: isNil(rulesetId),
};
}),
this.router.navigate([
'/parties',
partyId,
'routing-rules',
'payment',
]),
},
...(delegates[idx].length
? delegates[idx].map((delegate) => ({
label:
'Routing rule' +
(delegates.length > 1 ? ` #${delegate.ruleset.id}` : ''),
click: () =>
this.router.navigate([
'/parties',
partyId,
'routing-rules',
'payment',
delegate.ruleset.id,
]),
}))
: [noShopRuleset]),
];
});
}),
startWith([
{
label: 'Routing rule loading...',
disabled: true,
},
]),
map((rrItems) => ({
items: [
...rrItems,
{
label:
getUnionKey(d.data.suspension) === 'suspended'
Expand Down Expand Up @@ -263,55 +339,8 @@ export class ShopsTableComponent {
});
}

private openRoutingRules(
partyDelegateRulesetId: RoutingRulesetRef['id'],
shopId: string,
partyId: string,
) {
this.domainStoreService
.getObject({ routing_rules: { id: partyDelegateRulesetId } })
.getFirstValue()
.subscribe((ruleset) => {
const delegates =
ruleset?.object?.routing_rules?.data?.decisions?.delegates?.filter?.(
(delegate) =>
delegate?.allowed?.condition?.party?.party_ref?.id === partyId &&
delegate?.allowed?.condition?.party?.definition?.shop_is === shopId,
) || [];
const paymentRulesCommands = [
'/parties',
partyId,
'routing-rules',
'payment',
partyDelegateRulesetId,
];
if (delegates.length === 1) {
void this.router.navigate([
...paymentRulesCommands,
'delegate',
delegates[0].ruleset.id,
]);
return;
}
this.log.success(
delegates.length === 0
? 'No routing rules'
: `${delegates.length} routing rules`,
);
void this.router.navigate(paymentRulesCommands, {
queryParams: {
routingRulesList: JSON.stringify({
filter: shopId,
exact: true,
}),
},
});
});
}

private getDelegatesByParty() {
return toObservable(this.shops, { injector: this.injector }).pipe(
startWith(null),
map((shops) =>
shops?.length ? Array.from(new Set(shops.map((s) => s.data.party_ref.id))) : [],
),
Expand Down
Loading