diff --git a/projects/matez/src/lib/components/table/table-resource.component.ts b/projects/matez/src/lib/components/table/table-resource.component.ts index ea336a59b..8f5f92ba5 100644 --- a/projects/matez/src/lib/components/table/table-resource.component.ts +++ b/projects/matez/src/lib/components/table/table-resource.component.ts @@ -27,7 +27,9 @@ import { TableModule } from './table.module'; imports: [TableModule], }) export class TableResourceComponent { - resource = input | ObservableResource>(); + resource = input< + PagedObservableResource | ObservableResource + >(); columns = input[]>([]); filter = model(''); externalFilter = input(false, { transform: booleanAttribute }); diff --git a/src/app/domain-config/domain-objects-table/domain-objects-table.component.ts b/src/app/domain-config/domain-objects-table/domain-objects-table.component.ts index ff5614521..1e472e02a 100644 --- a/src/app/domain-config/domain-objects-table/domain-objects-table.component.ts +++ b/src/app/domain-config/domain-objects-table/domain-objects-table.component.ts @@ -3,6 +3,7 @@ import startCase from 'lodash-es/startCase'; import { CommonModule } from '@angular/common'; import { Component, + Injector, TemplateRef, booleanAttribute, computed, @@ -10,6 +11,7 @@ import { input, model, output, + runInInjectionContext, } from '@angular/core'; import { ReactiveFormsModule } from '@angular/forms'; import { MatButtonModule } from '@angular/material/button'; @@ -20,6 +22,7 @@ import { ActionsModule, Column, DialogResponseStatus, + MenuItem, PagedObservableResource, SelectFieldModule, TableModule, @@ -51,52 +54,14 @@ import { export class DomainObjectsTableComponent { private sidenavInfoService = inject(SidenavInfoService); private domainObjectService = inject(DomainObjectService); + private injector = inject(Injector); selectedTypeChange = output(); resource = input>(); filter = model(''); tableInputsContent = input>(); externalFilter = input(false, { transform: booleanAttribute }); - menu = input>( - createMenuColumn((d) => ({ - items: [ - { - label: 'Details', - click: () => { - this.sidenavInfoService.toggle(DomainObjectCardComponent, { - ref: d.ref, - version: d.info.version, - }); - }, - }, - { - label: 'History', - click: () => { - this.domainObjectService.history(d.ref); - }, - }, - { - label: 'Edit', - click: () => { - this.domainObjectService.edit(d.ref).next((res) => { - if (res.status === DialogResponseStatus.Success) { - this.resource().reload(); - } - }); - }, - }, - { - label: 'Delete', - click: () => { - this.domainObjectService.delete(d.ref).next(() => { - this.resource().reload(); - }); - }, - }, - ], - })), - ); - + menu = input<(d: LimitedVersionedObject) => MenuItem[]>(); columns = computed[]>(() => [ { field: 'id', cell: (d) => ({ value: getReferenceId(d.ref) }) }, { @@ -126,6 +91,46 @@ export class DomainObjectsTableComponent { description: d.info.changed_by?.email, }), }, - this.menu(), + runInInjectionContext(this.injector, () => + createMenuColumn((d) => ({ + items: this.menu() + ? this.menu()(d) + : [ + { + label: 'Details', + click: () => { + this.sidenavInfoService.toggle(DomainObjectCardComponent, { + ref: d.ref, + version: d.info.version, + }); + }, + }, + { + label: 'History', + click: () => { + this.domainObjectService.history(d.ref); + }, + }, + { + label: 'Edit', + click: () => { + this.domainObjectService.edit(d.ref).next((res) => { + if (res.status === DialogResponseStatus.Success) { + this.resource().reload(); + } + }); + }, + }, + { + label: 'Delete', + click: () => { + this.domainObjectService.delete(d.ref).next(() => { + this.resource().reload(); + }); + }, + }, + ], + })), + ), ]); } diff --git a/src/app/wallets/wallets.component.html b/src/app/wallets/wallets.component.html index e71d7ad83..c355dd1bf 100644 --- a/src/app/wallets/wallets.component.html +++ b/src/app/wallets/wallets.component.html @@ -1,10 +1,3 @@ - + diff --git a/src/app/wallets/wallets.component.ts b/src/app/wallets/wallets.component.ts index 66f69b236..8e39da50d 100644 --- a/src/app/wallets/wallets.component.ts +++ b/src/app/wallets/wallets.component.ts @@ -1,73 +1,22 @@ -import { startCase } from 'lodash-es'; -import { filter, map, shareReplay, switchMap } from 'rxjs/operators'; -import { MemoizeExpiring } from 'typescript-memoize'; +import { map } from 'rxjs/operators'; -import { CommonModule } from '@angular/common'; -import { Component, Injector, inject, runInInjectionContext } 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 { Component, inject } from '@angular/core'; -import { VersionedObject } from '@vality/domain-proto/domain_config_v2'; -import { - Column, - ConfirmDialogComponent, - DialogResponseStatus, - DialogService, - FiltersModule, - ListFieldModule, - NotifyLogService, - SwitchButtonModule, - TableModule, - UpdateOptions, - createMenuColumn, -} from '@vality/matez'; -import { ThriftFormModule, getUnionKey } from '@vality/ng-thrift'; - -import { DomainObjectsStoreService, FetchFullDomainObjectsService } from '~/api/domain-config'; -import { PartiesStoreService } from '~/api/payment-processing'; -import { ThriftPartyManagementService } from '~/api/services'; -import { MerchantFieldModule } from '~/components/merchant-field'; +import { DomainObjectsStoreService } from '~/api/domain-config'; import { PageLayoutModule } from '~/components/page-layout'; -import { getDelegatesByPartyItem } from '~/components/shops-table/utils/get-rr-by-party-item'; -import { createCurrencyColumn, createDomainObjectColumn, createPartyColumn } from '~/utils'; +import { WalletsTableComponent } from '~/components/wallets-table'; import { PartyStoreService } from '../parties/party'; -import { PartyDelegateRulesetsService } from '../parties/party/routing-rules/party-delegate-rulesets'; -import { RoutingRulesType } from '../parties/party/routing-rules/types/routing-rules-type'; @Component({ selector: 'cc-wallets', templateUrl: './wallets.component.html', - providers: [PartyStoreService, FetchFullDomainObjectsService, PartyDelegateRulesetsService], - imports: [ - CommonModule, - MatCardModule, - TableModule, - MatProgressSpinnerModule, - ThriftFormModule, - ReactiveFormsModule, - MatInputModule, - MerchantFieldModule, - MatButtonModule, - MatIconModule, - PageLayoutModule, - ListFieldModule, - FiltersModule, - SwitchButtonModule, - ], + providers: [PartyStoreService], + imports: [PageLayoutModule, WalletsTableComponent], }) export class WalletsComponent { private domainObjectsStoreService = inject(DomainObjectsStoreService); private partyStoreService = inject(PartyStoreService); - private partyManagementService = inject(ThriftPartyManagementService); - private injector = inject(Injector); - private log = inject(NotifyLogService); - private dialogService = inject(DialogService); - private partiesStoreService = inject(PartiesStoreService); wallets = this.domainObjectsStoreService .getObjects('wallet_config') @@ -80,185 +29,4 @@ export class WalletsComponent { ), ), ); - - columns: Column[] = [ - { field: 'id', cell: (d) => ({ value: d.object.wallet_config.ref.id }) }, - { field: 'name', cell: (d) => ({ value: d.object.wallet_config.data.name }) }, - createPartyColumn((d) => ({ id: d.object.wallet_config.data.party_ref.id })), - { - field: 'blocking', - cell: (d) => ({ - value: startCase(getUnionKey(d.object.wallet_config.data.block)), - color: ( - { - blocked: 'warn', - unblocked: 'success', - } as const - )[getUnionKey(d.object.wallet_config.data.block)], - }), - }, - { - field: 'suspension', - cell: (d) => ({ - value: startCase(getUnionKey(d.object.wallet_config.data.suspension)), - color: ( - { - suspended: 'warn', - active: 'success', - } as const - )[getUnionKey(d.object.wallet_config.data.suspension)], - }), - }, - createDomainObjectColumn( - (d) => ({ - ref: { payment_institution: d.object.wallet_config.data.payment_institution }, - }), - { field: 'payment_institution' }, - ), - createDomainObjectColumn( - (d) => ({ - ref: { term_set_hierarchy: d.object.wallet_config.data.terms }, - }), - { field: 'terms' }, - ), - createCurrencyColumn( - (d) => - this.getAccountState(d).pipe( - map((b) => ({ amount: b.own_amount, code: b.currency.symbolic_code })), - ), - { header: 'Own', isLazyCell: true }, - ), - createCurrencyColumn( - (d) => - this.getAccountState(d).pipe( - map((b) => ({ - amount: b.own_amount - b.available_amount, - code: b.currency.symbolic_code, - })), - ), - { header: 'Hold', isLazyCell: true }, - ), - createCurrencyColumn( - (d) => - this.getAccountState(d).pipe( - map((b) => ({ amount: b.available_amount, code: b.currency.symbolic_code })), - ), - { header: 'Available', isLazyCell: true }, - ), - createMenuColumn((d) => - this.wallets.value$.pipe( - switchMap((wallets) => - runInInjectionContext(this.injector, () => - getDelegatesByPartyItem( - wallets?.length - ? wallets.map((w) => w.object.wallet_config.data.party_ref.id) - : [], - RoutingRulesType.Withdrawal, - d.object.wallet_config.data.party_ref.id, - d.object.wallet_config.ref.id, - ), - ), - ), - map((rr) => ({ - items: [ - ...rr.partyRr, - ...rr.itemRr, - { - label: - getUnionKey(d.object.wallet_config.data.suspension) === 'suspended' - ? 'Activate' - : 'Suspend', - click: () => { - this.toggleSuspension(d); - }, - }, - { - label: - getUnionKey(d.object.wallet_config.data.block) === 'blocked' - ? 'Unblock' - : 'Block', - click: () => { - this.toggleBlocking(d); - }, - }, - ], - })), - ), - ), - ]; - party$ = this.partyStoreService.party$; - - reload(_options: UpdateOptions) { - this.wallets.reload(); - } - - @MemoizeExpiring(5 * 60_000) - getAccountState(wallet: VersionedObject) { - return this.partyManagementService - .GetAccountState( - wallet.object.wallet_config.data.party_ref, - wallet.object.wallet_config.data.account.settlement, - wallet.info.version, - ) - .pipe(shareReplay({ refCount: true, bufferSize: 1 })); - } - - toggleBlocking(obj: VersionedObject) { - const wallet = obj.object.wallet_config; - this.dialogService - .open(ConfirmDialogComponent, { - title: - getUnionKey(wallet.data.block) === 'unblocked' - ? 'Block wallet' - : 'Unblock wallet', - hasReason: true, - }) - .afterClosed() - .pipe( - filter((r) => r.status === DialogResponseStatus.Success), - switchMap((r) => - getUnionKey(wallet.data.block) === 'unblocked' - ? this.partiesStoreService.blockWallet(wallet, r.data.reason) - : this.partiesStoreService.unblockWallet(wallet, r.data.reason), - ), - ) - .subscribe({ - next: () => { - this.wallets.reload(); - this.log.success(); - }, - error: (err) => { - this.log.error(err); - }, - }); - } - - toggleSuspension(obj: VersionedObject) { - const wallet = obj.object.wallet_config; - this.dialogService - .open(ConfirmDialogComponent, { - title: - getUnionKey(wallet.data.suspension) === 'active' - ? 'Suspend wallet' - : 'Activate wallet', - }) - .afterClosed() - .pipe( - filter((r) => r.status === DialogResponseStatus.Success), - switchMap(() => - getUnionKey(wallet.data.suspension) === 'active' - ? this.partiesStoreService.suspendWallet(wallet) - : this.partiesStoreService.activateWallet(wallet), - ), - ) - .subscribe({ - next: () => { - this.wallets.reload(); - this.log.success(); - }, - error: (err) => { - this.log.error(err); - }, - }); - } } diff --git a/src/components/create-invoice-template-dialog/create-invoice-template-dialog.component.ts b/src/components/create-invoice-template-dialog/create-invoice-template-dialog.component.ts index ea4cf57ac..1963b7913 100644 --- a/src/components/create-invoice-template-dialog/create-invoice-template-dialog.component.ts +++ b/src/components/create-invoice-template-dialog/create-invoice-template-dialog.component.ts @@ -85,7 +85,7 @@ export class CreateInvoiceTemplateDialogComponent extends DialogSuperclass( - { context: { type: '', data: '' } } as InvoiceTemplateCreateParams, + { context: { type: 'application/json', data: '{}' } } as InvoiceTemplateCreateParams, { nonNullable: true }, ); progress = signal(0); @@ -96,7 +96,7 @@ export class CreateInvoiceTemplateDialogComponent extends DialogSuperclass { const url = new URL( - `http${(config.checkout.https ?? true) ? 's' : ''}://${config.checkout.hostname}${config.checkout.path ?? '/v1/checkout'}`, + `http${(config.checkout.https ?? true) ? 's' : ''}://${config.checkout.hostname}${config.checkout.path ?? '/v1/checkout.html'}`, ); url.searchParams.set('invoiceTemplateID', template.invoice_template.id); url.searchParams.set( diff --git a/src/components/shops-table/shops-table.component.ts b/src/components/shops-table/shops-table.component.ts index b62afabbb..bbcab1ae9 100644 --- a/src/components/shops-table/shops-table.component.ts +++ b/src/components/shops-table/shops-table.component.ts @@ -1,6 +1,6 @@ import startCase from 'lodash-es/startCase'; import { map, switchMap } from 'rxjs'; -import { filter, shareReplay } from 'rxjs/operators'; +import { combineLatestWith, filter, shareReplay } from 'rxjs/operators'; import { MemoizeExpiring } from 'typescript-memoize'; import { @@ -15,15 +15,15 @@ import { runInInjectionContext, } from '@angular/core'; import { toObservable } from '@angular/core/rxjs-interop'; -import { MatCardModule } from '@angular/material/card'; import { ShopConfigObject } from '@vality/domain-proto/domain'; +import { LimitedVersionedObject } from '@vality/domain-proto/domain_config_v2'; import { Column, ConfirmDialogComponent, DialogResponseStatus, DialogService, - InputFieldModule, + MenuItem, NotifyLogService, TableModule, UpdateOptions, @@ -44,7 +44,7 @@ import { getDelegatesByPartyItem } from './utils/get-rr-by-party-item'; @Component({ selector: 'cc-shops-table', - imports: [InputFieldModule, MatCardModule, TableModule], + imports: [TableModule], templateUrl: './shops-table.component.html', providers: [PartyDelegateRulesetsService], }) @@ -63,6 +63,7 @@ export class ShopsTableComponent { @Output() filterChange = new EventEmitter(); @Output() more = new EventEmitter(); + extendMenu = input<(d: LimitedVersionedObject) => MenuItem[]>(); noPartyColumn = input(false, { transform: booleanAttribute }); columns: Column[] = [ @@ -167,6 +168,15 @@ export class ShopsTableComponent { ), { header: 'Guarantee Available', isLazyCell: true }, ), + { field: 'version', cell: (d) => ({ value: d.info.version }) }, + { field: 'changed_at', cell: (d) => ({ value: d.info.changed_at, type: 'datetime' }) }, + { + field: 'changed_by', + cell: (d) => ({ + value: d.info.changed_by?.name, + description: d.info.changed_by?.email, + }), + }, createMenuColumn((d) => toObservable(this.shops, { injector: this.injector }).pipe( switchMap((shops) => @@ -200,6 +210,21 @@ export class ShopsTableComponent { }, ], })), + combineLatestWith(toObservable(this.extendMenu, { injector: this.injector })), + map(([menu, extendMenu]) => ({ + ...menu, + items: extendMenu + ? [ + ...menu.items, + ...extendMenu({ + name: d.data.name, + description: d.data.description, + ref: { shop_config: d.ref }, + info: d.info, + }), + ] + : menu.items, + })), ), ), ]; diff --git a/src/components/thrift-api-crud/domain/domain-object-history-card/domain-object-history-card.component.html b/src/components/thrift-api-crud/domain/domain-object-history-card/domain-object-history-card.component.html index 2b125c078..f763fe89a 100644 --- a/src/components/thrift-api-crud/domain/domain-object-history-card/domain-object-history-card.component.html +++ b/src/components/thrift-api-crud/domain/domain-object-history-card/domain-object-history-card.component.html @@ -4,5 +4,21 @@ - + @switch (ref() | ngtUnionKey) { + @case ('shop_config') { + + } + @case ('wallet_config') { + + } + @default { + + } + } diff --git a/src/components/thrift-api-crud/domain/domain-object-history-card/domain-object-history-card.component.ts b/src/components/thrift-api-crud/domain/domain-object-history-card/domain-object-history-card.component.ts index 133bee5e4..63f533859 100644 --- a/src/components/thrift-api-crud/domain/domain-object-history-card/domain-object-history-card.component.ts +++ b/src/components/thrift-api-crud/domain/domain-object-history-card/domain-object-history-card.component.ts @@ -1,14 +1,18 @@ -import { first, map } from 'rxjs'; +import { combineLatest, first, map } from 'rxjs'; import { Component, computed, inject, input } from '@angular/core'; import { MatButtonModule } from '@angular/material/button'; import { Reference } from '@vality/domain-proto/domain'; import { LimitedVersionedObject } from '@vality/domain-proto/domain_config_v2'; -import { DialogResponseStatus, createMenuColumn, pagedObservableResource } from '@vality/matez'; +import { DialogResponseStatus, pagedObservableResource } from '@vality/matez'; import { ThriftPipesModule, getUnionValue } from '@vality/ng-thrift'; import { DomainService } from '~/api/domain-config'; +import { ShopWithInfo } from '~/api/payment-processing'; +import { ThriftRepositoryClientService } from '~/api/services'; +import { ShopsTableComponent } from '~/components/shops-table'; +import { WalletsTableComponent } from '~/components/wallets-table'; import { DomainObjectsTableComponent } from '../../../../app/domain-config/domain-objects-table'; import { SidenavInfoModule, SidenavInfoService } from '../../../sidenav-info'; @@ -23,6 +27,8 @@ import { DomainObjectService } from '../services/domain-object.service'; MatButtonModule, ThriftPipesModule, DomainObjectsTableComponent, + ShopsTableComponent, + WalletsTableComponent, ], templateUrl: './domain-object-history-card.component.html', }) @@ -30,6 +36,7 @@ export class DomainObjectHistoryCardComponent { private domainService = inject(DomainService); private domainObjectService = inject(DomainObjectService); private sidenavInfoService = inject(SidenavInfoService); + private repositoryClientService = inject(ThriftRepositoryClientService); ref = input(); @@ -48,31 +55,40 @@ export class DomainObjectHistoryCardComponent { })), ), }); + fullObjectsResource = this.resource.map((objs) => + combineLatest( + objs.map((obj) => + this.repositoryClientService.CheckoutObject({ version: obj.info.version }, obj.ref), + ), + ), + ); + shopsResource = this.fullObjectsResource.map((objs) => + objs.map((r): ShopWithInfo => ({ ...r.object.shop_config, info: r.info })), + ); + version = computed(() => Math.max(0, ...(this.resource.value() || []).map((r) => r.info.version)), ); - menuColumn = createMenuColumn((d) => ({ - items: [ - { - label: 'Revert to this version', - disabled: d.info.version === this.version(), - click: () => { - this.domainService - .get(d.ref, d.info.version) - .pipe(first()) - .subscribe((obj) => { - this.domainObjectService - .edit(d.ref, getUnionValue(obj.object).data) - .next((res) => { - if (res.status === DialogResponseStatus.Success) { - this.resource.reload(); - } - }); - }); - }, + menuColumn = (d: LimitedVersionedObject) => [ + { + label: 'Revert to this version', + disabled: d.info.version === this.version(), + click: () => { + this.domainService + .get(d.ref, d.info.version) + .pipe(first()) + .subscribe((obj) => { + this.domainObjectService + .edit(d.ref, getUnionValue(obj.object).data) + .next((res) => { + if (res.status === DialogResponseStatus.Success) { + this.resource.reload(); + } + }); + }); }, - ], - })); + }, + ]; latest() { this.domainObjectService.view(this.ref()); diff --git a/src/components/thrift-api-crud/domain/services/domain-metadata-form-extensions/domain-metadata-form-extensions.service.ts b/src/components/thrift-api-crud/domain/services/domain-metadata-form-extensions/domain-metadata-form-extensions.service.ts index b599c5178..46ee806b6 100644 --- a/src/components/thrift-api-crud/domain/services/domain-metadata-form-extensions/domain-metadata-form-extensions.service.ts +++ b/src/components/thrift-api-crud/domain/services/domain-metadata-form-extensions/domain-metadata-form-extensions.service.ts @@ -97,10 +97,6 @@ export class DomainMetadataFormExtensionsService { generate: () => of('authorization_failed:unknown'), }), }, - { - determinant: (data) => of(isTypeWithAliases(data, 'InvoiceContext', 'domain')), - extension: () => of({ hidden: true }), - }, ]), shareReplay({ refCount: true, bufferSize: 1 }), ); diff --git a/src/components/wallets-table/index.ts b/src/components/wallets-table/index.ts new file mode 100644 index 000000000..5afc22d57 --- /dev/null +++ b/src/components/wallets-table/index.ts @@ -0,0 +1 @@ +export * from './wallets-table.component'; diff --git a/src/components/wallets-table/wallets-table.component.html b/src/components/wallets-table/wallets-table.component.html new file mode 100644 index 000000000..671ddd7ae --- /dev/null +++ b/src/components/wallets-table/wallets-table.component.html @@ -0,0 +1 @@ + diff --git a/src/components/wallets-table/wallets-table.component.ts b/src/components/wallets-table/wallets-table.component.ts new file mode 100644 index 000000000..9b3bd0fed --- /dev/null +++ b/src/components/wallets-table/wallets-table.component.ts @@ -0,0 +1,257 @@ +import { startCase } from 'lodash-es'; +import { combineLatestWith, filter, map, shareReplay, switchMap } from 'rxjs/operators'; +import { MemoizeExpiring } from 'typescript-memoize'; + +import { Component, Injector, inject, input, runInInjectionContext } from '@angular/core'; +import { toObservable } from '@angular/core/rxjs-interop'; + +import { LimitedVersionedObject, VersionedObject } from '@vality/domain-proto/domain_config_v2'; +import { + Column, + ConfirmDialogComponent, + DialogResponseStatus, + DialogService, + MenuItem, + NotifyLogService, + ObservableResource, + TableResourceComponent, + createMenuColumn, +} from '@vality/matez'; +import { getUnionKey } from '@vality/ng-thrift'; + +import { PartiesStoreService } from '~/api/payment-processing'; +import { ThriftPartyManagementService } from '~/api/services'; +import { getDelegatesByPartyItem } from '~/components/shops-table/utils/get-rr-by-party-item'; +import { SidenavInfoService } from '~/components/sidenav-info'; +import { DomainObjectCardComponent } from '~/components/thrift-api-crud'; +import { createCurrencyColumn, createDomainObjectColumn, createPartyColumn } from '~/utils'; + +import { PartyDelegateRulesetsService } from '../../app/parties/party/routing-rules/party-delegate-rulesets'; +import { RoutingRulesType } from '../../app/parties/party/routing-rules/types/routing-rules-type'; + +@Component({ + selector: 'cc-wallets-table', + templateUrl: './wallets-table.component.html', + imports: [TableResourceComponent], + providers: [PartyDelegateRulesetsService], +}) +export class WalletsTableComponent { + private partyManagementService = inject(ThriftPartyManagementService); + private injector = inject(Injector); + private log = inject(NotifyLogService); + private dialogService = inject(DialogService); + private partiesStoreService = inject(PartiesStoreService); + private sidenavInfoService = inject(SidenavInfoService); + + resource = input>(); + extendMenu = input<(d: LimitedVersionedObject) => MenuItem[]>(() => []); + + columns: Column[] = [ + { field: 'id', cell: (d) => ({ value: d.object.wallet_config.ref.id }) }, + { + field: 'name', + cell: (d) => ({ + value: d.object.wallet_config.data.name, + description: d.object.wallet_config.data.description, + click: () => { + this.sidenavInfoService.toggle(DomainObjectCardComponent, { + ref: { wallet_config: { id: d.object.wallet_config.ref.id } }, + }); + }, + }), + }, + createPartyColumn((d) => ({ id: d.object.wallet_config.data.party_ref.id })), + { + field: 'blocking', + cell: (d) => ({ + value: startCase(getUnionKey(d.object.wallet_config.data.block)), + color: ( + { + blocked: 'warn', + unblocked: 'success', + } as const + )[getUnionKey(d.object.wallet_config.data.block)], + }), + }, + { + field: 'suspension', + cell: (d) => ({ + value: startCase(getUnionKey(d.object.wallet_config.data.suspension)), + color: ( + { + suspended: 'warn', + active: 'success', + } as const + )[getUnionKey(d.object.wallet_config.data.suspension)], + }), + }, + createDomainObjectColumn( + (d) => ({ + ref: { payment_institution: d.object.wallet_config.data.payment_institution }, + }), + { field: 'payment_institution' }, + ), + createDomainObjectColumn( + (d) => ({ + ref: { term_set_hierarchy: d.object.wallet_config.data.terms }, + }), + { field: 'terms' }, + ), + createCurrencyColumn( + (d) => + this.getAccountState(d).pipe( + map((b) => ({ amount: b.own_amount, code: b.currency.symbolic_code })), + ), + { header: 'Own', isLazyCell: true }, + ), + createCurrencyColumn( + (d) => + this.getAccountState(d).pipe( + map((b) => ({ + amount: b.own_amount - b.available_amount, + code: b.currency.symbolic_code, + })), + ), + { header: 'Hold', isLazyCell: true }, + ), + createCurrencyColumn( + (d) => + this.getAccountState(d).pipe( + map((b) => ({ amount: b.available_amount, code: b.currency.symbolic_code })), + ), + { header: 'Available', isLazyCell: true }, + ), + { field: 'version', cell: (d) => ({ value: d.info.version }) }, + { field: 'changed_at', cell: (d) => ({ value: d.info.changed_at, type: 'datetime' }) }, + { + field: 'changed_by', + cell: (d) => ({ + value: d.info.changed_by?.name, + description: d.info.changed_by?.email, + }), + }, + createMenuColumn((d) => + this.resource().value$.pipe( + switchMap((wallets) => + runInInjectionContext(this.injector, () => + getDelegatesByPartyItem( + wallets?.length + ? wallets.map((w) => w.object.wallet_config.data.party_ref.id) + : [], + RoutingRulesType.Withdrawal, + d.object.wallet_config.data.party_ref.id, + d.object.wallet_config.ref.id, + ), + ), + ), + map((rr) => [ + ...rr.partyRr, + ...rr.itemRr, + { + label: + getUnionKey(d.object.wallet_config.data.suspension) === 'suspended' + ? 'Activate' + : 'Suspend', + click: () => { + this.toggleSuspension(d); + }, + }, + { + label: + getUnionKey(d.object.wallet_config.data.block) === 'blocked' + ? 'Unblock' + : 'Block', + click: () => { + this.toggleBlocking(d); + }, + }, + ]), + combineLatestWith( + toObservable(this.extendMenu, { injector: this.injector }).pipe( + map((extendMenu) => + extendMenu + ? extendMenu({ + name: d.object.wallet_config.data.name, + description: d.object.wallet_config.data.description, + ref: { wallet_config: d.object.wallet_config.ref }, + info: d.info, + }) + : [], + ), + ), + ), + map(([items, extendItems]) => ({ items: [...items, ...extendItems] })), + ), + ), + ]; + + @MemoizeExpiring(5 * 60_000) + getAccountState(wallet: VersionedObject) { + return this.partyManagementService + .GetAccountState( + wallet.object.wallet_config.data.party_ref, + wallet.object.wallet_config.data.account.settlement, + wallet.info.version, + ) + .pipe(shareReplay({ refCount: true, bufferSize: 1 })); + } + + toggleBlocking(obj: VersionedObject) { + const wallet = obj.object.wallet_config; + this.dialogService + .open(ConfirmDialogComponent, { + title: + getUnionKey(wallet.data.block) === 'unblocked' + ? 'Block wallet' + : 'Unblock wallet', + hasReason: true, + }) + .afterClosed() + .pipe( + filter((r) => r.status === DialogResponseStatus.Success), + switchMap((r) => + getUnionKey(wallet.data.block) === 'unblocked' + ? this.partiesStoreService.blockWallet(wallet, r.data.reason) + : this.partiesStoreService.unblockWallet(wallet, r.data.reason), + ), + ) + .subscribe({ + next: () => { + this.resource().reload(); + this.log.success(); + }, + error: (err) => { + this.log.error(err); + }, + }); + } + + toggleSuspension(obj: VersionedObject) { + const wallet = obj.object.wallet_config; + this.dialogService + .open(ConfirmDialogComponent, { + title: + getUnionKey(wallet.data.suspension) === 'active' + ? 'Suspend wallet' + : 'Activate wallet', + }) + .afterClosed() + .pipe( + filter((r) => r.status === DialogResponseStatus.Success), + switchMap(() => + getUnionKey(wallet.data.suspension) === 'active' + ? this.partiesStoreService.suspendWallet(wallet) + : this.partiesStoreService.activateWallet(wallet), + ), + ) + .subscribe({ + next: () => { + this.resource().reload(); + this.log.success(); + }, + error: (err) => { + this.log.error(err); + }, + }); + } +}