Shop creation support (#139)

* FE-396: Added claim types and service. (#134)

* FE-401: Shop creation support (#136)
This commit is contained in:
Ildar Galeev 2017-07-17 14:57:08 +03:00 committed by GitHub
parent 5adda5d481
commit 8be54782d4
97 changed files with 1353 additions and 151 deletions

View File

@ -33,7 +33,8 @@
"primeng": "~4.1.0-rc.2",
"reflect-metadata": "~0.1.10",
"rxjs": "~5.4.1",
"suggestions-jquery": "git@github.com:hflabs/suggestions-jquery.git#9580698defdc94384e3a3692e1fc841b0c1aec54",
"suggestions-jquery": "~17.5.0",
"uuid": "~3.1.0",
"xlsx-style": "~0.8.13",
"zone.js": "~0.8.5"
},
@ -44,6 +45,7 @@
"@types/jquery": "~3.2.5",
"@types/lodash": "~4.14.66",
"@types/node": "~8.0.3",
"@types/uuid": "~3.0.0",
"angular2-template-loader": "~0.6.2",
"awesome-typescript-loader": "~3.1.3",
"codelyzer": "~3.1.1",

View File

@ -15,7 +15,7 @@ import { AnalyticsService } from 'koffing/analytics/analytics.service';
})
export class AnalyticsComponent implements OnInit {
public currentShopID: number;
public currentShopID: string;
public shopItems: SelectItem[] = [];
public isLoading: boolean = true;

View File

@ -2,10 +2,10 @@ import { Injectable } from '@angular/core';
import { Router, ActivatedRoute } from '@angular/router';
import { Observable } from 'rxjs/Observable';
import { Shop } from 'koffing/backend/model/shop';
import { SelectItem } from 'koffing/common/select/select-item';
import { ShopIDStorage } from 'koffing/analytics/shop-id-storage.service';
import { ShopService } from 'koffing/backend/shop.service';
import { Shop } from 'koffing/backend/model/shop/shop';
@Injectable()
export class AnalyticsService {
@ -18,18 +18,18 @@ export class AnalyticsService {
}
public getShopItems(): Observable<SelectItem[]> {
return Observable.fromPromise(this.shopService.getShops()).map((shops: Shop[]) => {
return this.shopService.getShopsObs().map((shops: Shop[]) => {
this.shops = shops;
return this.toShopItems(shops);
});
}
public getActiveShopID(): number {
public getActiveShopID(): string {
const routeShopID = this.route.snapshot.params['shopID'];
return routeShopID ? routeShopID : this.getFromStorage(this.shops);
}
public navigateToShop(shopID: number) {
public navigateToShop(shopID: string) {
ShopIDStorage.set(shopID);
const hasChildren = this.route.children.length > 0;
const childComponent = hasChildren ? this.route.children[0].routeConfig.path : 'dashboard';

View File

@ -17,7 +17,7 @@ import { DoughnutChartData } from './stats-data/doughnut-chart-data';
})
export class DashboardComponent implements OnInit {
public shopID: number;
public shopID: string;
public fromTime: Date = moment().subtract(1, 'month').startOf('day').toDate();
public toTime: Date = moment().endOf('day').toDate();
public profit: number = 0;
@ -61,21 +61,21 @@ export class DashboardComponent implements OnInit {
});
}
private loadPaymentMethod(shopID: number, fromTime: Date, toTime: Date) {
private loadPaymentMethod(shopID: string, fromTime: Date, toTime: Date) {
this.dashboardService.getPaymentMethodChartData(shopID, fromTime, toTime).subscribe((data) => {
this.paymentMethodChartData.next(data);
this.loadStatistic.next();
});
}
private loadRate(shopID: number, from: Date, to: Date) {
private loadRate(shopID: string, from: Date, to: Date) {
this.dashboardService.getUniqueCount(shopID, from, to).subscribe((count) => {
this.panelData.next({uniqueCount: count});
this.loadStatistic.next();
});
}
private loadConversionStat(shopID: number, from: Date, to: Date) {
private loadConversionStat(shopID: string, from: Date, to: Date) {
this.dashboardService.getPaymentConversionData(shopID, from, to).subscribe((data) => {
this.panelData.next({
successfulCount: data.paymentCount.successfulCount,
@ -86,14 +86,14 @@ export class DashboardComponent implements OnInit {
});
}
private loadGeoChartData(shopID: number, from: Date, to: Date) {
private loadGeoChartData(shopID: string, from: Date, to: Date) {
this.dashboardService.getPaymentGeoChartData(shopID, from, to).subscribe((data) => {
this.geoChartData.next(data);
this.loadStatistic.next();
});
}
private loadRevenueStat(shopID: number, from: Date, to: Date) {
private loadRevenueStat(shopID: string, from: Date, to: Date) {
this.dashboardService.getPaymentRevenueData(shopID, from, to).subscribe((data) => {
this.profit = data.profit;
this.revenueChartData.next(data.revenueChartData);
@ -101,8 +101,8 @@ export class DashboardComponent implements OnInit {
});
}
private loadAccounts(shopID: number) {
this.shopService.getShop(shopID).then((shop) => {
private loadAccounts(shopID: string) {
this.shopService.getShopByID(shopID).subscribe((shop) => {
this.accountsService.getAccountByID(shop.account.settlementID).subscribe((account) => {
this.panelData.next({settlementBalance: account.ownAmount});
this.loadStatistic.next();

View File

@ -16,17 +16,17 @@ export class DashboardService {
private locationService: LocationService) {
}
public getPaymentMethodChartData(shopID: number, from: Date, to: Date): Observable<DoughnutChartData> {
public getPaymentMethodChartData(shopID: string, from: Date, to: Date): Observable<DoughnutChartData> {
return this.analyticsService.getPaymentMethodStats(shopID, from, to)
.map((paymentMethodStats) => StatsDataConverter.toPaymentMethodChartData(paymentMethodStats));
}
public getUniqueCount(shopID: number, from: Date, to: Date): Observable<number> {
public getUniqueCount(shopID: string, from: Date, to: Date): Observable<number> {
return this.analyticsService.getPaymentRateStats(shopID, from, to)
.map((paymentRateStat) => paymentRateStat ? paymentRateStat.uniqueCount : 0);
}
public getPaymentConversionData(shopID: number, from: Date, to: Date): Observable<PaymentConversionData> {
public getPaymentConversionData(shopID: string, from: Date, to: Date): Observable<PaymentConversionData> {
return this.analyticsService.getPaymentConversionStats(shopID, from, to).map((paymentConversionStat) => {
const paymentCount = StatsDataConverter.toPaymentCountInfo(paymentConversionStat);
const conversionChartData = StatsDataConverter.toConversionChartData(from, paymentConversionStat);
@ -34,7 +34,7 @@ export class DashboardService {
});
}
public getPaymentGeoChartData(shopID: number, from: Date, to: Date): Observable<DoughnutChartData> {
public getPaymentGeoChartData(shopID: string, from: Date, to: Date): Observable<DoughnutChartData> {
return Observable.create((observer: Observer<DoughnutChartData>) => {
this.analyticsService.getPaymentGeoStats(shopID, from, to).subscribe((paymentGeoStat) => {
const data = StatsDataConverter.toGeoChartData(paymentGeoStat);
@ -47,7 +47,7 @@ export class DashboardService {
});
}
public getPaymentRevenueData(shopID: number, from: Date, to: Date): Observable<PaymentRevenueData> {
public getPaymentRevenueData(shopID: string, from: Date, to: Date): Observable<PaymentRevenueData> {
return this.analyticsService.getPaymentRevenueStats(shopID, from, to).map((paymentRevenueStat) => {
const profit = StatsDataConverter.toTotalProfit(paymentRevenueStat);
const revenueChartData = StatsDataConverter.toRevenueChartData(from, paymentRevenueStat);

View File

@ -31,7 +31,7 @@ export class CreateInvoiceComponent implements OnInit {
public create() {
const params = {
shopID: Number(this.shopID),
shopID: this.shopID,
amount: this.formData.amount * 100,
currency: 'RUB',
metadata: {},

View File

@ -1,19 +1,19 @@
import { Injectable } from '@angular/core';
import * as _ from 'lodash';
import { filter, forEach, find } from 'lodash';
import { Observable, Observer } from 'rxjs';
import 'rxjs/add/observable/forkJoin';
import { ShopService } from 'koffing/backend/shop.service';
import { ContractService } from 'koffing/backend/contract.service';
import { SearchService } from 'koffing/backend/search.service';
import { Shop } from 'koffing/backend/model/shop';
import { Contract } from 'koffing/backend/model/contract';
import { Invoice } from 'koffing/backend/model/invoice';
import { Payment } from 'koffing/backend/model/payment';
import { RussianLegalEntity } from 'koffing/backend/model/russian-legal-entity';
import { SearchPaymentsParams } from 'koffing/backend/requests/search-payments-request';
import { Registry } from './registry';
import { RegistryItem } from './registry-item';
import { Shop } from 'koffing/backend/model/shop/shop';
import { Contract } from 'koffing/backend/model/contract/contract';
import { RussianLegalEntity } from 'koffing/backend/model/contract/contractor/russian-legal-entity';
@Injectable()
export class RegistryDataService {
@ -31,14 +31,14 @@ export class RegistryDataService {
const searchParams = this.toSearchParams(fromTime, toTime);
const observablePayments = this.searchService.searchPayments(shopID, searchParams);
const observableInvoices = this.searchService.searchInvoices(shopID, searchParams);
const observableContracts = this.contractService.getContractsObservable();
const observableShop = this.shopService.getShopObservable(shopID);
const observableContracts = this.contractService.getContractsObs();
const observableShop = this.shopService.getShopByID(shopID);
Observable.forkJoin([observablePayments, observableInvoices, observableContracts, observableShop]).subscribe((response) => {
const payments = response[0].result;
const invoices = response[1].result;
const contracts = response[2];
const shop = response[3];
const successPayments = _.filter(payments, (payment: Payment) => payment.status === 'captured');
const successPayments = filter(payments, (payment: Payment) => payment.status === 'captured');
const registryItems = this.getRegistryItems(successPayments, invoices);
const client = this.getClient(shop, contracts);
observer.next(new Registry(registryItems, fromTime, toTime, client));
@ -49,8 +49,8 @@ export class RegistryDataService {
private getRegistryItems(payments: Payment[], invoices: Invoice[]): RegistryItem[] {
const registryItems: RegistryItem[] = [];
_.forEach(payments, (payment: Payment) => {
const foundInvoice = _.find(invoices, (invoice: Invoice) => invoice.id === payment.invoiceID);
forEach(payments, (payment: Payment) => {
const foundInvoice = find(invoices, (invoice: Invoice) => invoice.id === payment.invoiceID);
const registryItem = new RegistryItem();
registryItem.invoiceID = `${payment.invoiceID}.${payment.id}`;
registryItem.paymentDate = payment.createdAt;
@ -66,10 +66,10 @@ export class RegistryDataService {
private getClient(shop: Shop, contracts: Contract[]): string {
let client = '';
const activeContract = _.find(contracts, (contract: Contract) => contract.id === shop.contractID);
if (activeContract.contractor && activeContract.contractor.legalEntity) {
const russianLegalEntity = activeContract.contractor.legalEntity as RussianLegalEntity;
client = russianLegalEntity.registeredName;
const activeContract = find(contracts, (contract: Contract) => contract.id === shop.contractID);
if (activeContract.contractor) {
const legalEntity = activeContract.contractor as RussianLegalEntity;
client = legalEntity.registeredName;
}
return client;
}

View File

@ -1,21 +1,21 @@
import * as _ from 'lodash';
import { Shop } from 'koffing/backend/model/shop';
import { find } from 'lodash';
import { Shop } from 'koffing/backend/model/shop/shop';
export class ShopIDStorage {
public static key: string = 'activeShop';
public static set(shopID: number) {
localStorage.setItem(this.key, _.toString(shopID));
public static set(shopID: string) {
localStorage.setItem(this.key, shopID);
}
public static get(): number {
public static get(): string {
const id = localStorage.getItem('activeShop');
return id ? _.toNumber(id) : null;
return id ? id : null;
}
public static isAvailable(shops: Shop[]) {
const id = this.get();
return id ? !!_.find(shops, (shop) => id === shop.id) : false;
return id ? !!find(shops, (shop) => id === shop.id) : false;
}
}

View File

@ -14,60 +14,63 @@ import { PaymentRevenueStat } from './model/payment-revenue-stat';
@Injectable()
export class AnalyticsService {
constructor(
private http: Http,
private config: ConfigService
) { }
constructor(private http: Http,
private config: ConfigService) {
}
public getPaymentMethodStats(shopID: number, from: Date, to: Date, splitUnit?: string, splitSize?: number, paymentMethod?: string): Observable<PaymentMethodStat[]> {
const params = new URLSearchParams();
params.set('fromTime', this.toUTC(from));
params.set('toTime', this.toUTC(to));
params.set('splitUnit', splitUnit || 'minute');
params.set('splitSize', this.getSplitSize(splitSize));
params.set('paymentMethod', paymentMethod || 'bankCard');
return this.http.get(`${this.config.capiUrl}/analytics/shops/${shopID}/customers/stats/payment_method`, {search: params})
public getPaymentMethodStats(shopID: string, from: Date, to: Date, splitUnit?: string, splitSize?: number, paymentMethod?: string): Observable<PaymentMethodStat[]> {
const search = new URLSearchParams();
search.set('fromTime', this.toUTC(from));
search.set('toTime', this.toUTC(to));
search.set('splitUnit', splitUnit || 'minute');
search.set('splitSize', this.getSplitSize(splitSize));
search.set('paymentMethod', paymentMethod || 'bankCard');
return this.http.get(`${this.getEndpoint(shopID, 'customers')}/payment_method`, {search})
.map((res) => res.json());
}
public getPaymentRateStats(shopID: number, from: Date, to: Date): Observable<PaymentRateStat> {
const params = new URLSearchParams();
params.set('fromTime', this.toUTC(from));
params.set('toTime', this.toUTC(to));
return this.http.get(`${this.config.capiUrl}/analytics/shops/${shopID}/customers/stats/rate`, {search: params})
public getPaymentRateStats(shopID: string, from: Date, to: Date): Observable<PaymentRateStat> {
const search = new URLSearchParams();
search.set('fromTime', this.toUTC(from));
search.set('toTime', this.toUTC(to));
return this.http.get(`${this.getEndpoint(shopID, 'customers')}/rate`, {search})
.map((res) => res.json());
}
public getPaymentConversionStats(shopID: number, from: Date, to: Date, splitUnit?: string, splitSize?: number): Observable<PaymentConversionStat[]> {
const params = new URLSearchParams();
params.set('fromTime', this.toUTC(from));
params.set('toTime', this.toUTC(to));
params.set('splitUnit', splitUnit || 'minute');
params.set('splitSize', this.getSplitSize(splitSize));
return this.http.get(`${this.config.capiUrl}/analytics/shops/${shopID}/payments/stats/conversion`, {search: params})
public getPaymentConversionStats(shopID: string, from: Date, to: Date, splitUnit?: string, splitSize?: number): Observable<PaymentConversionStat[]> {
const search = new URLSearchParams();
search.set('fromTime', this.toUTC(from));
search.set('toTime', this.toUTC(to));
search.set('splitUnit', splitUnit || 'minute');
search.set('splitSize', this.getSplitSize(splitSize));
return this.http.get(`${this.getEndpoint(shopID, 'payments')}/conversion`, {search})
.map((res) => res.json());
}
public getPaymentGeoStats(shopID: number, from: Date, to: Date, splitUnit?: string, splitSize?: number): Observable<PaymentGeoStat[]> {
const params = new URLSearchParams();
params.set('fromTime', this.toUTC(from));
params.set('toTime', this.toUTC(to));
params.set('splitUnit', splitUnit || 'day');
params.set('splitSize', this.getSplitSize(splitSize));
return this.http.get(`${this.config.capiUrl}/analytics/shops/${shopID}/payments/stats/geo`, {search: params})
public getPaymentGeoStats(shopID: string, from: Date, to: Date, splitUnit?: string, splitSize?: number): Observable<PaymentGeoStat[]> {
const search = new URLSearchParams();
search.set('fromTime', this.toUTC(from));
search.set('toTime', this.toUTC(to));
search.set('splitUnit', splitUnit || 'day');
search.set('splitSize', this.getSplitSize(splitSize));
return this.http.get(`${this.getEndpoint(shopID, 'payments')}/geo`, {search})
.map((res) => res.json());
}
public getPaymentRevenueStats(shopID: number, from: Date, to: Date, splitUnit?: string, splitSize?: number): Observable<PaymentRevenueStat[]> {
const params = new URLSearchParams();
params.set('fromTime', this.toUTC(from));
params.set('toTime', this.toUTC(to));
params.set('splitUnit', splitUnit || 'minute');
params.set('splitSize', this.getSplitSize(splitSize));
return this.http.get(`${this.config.capiUrl}/analytics/shops/${shopID}/payments/stats/revenue`, {search: params})
public getPaymentRevenueStats(shopID: string, from: Date, to: Date, splitUnit?: string, splitSize?: number): Observable<PaymentRevenueStat[]> {
const search = new URLSearchParams();
search.set('fromTime', this.toUTC(from));
search.set('toTime', this.toUTC(to));
search.set('splitUnit', splitUnit || 'minute');
search.set('splitSize', this.getSplitSize(splitSize));
return this.http.get(`${this.getEndpoint(shopID, 'payments')}/revenue`, {search})
.map(res => res.json());
}
private getEndpoint(shopID: string, resource: 'customers' | 'payments'): string {
return `${this.config.capiUrl}/analytics/shops/${shopID}/${resource}/stats`;
}
private toUTC(date: Date): string {
return moment(date).utc().format();
}

View File

@ -1,6 +1,6 @@
import { Injectable } from '@angular/core';
import { Http } from '@angular/http';
import 'rxjs/add/operator/toPromise';
import { Observable } from 'rxjs/Observable';
import { Category } from './model/category';
import { ConfigService } from './config.service';
@ -8,14 +8,27 @@ import { ConfigService } from './config.service';
@Injectable()
export class CategoryService {
private endpoint = `${this.config.capiUrl}/processing/categories`;
constructor(
private http: Http,
private config: ConfigService
) { }
/**
* @deprecated Use getCategoriesObs
*/
public getCategories(): Promise<Category[]> {
return this.http.get(`${this.config.capiUrl}/processing/categories`)
return this.http.get(this.endpoint)
.toPromise()
.then(response => response.json());
}
public getCategoriesObs(): Observable<Category[]> {
return this.http.get(this.endpoint).map((res) => res.json());
}
public getCategoryByID(categoryID: number): Observable<Category> {
return this.http.get(`${this.endpoint}/${categoryID}`).map((res) => res.json());
}
}

View File

@ -0,0 +1,45 @@
import { Injectable } from '@angular/core';
import { Http } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import { ConfigService } from './config.service';
import { Claim } from './model/claim/claim';
import { PartyModification } from './model/claim/party-modification/party-modification';
@Injectable()
export class ClaimService {
private endpoint = `${this.config.capiUrl}/processing/claims`;
constructor(private http: Http,
private config: ConfigService) {
}
public getClaims(claimStatus?: string): Observable<Claim[]> {
const search = new URLSearchParams();
if (claimStatus) {
search.set('claimStatus', claimStatus);
}
return this.http.get(this.endpoint, {search}).map((res) => res.json());
}
public createClaim(claimChangeset: PartyModification[]): Observable<Claim> {
return this.http.post(this.endpoint, claimChangeset).map((res) => res.json());
}
public getClaimByID(claimID: number): Observable<Claim> {
return this.http.get(`${this.endpoint}/${claimID}`).map((res) => res.json());
}
public revokeClaimByID(claimID: number, claimRevision: number, reason: string): Observable<void> {
const search = new URLSearchParams();
search.set('claimRevision', String(claimRevision));
return this.http.put(`${this.endpoint}/${claimID}/revoke`, reason, {search}).map((res) => res.json());
}
public updateClaimByID(claimID: number, claimRevision: number, claimChangeset: PartyModification[]): Observable<void> {
const search = new URLSearchParams();
search.set('claimRevision', String(claimRevision));
return this.http.post(`${this.endpoint}/${claimID}/update`, claimChangeset, {search}).map((res) => res.json());
}
}

View File

@ -1,56 +1,84 @@
import { Injectable } from '@angular/core';
import { Http } from '@angular/http';
import { Observable } from 'rxjs';
import 'rxjs/add/operator/toPromise';
import { ConfigService } from './config.service';
import { Contract } from './model/contract';
import { PayoutTool } from './model/payout-tool';
import { ContractParams } from './model/contract-params';
import { PayoutToolParams } from './model/payout-tool-params';
import { Contract } from './model/contract';
import { Contract as ContractNew } from './model/contract/contract';
@Injectable()
export class ContractService {
private contractsUrl: string = `${this.config.capiUrl}/processing/contracts`;
private endpoint: string = `${this.config.capiUrl}/processing/contracts`;
constructor(
private http: Http,
private config: ConfigService
) { }
/**
* @deprecated Use getContractsObs
*/
public getContracts(): Promise<Contract[]> {
return this.http.get(this.contractsUrl)
return this.http.get(this.endpoint)
.toPromise()
.then(response => response.json());
}
/**
* @deprecated Use getContractsObs
*/
public getContractsObservable(): Observable<Contract[]> {
return this.http.get(this.contractsUrl)
return this.http.get(this.endpoint)
.map((res) => res.json());
}
/**
* @deprecated Use getContractByID
*/
public getContract(contractID: number): Promise<Contract> {
return this.http.get(`${this.contractsUrl}/${contractID}`)
return this.http.get(`${this.endpoint}/${contractID}`)
.toPromise()
.then(response => response.json() as Contract);
}
/**
* @deprecated Use ClaimService
*/
public createContract(request: ContractParams): Promise<any> {
return this.http.post(this.contractsUrl, request)
return this.http.post(this.endpoint, request)
.toPromise()
.then(response => response.json());
}
/**
* @deprecated Use PayoutToolService
*/
public getPayoutTools(contractID: number): Promise<PayoutTool[]> {
return this.http.get(`${this.contractsUrl}/${contractID}/payout_tools`)
return this.http.get(`${this.endpoint}/${contractID}/payout_tools`)
.toPromise()
.then(response => response.json() as PayoutTool[]);
}
/**
* @deprecated Use ClaimService
*/
public createPayoutTool(contractID: number, payoutToolParams: PayoutToolParams): Promise<any> {
return this.http.post(`${this.contractsUrl}/${contractID}/payout_tools`, payoutToolParams)
return this.http.post(`${this.endpoint}/${contractID}/payout_tools`, payoutToolParams)
.toPromise()
.then(response => response.json());
}
public getContractsObs(): Observable<ContractNew[]> {
return this.http.get(this.endpoint).map((res) => res.json());
}
public getContractByID(contractID: string): Observable<ContractNew> {
return this.http.get(`${this.endpoint}/${contractID}`).map((res) => res.json());
}
// TODO getContractAdjustments, getContractAdjustmentsByID
}

1
src/app/backend/index.ts Normal file
View File

@ -0,0 +1 @@
export * from './model';

View File

@ -10,16 +10,18 @@ import { InvoiceAccessToken } from './model/invoice-access-token';
@Injectable()
export class InvoiceService {
private endpoint = `${this.config.capiUrl}/processing/invoices`;
constructor(
private http: Http,
private config: ConfigService
) {}
public createInvoice(params: CreateInvoiceParams): Observable<Invoice> {
return this.http.post(`${this.config.capiUrl}/processing/invoices`, params).map(res => res.json());
return this.http.post(this.endpoint, params).map(res => res.json());
}
public createInvoiceAccessToken(invoiceID: string): Observable<InvoiceAccessToken> {
return this.http.post(`${this.config.capiUrl}/processing/invoices/${invoiceID}/access_tokens`, {}).map(res => res.json());
return this.http.post(`${this.endpoint}/${invoiceID}/access_tokens`, {}).map(res => res.json());
}
}

View File

@ -22,9 +22,9 @@ export class LocationService {
observer.complete();
});
}
const params = new URLSearchParams();
params.set('geoIDs', geoIDs.join(','));
params.set('language', language || 'ru');
return this.http.get(`${this.config.capiUrl}/reference/geo/location/names`, {search: params}).map((res) => res.json());
const search = new URLSearchParams();
search.set('geoIDs', geoIDs.join(','));
search.set('language', language || 'ru');
return this.http.get(`${this.config.capiUrl}/reference/geo/location/names`, {search}).map((res) => res.json());
}
}

View File

@ -0,0 +1,11 @@
import { Claim } from './claim';
export class ClaimAccepted extends Claim {
public acceptedAt: string;
constructor() {
super();
this.status = 'ClaimAccepted';
}
}

View File

@ -0,0 +1,11 @@
import { Claim } from './claim';
export class ClaimDenied extends Claim {
public reason: string;
constructor() {
super();
this.status = 'ClaimDenied';
}
}

View File

@ -0,0 +1,9 @@
import { Claim } from './claim';
export class ClaimPending extends Claim {
constructor() {
super();
this.status = 'ClaimPending';
}
}

View File

@ -0,0 +1,9 @@
import { Claim } from './claim';
export class ClaimRevoked extends Claim {
constructor() {
super();
this.status = 'ClaimRevoked';
}
}

View File

@ -0,0 +1,10 @@
import { PartyModification } from './party-modification/party-modification';
export abstract class Claim {
public id: number;
public revision: number;
public createdAt: string;
public updatedAt: string;
public status: string;
public changeset: PartyModification[];
}

View File

@ -0,0 +1,19 @@
export * from './party-modification/contract-modification/contract-adjustment-creation';
export * from './party-modification/contract-modification/contract-creation';
export * from './party-modification/contract-modification/contract-legal-agreement-binding';
export * from './party-modification/contract-modification/contract-modification';
export * from './party-modification/contract-modification/contract-payout-tool-creation';
export * from './party-modification/contract-modification/contract-termination';
export * from './party-modification/shop-modification/shop-account-creation';
export * from './party-modification/shop-modification/shop-category-change';
export * from './party-modification/shop-modification/shop-contract-binding';
export * from './party-modification/shop-modification/shop-creation';
export * from './party-modification/shop-modification/shop-details-change';
export * from './party-modification/shop-modification/shop-location-change';
export * from './party-modification/shop-modification/shop-modification';
export * from './party-modification/party-modification';
export * from './claim';
export * from './claim-accepted';
export * from './claim-denied';
export * from './claim-pending';
export * from './claim-revoked';

View File

@ -0,0 +1,11 @@
import { ContractModification } from './contract-modification';
export class ContractAdjustmentCreation extends ContractModification {
public adjustmentID: string;
constructor() {
super();
this.contractModificationType = 'ContractAdjustmentCreation';
}
}

View File

@ -0,0 +1,14 @@
import { ContractModification } from './contract-modification';
import { Contractor } from '../../../contract/contractor/contractor';
export class ContractCreation extends ContractModification {
public contractor: Contractor;
constructor(contractID: string, contractor: Contractor) {
super();
this.contractModificationType = 'ContractCreation';
this.contractID = contractID;
this.contractor = contractor;
}
}

View File

@ -0,0 +1,12 @@
import { ContractModification } from './contract-modification';
import { LegalAgreement } from '../../../contract/legal-agreement';
export class ContractLegalAgreementBinding extends ContractModification {
public legalAgreement: LegalAgreement;
constructor() {
super();
this.contractModificationType = 'ContractLegalAgreementBinding';
}
}

View File

@ -0,0 +1,12 @@
import { PartyModification } from '../party-modification';
export abstract class ContractModification extends PartyModification {
public contractID: string;
public contractModificationType: string;
constructor() {
super();
this.partyModificationType = 'ContractModification';
}
}

View File

@ -0,0 +1,18 @@
import { ContractModification } from './contract-modification';
import { PayoutToolDetails } from '../../../payout-tool/payout-tool-details/payout-tool-details';
export class ContractPayoutToolCreation extends ContractModification {
public payoutToolID: string;
public currency: string;
public details: PayoutToolDetails;
constructor(contractID: string, payoutToolID: string, details: PayoutToolDetails) {
super();
this.currency = 'RUB';
this.contractModificationType = 'ContractPayoutToolCreation';
this.contractID = contractID;
this.payoutToolID = payoutToolID;
this.details = details;
}
}

View File

@ -0,0 +1,12 @@
import { ContractModification } from './contract-modification';
export class ContractTermination extends ContractModification {
public reason: string;
constructor() {
super();
this.contractModificationType = 'ContractTermination';
}
}

View File

@ -0,0 +1,3 @@
export abstract class PartyModification {
public partyModificationType: string;
}

View File

@ -0,0 +1,11 @@
import { ShopModification } from './shop-modification';
export class ShopAccountCreation extends ShopModification {
public currency: string;
constructor() {
super();
this.shopModificationType = 'ShopAccountCreation';
}
}

View File

@ -0,0 +1,11 @@
import { ShopModification } from './shop-modification';
export class ShopCategoryChange extends ShopModification {
public categoryID: number;
constructor() {
super();
this.shopModificationType = 'ShopCategoryChange';
}
}

View File

@ -0,0 +1,12 @@
import { ShopModification } from './shop-modification';
export class ShopContractBinding extends ShopModification {
public contractID: string;
public payoutToolID: string;
constructor() {
super();
this.shopModificationType = 'ShopContractBinding';
}
}

View File

@ -0,0 +1,27 @@
import { ShopModification } from './shop-modification';
import { ShopLocation } from '../../../shop/shop-location/shop-location';
import { ShopDetails } from '../../../shop/shop-details';
export class ShopCreation extends ShopModification {
public location: ShopLocation;
public details: ShopDetails;
public contractID: string;
public payoutToolID: string;
constructor(options: {
shopID: string,
location: ShopLocation,
details: ShopDetails,
contractID: string,
payoutToolID: string
}) {
super();
this.shopModificationType = 'ShopCreation';
this.shopID = options.shopID;
this.location = options.location;
this.details = options.details;
this.contractID = options.contractID;
this.payoutToolID = options.payoutToolID;
}
}

View File

@ -0,0 +1,12 @@
import { ShopModification } from './shop-modification';
import { ShopDetails } from '../../../shop-details';
export class ShopDetailsChange extends ShopModification {
public details: ShopDetails;
constructor() {
super();
this.shopModificationType = 'ShopDetailsChange';
}
}

View File

@ -0,0 +1,12 @@
import { ShopModification } from './shop-modification';
import { ShopLocation } from 'koffing/backend/model/shop/shop-location/shop-location';
export class ShopLocationChange extends ShopModification {
public location: ShopLocation;
constructor() {
super();
this.shopModificationType = 'ShopLocationChange';
}
}

View File

@ -0,0 +1,12 @@
import { PartyModification } from '../party-modification';
export abstract class ShopModification extends PartyModification {
public shopID: string;
public shopModificationType: string;
constructor() {
super();
this.partyModificationType = 'ShopModification';
}
}

View File

@ -1,6 +1,9 @@
import { Contractor } from './contractor';
import { PayoutToolParams } from './payout-tool-params';
/**
* @deprecated
*/
export class ContractParams {
public contractor: Contractor;
public payoutToolParams: PayoutToolParams;

View File

@ -1,5 +1,8 @@
import { Contractor } from './contractor';
/**
* @deprecated Use koffing/backend/model/contract/contract
*/
export class Contract {
public id: number;
public contractor: Contractor;

View File

@ -0,0 +1,13 @@
import { Contractor } from './contractor/contractor';
import { LegalAgreement } from './legal-agreement';
export class Contract {
public id: string;
public createdAt: string;
public status: string;
public validSince: string;
public validUntil: string;
public terminatedAt: string;
public contractor: Contractor;
public legalAgreement: LegalAgreement;
}

View File

@ -0,0 +1,3 @@
export abstract class Contractor {
public contractorType: string;
}

View File

@ -0,0 +1,11 @@
import { Contractor } from './contractor';
export abstract class LegalEntity extends Contractor {
public entityType: string;
constructor() {
super();
this.contractorType = 'LegalEntity';
}
}

View File

@ -0,0 +1,39 @@
import { LegalEntity } from './legal-entity';
import { BankAccount } from '../../bank-account';
export class RussianLegalEntity extends LegalEntity {
public registeredName: string;
public registeredNumber: string;
public inn: string;
public actualAddress: string;
public postAddress: string;
public representativePosition: string;
public representativeFullName: string;
public representativeDocument: string;
public bankAccount: BankAccount;
constructor(options: {
registeredName: string,
registeredNumber: string,
inn: string,
actualAddress: string,
postAddress: string,
representativePosition: string,
representativeFullName: string,
representativeDocument: string,
bankAccount: BankAccount
}) {
super();
this.entityType = 'RussianLegalEntity';
this.registeredName = options.registeredName;
this.registeredNumber = options.registeredNumber;
this.inn = options.inn;
this.actualAddress = options.actualAddress;
this.postAddress = options.postAddress;
this.representativePosition = options.representativePosition;
this.representativeFullName = options.representativeFullName;
this.representativeDocument = options.representativeDocument;
this.bankAccount = options.bankAccount;
}
}

View File

@ -0,0 +1,5 @@
export * from './contractor/contractor';
export * from './contractor/legal-entity';
export * from './contractor/russian-legal-entity';
export * from './contract';
export * from './legal-agreement';

View File

@ -0,0 +1,4 @@
export class LegalAgreement {
public id: string;
public signedAt: string;
}

View File

@ -1,6 +1,9 @@
import { BankAccount } from './bank-account';
import { LegalEntity } from './legal-entity';
/**
* @deprecated
*/
export class Contractor {
public bankAccount: BankAccount;
public legalEntity: LegalEntity;

View File

@ -0,0 +1,4 @@
export * from './claim';
export * from './contract';
export * from './payout-tool';
export * from './shop';

View File

@ -1,3 +1,6 @@
/**
* @deprecated
*/
export class LegalEntity {
public entityType: string;
}

View File

@ -1,6 +1,9 @@
import { PayoutToolParams } from './payout-tool-params';
import { BankAccount } from './bank-account';
/**
* @deprecated Use koffing/backend/model/payout-tool/payout-tool-details/payout-tool-bank-account
*/
export class PayoutToolBankAccount extends PayoutToolParams {
public bankAccount: BankAccount;

View File

@ -1,3 +1,6 @@
/**
* @deprecated Use koffing/backend/model/payout-tool/payout-tool-details/payout-tool-details
*/
export class PayoutToolParams {
public payoutToolType: string;
public currency: string;

View File

@ -1,5 +1,8 @@
import { PayoutToolParams } from './payout-tool-params';
/**
* @deprecated Use koffing/backend/model/payout-tool/payout-tool
*/
export class PayoutTool {
public id: number;
public params: PayoutToolParams;

View File

@ -0,0 +1,3 @@
export * from './payout-tool-details/payout-tool-bank-account';
export * from './payout-tool-details/payout-tool-details';
export * from './payout-tool';

View File

@ -0,0 +1,13 @@
import { PayoutToolDetails } from './payout-tool-details';
import { BankAccount } from '../../bank-account';
export class PayoutToolBankAccount extends PayoutToolDetails {
public bankAccount: BankAccount;
constructor(bankAccount: BankAccount) {
super();
this.type = 'PayoutToolBankAccount';
this.bankAccount = bankAccount;
}
}

View File

@ -0,0 +1,3 @@
export abstract class PayoutToolDetails {
public type: string;
}

View File

@ -0,0 +1,7 @@
import { PayoutToolDetails } from './payout-tool-details/payout-tool-details';
export class PayoutTool {
public id: string;
public currency: string;
public details: PayoutToolDetails;
}

View File

@ -1,5 +1,8 @@
import { LegalEntity } from './legal-entity';
/**
* @deprecated
*/
export class RussianLegalEntity extends LegalEntity {
public registeredName: string;
public registeredNumber: string;

View File

@ -1,3 +1,6 @@
/**
* @deprecated Use koffing/backend/model/shop/shop-account
*/
export class ShopAccount {
public guaranteeID: number;
public settlementID: number;

View File

@ -1,5 +1,8 @@
import { ShopLocation } from './shop-location';
/**
* @deprecated
*/
export class ShopDetails {
public name: string;
public description: string;

View File

@ -1,5 +1,8 @@
import { ShopLocation } from './shop-location';
/**
* @deprecated
*/
export class ShopLocationUrl extends ShopLocation {
public url: string;

View File

@ -1,3 +1,6 @@
/**
* @deprecated
*/
export class ShopLocation {
public locationType: string;
}

View File

@ -4,6 +4,9 @@ import { ShopDetails } from './shop-details';
import { ShopAccount } from './shop-account';
import { ShopParams } from '../requests/shop-request';
/**
* @deprecated Use koffing/backend/model/shop/shop
*/
export class Shop {
public id: number;
public isBlocked: boolean;

View File

@ -0,0 +1,5 @@
export * from './shop-location/shop-location';
export * from './shop-location/shop-location-url';
export * from './shop';
export * from './shop-account';
export * from './shop-details';

View File

@ -0,0 +1,5 @@
export class ShopAccount {
public currency: string;
public guaranteeID: number;
public settlementID: number;
}

View File

@ -0,0 +1,9 @@
export class ShopDetails {
public name: string;
public description: string;
constructor(name: string, description?: string) {
this.name = name;
this.description = description;
}
}

View File

@ -0,0 +1,12 @@
import { ShopLocation } from './shop-location';
export class ShopLocationUrl extends ShopLocation {
public url: string;
constructor(url: string) {
super();
this.locationType = 'ShopLocationUrl';
this.url = url;
}
}

View File

@ -0,0 +1,3 @@
export abstract class ShopLocation {
public locationType: string;
}

View File

@ -0,0 +1,16 @@
import { ShopLocation } from './shop-location/shop-location';
import { ShopDetails } from './shop-details';
import { ShopAccount } from './shop-account';
export class Shop {
public id: string;
public createdAt: string;
public isBlocked: boolean;
public isSuspended: boolean;
public categoryID: number;
public location: ShopLocation;
public details: ShopDetails;
public contractID: string;
public payoutToolID: string;
public account: ShopAccount;
}

View File

@ -0,0 +1,27 @@
import { Injectable } from '@angular/core';
import { Http } from '@angular/http/src';
import { Observable } from 'rxjs/Observable';
import { ConfigService } from './config.service';
import { PayoutTool } from './model/payout-tool/payout-tool';
@Injectable()
export class PayoutToolService {
constructor(private http: Http,
private config: ConfigService) {
}
public getPayoutTools(contractID: string): Observable<PayoutTool[]> {
return this.http.get(this.getEndpoint(contractID)).map((res) => res.json());
}
public getPayoutToolByID(contractID: string, payoutToolID: string): Observable<PayoutTool> {
return this.http.get(`${this.getEndpoint(contractID)}/${payoutToolID}`).map((res) => res.json());
}
private getEndpoint(contractID: string) {
return `${this.config.capiUrl}/processing/contracts/${contractID}/payout_tools`;
}
}

View File

@ -1,5 +1,5 @@
export class CreateInvoiceParams {
public shopID: number;
public shopID: string;
public amount: number;
public currency: string;
public metadata: Object;

View File

@ -1,6 +1,9 @@
import { ShopDetails } from '../model/shop-details';
import * as _ from 'lodash';
/**
* @deprecated Use ClaimService
*/
export class ShopParams {
public details: ShopDetails;

View File

@ -19,17 +19,21 @@ export class SearchService {
) { }
public searchInvoices(shopID: string, invoiceParams: SearchInvoicesParams): Observable<InvoiceSearchResult> {
const params = this.toSearchParams(invoiceParams);
return this.http.get(`${this.config.capiUrl}/analytics/shops/${shopID}/invoices`, {search: params})
const search = this.toSearchParams(invoiceParams);
return this.http.get(`${this.getEndpoint(shopID)}/invoices`, {search})
.map((res) => res.json());
}
public searchPayments(shopID: string, paymentsParams: SearchPaymentsParams): Observable<PaymentSearchResult> {
const params = this.toSearchParams(paymentsParams);
return this.http.get(`${this.config.capiUrl}/analytics/shops/${shopID}/payments`, {search: params})
const search = this.toSearchParams(paymentsParams);
return this.http.get(`${this.getEndpoint(shopID)}/payments`, {search})
.map((res) => res.json());
}
private getEndpoint(shopID: string): string {
return `${this.config.capiUrl}/analytics/shops/${shopID}`;
}
private toSearchParams(params: object): URLSearchParams {
const result = new URLSearchParams();
forEach(params, (value, field) => {

View File

@ -1,60 +1,96 @@
import { Injectable } from '@angular/core';
import { Http } from '@angular/http';
import 'rxjs/add/operator/toPromise';
import { Observable } from 'rxjs';
import { Shop } from './model/shop';
import { ConfigService } from './config.service';
import { ShopParams } from './requests/shop-request';
import { Observable } from 'rxjs';
import { Shop as ShopNew } from 'koffing/backend/model/shop/shop';
@Injectable()
export class ShopService {
private shopsUrl: string = `${this.config.capiUrl}/processing/shops`;
private endpoint: string = `${this.config.capiUrl}/processing/shops`;
constructor(
private http: Http,
private config: ConfigService
) { }
constructor(private http: Http,
private config: ConfigService) {
}
/**
* @deprecated Use getShopsObs
*/
public getShops(): Promise<Shop[]> {
return this.http.get(this.shopsUrl)
return this.http.get(this.endpoint)
.toPromise()
.then(response => response.json() as Shop[]);
}
/**
* @deprecated Use getShopObs
*/
public getShop(shopID: number): Promise<Shop> {
return this.http.get(`${this.shopsUrl}/${shopID}`)
return this.http.get(`${this.endpoint}/${shopID}`)
.toPromise()
.then(response => response.json() as Shop);
}
/**
* @deprecated Use getShopObs
*/
public getShopObservable(shopID: string): Observable<Shop> {
return this.http.get(`${this.shopsUrl}/${shopID}`)
return this.http.get(`${this.endpoint}/${shopID}`)
.map((res) => res.json());
}
/**
* @deprecated Use ClaimService
*/
public createShop(args: ShopParams): Promise<string> {
return this.http.post(this.shopsUrl, args)
return this.http.post(this.endpoint, args)
.toPromise()
.then(response => response.json());
}
/**
* @deprecated Use ClaimService
*/
public updateShop(shopID: number, args: ShopParams): Promise<string> {
return this.http.post(`${this.shopsUrl}/${shopID}`, args)
return this.http.post(`${this.endpoint}/${shopID}`, args)
.toPromise()
.then(response => response.json());
}
/**
* @deprecated Use activateShopObs
*/
public activateShop(shopID: any): Promise<string> {
return this.http.put(`${this.shopsUrl}/${shopID}/activate`, {})
return this.http.put(`${this.endpoint}/${shopID}/activate`, {})
.toPromise()
.then(response => response.json());
}
/**
* @deprecated Use suspendShopObs
*/
public suspendShop(shopID: any): Promise<string> {
return this.http.put(`${this.shopsUrl}/${shopID}/suspend`, {})
return this.http.put(`${this.endpoint}/${shopID}/suspend`, {})
.toPromise()
.then(response => response.json());
}
public getShopsObs(): Observable<ShopNew[]> {
return this.http.get(this.endpoint).map((res) => res.json());
}
public getShopByID(shopID: string): Observable<ShopNew> {
return this.http.get(`${this.endpoint}/${shopID}`).map((res) => res.json());
}
public activateShopObs(shopID: string): Observable<void> {
return this.http.put(`${this.endpoint}/${shopID}/activate`, {}).map((res) => res.json());
}
public suspendShopObs(shopID: string): Observable<void> {
return this.http.put(`${this.endpoint}/${shopID}/suspend`, {}).map((res) => res.json());
}
}

View File

@ -9,24 +9,26 @@ import { CreateWebhookParams } from './requests/create-webhook-request';
@Injectable()
export class WebhooksService {
private endpoint = `${this.config.capiUrl}/processing/webhooks`;
constructor(
private http: Http,
private config: ConfigService
) { }
public createWebhook(webhook: CreateWebhookParams): Observable<Webhook> {
return this.http.post(`${this.config.capiUrl}/processing/webhooks`, webhook).map(res => res.json());
return this.http.post(this.endpoint, webhook).map(res => res.json());
}
public getWebhooks(): Observable<Webhook[]> {
return this.http.get(`${this.config.capiUrl}/processing/webhooks`).map(res => res.json());
return this.http.get(this.endpoint).map(res => res.json());
}
public getWebhookByID(webhookID: string): Observable<Webhook> {
return this.http.get(`${this.config.capiUrl}/processing/webhooks/${webhookID}`).map(res => res.json());
return this.http.get(`${this.endpoint}/${webhookID}`).map(res => res.json());
}
public deleteWebhookByID(webhookID: string): Observable<Webhook> {
return this.http.delete(`${this.config.capiUrl}/processing/webhooks/${webhookID}`).map(res => res.json());
return this.http.delete(`${this.endpoint}/${webhookID}`).map(res => res.json());
}
}

View File

@ -0,0 +1 @@
@import '../../../styles/form';

View File

@ -0,0 +1,27 @@
form.form-horizontal.form-label-left.css-form([formGroup]="form", novalidate)
.form-group
.col-xs-12.col-sm-5
label.text-left БИК банковской организации
span.highlighted *
.col-xs-12.col-sm-7
input.form-control.has-feedback-right.bank-suggestions(type="text", formControlName="bankBik")
i.fa.fa-magic.form-control-feedback.right(aria-hidden="true")
.form-group
.col-xs-12.col-sm-5
label.text-left Наименование банка
span.highlighted *
.col-xs-12.col-sm-7
input.form-control.has-feedback-right.bank-suggestions(type="text", formControlName="bankName")
i.fa.fa-magic.form-control-feedback.right(aria-hidden="true")
.form-group
.col-xs-12.col-sm-5
label.text-left Корреспондентский счет
span.highlighted *
.col-xs-12.col-sm-7
input.form-control(type="text", formControlName="bankPostAccount")
.form-group
.col-xs-12.col-sm-5
label.text-left Расчетный счет
span.highlighted *
.col-xs-12.col-sm-7
input.form-control(type="text", formControlName="account")

View File

@ -0,0 +1,34 @@
import { AfterViewInit, Component, Input } from '@angular/core';
import { FormGroup } from '@angular/forms';
import { SuggestionsService } from 'koffing/suggestions/services/suggestions.service';
import { BankAccountFormService } from './bank-account-form.service';
@Component({
selector: 'kof-bank-account-form',
templateUrl: 'bank-account-form.component.pug',
styleUrls: ['bank-account-form.component.less'],
providers: [BankAccountFormService]
})
export class BankAccountFormComponent implements AfterViewInit {
@Input()
public form: FormGroup;
constructor(private suggestionsService: SuggestionsService,
private bankAccountFormService: BankAccountFormService) { }
public ngAfterViewInit() {
this.initBankSuggestions();
}
private initBankSuggestions() {
const selector = '.bank-suggestions';
this.suggestionsService.initBankSuggestions(selector, this.handleBank.bind(this));
}
private handleBank(suggestion: BankSuggestion) {
const value = this.bankAccountFormService.toFormValue(suggestion);
this.form.patchValue(value);
}
}

View File

@ -0,0 +1,17 @@
import { Injectable } from '@angular/core';
@Injectable()
export class BankAccountFormService {
public toFormValue(suggestion: BankSuggestion): any {
const value: any = {};
if (suggestion) {
value.bankName = suggestion.unrestricted_value;
if (suggestion.data) {
value.bankPostAccount = suggestion.data.correspondent_account;
value.bankBik = suggestion.data.bic;
}
}
return value;
}
}

View File

@ -0,0 +1,19 @@
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({
name: 'kofClaimStatus'
})
export class ClaimStatusPipe implements PipeTransform {
private statuses = {
ClaimAccepted: 'Подтверждена',
ClaimDenied: 'Отклонена',
ClaimPending: 'На рассмотрении',
ClaimRevoked: 'Отозвана'
};
public transform(input: string): string {
const status = this.statuses[input];
return status ? status : input;
}
}

View File

@ -0,0 +1 @@
@import '../../../styles/form';

View File

@ -0,0 +1,55 @@
form.form-horizontal.form-label-left.css-form([formGroup]="form", novalidate)
.form-group
.col-xs-12.col-sm-5
label.text-left Зарегистрированное наименование юридического лица
span.highlighted *
.col-xs-12.col-sm-7
input.form-control.has-feedback-right.contractor-suggestions(type="text", formControlName="registeredName")
i.fa.fa-magic.form-control-feedback.right(aria-hidden="true")
.form-group
.col-xs-12.col-sm-5
label.text-left Регистрационный номер (ОГРН/ОГРНИП)
span.highlighted *
.col-xs-12.col-sm-7
input.form-control.has-feedback-right.contractor-suggestions(type="text", formControlName="registeredNumber")
i.fa.fa-magic.form-control-feedback.right(aria-hidden="true")
.form-group
.col-xs-12.col-sm-5
label.text-left Идентификационный номер налогоплательщика (ИНН)
span.highlighted *
.col-xs-12.col-sm-7
input.form-control.has-feedback-right.contractor-suggestions(type="text", formControlName="inn")
i.fa.fa-magic.form-control-feedback.right(aria-hidden="true")
.form-group
.col-xs-12.col-sm-5
label.text-left Почтовый адрес для отправки корреспонденции
span.highlighted *
.col-xs-12.col-sm-7
input.form-control.has-feedback-right.contractor-suggestions(type="text", formControlName="postAddress")
i.fa.fa-magic.form-control-feedback.right(aria-hidden="true")
.form-group
.col-xs-12.col-sm-5
label.text-left Почтовый адрес места нахождения
span.highlighted *
.col-xs-12.col-sm-7
input.form-control(type="text", formControlName="actualAddress")
.form-group
.col-xs-12.col-sm-5
label.text-left Наименование должности ЕИО/представителя
span.highlighted *
.col-xs-12.col-sm-7
input.form-control(type="text", formControlName="representativePosition")
.form-group
.col-xs-12.col-sm-5
label.text-left ФИО ЕИО/представителя
span.highlighted *
.col-xs-12.col-sm-7
input.form-control(type="text", formControlName="representativeFullName")
.form-group
.col-xs-12.col-sm-5
label.text-left Данные документа ЕИО/представителя
span.highlighted *
.col-xs-12.col-sm-7
input.form-control(type="text", formControlName="representativeDocument")
.ln_solid
kof-bank-account-form([form]="accountGroup")

View File

@ -0,0 +1,41 @@
import { AfterViewInit, Component, Input, OnInit } from '@angular/core';
import { AbstractControl, FormGroup } from '@angular/forms';
import { SuggestionsService } from 'koffing/suggestions/services/suggestions.service';
import { ContractFormService } from './contract-form.service';
@Component({
selector: 'kof-contract-form',
templateUrl: 'contract-form.component.pug',
styleUrls: ['contract-form.component.less'],
providers: [ContractFormService]
})
export class ContractFormComponent implements OnInit, AfterViewInit {
@Input()
public form: FormGroup;
public accountGroup: AbstractControl;
constructor(private suggestionsService: SuggestionsService,
private contractFormService: ContractFormService) {
}
public ngOnInit() {
this.accountGroup = this.form.get('bankAccount');
}
public ngAfterViewInit() {
this.initContractorSuggestions();
}
private handleContractor(suggestion: OgranizationSuggestion) {
const value = this.contractFormService.toFormValue(suggestion);
this.form.patchValue(value);
}
private initContractorSuggestions() {
const selector = '.contractor-suggestions';
this.suggestionsService.initContractorSuggestions(selector, this.handleContractor.bind(this));
}
}

View File

@ -0,0 +1,24 @@
import { Injectable } from '@angular/core';
@Injectable()
export class ContractFormService {
public toFormValue(suggestion: OgranizationSuggestion): any {
const value: any = {};
if (suggestion) {
value.registeredName = suggestion.unrestricted_value;
if (suggestion.data) {
value.registeredNumber = suggestion.data.ogrn;
value.inn = suggestion.data.inn;
if (suggestion.data.address) {
value.postAddress = suggestion.data.address.unrestricted_value;
}
if (suggestion.data.management) {
value.representativePosition = suggestion.data.management.post;
value.representativeFullName = suggestion.data.management.name;
}
}
}
return value;
}
}

View File

@ -0,0 +1,7 @@
.wizard_steps {
padding-left: 0;
}
.wizard_horizontal ul.wizard_steps li {
width: 33%;
display: table-cell!important;
}

View File

@ -0,0 +1,34 @@
.x_panel
.x_content
.form_wizard.wizard_horizontal
ul.wizard_steps
li.first_step
a([ngClass]="{'done': currentStep > step.contract, 'selected': currentStep === step.contract}")
span.step_no 1
span.step_descr Контракт
li
a([ngClass]="{'disabled': currentStep < step.payoutTool, 'done': currentStep > step.payoutTool, 'selected': currentStep === step.payoutTool}")
span.step_no 2
span.step_descr Средство вывода
li
a([ngClass]="{'disabled': currentStep < step.shop, 'done': currentStep > step.shop, 'selected': currentStep === step.shop}")
span.step_no 3
span.step_descr Данные магазина
.ln_solid
kof-contract-form(*ngIf="currentStep === step.contract", [form]="contractGroup")
kof-bank-account-form(*ngIf="currentStep === step.payoutTool", [form]="payoutToolGroup")
kof-shop-form(*ngIf="currentStep === step.shop", [form]="shopGroup")
.ln_solid
.row
.col-xs-12
button.btn.btn-default(
[disabled]="currentStep === step.contract",
(click)="prev()") Назад
button.btn.btn-default.pull-right(
*ngIf="currentStep !== step.shop",
[disabled]="!validStep",
(click)="next()") Далее
button.btn.btn-primary.pull-right(
*ngIf="currentStep === step.shop",
[disabled]="!validStep",
(click)="createClaim()") Создать заявку

View File

@ -0,0 +1,57 @@
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { CreateShopService } from './create-shop.service';
import { ShopCreationStep } from './shop-creation-step';
import { ClaimService } from 'koffing/backend/claim.service';
import { PartyModification } from 'koffing/backend/model/claim/party-modification/party-modification';
import { FormResolver } from './form-resolver.service';
@Component({
templateUrl: 'create-shop.component.pug',
providers: [
CreateShopService,
FormResolver
],
styleUrls: ['create-shop.component.less']
})
export class CreateShopComponent implements OnInit {
public validStep = false;
public step = ShopCreationStep;
public currentStep = ShopCreationStep.contract;
public contractGroup = this.createShopService.contractGroup;
public payoutToolGroup = this.createShopService.payoutToolGroup;
public shopGroup = this.createShopService.shopGroup;
private changeset: PartyModification[];
constructor(private claimService: ClaimService,
private createShopService: CreateShopService,
private router: Router) { }
public ngOnInit() {
this.createShopService.changesetEmitter.subscribe((changeset) => {
this.changeset = changeset;
this.validStep = this.isValid();
});
}
public next() {
this.currentStep = this.currentStep + 1;
this.validStep = this.isValid();
}
public prev() {
this.currentStep = this.currentStep - 1;
this.validStep = this.isValid();
}
public createClaim() {
this.claimService.createClaim(this.changeset).subscribe(() =>
this.router.navigate(['/management']));
}
private isValid(): boolean {
return !!this.changeset[this.currentStep];
}
}

View File

@ -0,0 +1,49 @@
import { Injectable } from '@angular/core';
import { FormGroup } from '@angular/forms';
import { Subject } from 'rxjs/Subject';
import { PartyModification } from 'koffing/backend/model/claim/party-modification/party-modification';
import { FormResolver } from 'koffing/management-2/create-shop/form-resolver.service';
import { ShopCreationStep } from 'koffing/management-2/create-shop/shop-creation-step';
@Injectable()
export class CreateShopService {
public contractGroup: FormGroup;
public payoutToolGroup: FormGroup;
public shopGroup: FormGroup;
public changesetEmitter: Subject<PartyModification[]> = new Subject();
private changeset: PartyModification[] = [ , , ];
private contractID: string;
private payoutToolID: string;
constructor(private formResolver: FormResolver) {
this.contractGroup = this.formResolver.prepareContractGroup();
this.payoutToolGroup = this.formResolver.prepareBankAccountGroup();
this.shopGroup = this.formResolver.prepareShopGroup();
this.handleGroups();
}
private handleGroups() {
this.handleStatus(this.contractGroup, () => {
const contractCreation = this.formResolver.toContractCreation(this.contractGroup);
this.contractID = contractCreation.contractID;
this.changeset[ShopCreationStep.contract] = contractCreation;
});
this.handleStatus(this.payoutToolGroup, () => {
const payoutToolCreation = this.formResolver.toPayoutToolCreation(this.contractID, this.payoutToolGroup);
this.payoutToolID = payoutToolCreation.payoutToolID;
this.changeset[ShopCreationStep.payoutTool] = payoutToolCreation;
});
this.handleStatus(this.shopGroup, () => {
this.changeset[ShopCreationStep.shop] = this.formResolver.toShopCreation(this.contractID, this.payoutToolID, this.shopGroup);
});
}
private handleStatus(group: FormGroup, doHandler: any) {
group.statusChanges
.filter((status) => status === 'VALID')
.do(doHandler)
.subscribe(() => this.changesetEmitter.next(this.changeset));
}
}

View File

@ -0,0 +1,109 @@
import { Injectable } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import * as uuid from 'uuid/v4';
import { ContractCreation, ContractPayoutToolCreation, ShopCreation } from 'koffing/backend/model/claim';
// TODO fix urls
import { RussianLegalEntity } from 'koffing/backend/model/contract/contractor/russian-legal-entity';
import { PayoutToolBankAccount } from 'koffing/backend/model/payout-tool/payout-tool-details/payout-tool-bank-account';
import { ShopDetails } from 'koffing/backend/model/shop/shop-details';
import { ShopLocationUrl } from 'koffing/backend/model/shop/shop-location/shop-location-url';
@Injectable()
export class FormResolver {
constructor(private fb: FormBuilder) { }
public prepareContractGroup(): FormGroup {
return this.fb.group({
registeredName: ['', [
Validators.required,
Validators.maxLength(100)
]],
registeredNumber: ['', [
Validators.required,
Validators.pattern(/^(\d{13}|\d{15})$/)
]],
inn: ['', [
Validators.required,
Validators.pattern(/^\d{10}$/)
]],
postAddress: ['', [
Validators.required,
Validators.maxLength(1000)
]],
actualAddress: ['', [
Validators.required,
Validators.maxLength(1000)
]],
representativePosition: ['', [
Validators.required,
Validators.maxLength(100)
]],
representativeFullName: ['', [
Validators.required,
Validators.maxLength(100)
]],
representativeDocument: ['', [
Validators.required,
Validators.maxLength(1000)
]],
bankAccount: this.prepareBankAccountGroup()
});
}
public prepareBankAccountGroup(): FormGroup {
return this.fb.group({
account: ['', [
Validators.required,
Validators.pattern(/^\d{20}$/)
]],
bankName: ['', [
Validators.required,
Validators.maxLength(100)
]],
bankPostAccount: ['', [
Validators.required,
Validators.pattern(/^\d{20}$/)
]],
bankBik: ['', [
Validators.required,
Validators.pattern(/^\d{9}$/)
]]
});
}
public prepareShopGroup(): FormGroup {
return this.fb.group({
url: ['', [
Validators.required,
Validators.maxLength(1000)
]],
name: ['', [
Validators.required,
Validators.maxLength(100)
]],
description: ['', Validators.maxLength(1000)]
});
}
public toContractCreation(contractForm: FormGroup): ContractCreation {
const contractor = new RussianLegalEntity(contractForm.value);
return new ContractCreation(uuid(), contractor);
}
public toPayoutToolCreation(contractID: string, bankAccount: FormGroup): ContractPayoutToolCreation {
const details = new PayoutToolBankAccount(bankAccount.value);
return new ContractPayoutToolCreation(contractID, uuid(), details);
}
public toShopCreation(contractID: string, payoutToolID: string, shopForm: FormGroup): ShopCreation {
const val = shopForm.value;
return new ShopCreation({
shopID: uuid(),
location: new ShopLocationUrl(val.url),
details: new ShopDetails(val.name, val.description),
contractID, payoutToolID
});
}
}

View File

@ -0,0 +1,3 @@
export enum ShopCreationStep {
contract, payoutTool, shop
}

View File

@ -0,0 +1,21 @@
import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';
import { CreateShopComponent } from './create-shop/create-shop.component';
import { ManagementComponent } from './management.component';
@NgModule({
imports: [
RouterModule.forChild([
{
path: 'management',
component: ManagementComponent
},
{
path: 'management/shop/create',
component: CreateShopComponent
}
])
]
})
export class ManagementRoutingModule {}

View File

@ -0,0 +1,24 @@
.x_panel
.x_title
h5 Действия
.x_content
button.btn.btn-primary((click)="createShop()") Создать магазин
.x_panel
.x_title
h5 Заявки
.x_content
table.table.table-hover.table-striped
thead
tr
th Идентификатор
th Статус
th Дата и время создания
th Дата и время изменения
th Номер ревизии
tbody(*ngFor="let claim of claims")
tr
td {{claim.id}}
td {{claim.status | kofClaimStatus}}
td {{claim.createdAt | date: "dd.MM.yyyy HH:mm:ss"}}
td {{claim.updatedAt | date: "dd.MM.yyyy HH:mm:ss"}}
td {{claim.revision}}

View File

@ -0,0 +1,25 @@
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { ClaimService } from 'koffing/backend/claim.service';
import { Claim } from 'koffing/backend';
@Component({
templateUrl: 'management.component.pug'
})
export class ManagementComponent implements OnInit {
public claims: Claim[];
constructor(private claimService: ClaimService, private router: Router) { }
public ngOnInit() {
this.claimService.getClaims().subscribe((claims: Claim[]) => {
this.claims = claims;
});
}
public createShop() {
this.router.navigate(['/management/shop/create']);
}
}

View File

@ -0,0 +1,37 @@
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { CommonModule } from 'koffing/common/common.module';
import { BackendModule } from 'koffing/backend/backend.module';
import { SuggestionsModule } from 'koffing/suggestions/suggestions.module';
import { ManagementRoutingModule } from './management-routing.module';
import { CreateShopComponent } from './create-shop/create-shop.component';
import { ContractFormComponent } from './contract-form/contract-form.component';
import { ShopGroupComponent } from './shop-form/shop-form.component';
import { BankAccountFormComponent } from './bank-account-form/bank-account-form.component';
import { ManagementComponent } from './management.component';
import { ClaimService } from 'koffing/backend/claim.service';
import { ClaimStatusPipe } from 'koffing/management-2/claim-status.pipe';
@NgModule({
imports: [
ManagementRoutingModule,
BrowserModule,
FormsModule,
ReactiveFormsModule,
CommonModule,
BackendModule,
SuggestionsModule
],
declarations: [
ManagementComponent,
CreateShopComponent,
ContractFormComponent,
ShopGroupComponent,
BankAccountFormComponent,
ClaimStatusPipe
],
providers: [ClaimService]
})
export class ManagementModule { }

View File

@ -0,0 +1 @@
@import '../../../styles/form';

View File

@ -0,0 +1,18 @@
form.form-horizontal.form-label-left.css-form([formGroup]="form", novalidate)
.form-group
.col-xs-12.col-sm-5
label.text-left URL сайта магазина
span.highlighted *
.col-xs-12.col-sm-7
input.form-control(type="text", formControlName="url")
.form-group
.col-xs-12.col-sm-5
label.text-left Название магазина
span.highlighted *
.col-xs-12.col-sm-7
input.form-control(type="text", formControlName="name")
.form-group
.col-xs-12.col-sm-5
label.text-left Краткое описание
.col-xs-12.col-sm-7
input.form-control(type="text", formControlName="description")

View File

@ -0,0 +1,14 @@
import { Component, Input } from '@angular/core';
import { FormGroup } from '@angular/forms';
@Component({
selector: 'kof-shop-form',
templateUrl: 'shop-form.component.pug',
styleUrls: ['shop-form.component.less']
})
export class ShopGroupComponent {
@Input()
public form: FormGroup;
}

View File

@ -11,10 +11,6 @@
a([routerLink]=["/analytics"])
i.fa.fa-bar-chart-o
| Аналитика
//li([routerLinkActive]="['active']")
a([routerLink]=["/management"])
i.fa.fa-shopping-cart
| Управление магазинами
li([routerLinkActive]="['active']")
a([routerLink]=["/webhooks"])
i.fa.fa-cogs
@ -23,3 +19,7 @@
a([routerLink]=["/key"])
i.fa.fa-key
| API ключ
li([routerLinkActive]="['active']")
a([routerLink]=["/management"])
i.fa.fa-shopping-cart
| Управление магазинами

View File

@ -1,13 +1,6 @@
import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';
// todo выпилить эти костыли, перенести в management.module
import { ContractCreateComponent } from 'koffing/management/contracts/contract-create/contract-create.component';
import { PayoutToolCreateComponent } from 'koffing/management/contracts/payout-tool-create/payout-tool-create.component';
import { ShopEditingComponent } from 'koffing/management/shops/shop-editing/shop-editing.component';
import { CreateShopWizardComponent } from 'koffing/management/shops/create-shop-wizard/create-shop-wizard.component';
import { ClaimsEditComponent } from 'koffing/management/claims/claims-edit/claims-edit.component';
@NgModule({
imports: [
RouterModule.forRoot([
@ -15,26 +8,6 @@ import { ClaimsEditComponent } from 'koffing/management/claims/claims-edit/claim
path: '',
redirectTo: '/analytics',
pathMatch: 'full'
},
{
path: 'shops/create',
component: CreateShopWizardComponent
},
{
path: 'shops/:shopID/edit',
component: ShopEditingComponent
},
{
path: 'shops/:shopID/edit/contract/create',
component: ContractCreateComponent
},
{
path: 'shops/:shopID/edit/contract/:contractID/payoutTool/create',
component: PayoutToolCreateComponent
},
{
path: 'claims/edit',
component: ClaimsEditComponent
}
])
],

View File

@ -8,7 +8,7 @@ import { BroadcasterModule } from '../broadcaster/broadcaster.module';
import { TokenizationModule } from '../tokenization/tokenization.module';
import { WebhooksModule } from '../webhooks/webhooks.module';
import { AnalyticsModule } from '../analytics/analytics.module';
import { ManagementModule } from '../management/management.module';
import { ManagementModule } from '../management-2/management.module';
import { SidebarComponent } from './components/sidebar/sidebar.component';
import { TopPanelComponent } from './components/top-panel/top-panel.component';
import { ContainerComponent } from './components/container/container.component';

3
src/styles/form.less Normal file
View File

@ -0,0 +1,3 @@
input.ng-dirty.ng-invalid {
border-color: #a94442;
}