FE-672: documents refactoring (#220)

This commit is contained in:
Alexandra Usacheva 2018-09-28 14:55:44 +03:00 committed by GitHub
parent 2cd7f01551
commit 54ce986a0b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 67 additions and 551 deletions

View File

@ -1,10 +1,15 @@
import { FileMeta } from './file-meta';
export enum ReportType {
provisionOfService = 'provisionOfService',
paymentRegistry = 'paymentRegistry'
}
export class Report {
public id: number;
public createdAt: string;
public fromTime: string;
public toTime: string;
public type: string;
public type: ReportType;
public files: FileMeta[];
}

View File

@ -17,7 +17,7 @@ import {
InvoiceSearchResult,
PaymentSearchResult,
PayoutSearchResult,
RefundsSearchResult
RefundsSearchResult, Report
} from './model';
@Injectable()
@ -52,7 +52,7 @@ export class SearchService {
.map((res) => res.json());
}
public getReports(shopID: string, reportParams: SearchReportParams): Observable<any> { // todo type
public getReports(shopID: string, reportParams: SearchReportParams): Observable<Report[]> {
const search = this.toSearchParams(reportParams);
return this.http.get(`${this.config.capiUrl}/shops/${shopID}/reports`, {search})
.map((res) => res.json());

View File

@ -3,9 +3,9 @@
.x_panel
.x_content
ul.nav.nav-tabs.bar_tabs
li.hand-cursor([routerLink]="['reports']", [routerLinkActive]="['active']")
li.hand-cursor([routerLink]="['reports', reportTypes.provisionOfService]", [routerLinkActive]="['active']")
a Акты
li.hand-cursor([routerLink]="['registry']", [routerLinkActive]="['active']")
li.hand-cursor([routerLink]="['reports', reportTypes.paymentRegistry]", [routerLinkActive]="['active']")
a Реестр операций
.tab-content
router-outlet

View File

@ -1,8 +1,9 @@
import { Component } from '@angular/core';
import { ReportType } from 'koffing/backend';
@Component({
templateUrl: 'documents.component.pug'
})
export class DocumentsComponent {
public reportTypes = ReportType;
}

View File

@ -5,11 +5,10 @@ import { BrowserModule } from '@angular/platform-browser';
import { CommonModule } from 'koffing/common/common.module';
import { BackendModule } from 'koffing/backend/backend.module';
import { DocumentsComponent } from './documents.component';
import { SearchReportsResultComponent } from './reports/search-result/search-reports-result.component';
import { ReportFilesComponent } from './reports/search-result/report-files/report-files.component';
import { ReportTypePipe } from './reports/search-result/report-type.pipe';
import { ReportsComponent } from './reports/reports.component';
import { SearchReportsResultComponent } from './reports/search-reports-result/search-reports-result.component';
import { ReportFilesComponent } from './reports/search-reports-result/report-files/report-files.component';
import { ReportTypePipe } from './reports/search-reports-result/report-type.pipe';
import { RegistryComponent } from './registry/registry.component';
@NgModule({
imports: [
@ -20,11 +19,10 @@ import { RegistryComponent } from './registry/registry.component';
],
declarations: [
DocumentsComponent,
ReportsComponent,
SearchReportsResultComponent,
ReportFilesComponent,
ReportTypePipe,
RegistryComponent,
ReportsComponent
]
})
export class DocumentsModule { }

View File

@ -1,8 +0,0 @@
export class Cell {
public v: any;
public t: string;
public s: object;
public w: string;
public h: string;
public r: string;
}

View File

@ -1,65 +0,0 @@
import { Injectable } from '@angular/core';
import { saveAs } from 'file-saver';
import { Cell } from './cell';
declare const XLSX: any;
@Injectable()
export class ExcelService {
public worksheetFromArrayOfArrays(data: any[], offsetRow?: number, cellStyle?: object): object {
offsetRow = offsetRow || 0;
const ws = {};
const range = {s: {c: 10000000, r: 10000000}, e: {c: 0, r: 0 }};
for (let R = 0; R !== data.length; ++R) {
for (let C = 0; C !== data[R].length; ++C) {
const cell = new Cell();
cell.v = data[R][C];
if (cell.v === null) {
continue;
}
if (typeof cell.v === 'number') {
cell.t = 'n';
} else if (typeof cell.v === 'boolean') {
cell.t = 'b';
} else {
cell.t = 's';
}
if (cellStyle) {
cell.s = cellStyle;
}
const cellRef = XLSX.utils.encode_cell({r: R + offsetRow, c: C});
ws[cellRef] = cell;
if (range.s.r > R) { range.s.r = R; }
if (range.s.c > C) { range.s.c = C; }
if (range.e.r < R) { range.e.r = R; }
if (range.e.c < C) { range.e.c = C; }
}
}
if (range.s.c < 10000000) {
range.e.r = range.e.r + offsetRow;
ws['!ref'] = XLSX.utils.encode_range(range.s, range.e);
}
return ws;
}
public getEncodeRange(countRows: number, countsColumns: number): string {
const range = {s: {r: 0, c: 0}, e: {r: countRows - 1, c: countsColumns - 1}};
return XLSX.utils.encode_range(range.s, range.e);
}
public saveAsXLSX(workbook: any, fileName: string) {
function s2ab(s: any) {
const buf = new ArrayBuffer(s.length);
const view = new Uint8Array(buf);
for (let i = 0; i !== s.length; ++i) {
view[i] = s.charCodeAt(i) & 0xFF;
}
return buf;
}
const wbout = XLSX.write(workbook, {bookType: 'xlsx', bookSST: false, type: 'binary'});
saveAs(new Blob([s2ab(wbout)], {type: 'application/octet-stream'}), `${fileName}.xlsx`);
}
}

View File

@ -1,9 +0,0 @@
export class Workbook {
public SheetNames: string[];
public Sheets: object;
constructor() {
this.SheetNames = [];
this.Sheets = {};
}
}

View File

@ -1,9 +0,0 @@
export class PaymentRegistryItem {
public paymentDate: string;
public invoiceID: string;
public amount: number;
public fee: number;
public userEmail: string;
public product: string;
public description: string;
}

View File

@ -1,5 +0,0 @@
export class RefundRegistryItem {
public refundDate: string;
public invoiceID: string;
public amount: number;
}

View File

@ -1,171 +0,0 @@
import { Injectable } from '@angular/core';
import { ceil, concat, get } from 'lodash';
import { Observable, Observer } from 'rxjs';
import {
PAYMENT_STATUS,
Invoice,
Payment,
RussianLegalEntity,
PaymentResourcePayer,
SearchPaymentsParams,
PaymentSearchResult,
SearchInvoicesParams,
RefundsSearchResult,
Refund
} from 'koffing/backend';
import { ShopService } from 'koffing/backend/shop.service';
import { ContractService } from 'koffing/backend/contract.service';
import { SearchService } from 'koffing/backend/search.service';
import { SearchParams } from './search-params';
import { Registry } from './registry';
import { PaymentRegistryItem } from './payment-registry-item';
import { RefundRegistryItem } from './refund-registry-item';
import { InvoiceSearchResult } from 'koffing/backend/model/invoice-search-result';
import { SearchRefundsParams } from 'koffing/backend/requests';
type SearchFn<P, R> = (shopID: string, paymentsParams: P) => Observable<R>;
@Injectable()
export class RegistryDataService {
private limit: number = 1000;
constructor(public searchService: SearchService,
private contractService: ContractService,
private shopService: ShopService) {
}
public getRegistry(shopID: string, fromTime: Date, toTime: Date): Observable<Registry> {
const paymentsSearchParams: SearchPaymentsParams = {
fromTime,
toTime,
limit: this.limit,
paymentStatus: PAYMENT_STATUS.captured
};
const refundsSearchParams: SearchRefundsParams = {
fromTime,
toTime,
limit: this.limit,
refundStatus: 'succeeded'
};
const invoicesSearchParams = new SearchParams(fromTime, toTime, this.limit);
const payments$ = this.loadAllData<SearchPaymentsParams, PaymentSearchResult, Payment>(this.searchService.searchPayments, this.searchService, shopID, paymentsSearchParams);
const refunds$ = this.loadAllOffsetData<SearchRefundsParams, RefundsSearchResult, Refund>(this.searchService.searchRefunds, this.searchService, shopID, refundsSearchParams);
const invoices$ = this.loadAllData<SearchInvoicesParams, InvoiceSearchResult, Invoice>(this.searchService.searchInvoices, this.searchService, shopID, invoicesSearchParams);
const shop$ = this.shopService.getShopByID(shopID);
return Observable.create((observer: Observer<Registry>) => {
Observable.forkJoin([payments$, refunds$, invoices$, shop$]).subscribe((response: any[]) => {
const [payments, refunds, invoices, shop] = response;
const contract$ = this.contractService.getContractByID(shop.contractID);
return contract$.subscribe((contract) => {
const {registeredName: client} = contract.contractor as RussianLegalEntity;
const capturedPaymentItems = this.getPaymentRegistryItems(payments, invoices);
const refundedPaymentItems = this.getRefundRegistryItems(refunds);
observer.next(new Registry(fromTime, toTime, client, capturedPaymentItems, refundedPaymentItems));
observer.complete();
});
});
});
}
// problem with parallel load - some payments may not load (because of historicity, both parts may not contain payment)
private loadAllDataParallel<Params extends { fromTime: Date, toTime: Date }, Result extends { continuationToken?: string, result: Item[] }, Item>(fn: SearchFn<Params, Result>, context: any, shopID: string, params: Params, countRequests: number = 1): Observable<Item[]> {
const fullIntervalMs = params.toTime.getTime() - params.fromTime.getTime();
if (fullIntervalMs < 24 * 60 * 60 * 1000 || fullIntervalMs < countRequests * 1000) {
countRequests = 1;
}
const intervalMs = Math.floor(fullIntervalMs / countRequests / 1000) * 1000;
const streamRequests$: Array<Observable<Item[]>> = [];
for (let i = 1, lastToTime = params.fromTime; i <= countRequests; i++) {
const nextParams = Object.assign({}, params, {});
nextParams.fromTime = lastToTime;
nextParams.toTime = i === countRequests ? params.toTime : new Date(lastToTime.getTime() + intervalMs);
lastToTime = nextParams.toTime;
const request$ = this.loadAllData<Params, Result, Item>(fn, context, shopID, nextParams);
streamRequests$.push(request$);
}
let searchData: Item[] = [];
return Observable.create((observer: Observer<Item[]>) => {
Observable.forkJoin(streamRequests$).subscribe((streamData: Item[][]) => {
streamData.forEach((data) => searchData = concat(searchData, data));
observer.next(searchData);
observer.complete();
});
});
}
private loadAllData<Params extends { fromTime: Date, toTime: Date }, Result extends { continuationToken?: string, result: Item[] }, Item>(fn: SearchFn<Params, Result>, context: any, shopID: string, params: Params): Observable<Item[]> {
return Observable.create((observer: Observer<Item[]>) => {
const request$ = fn.apply(context, [shopID, params]);
request$.subscribe((streamData: Result) => {
if (streamData.continuationToken) {
const nextParams: Params = Object.assign({}, params, {continuationToken: streamData.continuationToken});
this.loadAllData(fn, context, shopID, nextParams).subscribe(
(result: Item[]) => {
const data = concat(streamData.result, result);
observer.next(data);
observer.complete();
}
);
} else {
observer.next(streamData.result);
observer.complete();
}
});
});
}
private loadAllOffsetData<Params extends { offset?: number, limit: number }, Result extends { totalCount: number, result: Item[] }, Item>(fn: SearchFn<Params, Result>, context: any, shopID: string, params: Params): Observable<Item[]> {
return Observable.create((observer: Observer<Item[]>) => {
fn.apply(context, [shopID, params]).subscribe((response: Result) => {
let searchData: Item[] = response.result;
const countRequests = ceil(response.totalCount / params.limit);
if (countRequests > 1) {
const streamRequests$: Array<Observable<Result>> = [];
for (let i = 1; i < countRequests; i++) {
const nextParams = Object.assign({}, params, {offset: params.limit * i});
const request$ = fn.apply(context, [shopID, nextParams]);
streamRequests$.push(request$);
}
Observable.forkJoin(streamRequests$).subscribe((streamData: Result[]) => {
streamData.forEach((data) => searchData = concat(searchData, data.result));
observer.next(searchData);
observer.complete();
});
} else {
observer.next(searchData);
observer.complete();
}
});
});
}
private getPaymentRegistryItems(payments: Payment[], invoices: Invoice[]): PaymentRegistryItem[] {
// optimization: get 'map-object'[key] much faster than 'array'.find({id} => id === key)
const invoicesObject: { [id: string]: Invoice } = invoices.reduce((map, invoice) => {
map[invoice.id] = invoice;
return map;
}, {});
return payments.map((payment) => {
const invoice = invoicesObject[payment.invoiceID];
return {
invoiceID: `${payment.invoiceID}.${payment.id}`,
paymentDate: payment.statusChangedAt || payment.createdAt,
amount: payment.amount,
fee: payment.fee,
userEmail: payment.payer.payerType === 'PaymentResourcePayer' ? (payment.payer as PaymentResourcePayer).contactInfo.email : '',
product: get(invoice, 'product', ''),
description: get(invoice, 'description', ''),
};
});
}
private getRefundRegistryItems(refunds: Refund[]): RefundRegistryItem[] {
return refunds.map((refund) => ({
invoiceID: `${refund.invoiceID}.${refund.paymentID}`,
refundDate: refund.createdAt,
amount: refund.amount
}));
}
}

View File

@ -1,157 +0,0 @@
import { Injectable } from '@angular/core';
import { merge, map } from 'lodash';
import * as moment from 'moment';
import { CurrencyService } from 'koffing/common/currency.service';
import { Registry } from './registry';
import { PaymentRegistryItem } from './payment-registry-item';
import { RefundRegistryItem } from './refund-registry-item';
import { Workbook } from './excel/workbook';
import { ExcelService } from './excel/excel.service';
import { WorksheetProperties } from './worksheet-properties';
@Injectable()
export class RegistryExportService {
private capturedPaymentsWorksheet: WorksheetProperties = {
name: 'Успешные платежи',
headerSizes: {rows: 7, columns: 7}
};
private refundedPaymentsWorksheet: WorksheetProperties = {
name: 'Возвраты',
headerSizes: {rows: 7, columns: 6}
};
private cellBorder = {
left: {style: 'thin', color: {auto: 1}},
right: {style: 'thin', color: {auto: 1}},
top: {style: 'thin', color: {auto: 1}},
bottom: {style: 'thin', color: {auto: 1}}
};
private alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
constructor(
private excelService: ExcelService
) {
}
public exportRegistryToXLSX(registry: Registry) {
const workbook = this.createWorkbookFromRegistry(registry);
const fileName = `Реестр операций ${this.getStringifyDateInterval(registry.fromTime, registry.toTime)}`;
this.excelService.saveAsXLSX(workbook, fileName);
}
private getStringifyDateInterval(fromTime: Date, toTime: Date): string {
return `с ${moment(fromTime).format('DD.MM.YY')} по ${moment(toTime).format('DD.MM.YY')}`;
}
private createWorkbookFromRegistry(registry: Registry): Workbook {
const workbook = new Workbook();
workbook.SheetNames.push(this.capturedPaymentsWorksheet.name);
workbook.SheetNames.push(this.refundedPaymentsWorksheet.name);
workbook.Sheets[this.capturedPaymentsWorksheet.name] = this.createCapturedPaymentsWorksheetFromRegistry(registry);
workbook.Sheets[this.refundedPaymentsWorksheet.name] = this.createRefundedPaymentsWorksheetFromRegistry(registry);
return workbook;
}
private createCapturedPaymentsWorksheetFromRegistry(registry: Registry): object {
let worksheet = {};
worksheet = merge(worksheet, this.createCapturedPaymentsHeader(registry));
worksheet = merge(worksheet, this.createCapturedPaymentsBody(registry.capturedPaymentItems));
return worksheet;
}
private createCapturedPaymentsHeader(registry: Registry): object {
return this.createHeader({
title: 'Успешные платежи за период',
header: 'Выполнено переводов в пользу клиента за период:',
client: registry.client
},
registry,
[10, 18, 20, 18, 18, 30, 30, 50],
[
'№ п/п',
'Дата платежа',
'ID инвойса и платежа',
'Принято, руб.',
'К зачислению, руб.',
'Email плательщика',
'Наименование товара',
'Описание предоставленных товаров или услуг'
]);
}
private createCapturedPaymentsBody(registryItems: PaymentRegistryItem[]): object {
const offsetRow = this.capturedPaymentsWorksheet.headerSizes.rows;
const arrayOfArrays = map(registryItems, (item: PaymentRegistryItem, index) => ([
index + 1,
moment(item.paymentDate).format('DD.MM.YY HH:mm:ss'),
item.invoiceID,
CurrencyService.toMajor(item.amount),
CurrencyService.toMajor(item.amount - (item.fee || 0)),
item.userEmail,
item.product,
item.description
]));
return this.excelService.worksheetFromArrayOfArrays(arrayOfArrays, offsetRow, {border: this.cellBorder});
}
private createRefundedPaymentsWorksheetFromRegistry(registry: Registry): object {
let worksheet = {};
worksheet = merge(worksheet, this.createRefundedPaymentsHeader(registry));
worksheet = merge(worksheet, this.createRefundedPaymentsBody(registry.refundedPaymentItems));
return worksheet;
}
private createRefundedPaymentsHeader(registry: Registry): object {
return this.createHeader({
title: 'Возвраты за период',
header: 'Выполнено возвратов за период:',
client: registry.client
}, registry,
[10, 18, 20, 18],
['№ п/п', 'Дата возврата', 'ID инвойса и платежа', 'Возвращено, руб.']);
}
private createHeader(titles: { title: string, header: string, client: string }, interval: { fromTime: Date, toTime: Date }, colWidths: number[], tableHeader: string[]) {
const tableHeaderLastColNum = tableHeader.length - 1;
return {
'A1': {
v: `${titles.title} с ${this.getStringifyDateInterval(interval.fromTime, interval.toTime)}`,
s: {alignment: {horizontal: 'center', vertical: 'center'}, font: {bold: true}}
},
'A3': {v: 'НКО:', s: {font: {bold: true}}},
'B3': {v: 'НКО «ЭПС» (ООО)'},
'A4': {v: 'Клиент:', s: {font: {bold: true}}},
'B4': {v: titles.client},
'A6': {
v: titles.header,
s: {alignment: {horizontal: 'center', vertical: 'center'}}
},
...this.createTableHeader(tableHeader, 7),
'!ref': this.excelService.getEncodeRange(this.capturedPaymentsWorksheet.headerSizes.rows, this.capturedPaymentsWorksheet.headerSizes.columns),
'!cols': colWidths.map(width => ({wch: width})),
'!merges': [
{s: {r: 0, c: 0}, e: {r: 0, c: tableHeaderLastColNum}},
{s: {r: 5, c: 0}, e: {r: 5, c: tableHeaderLastColNum}}
]
};
}
private createTableHeader(tableHeader: string[], rowNum: number): object {
const style = {font: {bold: true}, border: this.cellBorder};
const tableHeaderObject: object = {};
tableHeader.forEach((item, idx) => tableHeaderObject[this.alphabet[idx] + rowNum] = {v: item, s: style});
return tableHeaderObject;
}
private createRefundedPaymentsBody(registryItems: RefundRegistryItem[]): object {
const offsetRow = this.capturedPaymentsWorksheet.headerSizes.rows;
const arrayOfArrays = map(registryItems, (item: RefundRegistryItem, index) => ([
index + 1,
moment(item.refundDate).format('DD.MM.YY HH:mm:ss'),
item.invoiceID,
CurrencyService.toMajor(item.amount)
]));
return this.excelService.worksheetFromArrayOfArrays(arrayOfArrays, offsetRow, {border: this.cellBorder});
}
}

View File

@ -1,9 +0,0 @@
.row
.col-xs-12.col-sm-6
kof-date-range((onSelect)="selectDateRange($event)")
.row
.col-xs-12
button.btn.btn-default([disabled]="isLoading", (click)="exportRegistryToXLSX()")
i.fa.fa-cog.fa-spin.fa-1x.fa-fw(*ngIf="isLoading")
span Скачать как Excel-файл

View File

@ -1,46 +0,0 @@
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { DateRange } from 'koffing/common/date-range/date-range';
import { RegistryExportService } from './registry-export.service';
import { RegistryDataService } from './registry-data.service';
import { ExcelService } from './excel/excel.service';
@Component({
templateUrl: 'registry.component.pug',
providers: [
RegistryExportService,
RegistryDataService,
ExcelService
]
})
export class RegistryComponent implements OnInit {
public shopID: string;
public dateRange: DateRange;
public isLoading: boolean = false;
constructor(
private route: ActivatedRoute,
private registryDataService: RegistryDataService,
private registryExportService: RegistryExportService
) { }
public ngOnInit() {
this.route.parent.parent.params.subscribe((params) => {
this.shopID = params['shopID'];
});
}
public selectDateRange(dateRange: DateRange) {
this.dateRange = dateRange;
}
public exportRegistryToXLSX() {
this.isLoading = true;
this.registryDataService.getRegistry(this.shopID, this.dateRange.fromTime, this.dateRange.toTime).subscribe((registry) => {
this.registryExportService.exportRegistryToXLSX(registry);
this.isLoading = false;
});
}
}

View File

@ -1,18 +0,0 @@
import { PaymentRegistryItem } from './payment-registry-item';
import { RefundRegistryItem } from './refund-registry-item';
export class Registry {
public fromTime: Date;
public toTime: Date;
public client: string;
public capturedPaymentItems: PaymentRegistryItem[];
public refundedPaymentItems: RefundRegistryItem[];
constructor(fromTime?: Date, toTime?: Date, client?: string, capturedPaymentItems?: PaymentRegistryItem[], refundedPaymentItems?: RefundRegistryItem[]) {
this.fromTime = fromTime;
this.toTime = toTime;
this.client = client;
this.capturedPaymentItems = capturedPaymentItems;
this.refundedPaymentItems = refundedPaymentItems;
}
}

View File

@ -1,13 +0,0 @@
export class SearchParams {
public fromTime: Date;
public toTime: Date;
public limit: number;
public continuationToken?: string;
constructor(fromTime: Date, toTime: Date, limit: number, continuationToken?: string) {
this.fromTime = fromTime;
this.toTime = toTime;
this.limit = limit;
this.continuationToken = continuationToken;
}
}

View File

@ -1,4 +0,0 @@
export class WorksheetProperties {
public name: string;
public headerSizes: {rows: number, columns: number};
}

View File

@ -0,0 +1,4 @@
export interface ReportsFilter {
path: string;
value: any;
}

View File

@ -3,4 +3,4 @@
kof-date-range((onSelect)="selectDateRange($event)")
.row
.col-xs-12
kof-search-reports-result([reports$]="reports$")
kof-search-reports-result([reports$]="reports$", [filter]="filter")

View File

@ -1,33 +1,49 @@
import { Component, OnInit, ViewEncapsulation } from '@angular/core';
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { Subject } from 'rxjs/Subject';
import { Subject } from 'rxjs';
import { Report, SearchReportParams } from 'koffing/backend';
import { SearchService } from 'koffing/backend/search.service';
import { Report, ReportType, SearchReportParams } from 'koffing/backend';
import { DateRange } from 'koffing/common/date-range/date-range';
import { SearchService } from 'koffing/backend/search.service';
import { ReportsFilter } from './reports-filter';
@Component({
selector: 'kof-provision-of-service',
templateUrl: 'reports.component.pug',
styleUrls: ['reports.component.less'],
encapsulation: ViewEncapsulation.None
styleUrls: ['./reports.component.less']
})
export class ReportsComponent implements OnInit {
public reports$: Subject<Report[]> = new Subject();
public filter: ReportsFilter;
private shopID: string;
private dateRange: Subject<DateRange> = new Subject();
constructor(
private route: ActivatedRoute,
private searchService: SearchService
) { }
) {
}
public ngOnInit() {
this.route.params.subscribe((params) => {
this.filter = {
path: 'report.type',
value: params['type']
};
});
this.route.parent.parent.params.subscribe((params) => {
this.shopID = params['shopID'];
});
this.dateRange.subscribe((dateRange) => this.getReports(dateRange));
}
public selectDateRange(dateRange: DateRange) {
this.dateRange.next(dateRange);
}
private getReports(dateRange: DateRange) {
const params = new SearchReportParams(dateRange.fromTime, dateRange.toTime);
this.searchService.getReports(this.shopID, params).subscribe((reports) => {
this.reports$.next(reports);

View File

@ -1,8 +1,8 @@
import { Component, Input, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { DownloadService } from 'koffing/backend/download.service';
import { FileMeta } from 'koffing/backend';
import { DownloadService } from 'src/app/backend/download.service';
import { FileMeta } from 'src/app/backend/index';
@Component({
selector: 'kof-report-files',

View File

@ -1,4 +1,4 @@
import { Report } from 'koffing/backend';
import { Report } from 'src/app/backend/index';
export class ReportTableItem {

View File

@ -1,6 +1,6 @@
import { Pipe, PipeTransform } from '@angular/core';
import { REPORT_TYPE } from 'koffing/backend';
import { REPORT_TYPE } from 'src/app/backend/index';
@Pipe({
name: 'kofReportType'

View File

@ -4,14 +4,12 @@ table.table.table-striped
th Идентификатор
th.hidden-xs Временной интервал
th Время создания
th.hidden-xs Тип отчета
th
tbody(*ngFor="let item of reportItems")
tbody(*ngFor="let item of filtered(reportItems)")
tr
td {{item.report.id}}
td.hidden-xs {{item.report.fromTime | date: "dd.MM.yyyy"}} - {{item.report.toTime | date: "dd.MM.yyyy"}}
td {{item.report.createdAt | date: "dd.MM.yyyy HH:mm:ss"}}
td.hidden-xs {{item.report.type | kofReportType}}
td
.pull-right
button.btn.btn-xs.btn-default((click)="toggleFilesPanel(item)")

View File

@ -1,8 +1,10 @@
import { Component, Input, OnInit } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { get } from 'lodash';
import { Report } from 'koffing/backend';
import { Report } from 'src/app/backend';
import { ReportTableItem } from './report-item';
import { ReportsFilter } from '../reports-filter';
@Component({
selector: 'kof-search-reports-result',
@ -13,6 +15,9 @@ export class SearchReportsResultComponent implements OnInit {
@Input()
public reports$: Observable<Report[]>;
@Input()
public filter: ReportsFilter;
public reportItems: ReportTableItem[];
public ngOnInit() {
@ -24,4 +29,10 @@ export class SearchReportsResultComponent implements OnInit {
public toggleFilesPanel(item: ReportTableItem) {
item.isVisible = !item.isVisible;
}
public filtered(reports: ReportTableItem[]): ReportTableItem[] {
return this.filter && reports
? reports.filter((report) => get(report, this.filter.path) === this.filter.value)
: reports;
}
}

View File

@ -17,9 +17,9 @@ import { InvoiceComponent } from 'koffing/invoice/invoice.component';
import { ShopInfoComponent } from 'koffing/shop-info/shop-info.component';
import { ContractManageComponent } from 'koffing/shop-info/contract-manage/contract-manage.component';
import { DocumentsComponent } from 'koffing/documents/documents.component';
import { ReportsComponent } from 'koffing/documents/reports/reports.component';
import { RegistryComponent } from 'koffing/documents/registry/registry.component';
import { InitCreateShopComponent } from 'koffing/management/init-create-shop/init-create-shop.component';
import { ReportsComponent } from 'koffing/documents/reports/reports.component';
import { ReportType } from 'koffing/backend';
@NgModule({
imports: [
@ -89,16 +89,12 @@ import { InitCreateShopComponent } from 'koffing/management/init-create-shop/ini
children: [
{
path: '',
redirectTo: 'reports',
redirectTo: 'reports/' + ReportType.provisionOfService,
pathMatch: 'full'
},
{
path: 'reports',
path: 'reports/:type',
component: ReportsComponent
},
{
path: 'registry',
component: RegistryComponent
}
]
},
@ -122,4 +118,5 @@ import { InitCreateShopComponent } from 'koffing/management/init-create-shop/ini
RouterModule
]
})
export class RootRoutingModule { }
export class RootRoutingModule {
}