IMP-241: Fix create deposits by file minor to major amount and when an error occurs (#368)

This commit is contained in:
Rinat Arsaev 2024-06-19 15:04:02 +05:00 committed by GitHub
parent 6876deeab4
commit ba1e7c266b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 65 additions and 35 deletions

8
package-lock.json generated
View File

@ -26,7 +26,7 @@
"@vality/fistful-proto": "2.0.1-6600be9.0",
"@vality/machinegun-proto": "1.0.0",
"@vality/magista-proto": "2.0.2-28d11b9.0",
"@vality/ng-core": "17.2.1-pr-64-42bc8db.0",
"@vality/ng-core": "17.2.1-pr-64-0a6dad2.0",
"@vality/ng-thrift": "17.0.1-pr-5-2ce0f11.0",
"@vality/payout-manager-proto": "2.0.1-eb4091a.0",
"@vality/repairer-proto": "2.0.2-07b73e9.0",
@ -6462,9 +6462,9 @@
"integrity": "sha512-BsDy5ejotfTtUlwuoX3kz+PYJ5NSTW6m5ZRGv+p5HaKXSjR7tserPdv0q133Wp4T+sg0ED0Qr9Peqsrn+9XlDQ=="
},
"node_modules/@vality/ng-core": {
"version": "17.2.1-pr-64-42bc8db.0",
"resolved": "https://registry.npmjs.org/@vality/ng-core/-/ng-core-17.2.1-pr-64-42bc8db.0.tgz",
"integrity": "sha512-DWninh/LAka4i5vaQ/8TOCigTwEDdsMMe5tMg1F8N+xE8OuxuoqQPBjnpzFjULYL59fJg8ghppy21ikCY6ffUw==",
"version": "17.2.1-pr-64-0a6dad2.0",
"resolved": "https://registry.npmjs.org/@vality/ng-core/-/ng-core-17.2.1-pr-64-0a6dad2.0.tgz",
"integrity": "sha512-8MdMpFhhuJDmxp6rxUphfOOetEU3y+PV0Q23n4PfPRQo92bnPuI9G9tKnGOGZkmg/BrlGidFKNlkBp/lFH8DUg==",
"dependencies": {
"@angular/material-date-fns-adapter": "^17.2.0",
"@ng-matero/extensions": "^17.1.0",

View File

@ -34,7 +34,7 @@
"@vality/fistful-proto": "2.0.1-6600be9.0",
"@vality/machinegun-proto": "1.0.0",
"@vality/magista-proto": "2.0.2-28d11b9.0",
"@vality/ng-core": "17.2.1-pr-64-42bc8db.0",
"@vality/ng-core": "17.2.1-pr-64-0a6dad2.0",
"@vality/ng-thrift": "17.0.1-pr-5-2ce0f11.0",
"@vality/payout-manager-proto": "2.0.1-eb4091a.0",
"@vality/repairer-proto": "2.0.2-07b73e9.0",

View File

@ -1,8 +1,9 @@
<v-dialog [progress]="progress$ | async" title="Create chargebacks">
<cc-upload-csv
[(selected)]="selected"
[errors]="errors"
[formatDescription]="['reason.category: fraud, dispute, authorisation, processing_error']"
[props]="props"
(selectedChange)="selected = $event"
></cc-upload-csv>
<v-dialog-actions>
<button

View File

@ -29,6 +29,7 @@ export class CreateChargebacksByFileDialogComponent extends DialogSuperclass<
selected: CsvChargeback[] = [];
successfullyChargebacks: InvoicePaymentChargeback[] = [];
props = CSV_CHARGEBACK_PROPS;
errors?: Map<CsvChargeback, unknown>;
constructor(
private invoicingService: InvoicingService,
@ -59,6 +60,9 @@ export class CreateChargebacksByFileDialogComponent extends DialogSuperclass<
`Creating ${chargebacksWithError.length} chargebacks ended in an error. They were re-selected in the table.`,
);
this.selected = chargebacksWithError.map((c) => selected[c.index]);
this.errors = new Map(
chargebacksWithError.map((c) => [selected[c.index], c.error]),
);
} else {
this.log.successOperation('create', 'chargebacks');
this.closeWithSuccess();

View File

@ -1,5 +1,5 @@
<v-dialog [progress]="progress$ | async" title="Create deposits">
<cc-upload-csv [props]="props" (selectedChange)="selected = $event"></cc-upload-csv>
<cc-upload-csv [(selected)]="selected" [errors]="errors" [props]="props"></cc-upload-csv>
<v-dialog-actions>
<button
*ngIf="successfully?.length"
@ -7,7 +7,7 @@
mat-button
(click)="closeWithSuccess()"
>
Close and find {{ successfully.length }} successful deposits
Close and reload list ({{ successfully.length }} successful)
</button>
<button
[disabled]="!selected?.length || !!(progress$ | async)"

View File

@ -10,7 +10,7 @@ import {
DialogModule,
forkJoinToResult,
} from '@vality/ng-core';
import { BehaviorSubject } from 'rxjs';
import { BehaviorSubject, switchMap } from 'rxjs';
import { UploadCsvComponent } from '../../../../../components/upload-csv';
import { DepositManagementService } from '../../../../api/deposit';
@ -35,6 +35,7 @@ export class CreateDepositsByFileDialogComponent extends DialogSuperclass<
selected: CsvDeposit[] = [];
successfully: DepositState[] = [];
props = CSV_DEPOSIT_PROPS;
errors?: Map<CsvDeposit, unknown>;
constructor(
private depositManagementService: DepositManagementService,
@ -49,8 +50,8 @@ export class CreateDepositsByFileDialogComponent extends DialogSuperclass<
const selected = this.selected;
forkJoinToResult(
selected.map((c) =>
this.depositManagementService.Create(
...runInInjectionContext(this.injector, () => getCreateDepositArgs(c)),
runInInjectionContext(this.injector, () => getCreateDepositArgs(c)).pipe(
switchMap((params) => this.depositManagementService.Create(...params)),
),
),
this.progress$,
@ -66,6 +67,7 @@ export class CreateDepositsByFileDialogComponent extends DialogSuperclass<
`Creating ${withError.length} deposits ended in an error. They were re-selected in the table.`,
);
this.selected = withError.map((c) => selected[c.index]);
this.errors = new Map(withError.map((c) => [selected[c.index], c.error]));
} else {
this.log.successOperation('create', 'deposits');
this.closeWithSuccess();

View File

@ -1,29 +1,38 @@
import { inject } from '@angular/core';
import { CodegenClient } from '@vality/fistful-proto/internal/deposit-Management';
import { clean } from '@vality/ng-core';
import { map } from 'rxjs/operators';
import { UserInfoBasedIdGeneratorService } from '../../../../../shared/services';
import {
UserInfoBasedIdGeneratorService,
AmountCurrencyService,
} from '../../../../../shared/services';
import { CsvDeposit } from '../types/csv-deposit';
export function getCreateDepositArgs(c: CsvDeposit): Parameters<CodegenClient['Create']> {
export function getCreateDepositArgs(c: CsvDeposit) {
const userInfoBasedIdGeneratorService = inject(UserInfoBasedIdGeneratorService);
return [
clean(
{
id: userInfoBasedIdGeneratorService.getUsernameBasedId(),
wallet_id: c.wallet_id,
source_id: c.source_id,
body: {
amount: Number(c['body.amount']),
currency: { symbolic_code: c['body.currency'] },
},
external_id: c.external_id,
metadata: c.metadata ? JSON.parse(c.metadata) : undefined,
description: c.description,
},
false,
true,
const amountCurrencyService = inject(AmountCurrencyService);
return amountCurrencyService.toMinor(Number(c['body.amount']), c['body.currency']).pipe(
map(
(amount): Parameters<CodegenClient['Create']> => [
clean(
{
id: userInfoBasedIdGeneratorService.getUsernameBasedId(),
wallet_id: c.wallet_id,
source_id: c.source_id,
body: {
amount,
currency: { symbolic_code: c['body.currency'] },
},
external_id: c.external_id,
metadata: c.metadata ? JSON.parse(c.metadata) : undefined,
description: c.description,
},
false,
true,
),
new Map(),
],
),
new Map(),
];
);
}

View File

@ -1,5 +1,5 @@
import { Injectable } from '@angular/core';
import { toMajorByExponent } from '@vality/ng-core';
import { toMajorByExponent, toMinorByExponent } from '@vality/ng-core';
import { map, first } from 'rxjs/operators';
import { DomainStoreService } from '@cc/app/api/domain-config';
@ -17,6 +17,13 @@ export class AmountCurrencyService {
);
}
toMinor(amount: number, symbolicCode: string) {
return this.getCurrency(symbolicCode).pipe(
first(),
map((currency) => toMinorByExponent(amount, currency?.data?.exponent)),
);
}
getCurrency(symbolicCode: string) {
return this.domainStoreService
.getObjects('currency')

View File

@ -71,6 +71,7 @@ function getCsvObjectErrors<R extends string, O extends string>(
export class UploadCsvComponent<R extends string, O extends string> implements OnInit {
props = input<CsvProps<R, O>>({});
formatDescription = input<string[]>();
errors = input<Map<CsvProps<R, O>, { name?: string; message?: string }>>();
selected = input<CsvObject<R, O>[]>([]);
@Output() selectedChange = new EventEmitter<CsvObject<R, O>[]>();
@ -116,12 +117,18 @@ export class UploadCsvComponent<R extends string, O extends string> implements O
}),
shareReplay({ refCount: true, bufferSize: 1 }),
);
columns = computed<Column<CsvObject<R, O>>[]>(() =>
this.propsList().map((p) => ({
columns = computed<Column<CsvObject<R, O>>[]>(() => [
...this.propsList().map((p) => ({
field: p,
header: startCase(p),
})),
);
...(this.errors()?.size
? [
{ field: 'error_code', formatter: (d) => this.errors().get(d)?.name },
{ field: 'error_message', formatter: (d) => this.errors().get(d)?.message },
]
: []),
]);
constructor(
private log: NotifyLogService,