mirror of
https://github.com/valitydev/control-center.git
synced 2024-11-06 02:25:17 +00:00
TD-369: Change stat service (ANAPI V2) (#121)
This commit is contained in:
parent
26716d7c8a
commit
058b7147fd
@ -11,7 +11,7 @@
|
||||
"build-libs": "ng build ng-core",
|
||||
"build": "npm run build-libs && npm run build-app",
|
||||
"test": "ng test",
|
||||
"lint": "eslint \"src/**/*.{ts,js,html}\" --max-warnings 1115",
|
||||
"lint": "eslint \"src/**/*.{ts,js,html}\" --max-warnings 1033",
|
||||
"lint-fix": "npm run lint -- --fix",
|
||||
"lint-errors": "npm run lint -- --quiet",
|
||||
"lint-libs": "eslint \"projects/**/*.{ts,js,html}\" --max-warnings 0",
|
||||
|
@ -3,6 +3,7 @@ import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||
|
||||
import { DEFAULT_DIALOG_CONFIG } from '../tokens';
|
||||
import { BaseDialogResponse } from '../types/base-dialog-response';
|
||||
import { BaseDialogResponseStatus } from '../types/base-dialog-response-status';
|
||||
|
||||
@Directive()
|
||||
export class BaseDialogSuperclass<
|
||||
@ -18,4 +19,25 @@ export class BaseDialogSuperclass<
|
||||
dialogRef = this.injector.get(MatDialogRef) as MatDialogRef<DialogComponent, DialogResponse>;
|
||||
|
||||
constructor(private injector: Injector) {}
|
||||
|
||||
closeWithCancellation(data?: DialogResponseData) {
|
||||
this.dialogRef.close({
|
||||
status: BaseDialogResponseStatus.Cancelled,
|
||||
data,
|
||||
} as never);
|
||||
}
|
||||
|
||||
closeWithSuccess(data?: DialogResponseData) {
|
||||
this.dialogRef.close({
|
||||
status: BaseDialogResponseStatus.Success,
|
||||
data,
|
||||
} as never);
|
||||
}
|
||||
|
||||
closeWithError(data?: DialogResponseData) {
|
||||
this.dialogRef.close({
|
||||
status: BaseDialogResponseStatus.Error,
|
||||
data,
|
||||
} as never);
|
||||
}
|
||||
}
|
||||
|
@ -1 +1,2 @@
|
||||
export * from './components';
|
||||
export * from './utils/objects';
|
||||
|
26
projects/ng-core/src/lib/utils/objects/clean-object.ts
Normal file
26
projects/ng-core/src/lib/utils/objects/clean-object.ts
Normal file
@ -0,0 +1,26 @@
|
||||
import isEmpty from 'lodash-es/isEmpty';
|
||||
import isNil from 'lodash-es/isNil';
|
||||
import isObject from 'lodash-es/isObject';
|
||||
import { ValuesType } from 'utility-types';
|
||||
|
||||
function isEmptyValue(value: unknown): boolean {
|
||||
return isNil(value) || value === '' || (typeof value === 'object' && isEmpty(value));
|
||||
}
|
||||
|
||||
export function cleanObject<T extends object>(
|
||||
obj: T,
|
||||
requiredKeys: (keyof T)[] = [],
|
||||
isNotDeep = false
|
||||
): T {
|
||||
if (!isObject(obj)) return obj;
|
||||
if (Array.isArray(obj))
|
||||
return obj
|
||||
.slice()
|
||||
.map((v: unknown) => (isObject(v) && !isNotDeep ? cleanObject(v) : v))
|
||||
.filter((v) => !isEmptyValue(v)) as T;
|
||||
return Object.fromEntries(
|
||||
(Object.entries(obj) as [keyof T, ValuesType<T>][])
|
||||
.map(([k, v]) => [k, isObject(v) && !isNotDeep ? cleanObject(v as object) : v] as const)
|
||||
.filter(([k, v]) => requiredKeys.includes(k) || !isEmptyValue(v))
|
||||
) as T;
|
||||
}
|
1
projects/ng-core/src/lib/utils/objects/index.ts
Normal file
1
projects/ng-core/src/lib/utils/objects/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './clean-object';
|
@ -1 +0,0 @@
|
||||
export * from './party-payments.module';
|
@ -1,22 +0,0 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule } from '@angular/router';
|
||||
|
||||
import { AppAuthGuardService, OperationRole } from '@cc/app/shared/services';
|
||||
|
||||
import { PartyPaymentsComponent } from './party-payments.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
RouterModule.forChild([
|
||||
{
|
||||
path: '',
|
||||
component: PartyPaymentsComponent,
|
||||
canActivate: [AppAuthGuardService],
|
||||
data: {
|
||||
roles: [OperationRole.SearchPayments],
|
||||
},
|
||||
},
|
||||
]),
|
||||
],
|
||||
})
|
||||
export class PartyPaymentsRoutingModule {}
|
@ -1,10 +0,0 @@
|
||||
<div fxLayout="column" fxLayoutGap="24px">
|
||||
<div class="cc-headline">Merchant's payments</div>
|
||||
<cc-payments-searcher
|
||||
*ngIf="searchType"
|
||||
[initSearchParams]="initSearchParams$ | async"
|
||||
[type]="searchType"
|
||||
(paymentEventFired$)="paymentEventFired($event)"
|
||||
(searchParamsChanged$)="searchParamsUpdated($event)"
|
||||
></cc-payments-searcher>
|
||||
</div>
|
@ -1,50 +0,0 @@
|
||||
import { ChangeDetectionStrategy, Component } from '@angular/core';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { pluck, shareReplay } from 'rxjs/operators';
|
||||
|
||||
import {
|
||||
PaymentActions,
|
||||
PaymentMenuItemEvent,
|
||||
SearcherType,
|
||||
SearchFiltersParams,
|
||||
SearchType,
|
||||
} from '@cc/app/shared/components';
|
||||
|
||||
import { PartyPaymentsService } from './party-payments.service';
|
||||
|
||||
@Component({
|
||||
templateUrl: 'party-payments.component.html',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
providers: [PartyPaymentsService, PartyPaymentsService],
|
||||
})
|
||||
export class PartyPaymentsComponent {
|
||||
searchType: SearcherType;
|
||||
initSearchParams$ = this.partyPaymentsService.data$;
|
||||
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
private partyPaymentsService: PartyPaymentsService,
|
||||
private router: Router
|
||||
) {
|
||||
this.route.params.pipe(pluck('partyID'), shareReplay(1)).subscribe((partyID) => {
|
||||
this.searchType = {
|
||||
type: SearchType.PartySearcher,
|
||||
partyID,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
searchParamsUpdated($event: SearchFiltersParams) {
|
||||
this.partyPaymentsService.preserve($event);
|
||||
}
|
||||
|
||||
paymentEventFired($event: PaymentMenuItemEvent) {
|
||||
const { partyID, invoiceID, paymentID } = $event;
|
||||
switch ($event.action) {
|
||||
case PaymentActions.NavigateToPayment:
|
||||
void this.router.navigate([
|
||||
`/party/${partyID}/invoice/${invoiceID}/payment/${paymentID}`,
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,51 +0,0 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { FlexModule } from '@angular/flex-layout';
|
||||
import { ReactiveFormsModule } from '@angular/forms';
|
||||
import { MatBadgeModule } from '@angular/material/badge';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatCardModule } from '@angular/material/card';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
import { MatMenuModule } from '@angular/material/menu';
|
||||
import { MatProgressBarModule } from '@angular/material/progress-bar';
|
||||
import { MatTableModule } from '@angular/material/table';
|
||||
|
||||
import {
|
||||
PaymentsMainSearchFiltersModule,
|
||||
PaymentsOtherSearchFiltersModule,
|
||||
PaymentsSearcherModule,
|
||||
PaymentsTableModule,
|
||||
StatusModule,
|
||||
} from '@cc/app/shared/components';
|
||||
import { EmptySearchResultModule } from '@cc/components/empty-search-result';
|
||||
|
||||
import { PartyPaymentsRoutingModule } from './party-payments-routing.module';
|
||||
import { PartyPaymentsComponent } from './party-payments.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
FlexModule,
|
||||
MatCardModule,
|
||||
MatProgressBarModule,
|
||||
CommonModule,
|
||||
MatButtonModule,
|
||||
ReactiveFormsModule,
|
||||
MatFormFieldModule,
|
||||
MatInputModule,
|
||||
MatTableModule,
|
||||
MatMenuModule,
|
||||
MatIconModule,
|
||||
PaymentsMainSearchFiltersModule,
|
||||
PartyPaymentsRoutingModule,
|
||||
StatusModule,
|
||||
PaymentsTableModule,
|
||||
MatBadgeModule,
|
||||
PaymentsOtherSearchFiltersModule,
|
||||
EmptySearchResultModule,
|
||||
PaymentsSearcherModule,
|
||||
],
|
||||
declarations: [PartyPaymentsComponent],
|
||||
})
|
||||
export class PartyPaymentsModule {}
|
@ -1,27 +0,0 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { ActivatedRoute, Params, Router } from '@angular/router';
|
||||
import pickBy from 'lodash-es/pickBy';
|
||||
|
||||
import { SearchFiltersParams } from '@cc/app/shared/components';
|
||||
import { QueryParamsStore } from '@cc/app/shared/services';
|
||||
import { wrapValuesToArray } from '@cc/utils/wrap-values-to-array';
|
||||
|
||||
const SHOP_IDS_AND_PRIMITIVES = (v, k) => typeof v === 'string' && k === 'shopIDs';
|
||||
|
||||
@Injectable()
|
||||
export class PartyPaymentsService extends QueryParamsStore<SearchFiltersParams> {
|
||||
constructor(protected route: ActivatedRoute, protected router: Router) {
|
||||
super(router, route);
|
||||
}
|
||||
|
||||
mapToData(queryParams: Params): SearchFiltersParams {
|
||||
return {
|
||||
...queryParams,
|
||||
...wrapValuesToArray(pickBy(queryParams, SHOP_IDS_AND_PRIMITIVES)),
|
||||
} as SearchFiltersParams;
|
||||
}
|
||||
|
||||
mapToParams(data: SearchFiltersParams): Params {
|
||||
return data;
|
||||
}
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { ActivatedRoute, Params, Router } from '@angular/router';
|
||||
import pickBy from 'lodash-es/pickBy';
|
||||
|
||||
import { SearchFiltersParams } from '@cc/app/shared/components';
|
||||
import { QueryParamsStore } from '@cc/app/shared/services';
|
||||
import { wrapValuesToArray } from '@cc/utils/wrap-values-to-array';
|
||||
|
||||
const shopIdsAndPrimitives = (v, k) => typeof v === 'string' && k === 'shopIDs';
|
||||
|
||||
@Injectable()
|
||||
export class PaymentsSearchFiltersStore extends QueryParamsStore<SearchFiltersParams> {
|
||||
constructor(protected route: ActivatedRoute, protected router: Router) {
|
||||
super(router, route);
|
||||
}
|
||||
|
||||
mapToData(queryParams: Params): SearchFiltersParams {
|
||||
return {
|
||||
...queryParams,
|
||||
...wrapValuesToArray(pickBy(queryParams, shopIdsAndPrimitives)),
|
||||
} as SearchFiltersParams;
|
||||
}
|
||||
|
||||
mapToParams(data: SearchFiltersParams): Params {
|
||||
return data;
|
||||
}
|
||||
}
|
@ -16,11 +16,6 @@ import { PartyComponent } from './party.component';
|
||||
roles: [PartyRole.Get],
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: 'payments',
|
||||
loadChildren: () =>
|
||||
import('../party-payments').then((m) => m.PartyPaymentsModule),
|
||||
},
|
||||
{
|
||||
path: 'shops',
|
||||
loadChildren: () =>
|
||||
@ -31,17 +26,12 @@ import { PartyComponent } from './party.component';
|
||||
loadChildren: () =>
|
||||
import('../shop-details').then((m) => m.ShopDetailsModule),
|
||||
},
|
||||
{
|
||||
path: 'invoice/:invoiceID/payment/:paymentID',
|
||||
loadChildren: () =>
|
||||
import('../payment-details').then((m) => m.PaymentDetailsModule),
|
||||
},
|
||||
{
|
||||
path: 'routing-rules',
|
||||
loadChildren: () =>
|
||||
import('../routing-rules').then((m) => m.RoutingRulesModule),
|
||||
},
|
||||
{ path: '', redirectTo: 'payments', pathMatch: 'full' },
|
||||
{ path: '', redirectTo: 'shops', pathMatch: 'full' },
|
||||
],
|
||||
},
|
||||
]),
|
||||
|
@ -3,12 +3,7 @@ import { ActivatedRoute, NavigationEnd, Router } from '@angular/router';
|
||||
import { Observable, of } from 'rxjs';
|
||||
import { catchError, filter, map, pluck, shareReplay, startWith, switchMap } from 'rxjs/operators';
|
||||
|
||||
import {
|
||||
AppAuthGuardService,
|
||||
DomainConfigRole,
|
||||
OperationRole,
|
||||
PartyRole,
|
||||
} from '@cc/app/shared/services';
|
||||
import { AppAuthGuardService, DomainConfigRole, PartyRole } from '@cc/app/shared/services';
|
||||
|
||||
import { DeanonimusService, getMaxSearchHitParty } from '../../thrift-services/deanonimus';
|
||||
|
||||
@ -49,12 +44,6 @@ export class PartyComponent {
|
||||
|
||||
private getLinks() {
|
||||
const links = [
|
||||
{
|
||||
name: 'Payments',
|
||||
url: 'payments',
|
||||
otherActiveUrlFragments: ['payment', 'invoice'],
|
||||
activateRoles: [OperationRole.SearchPayments],
|
||||
},
|
||||
{
|
||||
name: 'Shops',
|
||||
url: 'shops',
|
||||
|
@ -2,7 +2,7 @@ import { Component, OnInit } from '@angular/core';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
|
||||
import { StatPayment } from '@vality/domain-proto/lib/merch_stat';
|
||||
import { StatPayment } from '@vality/magista-proto';
|
||||
|
||||
import { CreateAndCaptureComponent } from './create-and-capture/create-and-capture.component';
|
||||
import { PaymentAdjustmentService } from './payment-adjustment.service';
|
||||
|
@ -1,11 +1,12 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { StatPayment, StatResponse } from '@vality/domain-proto/lib/merch_stat';
|
||||
import { StatPayment } from '@vality/magista-proto';
|
||||
import { cleanObject } from '@vality/ng-core';
|
||||
import { Observable, of, Subject } from 'rxjs';
|
||||
import { mergeMap, shareReplay } from 'rxjs/operators';
|
||||
|
||||
import { MerchantStatisticsService } from '@cc/app/api/magista';
|
||||
|
||||
import { DomainService } from '../../domain';
|
||||
import { QueryDsl } from '../../query-dsl';
|
||||
import { MerchantStatisticsService } from '../../thrift-services/damsel/merchant-statistics.service';
|
||||
import { SearchFormParams } from './search-form/search-form-params';
|
||||
|
||||
@Injectable()
|
||||
@ -30,7 +31,7 @@ export class PaymentAdjustmentService {
|
||||
): Observable<StatPayment[]> {
|
||||
return this.getPayments(params, continuationToken).pipe(
|
||||
mergeMap((res) => {
|
||||
const mergedPayments = [...payments, ...res.data.payments];
|
||||
const mergedPayments = [...payments, ...res.payments];
|
||||
this.searchPaymentChanges$.next(mergedPayments);
|
||||
return res.continuation_token
|
||||
? this.getAllPayments(params, res.continuation_token, mergedPayments)
|
||||
@ -39,10 +40,7 @@ export class PaymentAdjustmentService {
|
||||
);
|
||||
}
|
||||
|
||||
private getPayments(
|
||||
params: SearchFormParams,
|
||||
continuationToken?: string
|
||||
): Observable<StatResponse> {
|
||||
private getPayments(params: SearchFormParams, continuationToken?: string) {
|
||||
const {
|
||||
fromRevision,
|
||||
toRevision,
|
||||
@ -55,24 +53,24 @@ export class PaymentAdjustmentService {
|
||||
providerID,
|
||||
terminalID,
|
||||
} = params;
|
||||
return this.merchantStatisticsService.getPayments({
|
||||
dsl: JSON.stringify({
|
||||
query: {
|
||||
payments: {
|
||||
...(partyId ? { merchant_id: partyId } : {}),
|
||||
...(shopId ? { shop_id: shopId } : {}),
|
||||
from_time: fromTime,
|
||||
to_time: toTime,
|
||||
from_payment_domain_revision: fromRevision,
|
||||
to_payment_domain_revision: toRevision,
|
||||
...(providerID ? { payment_provider_id: providerID } : {}),
|
||||
...(terminalID ? { payment_terminal_id: terminalID } : {}),
|
||||
...(status ? { payment_status: status } : {}),
|
||||
...(invoiceIds ? { invoice_ids: invoiceIds } : {}),
|
||||
},
|
||||
return this.merchantStatisticsService.SearchPayments(
|
||||
cleanObject({
|
||||
common_search_query_params: {
|
||||
from_time: fromTime,
|
||||
to_time: toTime,
|
||||
party_id: partyId,
|
||||
shop_ids: [shopId],
|
||||
continuation_token: continuationToken,
|
||||
},
|
||||
} as QueryDsl),
|
||||
...(continuationToken ? { continuation_token: continuationToken } : {}),
|
||||
});
|
||||
payment_params: {
|
||||
from_payment_domain_revision: fromRevision,
|
||||
to_payment_domain_revision: toRevision,
|
||||
payment_provider_id: providerID,
|
||||
payment_terminal_id: terminalID,
|
||||
payment_status: status,
|
||||
},
|
||||
invoice_ids: invoiceIds,
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,14 @@
|
||||
import { InvoicePaymentStatus } from '@vality/magista-proto';
|
||||
|
||||
export interface SearchFormParams {
|
||||
fromTime: string;
|
||||
toTime: string;
|
||||
partyId: string;
|
||||
fromRevision: string;
|
||||
toRevision: string;
|
||||
fromRevision: number;
|
||||
toRevision: number;
|
||||
providerID: string;
|
||||
terminalID: string;
|
||||
status: string;
|
||||
status: InvoicePaymentStatus;
|
||||
shopId: string;
|
||||
invoiceIds: string[];
|
||||
}
|
||||
|
@ -25,7 +25,7 @@
|
||||
<mat-form-field fxFlex>
|
||||
<mat-select formControlName="status" placeholder="Payment status">
|
||||
<mat-option [value]="null">any</mat-option>
|
||||
<mat-option *ngFor="let status of statuses" [value]="status">{{
|
||||
<mat-option *ngFor="let status of statuses" [value]="statusEnum[status]">{{
|
||||
status
|
||||
}}</mat-option>
|
||||
</mat-select>
|
||||
@ -38,6 +38,7 @@
|
||||
matInput
|
||||
placeholder="From domain revision"
|
||||
required
|
||||
type="number"
|
||||
/>
|
||||
</mat-form-field>
|
||||
<mat-form-field fxFlex>
|
||||
@ -46,6 +47,7 @@
|
||||
matInput
|
||||
placeholder="To domain revision"
|
||||
required
|
||||
type="number"
|
||||
/>
|
||||
</mat-form-field>
|
||||
<mat-form-field fxFlex>
|
||||
|
@ -1,9 +1,11 @@
|
||||
import { Component, EventEmitter, OnInit, Output } from '@angular/core';
|
||||
import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms';
|
||||
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
|
||||
import { InvoicePaymentStatus } from '@vality/magista-proto';
|
||||
import * as moment from 'moment';
|
||||
import { map } from 'rxjs/operators';
|
||||
|
||||
import { getEnumKeys } from '../../../../utils';
|
||||
import { PaymentAdjustmentService } from '../payment-adjustment.service';
|
||||
import { SearchFormParams } from './search-form-params';
|
||||
import { toSearchParams } from './to-search-params';
|
||||
@ -14,15 +16,13 @@ import { toSearchParams } from './to-search-params';
|
||||
templateUrl: './search-form.component.html',
|
||||
})
|
||||
export class SearchFormComponent implements OnInit {
|
||||
@Output()
|
||||
valueChanges: EventEmitter<SearchFormParams> = new EventEmitter();
|
||||
|
||||
@Output()
|
||||
statusChanges: EventEmitter<string> = new EventEmitter();
|
||||
@Output() valueChanges = new EventEmitter<SearchFormParams>();
|
||||
@Output() statusChanges = new EventEmitter<string>();
|
||||
|
||||
form: UntypedFormGroup;
|
||||
|
||||
statuses: string[] = ['pending', 'processed', 'captured', 'cancelled', 'refunded', 'failed'];
|
||||
statuses = getEnumKeys(InvoicePaymentStatus);
|
||||
statusEnum = InvoicePaymentStatus;
|
||||
|
||||
constructor(
|
||||
private paymentAdjustmentService: PaymentAdjustmentService,
|
||||
@ -34,7 +34,7 @@ export class SearchFormComponent implements OnInit {
|
||||
fromTime: [moment(), Validators.required],
|
||||
toTime: [moment(), Validators.required],
|
||||
invoiceIds: '',
|
||||
partyId: '',
|
||||
partyId: ['', Validators.required],
|
||||
shopId: '',
|
||||
fromRevision: [0, Validators.required],
|
||||
toRevision: ['', Validators.required],
|
||||
|
@ -30,7 +30,7 @@
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="revision">
|
||||
<th *matHeaderCellDef mat-header-cell>Revision</th>
|
||||
<td *matCellDef="let payment" mat-cell>{{ payment.domain_revision | ccThriftInt64 }}</td>
|
||||
<td *matCellDef="let payment" mat-cell>{{ payment.domain_revision }}</td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="invoiceId">
|
||||
<th *matHeaderCellDef mat-header-cell>Invoice ID</th>
|
||||
|
@ -12,9 +12,6 @@ import {
|
||||
import { MatPaginator } from '@angular/material/paginator';
|
||||
import { MatTableDataSource } from '@angular/material/table';
|
||||
import { StatPayment } from '@vality/domain-proto/lib/merch_stat';
|
||||
import { Int64 } from '@vality/thrift-ts';
|
||||
|
||||
import { i64ToNumber } from '@cc/utils/i64-to-number';
|
||||
|
||||
@Component({
|
||||
selector: 'cc-payment-adjustment-table',
|
||||
@ -48,13 +45,8 @@ export class TableComponent implements OnInit, OnChanges {
|
||||
|
||||
ngOnInit() {
|
||||
this.selection.changed.subscribe((e) => this.changeSelected.emit(e.source.selected));
|
||||
this.dataSource.filterPredicate = ({ domain_revision }, filter) => {
|
||||
const num = i64ToNumber(
|
||||
(domain_revision as unknown as Int64).buffer,
|
||||
(domain_revision as unknown as Int64).offset
|
||||
);
|
||||
return filter === num.toString();
|
||||
};
|
||||
this.dataSource.filterPredicate = ({ domain_revision }, filter) =>
|
||||
filter === domain_revision.toString();
|
||||
this.dataSource.paginator = this.paginator;
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
<div fxLayout="column" fxLayoutGap="24px">
|
||||
<div fxLayout="column" fxLayoutGap="24px" style="margin: 24px">
|
||||
<cc-headline>Payment details</cc-headline>
|
||||
<ng-container *ngIf="payment$ | async as payment">
|
||||
<mat-card>
|
||||
@ -14,6 +14,7 @@
|
||||
<h2 class="cc-headline">Refunds</h2>
|
||||
<cc-payment-refunds
|
||||
[invoiceID]="payment.invoice_id"
|
||||
[partyID]="payment.owner_id"
|
||||
[paymentID]="payment.id"
|
||||
></cc-payment-refunds>
|
||||
</mat-card-content>
|
||||
|
@ -1,7 +1,6 @@
|
||||
import { ChangeDetectionStrategy, Component } from '@angular/core';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { Subject } from 'rxjs';
|
||||
import { pluck, shareReplay } from 'rxjs/operators';
|
||||
import { pluck } from 'rxjs/operators';
|
||||
|
||||
import { PaymentDetailsService } from './payment-details.service';
|
||||
|
||||
@ -11,11 +10,10 @@ import { PaymentDetailsService } from './payment-details.service';
|
||||
providers: [PaymentDetailsService],
|
||||
})
|
||||
export class PaymentDetailsComponent {
|
||||
partyID$ = this.route.params.pipe(pluck('partyID'), shareReplay(1));
|
||||
partyID$ = this.route.params.pipe(pluck('partyID'));
|
||||
payment$ = this.paymentDetailsService.payment$;
|
||||
isLoading$ = this.paymentDetailsService.isLoading$;
|
||||
shop$ = this.paymentDetailsService.shop$;
|
||||
updateSearchParams$ = new Subject();
|
||||
|
||||
constructor(
|
||||
private paymentDetailsService: PaymentDetailsService,
|
||||
|
@ -1,15 +1,14 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { cleanObject } from '@vality/ng-core';
|
||||
import { combineLatest, of } from 'rxjs';
|
||||
import { map, pluck, shareReplay, switchMap, tap } from 'rxjs/operators';
|
||||
|
||||
import { MerchantStatisticsService } from '@cc/app/api/magista';
|
||||
import { PartyManagementService } from '@cc/app/api/payment-processing';
|
||||
import { progress } from '@cc/app/shared/custom-operators';
|
||||
|
||||
import { QueryDsl } from '../../query-dsl';
|
||||
import { MerchantStatisticsService } from '../../thrift-services/damsel/merchant-statistics.service';
|
||||
|
||||
@Injectable()
|
||||
export class PaymentDetailsService {
|
||||
private partyID$ = this.route.params.pipe(pluck('partyID'), shareReplay(1));
|
||||
@ -20,19 +19,21 @@ export class PaymentDetailsService {
|
||||
payment$ = this.routeParams$.pipe(
|
||||
switchMap(({ partyID, invoiceID, paymentID }) =>
|
||||
this.merchantStatisticsService
|
||||
.getPayments({
|
||||
dsl: JSON.stringify({
|
||||
query: {
|
||||
payments: {
|
||||
...(paymentID ? { payment_id: paymentID } : {}),
|
||||
...(partyID ? { merchant_id: partyID } : {}),
|
||||
...(invoiceID ? { invoice_id: invoiceID } : {}),
|
||||
},
|
||||
.SearchPayments(
|
||||
cleanObject({
|
||||
common_search_query_params: {
|
||||
from_time: new Date('2020-01-01').toISOString(), // TODO
|
||||
to_time: new Date().toISOString(),
|
||||
party_id: partyID,
|
||||
},
|
||||
} as QueryDsl),
|
||||
})
|
||||
payment_params: {
|
||||
payment_id: paymentID,
|
||||
},
|
||||
invoice_ids: [invoiceID],
|
||||
})
|
||||
)
|
||||
.pipe(
|
||||
map(({ data }) => data.payments[0]),
|
||||
map(({ payments }) => payments[0]),
|
||||
tap((payment) => {
|
||||
if (!payment) {
|
||||
this.snackBar.open('An error occurred when receiving payment', 'OK');
|
||||
|
@ -4,7 +4,7 @@ import {
|
||||
FailureReason,
|
||||
InvoicePaymentStatus,
|
||||
SubFailure,
|
||||
} from '@vality/domain-proto/lib/domain';
|
||||
} from '@vality/magista-proto/lib/domain';
|
||||
|
||||
import { getUnionKey } from '@cc/utils/get-union-key';
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
<div fxLayout="column" fxLayoutGap="16px">
|
||||
<div fxLayout fxLayoutGap="16px">
|
||||
<cc-details-item fxFlex title="Amount"
|
||||
>{{ payment.amount | ccThriftInt64 | ccFormatAmount }}
|
||||
>{{ payment.amount | ccFormatAmount }}
|
||||
{{ payment.currency_symbolic_code | ccCurrency }}</cc-details-item
|
||||
>
|
||||
<cc-details-item fxFlex title="Created At">{{
|
||||
|
@ -1,13 +1,9 @@
|
||||
import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
|
||||
import { Shop } from '@vality/domain-proto/lib/domain';
|
||||
import {
|
||||
InvoicePaymentStatus,
|
||||
Payer,
|
||||
PaymentTool,
|
||||
StatPayment,
|
||||
} from '@vality/domain-proto/lib/merch_stat';
|
||||
import { Payer, StatPayment } from '@vality/magista-proto';
|
||||
import { InvoicePaymentStatus, PaymentTool } from '@vality/magista-proto/lib/domain';
|
||||
|
||||
import { getUnionKey } from '@cc/utils/get-union-key';
|
||||
import { getUnionKey } from '../../../../utils';
|
||||
|
||||
@Component({
|
||||
selector: 'cc-payment-main-info',
|
||||
@ -20,13 +16,13 @@ export class PaymentMainInfoComponent {
|
||||
|
||||
getPayerEmail(payer: Payer): string {
|
||||
if (payer.customer) {
|
||||
return payer.customer.email;
|
||||
return payer.customer.contact_info.email;
|
||||
}
|
||||
if (payer.payment_resource) {
|
||||
return payer.payment_resource.email;
|
||||
return payer.payment_resource.contact_info.email;
|
||||
}
|
||||
if (payer.recurrent) {
|
||||
return payer.recurrent.email;
|
||||
return payer.recurrent.contact_info.email;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
@ -34,7 +30,7 @@ export class PaymentMainInfoComponent {
|
||||
getPaymentTool(payer: Payer): PaymentTool {
|
||||
return (
|
||||
payer?.customer?.payment_tool ||
|
||||
payer?.payment_resource?.payment_tool ||
|
||||
payer?.payment_resource?.resource?.payment_tool ||
|
||||
payer?.recurrent?.payment_tool
|
||||
);
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
|
||||
import { BankCard } from '@vality/domain-proto/lib/merch_stat';
|
||||
import { BankCard } from '@vality/magista-proto/lib/domain';
|
||||
|
||||
@Component({
|
||||
selector: 'cc-bank-card',
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Pipe, PipeTransform } from '@angular/core';
|
||||
import { BankCard } from '@vality/domain-proto/lib/merch_stat';
|
||||
import { BankCard } from '@vality/magista-proto/lib/domain';
|
||||
|
||||
@Pipe({
|
||||
name: 'toCardNumber',
|
||||
@ -11,4 +11,4 @@ export class ToCardNumberPipe implements PipeTransform {
|
||||
}
|
||||
|
||||
export const toCardNumber = (card: BankCard): string =>
|
||||
`${card.bin}******${card.masked_pan}`.replace(/(.{4})/g, '$& ');
|
||||
`${card.bin}******${card.last_digits}`.replace(/(.{4})/g, '$& ');
|
||||
|
@ -1,6 +1,6 @@
|
||||
<cc-bank-card *ngIf="paymentTool.bank_card" [bankCard]="paymentTool.bank_card"></cc-bank-card>
|
||||
<div *ngIf="paymentTool.crypto_currency">
|
||||
{{ paymentTool.crypto_currency?.crypto_currency?.id }}
|
||||
{{ paymentTool.crypto_currency?.id }}
|
||||
</div>
|
||||
<div *ngIf="paymentTool.digital_wallet">
|
||||
{{ paymentTool.digital_wallet?.id }}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
|
||||
import { PaymentTool } from '@vality/domain-proto/lib/merch_stat';
|
||||
import { PaymentTool } from '@vality/magista-proto/lib/domain';
|
||||
|
||||
@Component({
|
||||
selector: 'cc-payment-tool',
|
||||
|
@ -1,19 +1,21 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { StatRefund } from '@vality/domain-proto/lib/merch_stat';
|
||||
import { StatRefund, RefundSearchQuery } from '@vality/magista-proto';
|
||||
import { cleanObject } from '@vality/ng-core';
|
||||
import { Observable } from 'rxjs';
|
||||
import { map, shareReplay } from 'rxjs/operators';
|
||||
import { DeepPartial } from 'utility-types';
|
||||
|
||||
import { MerchantStatisticsService } from '@cc/app/api/magista';
|
||||
import { FetchResult, PartialFetcher } from '@cc/app/shared/services';
|
||||
import { booleanDelay } from '@cc/utils/boolean-delay';
|
||||
|
||||
import { QueryDsl } from '../../../query-dsl';
|
||||
import { MerchantStatisticsService } from '../../../thrift-services/damsel/merchant-statistics.service';
|
||||
import { RefundsSearchParams } from './refunds-search-params';
|
||||
|
||||
const SEARCH_LIMIT = 5;
|
||||
|
||||
@Injectable()
|
||||
export class FetchRefundsService extends PartialFetcher<StatRefund, RefundsSearchParams> {
|
||||
export class FetchRefundsService extends PartialFetcher<
|
||||
StatRefund,
|
||||
DeepPartial<RefundSearchQuery>
|
||||
> {
|
||||
isLoading$ = this.doAction$.pipe(booleanDelay(), shareReplay(1));
|
||||
|
||||
constructor(private merchantStatisticsService: MerchantStatisticsService) {
|
||||
@ -21,49 +23,27 @@ export class FetchRefundsService extends PartialFetcher<StatRefund, RefundsSearc
|
||||
}
|
||||
|
||||
protected fetch(
|
||||
params: RefundsSearchParams,
|
||||
params: DeepPartial<RefundSearchQuery>,
|
||||
continuationToken: string
|
||||
): Observable<FetchResult<StatRefund>> {
|
||||
const {
|
||||
invoiceID,
|
||||
id,
|
||||
paymentID,
|
||||
ownerID,
|
||||
shopID,
|
||||
status,
|
||||
createdAt,
|
||||
amount,
|
||||
fee,
|
||||
externalID,
|
||||
currencySymbolicCode,
|
||||
} = params;
|
||||
return this.merchantStatisticsService
|
||||
.getStatistics({
|
||||
dsl: JSON.stringify({
|
||||
query: {
|
||||
refunds: {
|
||||
size: SEARCH_LIMIT.toString(),
|
||||
...(invoiceID ? { invoice_id: invoiceID } : {}),
|
||||
...(id ? { id } : {}),
|
||||
...(paymentID ? { payment_id: paymentID } : {}),
|
||||
...(ownerID ? { owner_id: ownerID } : {}),
|
||||
...(shopID ? { shop_id: shopID } : {}),
|
||||
...(status ? { status } : {}),
|
||||
...(amount ? { amount } : {}),
|
||||
...(createdAt ? { created_at: createdAt } : {}),
|
||||
...(fee ? { fee } : {}),
|
||||
...(externalID ? { external_id: externalID } : {}),
|
||||
...(currencySymbolicCode
|
||||
? { currency_symbolic_code: currencySymbolicCode }
|
||||
: {}),
|
||||
.SearchRefunds(
|
||||
cleanObject({
|
||||
...params,
|
||||
common_search_query_params: Object.assign(
|
||||
{
|
||||
continuation_token: continuationToken,
|
||||
limit: SEARCH_LIMIT,
|
||||
from_time: new Date('01.01.2020').toISOString(), // TODO
|
||||
to_time: new Date().toISOString(),
|
||||
},
|
||||
},
|
||||
} as QueryDsl),
|
||||
...(continuationToken ? { continuation_token: continuationToken } : {}),
|
||||
})
|
||||
params.common_search_query_params
|
||||
),
|
||||
})
|
||||
)
|
||||
.pipe(
|
||||
map(({ data, continuation_token }) => ({
|
||||
result: data.refunds,
|
||||
map(({ refunds, continuation_token }) => ({
|
||||
result: refunds,
|
||||
continuationToken: continuation_token,
|
||||
}))
|
||||
);
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { Component, Input, OnInit } from '@angular/core';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
import { InvoiceID, InvoicePaymentID } from '@vality/domain-proto';
|
||||
import { InvoiceID, InvoicePaymentID, PartyID } from '@vality/domain-proto';
|
||||
|
||||
import { FetchRefundsService } from './fetch-refunds.service';
|
||||
|
||||
@ -11,6 +11,7 @@ import { FetchRefundsService } from './fetch-refunds.service';
|
||||
export class PaymentRefundsComponent implements OnInit {
|
||||
@Input() paymentID: InvoicePaymentID;
|
||||
@Input() invoiceID: InvoiceID;
|
||||
@Input() partyID: PartyID;
|
||||
|
||||
doAction$ = this.fetchRefundsService.doAction$;
|
||||
isLoading$ = this.fetchRefundsService.isLoading$;
|
||||
@ -21,8 +22,9 @@ export class PaymentRefundsComponent implements OnInit {
|
||||
|
||||
ngOnInit() {
|
||||
this.fetchRefundsService.search({
|
||||
paymentID: this.paymentID,
|
||||
invoiceID: this.invoiceID,
|
||||
common_search_query_params: { party_id: this.partyID },
|
||||
payment_id: this.paymentID,
|
||||
invoice_ids: [this.invoiceID],
|
||||
});
|
||||
this.fetchRefundsService.errors$.subscribe((e) =>
|
||||
this.snackBar.open(`An error occurred while search refunds (${String(e)})`, 'OK')
|
||||
|
@ -1,21 +0,0 @@
|
||||
import {
|
||||
InvoiceID,
|
||||
InvoicePaymentID,
|
||||
InvoicePaymentRefundID,
|
||||
InvoicePaymentRefundStatus,
|
||||
ShopID,
|
||||
} from '@vality/domain-proto/lib/domain';
|
||||
|
||||
export interface RefundsSearchParams {
|
||||
invoiceID?: InvoiceID;
|
||||
id?: InvoicePaymentRefundID;
|
||||
paymentID?: InvoicePaymentID;
|
||||
ownerID?: string;
|
||||
shopID?: ShopID;
|
||||
status?: InvoicePaymentRefundStatus;
|
||||
createdAt?: string;
|
||||
amount?;
|
||||
fee?;
|
||||
externalID?;
|
||||
currencySymbolicCode?;
|
||||
}
|
@ -14,9 +14,10 @@ import { MatTableModule } from '@angular/material/table';
|
||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||
import { ActionsModule, BaseDialogModule } from '@vality/ng-core';
|
||||
|
||||
import { MetadataFormModule } from '@cc/app/shared/components/metadata-form';
|
||||
|
||||
import { EmptySearchResultModule } from '../../../components/empty-search-result';
|
||||
import { TableModule } from '../../../components/table';
|
||||
import { MetadataFormModule } from '../../shared';
|
||||
import { DateRangeModule } from '../../shared/components/date-range/date-range.module';
|
||||
import { RepairByScenarioDialogComponent } from './components/repair-by-scenario-dialog/repair-by-scenario-dialog.component';
|
||||
import { RepairingRoutingModule } from './repairing-routing.module';
|
||||
|
@ -13,7 +13,7 @@ import { MatRadioModule } from '@angular/material/radio';
|
||||
import { MatSelectModule } from '@angular/material/select';
|
||||
import { BaseDialogModule } from '@vality/ng-core';
|
||||
|
||||
import { MetadataFormModule } from '@cc/app/shared';
|
||||
import { MetadataFormModule } from '@cc/app/shared/components/metadata-form';
|
||||
|
||||
import { AddRoutingRuleDialogComponent } from './add-routing-rule-dialog.component';
|
||||
import { ExpanderComponent } from './expander';
|
||||
|
@ -1,7 +1,6 @@
|
||||
<div fxLayout="column" fxLayoutGap="24px">
|
||||
<cc-payments-searcher
|
||||
[initSearchParams]="initsearchParams$ | async"
|
||||
[type]="searchType"
|
||||
(paymentEventFired$)="paymentEventFired($event)"
|
||||
(searchParamsChanged$)="searchParamsUpdated($event)"
|
||||
></cc-payments-searcher>
|
||||
|
@ -4,9 +4,7 @@ import { Router } from '@angular/router';
|
||||
import {
|
||||
PaymentActions,
|
||||
PaymentMenuItemEvent,
|
||||
SearcherType,
|
||||
SearchFiltersParams,
|
||||
SearchType,
|
||||
} from '@cc/app/shared/components';
|
||||
|
||||
import { SearchPaymentsService } from './search-payments.service';
|
||||
@ -17,10 +15,6 @@ import { SearchPaymentsService } from './search-payments.service';
|
||||
providers: [SearchPaymentsService],
|
||||
})
|
||||
export class SearchPaymentsComponent {
|
||||
searchType: SearcherType = {
|
||||
type: SearchType.GlobalSearcher,
|
||||
};
|
||||
|
||||
initsearchParams$ = this.searchPaymentsService.data$;
|
||||
|
||||
constructor(private searchPaymentsService: SearchPaymentsService, private router: Router) {}
|
||||
|
@ -13,7 +13,6 @@ import {
|
||||
} from '@cc/app/shared/components';
|
||||
import { EmptySearchResultModule } from '@cc/components/empty-search-result';
|
||||
|
||||
import { PartyPaymentsModule } from '../party-payments';
|
||||
import { SearchPaymentsRoutingModule } from './search-payments-routing.module';
|
||||
import { SearchPaymentsComponent } from './search-payments.component';
|
||||
|
||||
@ -29,7 +28,6 @@ import { SearchPaymentsComponent } from './search-payments.component';
|
||||
EmptySearchResultModule,
|
||||
PaymentsTableModule,
|
||||
MatButtonModule,
|
||||
PartyPaymentsModule,
|
||||
PaymentsSearcherModule,
|
||||
],
|
||||
declarations: [SearchPaymentsComponent],
|
||||
|
@ -6,6 +6,10 @@ const ROUTES: Routes = [
|
||||
path: 'party',
|
||||
loadChildren: () => import('./party/party.module').then((m) => m.PartyModule),
|
||||
},
|
||||
{
|
||||
path: 'party/:partyID/invoice/:invoiceID/payment/:paymentID',
|
||||
loadChildren: () => import('./payment-details').then((m) => m.PaymentDetailsModule),
|
||||
},
|
||||
{
|
||||
path: 'withdrawals',
|
||||
loadChildren: () =>
|
||||
|
@ -16,9 +16,10 @@ import { BaseDialogModule } from '@vality/ng-core';
|
||||
|
||||
import { EmptySearchResultModule } from '../../../components/empty-search-result';
|
||||
import { TableModule } from '../../../components/table';
|
||||
import { MetadataFormModule, ThriftPipesModule } from '../../shared';
|
||||
import { DateRangeModule } from '../../shared/components/date-range/date-range.module';
|
||||
import { MerchantFieldModule } from '../../shared/components/merchant-field';
|
||||
import { MetadataFormModule } from '../../shared/components/metadata-form';
|
||||
import { ThriftPipesModule } from '../../shared/pipes/thrift';
|
||||
import { CreateAdjustmentDialogComponent } from './components/create-adjustment-dialog/create-adjustment-dialog.component';
|
||||
import { WithdrawalsRoutingModule } from './withdrawals-routing.module';
|
||||
import { WithdrawalsComponent } from './withdrawals.component';
|
||||
|
@ -1,5 +1,5 @@
|
||||
export * from './metadata-form.module';
|
||||
export * from './types/metadata-form-data';
|
||||
export { MetadataFormExtension } from '@cc/app/shared/components/metadata-form/types/metadata-form-extension';
|
||||
export { MetadataFormExtensionResult } from '@cc/app/shared/components/metadata-form/types/metadata-form-extension';
|
||||
export { MetadataFormExtensionOption } from '@cc/app/shared/components/metadata-form/types/metadata-form-extension';
|
||||
export { MetadataFormExtension } from './types/metadata-form-extension';
|
||||
export { MetadataFormExtensionResult } from './types/metadata-form-extension';
|
||||
export { MetadataFormExtensionOption } from './types/metadata-form-extension';
|
||||
|
@ -3,10 +3,10 @@ import { Validator } from '@angular/forms';
|
||||
import { Field, ValueType } from '@vality/thrift-ts';
|
||||
|
||||
import { ThriftAstMetadata } from '@cc/app/api/utils';
|
||||
import { MetadataFormExtension } from '@cc/app/shared/components/metadata-form/types/metadata-form-extension';
|
||||
import { createControlProviders, ValidatedFormControlSuperclass } from '@cc/utils';
|
||||
|
||||
import { MetadataFormData } from './types/metadata-form-data';
|
||||
import { MetadataFormExtension } from './types/metadata-form-extension';
|
||||
|
||||
@Component({
|
||||
selector: 'cc-metadata-form',
|
||||
|
@ -15,8 +15,9 @@ import { MatRadioModule } from '@angular/material/radio';
|
||||
import { MatSelectModule } from '@angular/material/select';
|
||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||
|
||||
import { ThriftPipesModule, ValueTypeTitleModule } from '@cc/app/shared';
|
||||
import { JsonViewerModule } from '@cc/app/shared/components/json-viewer';
|
||||
import { ThriftPipesModule } from '@cc/app/shared/pipes/thrift';
|
||||
import { ValueTypeTitleModule } from '@cc/app/shared/pipes/value-type-title';
|
||||
|
||||
import { ComplexFormComponent } from './components/complex-form/complex-form.component';
|
||||
import { EnumFieldComponent } from './components/enum-field/enum-field.component';
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { ThemePalette } from '@angular/material/core';
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
import { MetadataFormData } from '@cc/app/shared';
|
||||
import { MetadataFormData } from './metadata-form-data';
|
||||
|
||||
export interface MetadataFormExtensionOption {
|
||||
value: unknown;
|
||||
|
@ -2,7 +2,8 @@ import { ValueType } from '@vality/thrift-ts';
|
||||
import { TypeDefs } from '@vality/thrift-ts/src/thrift-parser';
|
||||
|
||||
import { ThriftAstMetadata } from '@cc/app/api/utils';
|
||||
import { MetadataFormData, TypeGroup } from '@cc/app/shared';
|
||||
|
||||
import { MetadataFormData, TypeGroup } from '../types/metadata-form-data';
|
||||
|
||||
export function getDefaultValue(metadata: ThriftAstMetadata[], namespace: string, type: ValueType) {
|
||||
let data: MetadataFormData;
|
||||
|
@ -1,3 +1,2 @@
|
||||
export * from './payments-main-search-filters.module';
|
||||
export * from './payments-main-search-filters.component';
|
||||
export * from './main-filter-search-type';
|
||||
|
@ -1,11 +0,0 @@
|
||||
import { PartyID } from '@vality/domain-proto';
|
||||
|
||||
export enum MainSearchType {
|
||||
PartySearchFilter = 'PartySearchFilter',
|
||||
GlobalSearchFilter = 'GlobalSearchFilter',
|
||||
}
|
||||
|
||||
export interface MainFilterSearchType {
|
||||
type: MainSearchType;
|
||||
partyID?: PartyID;
|
||||
}
|
@ -1,66 +1,63 @@
|
||||
<form [formGroup]="form" fxLayout="column" fxLayoutGap="16px">
|
||||
<div fxFlexFill fxLayout fxLayoutGap="16px">
|
||||
<mat-form-field fxFlex>
|
||||
<mat-label>Date Range</mat-label>
|
||||
<mat-date-range-input [rangePicker]="picker">
|
||||
<input formControlName="fromTime" matInput matStartDate placeholder="Start Date" />
|
||||
<input formControlName="toTime" matEndDate matInput placeholder="End Date" />
|
||||
</mat-date-range-input>
|
||||
<mat-datepicker-toggle [for]="picker" matSuffix>
|
||||
<mat-icon matDatepickerToggleIcon>keyboard_arrow_down</mat-icon>
|
||||
</mat-datepicker-toggle>
|
||||
<mat-date-range-picker #picker></mat-date-range-picker>
|
||||
</mat-form-field>
|
||||
<mat-form-field fxFlex>
|
||||
<input
|
||||
autocomplete="false"
|
||||
formControlName="invoiceID"
|
||||
matInput
|
||||
placeholder="Invoice ID"
|
||||
type="string"
|
||||
/>
|
||||
</mat-form-field>
|
||||
<cc-merchant-searcher
|
||||
*ngIf="type.type === mainSearchType.GlobalSearchFilter"
|
||||
formControlName="partyID"
|
||||
fxFlex
|
||||
></cc-merchant-searcher>
|
||||
<mat-form-field *ngIf="type.type === mainSearchType.PartySearchFilter" fxFlex>
|
||||
<mat-label>Shops</mat-label>
|
||||
<mat-select class="select" formControlName="shopIDs" multiple>
|
||||
<mat-option *ngFor="let shop of shops$ | async" [value]="shop.id">
|
||||
{{ shop.details.name }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div fxFlexFill fxLayout fxLayoutGap="16px">
|
||||
<mat-form-field fxFlex>
|
||||
<input
|
||||
autocomplete="false"
|
||||
formControlName="bin"
|
||||
matInput
|
||||
placeholder="Card Bin"
|
||||
type="string"
|
||||
/>
|
||||
</mat-form-field>
|
||||
<mat-form-field fxFlex>
|
||||
<input
|
||||
autocomplete="false"
|
||||
formControlName="pan"
|
||||
matInput
|
||||
placeholder="Card Pan"
|
||||
type="string"
|
||||
/>
|
||||
</mat-form-field>
|
||||
<mat-form-field fxFlex>
|
||||
<input
|
||||
autocomplete="false"
|
||||
formControlName="rrn"
|
||||
matInput
|
||||
placeholder="Payment RRN"
|
||||
type="string"
|
||||
/>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</form>
|
||||
<div [formGroup]="form" gdColumns="1fr 1fr 1fr 1fr" gdGap="16px">
|
||||
<mat-form-field>
|
||||
<mat-label>Date Range</mat-label>
|
||||
<mat-date-range-input [rangePicker]="picker">
|
||||
<input formControlName="fromTime" matInput matStartDate placeholder="Start Date" />
|
||||
<input formControlName="toTime" matEndDate matInput placeholder="End Date" />
|
||||
</mat-date-range-input>
|
||||
<mat-datepicker-toggle [for]="picker" matSuffix>
|
||||
<mat-icon matDatepickerToggleIcon>keyboard_arrow_down</mat-icon>
|
||||
</mat-datepicker-toggle>
|
||||
<mat-date-range-picker #picker></mat-date-range-picker>
|
||||
</mat-form-field>
|
||||
<mat-form-field>
|
||||
<input
|
||||
autocomplete="false"
|
||||
formControlName="invoiceID"
|
||||
matInput
|
||||
placeholder="Invoice ID"
|
||||
type="string"
|
||||
/>
|
||||
</mat-form-field>
|
||||
<cc-merchant-field formControlName="partyID"></cc-merchant-field>
|
||||
<mat-form-field>
|
||||
<mat-label>Shops</mat-label>
|
||||
<mat-select
|
||||
[disabled]="!form.value['partyID']"
|
||||
class="select"
|
||||
formControlName="shopIDs"
|
||||
multiple
|
||||
>
|
||||
<mat-option *ngFor="let shop of shops$ | async" [value]="shop.id">
|
||||
{{ shop.details.name }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
<mat-form-field>
|
||||
<input
|
||||
autocomplete="false"
|
||||
formControlName="bin"
|
||||
matInput
|
||||
placeholder="Card Bin"
|
||||
type="string"
|
||||
/>
|
||||
</mat-form-field>
|
||||
<mat-form-field>
|
||||
<input
|
||||
autocomplete="false"
|
||||
formControlName="pan"
|
||||
matInput
|
||||
placeholder="Card Pan"
|
||||
type="string"
|
||||
/>
|
||||
</mat-form-field>
|
||||
<mat-form-field>
|
||||
<input
|
||||
autocomplete="false"
|
||||
formControlName="rrn"
|
||||
matInput
|
||||
placeholder="Payment RRN"
|
||||
type="string"
|
||||
/>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
@ -1,3 +0,0 @@
|
||||
.mat-form-field {
|
||||
min-width: 0;
|
||||
}
|
@ -6,48 +6,24 @@ import {
|
||||
OnInit,
|
||||
Output,
|
||||
} from '@angular/core';
|
||||
import { MAT_DATE_FORMATS } from '@angular/material/core';
|
||||
import { untilDestroyed, UntilDestroy } from '@ngneat/until-destroy';
|
||||
import { filter } from 'rxjs/operators';
|
||||
|
||||
import { SearchFiltersParams } from '../search-filters-params';
|
||||
import { MainFilterSearchType, MainSearchType } from './main-filter-search-type';
|
||||
import { PaymentsMainSearchFiltersService } from './payments-main-search-filters.service';
|
||||
|
||||
export const MY_FORMATS = {
|
||||
parse: {
|
||||
dateInput: ['l', 'LL'],
|
||||
},
|
||||
display: {
|
||||
dateInput: 'DD.MM.YYYY',
|
||||
monthYearLabel: 'DD.MM.YYYY',
|
||||
dateA11yLabel: 'DD.MM.YYYY',
|
||||
monthYearA11yLabel: 'DD.MM.YYYY',
|
||||
},
|
||||
};
|
||||
|
||||
@UntilDestroy()
|
||||
@Component({
|
||||
selector: 'cc-payments-main-search-filters',
|
||||
templateUrl: 'payments-main-search-filters.component.html',
|
||||
styleUrls: ['payments-main-search-filters.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
providers: [
|
||||
PaymentsMainSearchFiltersService,
|
||||
{ provide: MAT_DATE_FORMATS, useValue: MY_FORMATS },
|
||||
],
|
||||
providers: [PaymentsMainSearchFiltersService],
|
||||
})
|
||||
export class PaymentsMainSearchFiltersComponent implements OnInit {
|
||||
@Input()
|
||||
initParams: SearchFiltersParams;
|
||||
|
||||
@Input()
|
||||
type: MainFilterSearchType;
|
||||
|
||||
@Output()
|
||||
valueChanges = new EventEmitter<SearchFiltersParams>();
|
||||
|
||||
mainSearchType = MainSearchType;
|
||||
@Input() initParams: SearchFiltersParams;
|
||||
@Output() valueChanges = new EventEmitter<SearchFiltersParams>();
|
||||
|
||||
shops$ = this.paymentsMainSearchFiltersService.shops$;
|
||||
|
||||
form = this.paymentsMainSearchFiltersService.form;
|
||||
|
||||
constructor(private paymentsMainSearchFiltersService: PaymentsMainSearchFiltersService) {
|
||||
@ -58,8 +34,10 @@ export class PaymentsMainSearchFiltersComponent implements OnInit {
|
||||
|
||||
ngOnInit() {
|
||||
this.paymentsMainSearchFiltersService.init(this.initParams);
|
||||
if (this.type.type === MainSearchType.PartySearchFilter) {
|
||||
this.paymentsMainSearchFiltersService.getShops(this.type.partyID);
|
||||
}
|
||||
this.form.controls.partyID.valueChanges
|
||||
.pipe(filter(Boolean), untilDestroyed(this))
|
||||
.subscribe((partyID: string) => {
|
||||
this.paymentsMainSearchFiltersService.getShops(partyID);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
import { MatSelectModule } from '@angular/material/select';
|
||||
|
||||
import { MerchantFieldModule } from '../../merchant-field';
|
||||
import { MerchantSearcherModule } from '../../merchant-searcher';
|
||||
import { PaymentsMainSearchFiltersComponent } from './payments-main-search-filters.component';
|
||||
|
||||
@ -30,6 +31,7 @@ import { PaymentsMainSearchFiltersComponent } from './payments-main-search-filte
|
||||
FlexLayoutModule,
|
||||
MatSelectModule,
|
||||
MerchantSearcherModule,
|
||||
MerchantFieldModule,
|
||||
],
|
||||
declarations: [PaymentsMainSearchFiltersComponent],
|
||||
exports: [PaymentsMainSearchFiltersComponent],
|
||||
|
@ -4,10 +4,6 @@ import { SearchFiltersParams } from '../search-filters-params';
|
||||
|
||||
export const formParamsToSearchParams = (params: SearchFiltersParams): SearchFiltersParams => ({
|
||||
...params,
|
||||
...(params.paymentAmountFrom
|
||||
? { paymentAmountFrom: amountToMinor(params.paymentAmountFrom) }
|
||||
: {}),
|
||||
...(params.paymentAmountTo ? { paymentAmountTo: amountToMinor(params.paymentAmountTo) } : {}),
|
||||
...(params.paymentAmountFrom ? { paymentAmountFrom: toMinor(params.paymentAmountFrom) } : {}),
|
||||
...(params.paymentAmountTo ? { paymentAmountTo: toMinor(params.paymentAmountTo) } : {}),
|
||||
});
|
||||
|
||||
const amountToMinor = (amount: string): string => toMinor(Number(amount)).toString();
|
||||
|
@ -1,109 +0,0 @@
|
||||
import { RadioButtonObject } from '@cc/components/utils';
|
||||
|
||||
export const PAYMENT_STATUSES: RadioButtonObject[] = [
|
||||
{
|
||||
value: 'captured',
|
||||
title: 'Captured',
|
||||
},
|
||||
{
|
||||
value: 'failed',
|
||||
title: 'Failed',
|
||||
},
|
||||
{
|
||||
value: 'pending',
|
||||
title: 'Pending',
|
||||
},
|
||||
{
|
||||
value: 'processed',
|
||||
title: 'Processed',
|
||||
},
|
||||
{
|
||||
value: 'cancelled',
|
||||
title: 'Cancelled',
|
||||
},
|
||||
{
|
||||
value: 'refunded',
|
||||
title: 'Refunded',
|
||||
},
|
||||
];
|
||||
|
||||
export const PAYMENT_METHODS: RadioButtonObject[] = [
|
||||
{
|
||||
value: 'bank_card',
|
||||
title: 'Bank Card',
|
||||
},
|
||||
{
|
||||
value: 'terminal',
|
||||
title: 'Terminal',
|
||||
},
|
||||
{
|
||||
value: 'mobile',
|
||||
title: 'Mobile Commerce',
|
||||
},
|
||||
];
|
||||
|
||||
export const TOKEN_PROVIDERS: RadioButtonObject[] = [
|
||||
{
|
||||
value: 'applepay',
|
||||
title: 'Apple Pay',
|
||||
},
|
||||
{
|
||||
value: 'googlepay',
|
||||
title: 'Google Pay',
|
||||
},
|
||||
{
|
||||
value: 'samsungpay',
|
||||
title: 'Mobile Commerce',
|
||||
},
|
||||
];
|
||||
|
||||
export const PAYMENT_SYSTEMS: RadioButtonObject[] = [
|
||||
{
|
||||
value: 'visa',
|
||||
title: 'Visa',
|
||||
},
|
||||
{
|
||||
value: 'mastercard',
|
||||
title: 'Mastercard',
|
||||
},
|
||||
{
|
||||
value: 'visaelectron',
|
||||
title: 'Visa Electron',
|
||||
},
|
||||
{
|
||||
value: 'maestro',
|
||||
title: 'Maestro',
|
||||
},
|
||||
{
|
||||
value: 'forbrugsforeningen',
|
||||
title: 'Forbrugsforeningen',
|
||||
},
|
||||
{
|
||||
value: 'dankort',
|
||||
title: 'Dankort',
|
||||
},
|
||||
{
|
||||
value: 'amex',
|
||||
title: 'Amex',
|
||||
},
|
||||
{
|
||||
value: 'dinersclub',
|
||||
title: 'Dinersclub',
|
||||
},
|
||||
{
|
||||
value: 'discover',
|
||||
title: 'Discover',
|
||||
},
|
||||
{
|
||||
value: 'unionpay',
|
||||
title: 'UnionPay',
|
||||
},
|
||||
{
|
||||
value: 'jcb',
|
||||
title: 'JCB',
|
||||
},
|
||||
{
|
||||
value: 'nspkmir',
|
||||
title: 'NSPK Mir',
|
||||
},
|
||||
];
|
@ -1,28 +1,53 @@
|
||||
<div fxLayout="column" fxLayoutGap="32px">
|
||||
<h1 class="mat-headline">Other filters</h1>
|
||||
<mat-dialog-content [formGroup]="form" fxLayout="column" fxLayoutGap="24px">
|
||||
<div fxLayout="column" fxLayoutGap="16px">
|
||||
<div fxLayout fxLayoutGap="16px">
|
||||
<mat-form-field fxFlex>
|
||||
<input formControlName="payerEmail" matInput placeholder="Payer email" />
|
||||
</mat-form-field>
|
||||
<mat-form-field fxFlex>
|
||||
<input formControlName="terminalID" matInput placeholder="Terminal ID" />
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div fxLayout fxLayoutGap="16px">
|
||||
<mat-form-field fxFlex>
|
||||
<input formControlName="providerID" matInput placeholder="Provider ID" />
|
||||
</mat-form-field>
|
||||
<div fxFlex></div>
|
||||
</div>
|
||||
<cc-base-dialog title="Other filters">
|
||||
<div [formGroup]="form" fxLayout="column" fxLayoutGap="24px">
|
||||
<div fxLayout fxLayoutGap="16px">
|
||||
<mat-form-field fxFlex>
|
||||
<input formControlName="payerEmail" matInput placeholder="Payer email" />
|
||||
</mat-form-field>
|
||||
<mat-form-field fxFlex>
|
||||
<input formControlName="terminalID" matInput placeholder="Terminal ID" />
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<mat-divider></mat-divider>
|
||||
<h2 class="mat-title">Payment Status</h2>
|
||||
<cc-expandable-radio-group
|
||||
[values]="paymentStatuses"
|
||||
formControlName="paymentStatus"
|
||||
></cc-expandable-radio-group>
|
||||
<mat-form-field fxFlex>
|
||||
<input formControlName="providerID" matInput placeholder="Provider ID" />
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field>
|
||||
<mat-select formControlName="paymentStatus" placeholder="Payment Status">
|
||||
<mat-option [value]="null">any</mat-option>
|
||||
<mat-option *ngFor="let s of paymentStatuses" [value]="s.value">
|
||||
{{ s.key }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field>
|
||||
<mat-select formControlName="paymentMethod" placeholder="Payment Method">
|
||||
<mat-option [value]="null">any</mat-option>
|
||||
<mat-option *ngFor="let pm of paymentMethods" [value]="pm.value">
|
||||
{{ pm.key }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field>
|
||||
<mat-select formControlName="tokenProvider" placeholder="Token Provider">
|
||||
<mat-option [value]="null">any</mat-option>
|
||||
<mat-option *ngFor="let p of tokenProviders$ | async" [value]="p.ref.id">
|
||||
{{ p.data.name }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field>
|
||||
<mat-select formControlName="paymentSystem" placeholder="Payment System">
|
||||
<mat-option [value]="null">any</mat-option>
|
||||
<mat-option *ngFor="let ps of paymentSystems$ | async" [value]="ps.ref.id">
|
||||
{{ ps.data.name }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-divider></mat-divider>
|
||||
<h2 class="mat-title">Domain Revision</h2>
|
||||
<div fxLayout fxLayoutGap="16px">
|
||||
@ -46,27 +71,8 @@
|
||||
<input formControlName="paymentAmountTo" matInput placeholder="To" />
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<mat-divider></mat-divider>
|
||||
<h2 class="mat-title">Payment Method</h2>
|
||||
<cc-expandable-radio-group
|
||||
[values]="paymentMethods"
|
||||
formControlName="paymentMethod"
|
||||
></cc-expandable-radio-group>
|
||||
<mat-divider></mat-divider>
|
||||
<h2 class="mat-title">Token Provider</h2>
|
||||
<cc-expandable-radio-group
|
||||
[values]="tokenProviders"
|
||||
formControlName="tokenProvider"
|
||||
></cc-expandable-radio-group>
|
||||
<mat-divider></mat-divider>
|
||||
<h2 class="mat-title">Payment System</h2>
|
||||
<cc-expandable-radio-group
|
||||
[values]="paymentSystems"
|
||||
formControlName="paymentSystem"
|
||||
></cc-expandable-radio-group>
|
||||
</mat-dialog-content>
|
||||
<mat-dialog-actions fxLayout fxLayoutAlign="space-between">
|
||||
<button mat-button (click)="cancel()">CANCEL</button>
|
||||
</div>
|
||||
<cc-base-dialog-actions>
|
||||
<button [disabled]="form.invalid" color="primary" mat-button (click)="save()">SAVE</button>
|
||||
</mat-dialog-actions>
|
||||
</div>
|
||||
</cc-base-dialog-actions>
|
||||
</cc-base-dialog>
|
||||
|
@ -1,38 +1,46 @@
|
||||
import { ChangeDetectionStrategy, Component, Inject, OnInit } from '@angular/core';
|
||||
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
|
||||
import { ChangeDetectionStrategy, Component, OnInit, Injector } from '@angular/core';
|
||||
import { PaymentToolType, InvoicePaymentStatus } from '@vality/magista-proto';
|
||||
import { BaseDialogSuperclass } from '@vality/ng-core';
|
||||
|
||||
import { getEnumKeyValues } from '../../../../../../utils';
|
||||
import { DomainStoreService } from '../../../../../thrift-services/damsel/domain-store.service';
|
||||
import { SearchFiltersParams } from '../../search-filters-params';
|
||||
import { PAYMENT_METHODS, PAYMENT_STATUSES, PAYMENT_SYSTEMS, TOKEN_PROVIDERS } from './constants';
|
||||
import { OtherFiltersDialogService } from './other-filters-dialog.service';
|
||||
|
||||
@Component({
|
||||
templateUrl: 'other-filters-dialog.component.html',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
providers: [OtherFiltersDialogService],
|
||||
})
|
||||
export class OtherFiltersDialogComponent implements OnInit {
|
||||
paymentStatuses = PAYMENT_STATUSES;
|
||||
paymentMethods = PAYMENT_METHODS;
|
||||
tokenProviders = TOKEN_PROVIDERS;
|
||||
paymentSystems = PAYMENT_SYSTEMS;
|
||||
export class OtherFiltersDialogComponent
|
||||
extends BaseDialogSuperclass<
|
||||
OtherFiltersDialogComponent,
|
||||
SearchFiltersParams,
|
||||
SearchFiltersParams
|
||||
>
|
||||
implements OnInit
|
||||
{
|
||||
paymentStatuses = getEnumKeyValues(InvoicePaymentStatus);
|
||||
paymentMethods = getEnumKeyValues(PaymentToolType);
|
||||
tokenProviders$ = this.domainStoreService.getObjects('payment_token');
|
||||
paymentSystems$ = this.domainStoreService.getObjects('payment_system');
|
||||
|
||||
currentDomainVersion$ = this.paymentsOtherSearchFiltersService.currentDomainVersion$;
|
||||
form = this.paymentsOtherSearchFiltersService.form;
|
||||
|
||||
constructor(
|
||||
private dialogRef: MatDialogRef<OtherFiltersDialogComponent>,
|
||||
injector: Injector,
|
||||
private paymentsOtherSearchFiltersService: OtherFiltersDialogService,
|
||||
@Inject(MAT_DIALOG_DATA) public initParams: SearchFiltersParams
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.form.patchValue(this.initParams);
|
||||
private domainStoreService: DomainStoreService
|
||||
) {
|
||||
super(injector);
|
||||
}
|
||||
|
||||
cancel() {
|
||||
this.dialogRef.close();
|
||||
ngOnInit() {
|
||||
this.form.patchValue(this.dialogData);
|
||||
}
|
||||
|
||||
save() {
|
||||
this.dialogRef.close(this.form.value);
|
||||
this.closeWithSuccess(this.form.value);
|
||||
}
|
||||
}
|
||||
|
@ -10,11 +10,10 @@ import { MatDividerModule } from '@angular/material/divider';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
|
||||
import { ExpandableRadioGroupModule } from '@cc/components/expandable-radio-group';
|
||||
import { MatSelectModule } from '@angular/material/select';
|
||||
import { BaseDialogModule } from '@vality/ng-core';
|
||||
|
||||
import { OtherFiltersDialogComponent } from './other-filters-dialog.component';
|
||||
import { OtherFiltersDialogService } from './other-filters-dialog.service';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
@ -29,10 +28,10 @@ import { OtherFiltersDialogService } from './other-filters-dialog.service';
|
||||
MatDialogModule,
|
||||
MatDividerModule,
|
||||
FlexLayoutModule,
|
||||
ExpandableRadioGroupModule,
|
||||
MatSelectModule,
|
||||
BaseDialogModule,
|
||||
],
|
||||
declarations: [OtherFiltersDialogComponent],
|
||||
exports: [OtherFiltersDialogComponent],
|
||||
providers: [OtherFiltersDialogService],
|
||||
})
|
||||
export class OtherFiltersDialogModule {}
|
||||
|
@ -1,11 +1,11 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { UntypedFormBuilder, Validators } from '@angular/forms';
|
||||
|
||||
import { DomainService } from '../../../../../domain';
|
||||
import { DomainStoreService } from '../../../../../thrift-services/damsel/domain-store.service';
|
||||
|
||||
@Injectable()
|
||||
export class OtherFiltersDialogService {
|
||||
currentDomainVersion$ = this.domainService.version$;
|
||||
currentDomainVersion$ = this.domainStoreService.version$;
|
||||
|
||||
form = this.fb.group({
|
||||
payerEmail: ['', [Validators.email]],
|
||||
@ -18,8 +18,8 @@ export class OtherFiltersDialogService {
|
||||
paymentAmountTo: '',
|
||||
paymentMethod: null,
|
||||
tokenProvider: null,
|
||||
paymentSystemIs: null,
|
||||
paymentSystem: null,
|
||||
});
|
||||
|
||||
constructor(private fb: UntypedFormBuilder, private domainService: DomainService) {}
|
||||
constructor(private fb: UntypedFormBuilder, private domainStoreService: DomainStoreService) {}
|
||||
}
|
||||
|
@ -11,8 +11,6 @@ import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
|
||||
import { ExpandableRadioGroupModule } from '@cc/components/expandable-radio-group';
|
||||
|
||||
import { OtherFiltersDialogModule } from './other-filters-dialog';
|
||||
import { PaymentsOtherSearchFiltersComponent } from './payments-other-search-filters.component';
|
||||
|
||||
@ -29,7 +27,6 @@ import { PaymentsOtherSearchFiltersComponent } from './payments-other-search-fil
|
||||
MatDialogModule,
|
||||
MatDividerModule,
|
||||
FlexLayoutModule,
|
||||
ExpandableRadioGroupModule,
|
||||
OtherFiltersDialogModule,
|
||||
],
|
||||
declarations: [PaymentsOtherSearchFiltersComponent],
|
||||
|
@ -1,7 +1,8 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { Observable, ReplaySubject, Subject } from 'rxjs';
|
||||
import { filter, map, shareReplay, switchMap, take } from 'rxjs/operators';
|
||||
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
|
||||
import { BaseDialogService, BaseDialogResponseStatus } from '@vality/ng-core';
|
||||
import { ReplaySubject } from 'rxjs';
|
||||
import { filter, map, shareReplay, switchMap, first } from 'rxjs/operators';
|
||||
|
||||
import { removeEmptyProperties } from '@cc/utils/remove-empty-properties';
|
||||
|
||||
@ -11,11 +12,10 @@ import { OtherFiltersDialogComponent } from './other-filters-dialog';
|
||||
import { searchParamsToFormParams } from './search-params-to-form-params';
|
||||
import { toFiltersCount } from './to-filters-count';
|
||||
|
||||
@UntilDestroy()
|
||||
@Injectable()
|
||||
export class PaymentsOtherSearchFiltersService {
|
||||
private openFiltersDialog$ = new Subject<Observable<SearchFiltersParams> | void>();
|
||||
|
||||
private formParams = new ReplaySubject<SearchFiltersParams>();
|
||||
private formParams = new ReplaySubject<SearchFiltersParams>(1);
|
||||
|
||||
private countableKeys = [
|
||||
'payerEmail',
|
||||
@ -41,29 +41,22 @@ export class PaymentsOtherSearchFiltersService {
|
||||
shareReplay(1)
|
||||
);
|
||||
|
||||
constructor(private dialog: MatDialog) {
|
||||
this.openFiltersDialog$
|
||||
.pipe(
|
||||
switchMap(() => this.formParams.pipe(shareReplay(1), take(1))),
|
||||
switchMap((formParams) =>
|
||||
this.dialog
|
||||
.open(OtherFiltersDialogComponent, {
|
||||
disableClose: true,
|
||||
width: '552px',
|
||||
data: formParams,
|
||||
})
|
||||
.afterClosed()
|
||||
),
|
||||
filter((v) => !!v)
|
||||
)
|
||||
.subscribe((params) => this.formParams.next(params));
|
||||
}
|
||||
constructor(private baseDialogService: BaseDialogService) {}
|
||||
|
||||
init(params: SearchFiltersParams) {
|
||||
this.formParams.next(searchParamsToFormParams(params));
|
||||
}
|
||||
|
||||
openOtherFiltersDialog() {
|
||||
this.openFiltersDialog$.next();
|
||||
this.formParams
|
||||
.pipe(
|
||||
first(),
|
||||
switchMap((data) =>
|
||||
this.baseDialogService.open(OtherFiltersDialogComponent, data).afterClosed()
|
||||
),
|
||||
filter(({ status }) => status === BaseDialogResponseStatus.Success),
|
||||
untilDestroyed(this)
|
||||
)
|
||||
.subscribe(({ data }) => this.formParams.next(data));
|
||||
}
|
||||
}
|
||||
|
@ -4,10 +4,6 @@ import { SearchFiltersParams } from '../search-filters-params';
|
||||
|
||||
export const searchParamsToFormParams = (params: SearchFiltersParams): SearchFiltersParams => ({
|
||||
...params,
|
||||
...(params.paymentAmountFrom
|
||||
? { paymentAmountFrom: amountToMajor(params.paymentAmountFrom) }
|
||||
: {}),
|
||||
...(params.paymentAmountTo ? { paymentAmountTo: amountToMajor(params.paymentAmountTo) } : {}),
|
||||
...(params.paymentAmountFrom ? { paymentAmountFrom: toMajor(params.paymentAmountFrom) } : {}),
|
||||
...(params.paymentAmountTo ? { paymentAmountTo: toMajor(params.paymentAmountTo) } : {}),
|
||||
});
|
||||
|
||||
const amountToMajor = (amount: string): string => toMajor(Number(amount)).toString();
|
||||
|
@ -1,22 +1,23 @@
|
||||
import { InvoicePaymentStatus, PaymentToolType } from '@vality/magista-proto';
|
||||
|
||||
export interface SearchFiltersParams {
|
||||
partyID?: string;
|
||||
fromTime?: string;
|
||||
toTime?: string;
|
||||
invoiceID?: string;
|
||||
shopID?: string;
|
||||
shopIDs?: string[];
|
||||
payerEmail?: string;
|
||||
terminalID?: string;
|
||||
providerID?: string;
|
||||
rrn?: string;
|
||||
paymentMethod?: string;
|
||||
paymentMethod?: PaymentToolType;
|
||||
paymentSystem?: string;
|
||||
tokenProvider?: string;
|
||||
bin?: string;
|
||||
pan?: string;
|
||||
domainRevisionFrom?: string;
|
||||
domainRevisionTo?: string;
|
||||
paymentAmountFrom?: string;
|
||||
paymentAmountTo?: string;
|
||||
paymentStatus?: string;
|
||||
domainRevisionFrom?: number;
|
||||
domainRevisionTo?: number;
|
||||
paymentAmountFrom?: number;
|
||||
paymentAmountTo?: number;
|
||||
paymentStatus?: InvoicePaymentStatus;
|
||||
}
|
||||
|
@ -1,21 +1,20 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { StatPayment } from '@vality/domain-proto/lib/merch_stat';
|
||||
import { StatPayment } from '@vality/magista-proto';
|
||||
import { cleanObject } from '@vality/ng-core';
|
||||
import * as moment from 'moment';
|
||||
import { Observable } from 'rxjs';
|
||||
import { map, shareReplay } from 'rxjs/operators';
|
||||
import { map } from 'rxjs/operators';
|
||||
|
||||
import { MerchantStatisticsService } from '@cc/app/api/magista';
|
||||
import { FetchResult, PartialFetcher } from '@cc/app/shared/services';
|
||||
import { booleanDelay } from '@cc/utils/boolean-delay';
|
||||
|
||||
import { QueryDsl } from '../../../query-dsl';
|
||||
import { MerchantStatisticsService } from '../../../thrift-services/damsel/merchant-statistics.service';
|
||||
import { SearchFiltersParams } from '../payments-search-filters/search-filters-params';
|
||||
import { SearchFiltersParams } from '../payments-search-filters';
|
||||
|
||||
const SEARCH_LIMIT = 10;
|
||||
|
||||
@Injectable()
|
||||
export class FetchPaymentsService extends PartialFetcher<StatPayment, SearchFiltersParams> {
|
||||
isLoading$ = this.doAction$.pipe(booleanDelay(), shareReplay(1));
|
||||
isLoading$ = this.doAction$;
|
||||
|
||||
constructor(private merchantStatisticsService: MerchantStatisticsService) {
|
||||
super();
|
||||
@ -30,7 +29,6 @@ export class FetchPaymentsService extends PartialFetcher<StatPayment, SearchFilt
|
||||
fromTime,
|
||||
toTime,
|
||||
invoiceID,
|
||||
shopID,
|
||||
shopIDs,
|
||||
payerEmail,
|
||||
terminalID,
|
||||
@ -48,45 +46,41 @@ export class FetchPaymentsService extends PartialFetcher<StatPayment, SearchFilt
|
||||
paymentStatus,
|
||||
} = params;
|
||||
return this.merchantStatisticsService
|
||||
.getPayments({
|
||||
dsl: JSON.stringify({
|
||||
query: {
|
||||
payments: {
|
||||
.SearchPayments(
|
||||
cleanObject(
|
||||
{
|
||||
common_search_query_params: {
|
||||
from_time: moment(fromTime).utc().format(),
|
||||
to_time: moment(toTime).utc().format(),
|
||||
size: SEARCH_LIMIT.toString(),
|
||||
...(partyID ? { merchant_id: partyID } : {}),
|
||||
...(shopID ? { shop_id: shopID } : {}),
|
||||
...(shopIDs?.length ? { shop_ids: shopIDs } : {}),
|
||||
...(domainRevisionFrom
|
||||
? { from_payment_domain_revision: domainRevisionFrom }
|
||||
: {}),
|
||||
...(domainRevisionTo
|
||||
? { to_payment_domain_revision: domainRevisionTo }
|
||||
: {}),
|
||||
...(paymentAmountFrom
|
||||
? { payment_amount_from: paymentAmountFrom }
|
||||
: {}),
|
||||
...(paymentAmountTo ? { payment_amount_to: paymentAmountTo } : {}),
|
||||
...(providerID ? { payment_provider_id: providerID } : {}),
|
||||
...(terminalID ? { payment_terminal_id: terminalID } : {}),
|
||||
...(paymentStatus ? { payment_status: paymentStatus } : {}),
|
||||
...(invoiceID ? { invoice_id: invoiceID } : {}),
|
||||
...(payerEmail ? { payment_email: payerEmail } : {}),
|
||||
...(rrn ? { payment_rrn: rrn } : {}),
|
||||
...(paymentSystem ? { payment_system: paymentSystem } : {}),
|
||||
...(paymentMethod ? { payment_method: paymentMethod } : {}),
|
||||
...(tokenProvider ? { payment_token_provider: tokenProvider } : {}),
|
||||
...(bin ? { payment_first6: bin } : {}),
|
||||
...(pan ? { payment_last4: pan } : {}),
|
||||
limit: SEARCH_LIMIT,
|
||||
continuation_token: continuationToken,
|
||||
party_id: partyID,
|
||||
shop_ids: shopIDs,
|
||||
},
|
||||
invoice_ids: [invoiceID],
|
||||
payment_params: {
|
||||
payment_status: paymentStatus,
|
||||
payment_tool: paymentMethod,
|
||||
payment_email: payerEmail,
|
||||
payment_first6: bin,
|
||||
payment_system: { id: paymentSystem },
|
||||
payment_last4: pan,
|
||||
payment_provider_id: providerID,
|
||||
payment_terminal_id: terminalID,
|
||||
from_payment_domain_revision: domainRevisionFrom,
|
||||
to_payment_domain_revision: domainRevisionTo,
|
||||
payment_rrn: rrn,
|
||||
payment_amount_from: paymentAmountFrom,
|
||||
payment_amount_to: paymentAmountTo,
|
||||
payment_token_provider: { id: tokenProvider },
|
||||
},
|
||||
},
|
||||
} as QueryDsl),
|
||||
...(continuationToken ? { continuation_token: continuationToken } : {}),
|
||||
})
|
||||
['common_search_query_params', 'payment_params']
|
||||
)
|
||||
)
|
||||
.pipe(
|
||||
map(({ data, continuation_token }) => ({
|
||||
result: data.payments,
|
||||
map(({ payments, continuation_token }) => ({
|
||||
result: payments,
|
||||
continuationToken: continuation_token,
|
||||
}))
|
||||
);
|
||||
|
@ -1,2 +1 @@
|
||||
export * from './payments-searcher.module';
|
||||
export * from './searcher-type';
|
||||
|
@ -1,43 +1,41 @@
|
||||
<div fxLayout="column" fxLayoutGap="24px">
|
||||
<mat-card>
|
||||
<mat-card-content fxLayout>
|
||||
<cc-payments-main-search-filters
|
||||
[initParams]="initSearchParams"
|
||||
[type]="mainFilterSearchType"
|
||||
fxFlex="75"
|
||||
(valueChanges)="searchParamsChanges($event)"
|
||||
></cc-payments-main-search-filters>
|
||||
<cc-payments-other-search-filters
|
||||
[initParams]="initSearchParams"
|
||||
class="other-filters-button"
|
||||
fxFlex
|
||||
fxLayoutAlign="center start"
|
||||
(valueChanges)="searchParamsChanges($event)"
|
||||
></cc-payments-other-search-filters>
|
||||
</mat-card-content>
|
||||
<cc-payments-main-search-filters
|
||||
[initParams]="initSearchParams"
|
||||
(valueChanges)="searchParamsChanges($event)"
|
||||
></cc-payments-main-search-filters>
|
||||
<mat-card-footer *ngIf="doAction$ | async">
|
||||
<mat-progress-bar mode="indeterminate"></mat-progress-bar>
|
||||
</mat-card-footer>
|
||||
</mat-card>
|
||||
<ng-container *ngIf="payments$ | async as payments">
|
||||
<cc-empty-search-result
|
||||
*ngIf="!(isLoading$ | async) && payments.length === 0"
|
||||
></cc-empty-search-result>
|
||||
<mat-card *ngIf="payments.length > 0" fxLayout="column" fxLayoutGap="16px">
|
||||
<cc-payments-table
|
||||
[payments]="payments"
|
||||
[type]="tableType"
|
||||
(menuItemSelected$)="paymentMenuItemSelected($event)"
|
||||
></cc-payments-table>
|
||||
<button
|
||||
*ngIf="hasMore$ | async"
|
||||
[disabled]="doAction$ | async"
|
||||
fxFlex="100"
|
||||
mat-button
|
||||
(click)="fetchMore()"
|
||||
>
|
||||
{{ (doAction$ | async) ? 'LOADING...' : 'SHOW MORE' }}
|
||||
</button>
|
||||
</mat-card>
|
||||
</ng-container>
|
||||
<cc-actions>
|
||||
<cc-payments-other-search-filters
|
||||
[initParams]="initSearchParams"
|
||||
(valueChanges)="searchParamsChanges($event)"
|
||||
></cc-payments-other-search-filters>
|
||||
</cc-actions>
|
||||
<!-- TODO: Remove params (and params?.partyID validation) when backend starts working without merchant -->
|
||||
<cc-empty-search-result
|
||||
*ngIf="(!(isLoading$ | async) && (payments$ | async)?.length === 0) || !params?.partyID"
|
||||
[label]="params?.partyID ? 'Payments not found' : 'Merchant input field is required'"
|
||||
></cc-empty-search-result>
|
||||
<mat-card
|
||||
*ngIf="(payments$ | async)?.length > 0 && params?.partyID"
|
||||
fxLayout="column"
|
||||
fxLayoutGap="16px"
|
||||
>
|
||||
<cc-payments-table
|
||||
[payments]="payments$ | async"
|
||||
(menuItemSelected$)="paymentMenuItemSelected($event)"
|
||||
></cc-payments-table>
|
||||
<button
|
||||
*ngIf="hasMore$ | async"
|
||||
[disabled]="doAction$ | async"
|
||||
fxFlex="100"
|
||||
mat-button
|
||||
(click)="fetchMore()"
|
||||
>
|
||||
{{ (doAction$ | async) ? 'LOADING...' : 'SHOW MORE' }}
|
||||
</button>
|
||||
</mat-card>
|
||||
</div>
|
||||
|
@ -1,3 +0,0 @@
|
||||
.other-filters-button {
|
||||
padding-top: 16px;
|
||||
}
|
@ -7,94 +7,46 @@ import {
|
||||
Output,
|
||||
} from '@angular/core';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
import { untilDestroyed, UntilDestroy } from '@ngneat/until-destroy';
|
||||
|
||||
import {
|
||||
MainFilterSearchType,
|
||||
MainSearchType,
|
||||
SearchFiltersParams,
|
||||
} from '../payments-search-filters';
|
||||
import {
|
||||
PaymentActions,
|
||||
PaymentMenuItemEvent,
|
||||
PaymentsTableType,
|
||||
TableType,
|
||||
} from '../payments-table';
|
||||
import { SearchFiltersParams } from '../payments-search-filters';
|
||||
import { PaymentActions, PaymentMenuItemEvent } from '../payments-table';
|
||||
import { FetchPaymentsService } from './fetch-payments.service';
|
||||
import { PaymentsSearcherService } from './payments-searcher.service';
|
||||
import { SearcherType, SearchType } from './searcher-type';
|
||||
|
||||
@UntilDestroy()
|
||||
@Component({
|
||||
selector: 'cc-payments-searcher',
|
||||
templateUrl: 'payments-searcher.component.html',
|
||||
styleUrls: ['payments-searcher.component.scss'],
|
||||
providers: [FetchPaymentsService, PaymentsSearcherService],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class PaymentsSearcherComponent implements OnInit {
|
||||
private searcherType: SearcherType;
|
||||
@Input() initSearchParams: SearchFiltersParams;
|
||||
@Output() searchParamsChanged$: EventEmitter<SearchFiltersParams> = new EventEmitter();
|
||||
@Output() paymentEventFired$: EventEmitter<PaymentMenuItemEvent> = new EventEmitter();
|
||||
|
||||
@Input()
|
||||
set type(type: SearcherType) {
|
||||
this.searcherType = type;
|
||||
switch (type.type) {
|
||||
case SearchType.GlobalSearcher:
|
||||
this.tableType = { type: TableType.GlobalTable };
|
||||
this.mainFilterSearchType = { type: MainSearchType.GlobalSearchFilter };
|
||||
break;
|
||||
case SearchType.PartySearcher:
|
||||
this.tableType = { type: TableType.PartyTable, partyID: type.partyID };
|
||||
this.mainFilterSearchType = {
|
||||
type: MainSearchType.PartySearchFilter,
|
||||
partyID: type.partyID,
|
||||
};
|
||||
break;
|
||||
default:
|
||||
console.error('Wrong search type for payments searcher');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/member-ordering
|
||||
@Input()
|
||||
initSearchParams: SearchFiltersParams;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/member-ordering
|
||||
@Output()
|
||||
searchParamsChanged$: EventEmitter<SearchFiltersParams> = new EventEmitter();
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/member-ordering
|
||||
@Output()
|
||||
paymentEventFired$: EventEmitter<PaymentMenuItemEvent> = new EventEmitter();
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/member-ordering
|
||||
isLoading$ = this.fetchPaymentsService.isLoading$;
|
||||
// eslint-disable-next-line @typescript-eslint/member-ordering
|
||||
doAction$ = this.fetchPaymentsService.doAction$;
|
||||
// eslint-disable-next-line @typescript-eslint/member-ordering
|
||||
payments$ = this.fetchPaymentsService.searchResult$;
|
||||
// eslint-disable-next-line @typescript-eslint/member-ordering
|
||||
hasMore$ = this.fetchPaymentsService.hasMore$;
|
||||
// eslint-disable-next-line @typescript-eslint/member-ordering
|
||||
tableType: PaymentsTableType;
|
||||
// eslint-disable-next-line @typescript-eslint/member-ordering
|
||||
mainFilterSearchType: MainFilterSearchType;
|
||||
params: SearchFiltersParams;
|
||||
|
||||
constructor(
|
||||
private fetchPaymentsService: FetchPaymentsService,
|
||||
private paymentsSearcherService: PaymentsSearcherService,
|
||||
private snackBar: MatSnackBar
|
||||
) {
|
||||
this.paymentsSearcherService.searchParamsChanges$.subscribe((params) => {
|
||||
const searchParams = {
|
||||
...params,
|
||||
partyID:
|
||||
this.mainFilterSearchType.type === MainSearchType.PartySearchFilter
|
||||
? this.searcherType.partyID
|
||||
: params.partyID,
|
||||
};
|
||||
this.fetchPaymentsService.search(searchParams);
|
||||
this.searchParamsChanged$.emit(searchParams);
|
||||
});
|
||||
this.paymentsSearcherService.searchParamsChanges$
|
||||
.pipe(untilDestroyed(this))
|
||||
.subscribe((params) => {
|
||||
this.params = params;
|
||||
// TODO: the partyID is optional, but the backend returns 500
|
||||
if (params.partyID) {
|
||||
this.fetchPaymentsService.search(params);
|
||||
}
|
||||
this.searchParamsChanged$.emit(params);
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
|
@ -11,6 +11,7 @@ import { MatInputModule } from '@angular/material/input';
|
||||
import { MatMenuModule } from '@angular/material/menu';
|
||||
import { MatProgressBarModule } from '@angular/material/progress-bar';
|
||||
import { MatTableModule } from '@angular/material/table';
|
||||
import { ActionsModule } from '@vality/ng-core';
|
||||
|
||||
import { EmptySearchResultModule } from '@cc/components/empty-search-result';
|
||||
|
||||
@ -18,7 +19,7 @@ import {
|
||||
PaymentsMainSearchFiltersModule,
|
||||
PaymentsOtherSearchFiltersModule,
|
||||
} from '../payments-search-filters';
|
||||
import { PaymentsTableModule } from '../payments-table/payments-table.module';
|
||||
import { PaymentsTableModule } from '../payments-table';
|
||||
import { StatusModule } from '../status';
|
||||
import { PaymentsSearcherComponent } from './payments-searcher.component';
|
||||
|
||||
@ -41,6 +42,7 @@ import { PaymentsSearcherComponent } from './payments-searcher.component';
|
||||
MatBadgeModule,
|
||||
PaymentsOtherSearchFiltersModule,
|
||||
EmptySearchResultModule,
|
||||
ActionsModule,
|
||||
],
|
||||
declarations: [PaymentsSearcherComponent],
|
||||
exports: [PaymentsSearcherComponent],
|
||||
|
@ -1,9 +0,0 @@
|
||||
export enum SearchType {
|
||||
PartySearcher = 'PartySearcher',
|
||||
GlobalSearcher = 'GlobalSearcher',
|
||||
}
|
||||
|
||||
export interface SearcherType {
|
||||
type: SearchType;
|
||||
partyID?: string;
|
||||
}
|
@ -1,4 +1,3 @@
|
||||
export * from './payments-table.module';
|
||||
export * from './payments-table';
|
||||
export * from './payment-actions';
|
||||
export * from './payment-menu-item-event';
|
||||
|
@ -26,7 +26,7 @@
|
||||
<ng-container matColumnDef="shop">
|
||||
<th *matHeaderCellDef mat-header-cell>Shop</th>
|
||||
<td *matCellDef="let payment" mat-cell>
|
||||
{{ payment.shop_id | shopName: partyID }}
|
||||
{{ payment.shop_id | shopName: payment.owner_id }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
|
@ -1,10 +1,9 @@
|
||||
import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core';
|
||||
import { InvoiceID, InvoicePaymentID, PartyID } from '@vality/domain-proto/lib/domain';
|
||||
import { StatPayment } from '@vality/domain-proto/lib/merch_stat';
|
||||
import { StatPayment } from '@vality/magista-proto';
|
||||
|
||||
import { PaymentActions } from './payment-actions';
|
||||
import { PaymentMenuItemEvent } from './payment-menu-item-event';
|
||||
import { PaymentsTableType, TableType } from './payments-table';
|
||||
|
||||
@Component({
|
||||
selector: 'cc-payments-table',
|
||||
@ -13,29 +12,11 @@ import { PaymentsTableType, TableType } from './payments-table';
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class PaymentsTableComponent {
|
||||
@Input()
|
||||
payments: StatPayment[];
|
||||
|
||||
partyID: string;
|
||||
|
||||
@Input()
|
||||
set type(type: PaymentsTableType) {
|
||||
this.displayedColumns = [
|
||||
'amount',
|
||||
'status',
|
||||
'createdAt',
|
||||
...(type.type === TableType.PartyTable ? ['shop'] : []),
|
||||
'actions',
|
||||
];
|
||||
this.partyID = type.partyID;
|
||||
}
|
||||
|
||||
@Output()
|
||||
menuItemSelected$: EventEmitter<PaymentMenuItemEvent> = new EventEmitter();
|
||||
@Input() payments: StatPayment[];
|
||||
@Output() menuItemSelected$: EventEmitter<PaymentMenuItemEvent> = new EventEmitter();
|
||||
|
||||
paymentActions = Object.keys(PaymentActions);
|
||||
|
||||
displayedColumns: string[];
|
||||
displayedColumns = ['amount', 'status', 'createdAt', 'shop', 'actions'];
|
||||
|
||||
menuItemSelected(
|
||||
action: string,
|
||||
|
@ -1,9 +0,0 @@
|
||||
export enum TableType {
|
||||
PartyTable = 'PartyTable',
|
||||
GlobalTable = 'GlobalTable',
|
||||
}
|
||||
|
||||
export interface PaymentsTableType {
|
||||
type: TableType;
|
||||
partyID?: string;
|
||||
}
|
@ -1,12 +1,14 @@
|
||||
import { Pipe, PipeTransform } from '@angular/core';
|
||||
|
||||
import { i64ToNumber } from '@cc/utils/i64-to-number';
|
||||
import { Int64 } from '@vality/thrift-ts';
|
||||
|
||||
@Pipe({
|
||||
name: 'ccThriftInt64',
|
||||
})
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
export class ThriftInt64Pipe implements PipeTransform {
|
||||
transform(value: any): any {
|
||||
return i64ToNumber(value.buffer, value.offset);
|
||||
transform(value: Int64 | number): any {
|
||||
return typeof value === 'number' ? value : value.toNumber();
|
||||
}
|
||||
}
|
||||
|
@ -65,7 +65,7 @@ export abstract class PartialFetcher<R, P> {
|
||||
shareReplay(SHARE_REPLAY_CONF)
|
||||
);
|
||||
|
||||
this.doAction$ = progress(actionWithParams$, fetchResult$, true).pipe(
|
||||
this.doAction$ = progress(actionWithParams$, fetchResult$, false).pipe(
|
||||
shareReplay(SHARE_REPLAY_CONF)
|
||||
);
|
||||
this.doSearchAction$ = progress(
|
||||
|
@ -3,7 +3,6 @@ import { NgModule } from '@angular/core';
|
||||
import { ClaimManagementService } from './claim-management.service';
|
||||
import { DomainStoreService } from './domain-store.service';
|
||||
import { DomainService } from './domain.service';
|
||||
import { MerchantStatisticsService } from './merchant-statistics.service';
|
||||
import { PaymentProcessingService } from './payment-processing.service';
|
||||
import { RoutingRulesModule } from './routing-rules';
|
||||
|
||||
@ -12,7 +11,6 @@ import { RoutingRulesModule } from './routing-rules';
|
||||
providers: [
|
||||
DomainService,
|
||||
PaymentProcessingService,
|
||||
MerchantStatisticsService,
|
||||
DomainStoreService,
|
||||
ClaimManagementService,
|
||||
],
|
||||
|
@ -1,21 +0,0 @@
|
||||
import { Injectable, NgZone } from '@angular/core';
|
||||
import { StatRequest, StatResponse } from '@vality/domain-proto/lib/merch_stat';
|
||||
import { StatRequest as ThriftStatRequest } from '@vality/domain-proto/lib/merch_stat/gen-nodejs/merch_stat_types';
|
||||
import * as MerchantStatistics from '@vality/domain-proto/lib/merch_stat/gen-nodejs/MerchantStatistics';
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
import { KeycloakTokenInfoService } from '../../keycloak-token-info.service';
|
||||
import { ThriftService } from '../services/thrift/thrift-service';
|
||||
|
||||
@Injectable()
|
||||
export class MerchantStatisticsService extends ThriftService {
|
||||
constructor(zone: NgZone, keycloakTokenInfoService: KeycloakTokenInfoService) {
|
||||
super(zone, keycloakTokenInfoService, '/stat', MerchantStatistics);
|
||||
}
|
||||
|
||||
getPayments = (req: StatRequest): Observable<StatResponse> =>
|
||||
this.toObservableAction('GetPayments')(new ThriftStatRequest(req));
|
||||
|
||||
getStatistics = (req: StatRequest): Observable<StatResponse> =>
|
||||
this.toObservableAction('GetStatistics')(new ThriftStatRequest(req));
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
<ng-template #content>
|
||||
<div fxLayout="row" fxLayoutAlign="center center">
|
||||
<h2 class="mat-headline empty-result">Search result is empty</h2>
|
||||
<h2 class="mat-headline empty-result">{{ label || 'Search result is empty' }}</h2>
|
||||
</div>
|
||||
</ng-template>
|
||||
|
||||
|
@ -8,4 +8,5 @@ import { coerceBoolean } from 'coerce-property';
|
||||
})
|
||||
export class EmptySearchResultComponent {
|
||||
@Input() @coerceBoolean unwrapped = false;
|
||||
@Input() label: string;
|
||||
}
|
||||
|
@ -1,32 +0,0 @@
|
||||
<div fxLayout="column">
|
||||
<mat-form-field class="mat-form-field-container" fxFlexFill>
|
||||
<mat-radio-group [formControl]="formControl" fxLayout="column" fxLayoutGap="16px">
|
||||
<input [formControl]="control" matInput />
|
||||
<mat-radio-button color="primary">Any</mat-radio-button>
|
||||
<ng-container *ngFor="let v of visibleValues; index as i">
|
||||
<div *ngIf="!(i % 2)" fxLayout fxLayoutGap="16px">
|
||||
<mat-radio-button [value]="v.value" color="primary" fxFlex>{{
|
||||
v.title
|
||||
}}</mat-radio-button>
|
||||
<mat-radio-button
|
||||
*ngIf="values[i + 1]"
|
||||
[value]="values[i + 1].value"
|
||||
color="primary"
|
||||
fxFlex
|
||||
>{{ values[i + 1].title }}</mat-radio-button
|
||||
>
|
||||
</div>
|
||||
</ng-container>
|
||||
</mat-radio-group>
|
||||
</mat-form-field>
|
||||
<div
|
||||
class="show-others"
|
||||
fxLayout
|
||||
fxLayoutAlign="start center"
|
||||
fxLayoutGap="8px"
|
||||
(click)="changeVisibility(!isExpanded)"
|
||||
>
|
||||
<div class="mat-body-1">{{ isExpanded ? 'Show less' : 'Show others' }}</div>
|
||||
<mat-icon>{{ isExpanded ? 'keyboard_arrow_up' : 'keyboard_arrow_down' }}</mat-icon>
|
||||
</div>
|
||||
</div>
|
@ -1,15 +0,0 @@
|
||||
.show-others:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
input {
|
||||
display: none;
|
||||
}
|
||||
|
||||
::ng-deep .mat-form-field-container .mat-form-field-underline {
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
||||
::ng-deep .mat-form-field-container .mat-form-field-infix {
|
||||
border-top-width: 0;
|
||||
}
|
@ -1,80 +0,0 @@
|
||||
import { FocusMonitor } from '@angular/cdk/a11y';
|
||||
import { Platform } from '@angular/cdk/platform';
|
||||
import { AutofillMonitor } from '@angular/cdk/text-field';
|
||||
import {
|
||||
Component,
|
||||
ElementRef,
|
||||
Input,
|
||||
OnChanges,
|
||||
Optional,
|
||||
Self,
|
||||
SimpleChanges,
|
||||
ViewEncapsulation,
|
||||
} from '@angular/core';
|
||||
import { UntypedFormControl, FormGroupDirective, NgControl, NgForm } from '@angular/forms';
|
||||
import { ErrorStateMatcher } from '@angular/material/core';
|
||||
|
||||
import { CustomFormControl, RadioButtonObject } from '../utils';
|
||||
|
||||
@Component({
|
||||
selector: 'cc-expandable-radio-group',
|
||||
templateUrl: 'expandable-radio-group.component.html',
|
||||
styleUrls: ['expandable-radio-group.component.scss'],
|
||||
encapsulation: ViewEncapsulation.Emulated,
|
||||
})
|
||||
export class ExpandableRadioGroupComponent extends CustomFormControl implements OnChanges {
|
||||
form = new UntypedFormControl();
|
||||
|
||||
@Input()
|
||||
values: RadioButtonObject[];
|
||||
|
||||
control = new UntypedFormControl();
|
||||
|
||||
visibleValues: RadioButtonObject[];
|
||||
|
||||
isExpandable = false;
|
||||
|
||||
isExpanded = false;
|
||||
|
||||
constructor(
|
||||
focusMonitor: FocusMonitor,
|
||||
elementRef: ElementRef<HTMLElement>,
|
||||
platform: Platform,
|
||||
@Optional() @Self() ngControl: NgControl,
|
||||
autofillMonitor: AutofillMonitor,
|
||||
defaultErrorStateMatcher: ErrorStateMatcher,
|
||||
@Optional() parentForm: NgForm,
|
||||
@Optional() parentFormGroup: FormGroupDirective
|
||||
) {
|
||||
super(
|
||||
focusMonitor,
|
||||
elementRef,
|
||||
platform,
|
||||
ngControl,
|
||||
autofillMonitor,
|
||||
defaultErrorStateMatcher,
|
||||
parentForm,
|
||||
parentFormGroup
|
||||
);
|
||||
}
|
||||
|
||||
ngOnChanges(changes?: SimpleChanges) {
|
||||
this.isExpandable = changes?.values?.currentValue > 4;
|
||||
this.isExpanded =
|
||||
this.ngControl.value &&
|
||||
!this.values
|
||||
.slice(0, 2)
|
||||
.map((v) => v.value)
|
||||
.includes(this.ngControl.value);
|
||||
this.changeVisibility(this.isExpanded);
|
||||
}
|
||||
|
||||
changeVisibility(value: boolean) {
|
||||
this.isExpanded = value;
|
||||
if (value) {
|
||||
this.visibleValues = this.values;
|
||||
} else {
|
||||
this.visibleValues = this.values.slice(0, 2);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { FlexLayoutModule } from '@angular/flex-layout';
|
||||
import { ReactiveFormsModule } from '@angular/forms';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
import { MatRadioModule } from '@angular/material/radio';
|
||||
|
||||
import { ExpandableRadioGroupComponent } from './expandable-radio-group.component';
|
||||
|
||||
const EXPORTED_DECLARATIONS = [ExpandableRadioGroupComponent];
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
FlexLayoutModule,
|
||||
CommonModule,
|
||||
MatInputModule,
|
||||
MatFormFieldModule,
|
||||
MatRadioModule,
|
||||
ReactiveFormsModule,
|
||||
MatIconModule,
|
||||
],
|
||||
declarations: EXPORTED_DECLARATIONS,
|
||||
exports: EXPORTED_DECLARATIONS,
|
||||
})
|
||||
export class ExpandableRadioGroupModule {}
|
@ -1 +0,0 @@
|
||||
export * from './expandable-radio-group.module';
|
@ -1,3 +1,11 @@
|
||||
import { ValuesType } from 'utility-types';
|
||||
|
||||
export function getEnumKeyValues<E extends Record<PropertyKey, unknown>>(srcEnum: E) {
|
||||
return Object.entries(srcEnum)
|
||||
.filter(([, v]) => typeof v === 'string')
|
||||
.map(([value, key]) => ({ key, value })) as { key: keyof E; value: ValuesType<E> }[];
|
||||
}
|
||||
|
||||
export function getEnumKeys<E extends Record<PropertyKey, unknown>>(srcEnum: E): (keyof E)[] {
|
||||
return Object.values(srcEnum).filter((v) => typeof v === 'string') as string[];
|
||||
}
|
||||
|
@ -1,28 +0,0 @@
|
||||
export const i64ToNumber = (buffer: any, offset: number, allowImprecise = false) => {
|
||||
const b = buffer;
|
||||
const o = offset;
|
||||
// Running sum of octets, doing a 2's complement
|
||||
// eslint-disable-next-line no-bitwise
|
||||
const negate = b[o] & 0x80;
|
||||
let x = 0;
|
||||
let carry = 1;
|
||||
for (let i = 7, m = 1; i >= 0; i--, m *= 256) {
|
||||
let v = b[o + i];
|
||||
// 2's complement for negative numbers
|
||||
if (negate) {
|
||||
// eslint-disable-next-line no-bitwise
|
||||
v = (v ^ 0xff) + carry;
|
||||
// eslint-disable-next-line no-bitwise
|
||||
carry = v >> 8;
|
||||
// eslint-disable-next-line no-bitwise
|
||||
v = v & 0xff;
|
||||
}
|
||||
x += v * m;
|
||||
}
|
||||
// Return Infinity if we've lost integer precision
|
||||
const maxInt = Math.pow(2, 53);
|
||||
if (!allowImprecise && x >= maxInt) {
|
||||
return negate ? -Infinity : Infinity;
|
||||
}
|
||||
return negate ? -x : x;
|
||||
};
|
@ -8,7 +8,6 @@ export * from './wrap-values-to-array';
|
||||
export * from './get-or';
|
||||
export * from './skip-null-values';
|
||||
export * from './thrift-json-converter';
|
||||
export * from './i64-to-number';
|
||||
export * from './to-minor';
|
||||
export * from './to-major';
|
||||
export * from './java-thrift-formatter';
|
||||
|
Loading…
Reference in New Issue
Block a user