FE-199: [Заявки] Нужно уметь не только отменять, а ещё и пересоздавать ("изменять") заявку (#96)

* FE-199: изменение заявки

* FE-199: компонент edit-shop разбит на два - внешний и дочерний с формой

* FE-199: дополнения классов

* FE-199: замена цепочек с логическим && на безопасный оператор ? в шаблонах компонентов
This commit is contained in:
Max Minin 2017-03-17 19:01:04 +02:00 committed by GitHub
parent 1b4769ca8e
commit b3590c3abf
65 changed files with 990 additions and 279 deletions

View File

@ -36,7 +36,7 @@
"@types/core-js": "0.9.34",
"@types/jasmine": "2.5.35",
"@types/jquery": "2.0.40",
"@types/lodash": "4.14.38",
"@types/lodash": "4.14.55",
"@types/node": "6.0.45",
"angular2-template-loader": "0.4.0",
"awesome-typescript-loader": "3.0.0-beta.17",

View File

@ -42,7 +42,7 @@ export * from './classes/account.class';
export * from './classes/bank-account.class';
export * from './classes/callback-handler.class';
export * from './classes/category.class';
export * from './classes/claim.class';
export * from './classes/claim/claim.class';
export * from './classes/contract.class';
export * from './classes/contractor.class';
export * from './classes/conversion.class';
@ -56,7 +56,14 @@ export * from './classes/request-params.class';
export * from './classes/revenue.class';
export * from './classes/russian-legal-entity.class';
export * from './classes/shop.class';
export * from './classes/shop-detail.class';
export * from './classes/shop-details.class';
export * from './classes/shop-item.class';
export * from './classes/shop-location.class';
export * from './classes/location-name.class';
export * from './classes/shop-params.class';
export * from './classes/claim/contract-creation.class';
export * from './classes/claim/contract-modification.class';
export * from './classes/claim/contract-payout-tool-creation.class';
export * from './classes/claim/shop-creation.class';
export * from './classes/claim/shop-modification.class';
export * from './classes/claim/shop-update.class';

View File

@ -1,4 +1,4 @@
export class Account {
export class ShopAccount {
public guaranteeID: string;
public settlementID: string;
public currency: string;

View File

@ -1,7 +0,0 @@
export class Claim {
public id: number;
public changeset: any[];
public status: {
status: string;
};
}

View File

@ -0,0 +1,4 @@
export class ClaimStatus {
public status: string;
}

View File

@ -0,0 +1,9 @@
import { ClaimStatus } from './claim-status.class';
import { PartyModification } from './party-modification.class';
export class Claim {
public id: number;
public changeset: PartyModification[];
public status: ClaimStatus;
}

View File

@ -0,0 +1,7 @@
import { PartyModification } from './party-modification.class';
import { Contract } from 'koffing/backend/classes/contract.class';
export class ContractCreation extends PartyModification {
public contract: Contract;
}

View File

@ -0,0 +1,7 @@
import { PartyModification } from './party-modification.class';
export class ContractModification extends PartyModification {
public contractModificationType: string;
public contractID: number;
}

View File

@ -0,0 +1,7 @@
import { ContractModification } from './contract-modification.class';
import { PayoutTool } from 'koffing/backend/classes/payout-tool.class';
export class ContractPayoutToolCreation extends ContractModification {
public payoutTool: PayoutTool;
}

View File

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

View File

@ -0,0 +1,7 @@
import { ShopModification } from './shop-modification.class';
import { ShopAccount } from 'koffing/backend/classes/account.class';
export class ShopAccountCreation extends ShopModification {
public account: ShopAccount;
}

View File

@ -0,0 +1,7 @@
import { PartyModification } from './party-modification.class';
import { Shop } from 'koffing/backend/classes/shop.class';
export class ShopCreation extends PartyModification {
public shop: Shop;
}

View File

@ -0,0 +1,7 @@
import { PartyModification } from './party-modification.class';
export class ShopModification extends PartyModification {
public shopID: number;
public shopModificationType: string;
}

View File

@ -0,0 +1,7 @@
import { ShopModification } from './shop-modification.class';
import { ShopParams } from 'koffing/backend/classes/shop-params.class';
export class ShopUpdate extends ShopModification {
public details: ShopParams;
}

View File

@ -1,9 +0,0 @@
import { ShopDetail } from 'koffing/backend/classes/shop-detail.class';
export class CreateShopArgs {
public categoryID: number;
public details: ShopDetail;
public contractID: number;
public payoutToolID: number;
public callbackUrl: string;
}

View File

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

View File

@ -0,0 +1,33 @@
import { ShopDetails } from 'koffing/backend/backend.module';
import * as _ from 'lodash';
export class ShopParams {
public categoryID: number;
public details: ShopDetails;
public contractID: number;
public payoutToolID: number;
public callbackUrl: string;
constructor(
categoryID?: number,
details?: ShopDetails,
contractID?: number,
payoutToolID?: number,
callbackUrl?: string
) {
this.categoryID = categoryID;
this.details = details ? details : new ShopDetails();
this.contractID = contractID;
this.payoutToolID = payoutToolID;
this.callbackUrl = callbackUrl;
}
public update(params: ShopParams) {
this.categoryID = _.defaultTo(params.categoryID, this.categoryID);
_.assign(this.details, params.details);
this.contractID = _.defaultTo(params.contractID, this.contractID);
this.payoutToolID = _.defaultTo(params.payoutToolID, this.payoutToolID);
this.callbackUrl = _.defaultTo(params.callbackUrl, this.callbackUrl);
}
}

View File

@ -1,6 +1,9 @@
import { ShopDetail } from './shop-detail.class';
import { Account } from './account.class';
import * as _ from 'lodash';
import { ShopDetails } from './shop-details.class';
import { ShopAccount } from './account.class';
import { CallbackHandler } from './callback-handler.class';
import { ShopParams } from './shop-params.class';
export class Shop {
public id: number;
@ -9,13 +12,21 @@ export class Shop {
public categoryID: number;
public contractID: number;
public payoutToolID: number;
public details: ShopDetail;
public account: Account;
public details: ShopDetails;
public account: ShopAccount;
public callbackHandler: CallbackHandler;
constructor() {
this.details = new ShopDetail();
this.account = new Account();
this.details = new ShopDetails();
this.account = new ShopAccount();
this.callbackHandler = new CallbackHandler();
}
public update(params: ShopParams) {
this.categoryID = _.defaultTo(params.categoryID, this.categoryID);
_.assign(this.details, params.details);
this.contractID = _.defaultTo(params.contractID, this.contractID);
this.payoutToolID = _.defaultTo(params.payoutToolID, this.payoutToolID);
this.callbackHandler.url = _.defaultTo(params.callbackUrl, this.callbackHandler.url);
}
}

View File

@ -2,7 +2,7 @@ import { Injectable } from '@angular/core';
import { Http, URLSearchParams } from '@angular/http';
import 'rxjs/add/operator/toPromise';
import { Claim } from '../classes/claim.class';
import { Claim } from '../classes/claim/claim.class';
import { ConfigService } from './config.service';
@Injectable()

View File

@ -8,6 +8,7 @@ import { Contract } from '../classes/contract.class';
import { PayoutTool } from '../classes/payout-tool.class';
import { ContractParams } from 'koffing/backend/classes/contract-params.class';
import { PayoutToolBankAccount } from 'koffing/backend/classes/payout-tool-bank-account.class';
import { PayoutToolParams } from 'koffing/backend/classes/payout-tool-params.class';
@Injectable()
export class ContractService {
@ -41,8 +42,8 @@ export class ContractService {
.then(response => response.json() as PayoutTool[]);
}
public createPayoutTool(contractID: number, payoutTool: PayoutToolBankAccount): Promise<any> {
return this.http.post(`${this.contractsUrl}/${contractID}/payout_tools`, payoutTool)
public createPayoutTool(contractID: number, payoutToolParams: PayoutToolParams): Promise<any> {
return this.http.post(`${this.contractsUrl}/${contractID}/payout_tools`, payoutToolParams)
.toPromise()
.then(response => response.json());
}

View File

@ -4,7 +4,7 @@ import 'rxjs/add/operator/toPromise';
import { Shop } from '../classes/shop.class';
import { ConfigService } from './config.service';
import { CreateShopArgs } from 'koffing/backend/classes/create-shop-args.class';
import { ShopParams } from 'koffing/backend/classes/shop-params.class';
@Injectable()
export class ShopService {
@ -25,13 +25,13 @@ export class ShopService {
.then(response => response.json() as Shop);
}
public createShop(args: CreateShopArgs): Promise<string> {
public createShop(args: ShopParams): Promise<string> {
return this.http.post(this.shopsUrl, args)
.toPromise()
.then(response => response.json());
}
public updateShop(shopID: number, args: CreateShopArgs): Promise<string> {
public updateShop(shopID: number, args: ShopParams): Promise<string> {
return this.http.post(`${this.shopsUrl}/${shopID}`, args)
.toPromise()
.then(response => response.json());

View File

@ -2,7 +2,8 @@ import { NgModule } from '@angular/core';
import { Broadcaster } from './services/broadcaster.service';
import { ToggleMenuBroadcaster } from './services/toggle-menu-broadcaster.service';
import { HttpErrorBroadcaster } from './services/http-error-broadcaster.service';
import { ClaimReceiveBroadcaster } from './services/claim-receive.broadcaster.service';
import { ClaimReceiveBroadcaster } from 'koffing/broadcaster/services/claim-receive.broadcaster.service';
import { ClaimRevokeBroadcaster } from 'koffing/broadcaster/services/claim-revoke-broadcaster.service';
import { ClaimCreateBroadcaster } from './services/claim-create.broadcaster.service';
@NgModule({
@ -11,6 +12,7 @@ import { ClaimCreateBroadcaster } from './services/claim-create.broadcaster.serv
ToggleMenuBroadcaster,
HttpErrorBroadcaster,
ClaimReceiveBroadcaster,
ClaimRevokeBroadcaster,
ClaimCreateBroadcaster
]
})
@ -20,4 +22,5 @@ export * from './services/broadcaster.service';
export * from './services/toggle-menu-broadcaster.service';
export * from './services/http-error-broadcaster.service';
export * from './services/claim-receive.broadcaster.service';
export * from './services/claim-revoke-broadcaster.service';
export * from './services/claim-create.broadcaster.service';

View File

@ -0,0 +1,17 @@
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { Broadcaster } from './broadcaster.service';
@Injectable()
export class ClaimRevokeBroadcaster {
constructor(private broadcaster: Broadcaster) {}
public fire() {
this.broadcaster.broadcast(ClaimRevokeBroadcaster);
}
public on(): Observable<string> {
return this.broadcaster.on<string>(ClaimRevokeBroadcaster);
}
}

View File

@ -0,0 +1,14 @@
import { PayoutToolParams } from 'koffing/backend/classes/payout-tool-params.class';
import { Contractor } from 'koffing/backend/classes/contractor.class';
import { Shop } from 'koffing/backend/classes/shop.class';
import { ShopEditingParams } from 'koffing/management/components/management-container/claims-edit/shop-editing-params.class';
export class ClaimData {
public claimID: number;
public payoutToolParams: PayoutToolParams;
public payoutToolContractId: number;
public contractor: Contractor;
public shop: Shop;
public shopEditingParams: ShopEditingParams;
}

View File

@ -0,0 +1,29 @@
.x_panel.tile
.x_content
kof-loading([isLoading]="isLoading")
kof-create-contract(
*ngIf="initIncludes && claimData?.contractor",
(onChange)="onContractorChange($event)",
[defaultContractor]="claimData.contractor"
)
kof-create-paytool(
*ngIf="initIncludes && claimData?.payoutToolParams",
(onChange)="onPayoutToolChange($event)",
[contractBankAccount]="claimData.contractor?.bankAccount",
[defaultPayoutToolParams]="claimData.payoutToolParams"
)
kof-add-shop(
*ngIf="initIncludes && claimData?.shop",
(onChange)="onShopFieldsChange($event)",
[defaultShop]="claimData.shop"
)
kof-edit-shop(
*ngIf="initIncludes && claimData?.shopEditingParams",
[shop]="claimData.shopEditingParams.shop",
[defaultShopChanges]="claimData.shopEditingParams.claimShopChanges",
(onChange)="onShopEditingChange($event)"
)
.form-group
.col-xs-12.col-sm-6.col-sm-offset-3
button.btn.btn-primary.pull-right(type="button", [disabled]="!canSubmit()", (click)="saveChanges()") Сохранить изменения
a.btn.btn-default(type="reset", (click)="returnToManagement()") Назад

View File

@ -0,0 +1,124 @@
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import * as _ from 'lodash';
import { ContractorTransfer } from 'koffing/management/components/management-container/shops/create-shop-wizard/selection-contract/create-contract/contractor-transfer.class';
import { PaytoolTransfer } from 'koffing/management/components/management-container/shops/create-shop-wizard/selection-paytool/create-paytool/paytool-transfer.class';
import { ShopDetailTransfer } from 'koffing/management/components/management-container/shops/create-shop-wizard/selection-shop-fields/add-shop/shop-detail-transfer.class';
import { ShopEditingTransfer } from 'koffing/management/components/management-container/shops/shop-editing/edit-shop/shop-editing-transfer.class';
import { ClaimsEditService } from 'koffing/management/services/claims-edit.service';
import { ClaimData } from 'koffing/management/classes/claim-data.class';
@Component({
selector: 'kof-claims-edit',
templateUrl: 'claims-edit.component.pug'
})
export class ClaimsEditComponent implements OnInit {
public claimData: ClaimData;
public isLoading: boolean = false;
public initIncludes: boolean = false;
private contractorReady: boolean;
private paytoolReady: boolean;
private shopReady: boolean;
private formsTouched: boolean = false;
constructor(
private claimsEditService: ClaimsEditService,
private router: Router
) { }
public ngOnInit() {
this.getClaimData();
}
public onContractorChange(value: ContractorTransfer) {
this.formsTouched = true;
this.contractorReady = value.valid;
if (value.valid) {
this.claimData.contractor = value.contractor;
}
}
public onPayoutToolChange(value: PaytoolTransfer) {
this.formsTouched = true;
this.paytoolReady = value.valid;
if (value.valid) {
this.claimData.payoutToolParams = value.payoutToolParams;
}
}
public onShopFieldsChange(value: ShopDetailTransfer) {
this.formsTouched = true;
this.shopReady = value.valid;
if (value.valid) {
this.claimData.shop.details = value.shopDetail;
this.claimData.shop.categoryID = value.categoryID;
if (this.claimData.shop.callbackHandler) {
this.claimData.shop.callbackHandler.url = value.callbackUrl;
}
}
}
public onShopEditingChange(value: ShopEditingTransfer) {
this.claimData.shopEditingParams.valid = value.valid;
this.claimData.shopEditingParams.dirty = value.dirty;
if (value.dirty) {
this.formsTouched = true;
}
if (value.valid) {
this.claimData.shopEditingParams.updatedShopParams = value.shopEditing;
}
}
public canSubmit(): boolean {
let canSubmit = false;
if (this.formsTouched) {
canSubmit = true;
canSubmit = canSubmit && (this.claimData.contractor ? this.contractorReady : true);
canSubmit = canSubmit && (this.claimData.payoutToolParams ? this.paytoolReady : true);
canSubmit = canSubmit && (this.claimData.shop ? this.shopReady : true);
if (this.claimData.shopEditingParams) {
if (!this.claimData.contractor && !this.claimData.payoutToolParams && !this.claimData.shop) {
canSubmit = canSubmit && this.claimData.shopEditingParams.dirty && this.claimData.shopEditingParams.valid;
} else {
canSubmit = canSubmit && this.claimData.shopEditingParams.valid;
}
}
}
return canSubmit;
}
public returnToManagement() {
this.router.navigate(['/management']);
}
public saveChanges() {
this.isLoading = true;
this.claimsEditService.saveChanges(this.claimData).then(() => {
this.isLoading = false;
this.returnToManagement();
});
}
private handleClaimData(claimData: ClaimData) {
this.claimData = claimData;
this.contractorReady = Boolean(claimData.contractor);
this.paytoolReady = Boolean(claimData.payoutToolParams);
this.shopReady = Boolean(claimData.shop);
}
private getClaimData() {
this.isLoading = true;
this.claimsEditService.getClaimData().then((claimData: ClaimData) => {
this.handleClaimData(claimData);
this.isLoading = false;
_.delay(() => {
// TODO: здесь разрывается синхронное отображение компонентов после переключения флага isLoading,
// TODO: т.к. иначе не успевает отрендериться DOM в компонентах
// TODO: пока решение такое, но нужно найти более изящное/правильное
this.initIncludes = true;
}, 0);
});
}
}

View File

@ -0,0 +1,18 @@
import { Shop } from 'koffing/backend/classes/shop.class';
import { ShopParams } from 'koffing/backend/classes/shop-params.class';
export class ShopEditingParams {
public shop: Shop;
public claimShopChanges: ShopParams;
public updatedShopParams: ShopParams;
public valid: boolean;
public dirty: boolean;
constructor() {
this.shop = new Shop();
this.claimShopChanges = new ShopParams();
this.updatedShopParams = new ShopParams();
this.valid = false;
this.dirty = false;
}
}

View File

@ -10,6 +10,7 @@
kof-payout-tool-creation(*ngIf="item.partyModificationType === 'ContractModification' && item.contractModificationType === 'ContractPayoutToolCreation'", [payoutTool]="item.payoutTool")
kof-shop-account-creation(*ngIf="item.partyModificationType === 'ShopModification' && item.shopModificationType === 'ShopAccountCreation'")
button.btn.btn-danger.pull-right(data-toggle="modal" data-target=".revoke-modal" data-backdrop="false") Отмена заявки
a.btn.btn-warning.pull-right([routerLink]="['/claims/edit']") Изменить заявку
.modal.fade.revoke-modal(tabindex="-1" role="dialog")
.modal-dialog.modal-sm

View File

@ -3,6 +3,7 @@ import { Component, OnInit } from '@angular/core';
import { Claim } from 'koffing/backend/backend.module';
import { ClaimService } from 'koffing/backend/backend.module';
import { ClaimReceiveBroadcaster } from 'koffing/broadcaster/services/claim-receive.broadcaster.service';
import { ClaimRevokeBroadcaster } from 'koffing/broadcaster/services/claim-revoke-broadcaster.service';
@Component({
selector: 'kof-claims',
@ -16,7 +17,8 @@ export class ClaimsComponent implements OnInit {
public revokeReason: string;
constructor(private claimService: ClaimService,
private claimReceiveBroadcaster: ClaimReceiveBroadcaster) { }
private claimReceiveBroadcaster: ClaimReceiveBroadcaster,
private claimRevokeBroadcaster: ClaimRevokeBroadcaster) { }
public revoke(reasonControl: any) {
if (!reasonControl.valid) {
@ -29,6 +31,7 @@ export class ClaimsComponent implements OnInit {
this.claimService.revokeClaim(this.claim.id, revokeDetails).then(() => {
this.showClaimInfo = false;
this.claimRevokeBroadcaster.fire();
});
}

View File

@ -6,8 +6,8 @@
kof-modification-detail([displayName]="'Название магазина'", [value]="shop.details.name")
kof-modification-detail(*ngIf="shop.contractID", [displayName]="'Идентификатор контракта'", [value]="shop.contractID")
kof-modification-detail(*ngIf="shop.details.description", [displayName]="'Описание'", [value]="shop.details.description")
kof-modification-detail(*ngIf="shop.details.location && shop.details.location.url", [displayName]="'Адрес'", [value]="shop.details.location.url")
kof-modification-detail(*ngIf="shop.callbackHandler && shop.callbackHandler.url", [displayName]="'Callback handler url'", [value]="shop.callbackHandler.url")
kof-modification-detail(*ngIf="shop.callbackHandler && shop.callbackHandler.publicKey", [displayName]="'Callback handler public key'", [value]="shop.callbackHandler.publicKey")
kof-modification-detail(*ngIf="shop?.details?.location?.url", [displayName]="'Адрес'", [value]="shop.details.location.url")
kof-modification-detail(*ngIf="shop?.callbackHandler?.url", [displayName]="'Callback handler url'", [value]="shop.callbackHandler.url")
kof-modification-detail(*ngIf="shop?.callbackHandler?.publicKey", [displayName]="'Callback handler public key'", [value]="shop.callbackHandler.publicKey")
kof-modification-detail(*ngIf="shop.categoryID", [displayName]="'Идентификатор категории'", [value]="shop.categoryID")
kof-modification-detail(*ngIf="shop.payoutToolID", [displayName]="'Идентификатор средства вывода'", [value]="shop.payoutToolID")

View File

@ -6,5 +6,5 @@ kof-create-paytool((onChange)="onPayoutToolChange($event)", [contractBankAccount
type="button",
[disabled]="!isContractorReady || !isPayoutToolReady",
(click)="createContract()"
) Создать контракт
) Создать контракт
a.btn.btn-default(type="reset", (click)="navigateBack()") Назад

View File

@ -22,7 +22,7 @@ export class ContractCreateComponent {
public contractor: Contractor;
public contractorBankAccount: BankAccount;
public isPayoutToolReady: boolean = false;
public payoutTool: PayoutToolBankAccount;
public payoutToolParams: PayoutToolBankAccount;
constructor(
private router: Router,
@ -39,15 +39,15 @@ export class ContractCreateComponent {
public onPayoutToolChange(value: PaytoolTransfer) {
this.isPayoutToolReady = value.valid;
this.payoutTool = value.payoutTool;
this.payoutToolParams = value.payoutToolParams;
}
public createContract() {
if (this.isContractorReady && this.isContractorReady) {
if (this.isContractorReady && this.isPayoutToolReady) {
this.isLoading = true;
const contractParams = new ContractParams();
contractParams.contractor = this.contractor;
contractParams.payoutToolParams = this.payoutTool;
contractParams.payoutToolParams = this.payoutToolParams;
this.contractService.createContract(contractParams).then(() => {
this.isLoading = false;
this.claimReceiveBroadcaster.fire();

View File

@ -14,8 +14,8 @@
td {{contract.id}}
td {{contract.validSince | date:"dd.MM.yyyy"}}
td.hidden-xs {{contract.validUntil | date:"dd.MM.yyyy"}}
td.hidden-xs {{(contract.contractor && contract.contractor.legalEntity) ? contract.contractor.legalEntity.registeredName : null}}
td {{(contract.contractor && contract.contractor.legalEntity) ? contract.contractor.legalEntity.inn : null}}
td.hidden-xs {{contract?.contractor?.legalEntity ? contract.contractor.legalEntity.registeredName : null}}
td {{contract?.contractor?.legalEntity ? contract.contractor.legalEntity.inn : null}}
td {{!!contract.terminatedAt ? 'завершен' : !contract.validSince ? 'в&nbsp;обработке' : 'активен'}}
tr(*ngIf="contract === selectedContract")
td(colspan=6)
@ -23,5 +23,8 @@
.x_panel.tile
label Средства вывода
.x_content
kof-payout-tools([contractID]="contract.id")
a.btn.btn-primary.pull-right([routerLink]="['/management/contracts/create']") Создать контракт
kof-payout-tools([contractID]="contract.id", [claimFound]="claimFound")
a.btn.btn-primary.pull-right(
*ngIf="!claimFound",
[routerLink]="['/management/contracts/create']"
) Создать контракт

View File

@ -2,6 +2,9 @@ import { Component, OnInit } from '@angular/core';
import { ContractService } from 'koffing/backend/services/contract.service';
import { Contract } from 'koffing/backend/classes/contract.class';
import { ClaimRevokeBroadcaster } from 'koffing/broadcaster/services/claim-revoke-broadcaster.service';
import { ClaimService } from 'koffing/backend/services/claim.service';
import { Claim } from 'koffing/backend/classes/claim/claim.class';
@Component({
templateUrl: 'contracts.component.pug'
@ -11,15 +14,30 @@ export class ContractsComponent implements OnInit {
public contracts: Contract[] = [];
public isLoading: boolean = false;
public selectedContract: Contract;
public claimFound: boolean = false;
constructor(
private contractService: ContractService
private contractService: ContractService,
private claimRevokeBroadcaster: ClaimRevokeBroadcaster,
private claimService: ClaimService
) {}
public ngOnInit() {
this.loadData();
this.claimRevokeBroadcaster.on().subscribe(() => {
this.isLoading = true;
this.checkClaim().then(() => {
this.isLoading = false;
});
});
}
public loadData() {
this.isLoading = true;
this.contractService.getContracts().then((contracts: Contract[]) => {
this.contracts = contracts;
Promise.all([
this.getContracts(),
this.checkClaim()
]).then(() => {
this.isLoading = false;
});
}
@ -31,4 +49,22 @@ export class ContractsComponent implements OnInit {
this.selectedContract = contract;
}
}
private getContracts(): Promise<Contract[]> {
return new Promise((resolve) => {
this.contractService.getContracts().then((contracts: Contract[]) => {
this.contracts = contracts;
resolve();
});
});
}
private checkClaim(): Promise<Claim[]> {
return new Promise((resolve) => {
this.claimService.getClaim({status: 'pending'}).then((claims: Claim[]) => {
this.claimFound = claims.length > 0;
resolve();
});
});
}
}

View File

@ -1,4 +1,4 @@
kof-create-paytool((onChange)="onPayoutToolChange($event)", [isCopyBankAccountAvailable]="false")
kof-create-paytool((onChange)="onPayoutToolChange($event)")
.form-group
.col-xs-12.col-sm-6.col-sm-offset-3
button.btn.btn-primary.pull-right(

View File

@ -29,7 +29,7 @@ export class PayoutToolCreateComponent {
public onPayoutToolChange(value: PaytoolTransfer) {
this.isPayoutToolValid = value.valid;
this.payoutToolsParams = value.payoutTool;
this.payoutToolsParams = value.payoutToolParams;
}
public createPayoutTool() {

View File

@ -1,4 +1,4 @@
.x_panel.tile(*ngIf="payoutTool && payoutTool.params && payoutTool.params.bankAccount")
.x_panel.tile(*ngIf="payoutTool?.params?.bankAccount")
.x_content
form.form-horizontal.form-label-left.css-form
.form-group

View File

@ -14,4 +14,7 @@ kof-loading([isLoading]="isLoading")
td(colspan=4)
kof-payout-tool-view([payoutTool]="payoutTool")
span(*ngIf="!payoutTools.length") Нет средств вывода
a.btn.btn-primary.pull-right([routerLink]="['/management/contracts', contractID, 'payout-tool', 'create']") Создать средство вывода
a.btn.btn-primary.pull-right(
*ngIf="!claimFound",
[routerLink]="['/management/contracts', contractID, 'payout-tool', 'create']"
) Создать средство вывода

View File

@ -11,6 +11,8 @@ export class PayoutToolsComponent implements OnInit {
@Input()
public contractID: number;
@Input()
public claimFound: boolean = false;
public payoutTools: PayoutTool[] = [];
public isLoading: boolean = false;

View File

@ -1,4 +1,4 @@
import { Component, Output, EventEmitter, OnInit, ViewChild, AfterViewInit } from '@angular/core';
import { Component, Output, EventEmitter, OnInit, ViewChild, AfterViewInit, Input } from '@angular/core';
import { NgForm } from '@angular/forms';
import * as _ from 'lodash';
@ -25,10 +25,16 @@ export class CreateContractComponent implements OnInit, AfterViewInit {
public sameActualAddressChecked: boolean;
@Input()
private defaultContractor: Contractor;
constructor(private suggestionsService: SuggestionsService) { }
public ngOnInit() {
this.contractor = this.createInstance();
if (this.defaultContractor) {
_.assign(this.contractor, this.defaultContractor);
}
}
public ngAfterViewInit() {

View File

@ -1,7 +1,7 @@
kof-loading([isLoading]="isLoading")
.text-center(*ngIf="contracts && contracts.length === 0")
.text-center(*ngIf="contracts?.length === 0")
h4 Контракты отсутствуют
.x_panel.tile(*ngIf="contracts && contracts.length > 0")
.x_panel.tile(*ngIf="contracts?.length > 0")
.x_title
h4 Выбор существующего контракта
.x_content

View File

@ -13,10 +13,10 @@
.form-group
.col-xs-12.col-sm-3
label.text-left.title-label Банковские реквизиты
.col-xs-12.col-sm-6(*ngIf="isCopyBankAccountAvailable")
.col-xs-12.col-sm-6(*ngIf="contractBankAccount")
.checkbox
label
input(type="checkbox", name="sameBankAccountChecked", [(ngModel)]="sameBankAccountChecked", (click)="copyContractBankAccount()")
input(type="checkbox", name="sameBankAccountChecked", [(ngModel)]="sameBankAccountChecked", (change)="copyContractBankAccount($event)")
| Совпадают с банковскими реквизитами из контракта
.ln_solid
.form-group([ngClass]="{'has-error': hasError(bankBik)}")
@ -24,24 +24,24 @@
label.text-left БИК *
.col-xs-12.col-sm-6
input.form-control.has-feedback-right.paytool-bank-suggestions(type="text", required, name="bankBik",
[(ngModel)]="payoutTool.bankAccount.bankBik", #bankBik="ngModel", (keyup)="emitData()")
[(ngModel)]="payoutToolParams.bankAccount.bankBik", #bankBik="ngModel", (keyup)="emitData()")
i.fa.fa-magic.form-control-feedback.right(aria-hidden="true")
.form-group([ngClass]="{'has-error': hasError(bankName)}")
.col-xs-12.col-sm-3
label.text-left Наименование банка *
.col-xs-12.col-sm-6
input.form-control.has-feedback-right.paytool-bank-suggestions(type="text", required, name="bankName",
[(ngModel)]="payoutTool.bankAccount.bankName", #bankName="ngModel", (keyup)="emitData()")
[(ngModel)]="payoutToolParams.bankAccount.bankName", #bankName="ngModel", (keyup)="emitData()")
i.fa.fa-magic.form-control-feedback.right(aria-hidden="true")
.form-group([ngClass]="{'has-error': hasError(bankPostAccount)}")
.col-xs-12.col-sm-3
label.text-left Корреспондентский счет *
.col-xs-12.col-sm-6
input.form-control(type="text", required, name="bankPostAccount",
[(ngModel)]="payoutTool.bankAccount.bankPostAccount", #bankPostAccount="ngModel", (keyup)="emitData()")
[(ngModel)]="payoutToolParams.bankAccount.bankPostAccount", #bankPostAccount="ngModel", (keyup)="emitData()")
.form-group([ngClass]="{'has-error': hasError(bankAccount)}")
.col-xs-12.col-sm-3
label.text-left Расчетный счет *
.col-xs-12.col-sm-6
input.form-control(type="text", required, name="account",
[(ngModel)]="payoutTool.bankAccount.account", #bankAccount="ngModel", (keyup)="emitData()")
[(ngModel)]="payoutToolParams.bankAccount.account", #bankAccount="ngModel", (keyup)="emitData()")

View File

@ -19,25 +19,28 @@ export class CreatePayoutToolComponent implements OnInit, AfterViewInit {
@Input()
public contractBankAccount: BankAccount;
@Input()
public isCopyBankAccountAvailable: boolean = true;
@Output()
public onChange = new EventEmitter();
public payoutTool: PayoutToolBankAccount;
public payoutToolParams: PayoutToolBankAccount;
@ViewChild('createPaytoolForm')
public form: NgForm;
public sameBankAccountChecked: boolean;
@Input()
private defaultPayoutToolParams: PayoutToolBankAccount;
constructor(
private suggestionsService: SuggestionsService
) { }
public ngOnInit() {
this.payoutTool = this.getInstance();
this.payoutToolParams = this.getInstance();
if (this.defaultPayoutToolParams) {
_.assign(this.payoutToolParams, this.defaultPayoutToolParams);
}
}
public ngAfterViewInit() {
@ -45,8 +48,7 @@ export class CreatePayoutToolComponent implements OnInit, AfterViewInit {
}
public emitData() {
this.compare();
const transfer = new PaytoolTransfer(this.payoutTool, this.form.valid);
const transfer = new PaytoolTransfer(this.payoutToolParams, this.form.valid);
this.onChange.emit(transfer);
}
@ -54,19 +56,13 @@ export class CreatePayoutToolComponent implements OnInit, AfterViewInit {
return field.dirty && field.invalid;
}
public copyContractBankAccount() {
if (!this.sameBankAccountChecked) {
public copyContractBankAccount(event: any) {
if (this.sameBankAccountChecked) {
this.setFormControls(this.contractBankAccount);
this.emitData();
}
}
private compare() {
if (this.payoutTool) {
this.sameBankAccountChecked = BankAccountComparator.isEqual(this.payoutTool.bankAccount, this.contractBankAccount);
}
}
private getInstance() {
const bankAccount = new BankAccount();
const instance = new PayoutToolBankAccount();

View File

@ -1,11 +1,11 @@
import { PayoutToolBankAccount } from 'koffing/backend/classes/payout-tool-bank-account.class';
export class PaytoolTransfer {
public payoutTool: PayoutToolBankAccount;
public payoutToolParams: PayoutToolBankAccount;
public valid: boolean;
constructor(payoutTool: PayoutToolBankAccount, valid: boolean) {
this.payoutTool = payoutTool;
constructor(payoutToolParams: PayoutToolBankAccount, valid: boolean) {
this.payoutToolParams = payoutToolParams;
this.valid = valid;
}
}

View File

@ -3,12 +3,12 @@ import * as _ from 'lodash';
import { PaytoolDecision } from './paytool-decision.class';
import { PayoutToolBankAccount } from 'koffing/backend/classes/payout-tool-bank-account.class';
import { Claim } from 'koffing/backend/classes/claim.class';
import { Contractor } from 'koffing/backend/classes/contractor.class';
import { ContractParams } from 'koffing/backend/classes/contract-params.class';
import { PayoutToolParams } from 'koffing/backend/classes/payout-tool-params.class';
import { ContractService } from 'koffing/backend/services/contract.service';
import { ClaimService } from 'koffing/backend/services/claim.service';
import { Claim } from 'koffing/backend/classes/claim/claim.class';
@Injectable()
export class PaytoolDecisionService {
@ -17,7 +17,7 @@ export class PaytoolDecisionService {
private claimService: ClaimService) {
}
public createPayoutTool(contractID: number, payoutToolsParams: PayoutToolBankAccount): Promise<PaytoolDecision> {
public createPayoutTool(contractID: number, payoutToolsParams: PayoutToolParams): Promise<PaytoolDecision> {
return new Promise((resolve) => {
this.contractService.createPayoutTool(contractID, payoutToolsParams).then((result: any) => {
this.claimService.getClaimById(result.claimID).then((claim: Claim) => {

View File

@ -7,17 +7,17 @@ kof-loading([isLoading]="isLoading")
input(type="radio", name="way", value="existing")
span Выбрать существующее средство вывода
br
kof-create-paytool(
*ngIf="selectedOption === optionNew",
[contractBankAccount]="getContractBankAccount()",
[isCopyBankAccountAvailable]="isCopyBankAccountAvailable()",
(onChange)="onPayoutToolChange($event)"
)
kof-select-paytool(
*ngIf="selectedOption === optionExisting",
[contractID]="contractDecision.contract.id",
(onPayoutToolSelected)="onPayoutToolSelected($event)"
)
.tile
kof-create-paytool(
*ngIf="selectedOption === optionNew",
[contractBankAccount]="contractDecision?.contractor?.bankAccount",
(onChange)="onPayoutToolChange($event)"
)
kof-select-paytool(
*ngIf="selectedOption === optionExisting",
[contractID]="contractDecision.contract.id",
(onPayoutToolSelected)="onPayoutToolSelected($event)"
)
.actionBar
.text-center
a.btn.btn-danger(data-toggle="modal", data-target=".cancel-create-shop-modal", data-backdrop="false") Отмена

View File

@ -7,7 +7,6 @@ import { ContractDecision } from '../selection-contract/contract-decision.class'
import { PaytoolDecision } from './paytool-decision.class';
import { PaytoolTransfer } from './create-paytool/paytool-transfer.class';
import { PaytoolDecisionService } from './paytool-decision.service';
import { BankAccount } from 'koffing/backend/classes/bank-account.class';
@Component({
selector: 'kof-selection-paytool',
@ -43,7 +42,7 @@ export class SelectionPaytoolComponent implements AfterViewInit {
public onPayoutToolChange(value: PaytoolTransfer) {
this.isPayoutToolValid = value.valid;
this.payoutToolsParams = value.payoutTool;
this.payoutToolsParams = value.payoutToolParams;
}
public onPayoutToolSelected(payoutToolID: number) {
@ -61,21 +60,6 @@ export class SelectionPaytoolComponent implements AfterViewInit {
this.selectedOption = this.optionNew;
}
// TODO need separate decision classes
public getContractBankAccount(): BankAccount {
let result;
if (this.contractDecision.contract && this.contractDecision.contract.contractor) {
result = this.contractDecision.contract.contractor.bankAccount;
} else if (this.contractDecision.contractor) {
result = this.contractDecision.contractor.bankAccount;
}
return result;
}
public isCopyBankAccountAvailable(): boolean {
return !!this.contractDecision.contractor;
}
public stepForward() {
if (!this.isPayoutToolValid) {
return;

View File

@ -1,40 +1,42 @@
.x_title
h4 Добавление нового магазина
.x_content
kof-loading([isLoading]="isLoading")
form.form-horizontal.form-label-left.css-form(novalidate, name="form", #form="ngForm")
.form-group([ngClass]="{'has-error': hasError(shop_details_name)}")
.col-xs-12.col-sm-3
label.text-left Название магазина в системе *
.col-xs-12.col-sm-9.col-md-6
input.form-control(type="text", required, name="shop_details_name",
[(ngModel)]="shopDetail.name", #shop_details_name="ngModel",
(keyup)="keyup(form)")
.form-group
.col-xs-12.col-sm-3
label.text-left Категория *
.col-xs-12.col-sm-9.col-md-6
kof-select(
[(ngModel)]="categoryId",
[items]="categories",
[modelOptions]="{standalone: true}",
name="category")
.form-group
.col-xs-12.col-sm-3
label.text-left Описание магазина
.col-xs-12.col-sm-9.col-md-6
input.form-control(type="text", name="shop_details_description",
[(ngModel)]="shopDetail.description",
(keyup)="keyup(form)")
.form-group
.col-xs-12.col-sm-3
label.text-left Адрес
.col-xs-12.col-sm-9.col-md-6
input.form-control(type="text", name="shop_details_location", placeholder="https://example.com",
[ngModel]="url", (ngModelChange)="setLocation($event, form)")
.form-group
.col-xs-12.col-sm-3
label.text-left Callback handler URL
.col-xs-12.col-sm-9.col-md-6
input.form-control(type="text", name="callback_handler_url", placeholder="https://example.com",
[(ngModel)]="callbackUrl", (keyup)="keyup(form)")
.x_panel.tile
.x_title
h4 Добавление нового магазина
.x_content
kof-loading([isLoading]="isLoading")
form.form-horizontal.form-label-left.css-form(novalidate, name="form", #form="ngForm")
.form-group([ngClass]="{'has-error': hasError(shop_details_name)}")
.col-xs-12.col-sm-3
label.text-left Название магазина в системе *
.col-xs-12.col-sm-6
input.form-control(type="text", required, name="shop_details_name",
[(ngModel)]="shopDetail.name", #shop_details_name="ngModel",
(keyup)="keyup(form)")
.form-group
.col-xs-12.col-sm-3
label.text-left Категория *
.col-xs-12.col-sm-6
kof-select(
[(ngModel)]="categoryId",
[items]="categories",
[modelOptions]="{standalone: true}",
name="category",
(onChange)="onCategoryChange($event, form)")
.form-group
.col-xs-12.col-sm-3
label.text-left Описание магазина
.col-xs-12.col-sm-6
input.form-control(type="text", name="shop_details_description",
[(ngModel)]="shopDetail.description",
(keyup)="keyup(form)")
.form-group
.col-xs-12.col-sm-3
label.text-left Адрес
.col-xs-12.col-sm-6
input.form-control(type="text", name="shop_details_location", placeholder="https://example.com",
[ngModel]="url", (ngModelChange)="setLocation($event, form)")
.form-group
.col-xs-12.col-sm-3
label.text-left CallbackHandler URL
.col-xs-12.col-sm-6
input.form-control(type="text", name="callback_handler_url", placeholder="https://example.com",
[(ngModel)]="callbackUrl", (keyup)="keyup(form)")

View File

@ -1,12 +1,13 @@
import { Component, OnInit, Output, EventEmitter } from '@angular/core';
import { Component, OnInit, Output, EventEmitter, Input } from '@angular/core';
import * as _ from 'lodash';
import { CategoryService } from 'koffing/backend/backend.module';
import { SelectItem } from 'koffing/common/common.module';
import { ShopDetail } from 'koffing/backend/classes/shop-detail.class';
import { ShopDetails } from 'koffing/backend/backend.module';
import { ShopLocationUrl } from 'koffing/backend/classes/shop-location-url.class';
import { ShopDetailTransfer } from './shop-detail-transfer.class';
import { Category } from 'koffing/backend/classes/category.class';
import { Shop } from 'koffing/backend/classes/shop.class';
@Component({
selector: 'kof-add-shop',
@ -19,12 +20,17 @@ export class AddShopComponent implements OnInit {
public onChange = new EventEmitter();
public categories: SelectItem[] = [];
public isLoading: boolean = false;
public url: string;
public shopDetail: ShopDetail;
public shopDetail: ShopDetails;
public categoryId: number;
public callbackUrl: string;
@Input()
private defaultShop: Shop;
constructor(
private categoryService: CategoryService
) { }
@ -32,9 +38,25 @@ export class AddShopComponent implements OnInit {
public ngOnInit() {
this.isLoading = true;
this.getCategories().then(() => {
if (this.defaultShop) {
this.categoryId = this.defaultShop.categoryID;
}
this.isLoading = false;
});
this.shopDetail = new ShopDetail();
this.shopDetail = new ShopDetails();
if (this.defaultShop) {
this.assignDefault();
}
}
public assignDefault() {
_.assign(this.shopDetail, this.defaultShop.details);
if (this.defaultShop.details.location) {
this.url = (<ShopLocationUrl> this.defaultShop.details.location).url;
}
if (this.defaultShop.callbackHandler) {
this.callbackUrl = this.defaultShop.callbackHandler.url;
}
}
public getCategories() {
@ -62,4 +84,8 @@ export class AddShopComponent implements OnInit {
this.shopDetail.location = new ShopLocationUrl(url);
this.keyup(form);
}
public onCategoryChange(categoryId: string, form: any) {
this.keyup(form);
}
}

View File

@ -1,12 +1,12 @@
import { ShopDetail } from 'koffing/backend/classes/shop-detail.class';
import { ShopDetails } from 'koffing/backend/backend.module';
export class ShopDetailTransfer {
public shopDetail: ShopDetail;
public shopDetail: ShopDetails;
public categoryID: number;
public callbackUrl: string;
public valid: boolean;
constructor(shopDetail: ShopDetail, categoryID: number, callbackUrl: string, valid: boolean) {
constructor(shopDetail: ShopDetails, categoryID: number, callbackUrl: string, valid: boolean) {
this.shopDetail = shopDetail;
this.categoryID = categoryID;
this.callbackUrl = callbackUrl;

View File

@ -1,6 +1,6 @@
import { Component, Output, EventEmitter, Input } from '@angular/core';
import { CreateShopArgs } from 'koffing/backend/classes/create-shop-args.class';
import { ShopParams } from 'koffing/backend/classes/shop-params.class';
import { PaytoolDecision } from 'koffing/management/components/management-container/shops/create-shop-wizard/selection-paytool/paytool-decision.class';
import { ShopService } from 'koffing/backend/services/shop.service';
import { ShopDetailTransfer } from 'koffing/management/components/management-container/shops/create-shop-wizard/selection-shop-fields/add-shop/shop-detail-transfer.class';
@ -21,13 +21,13 @@ export class SelectionShopComponent {
@Output()
public onCreated = new EventEmitter();
private createShopArgs: CreateShopArgs;
private createShopArgs: ShopParams;
constructor(private shopService: ShopService) { }
public onShopFieldsChange(value: ShopDetailTransfer) {
this.isShopFieldsReady = value.valid;
this.createShopArgs = new CreateShopArgs();
this.createShopArgs = new ShopParams();
this.createShopArgs.contractID = this.payoutToolDecision.contractID;
this.createShopArgs.payoutToolID = this.payoutToolDecision.payoutToolID;
this.createShopArgs.categoryID = value.categoryID;

View File

@ -1,55 +0,0 @@
.row
.col-xs-12
.x_panel.tile
.x_title
h4 Изменение данных магазина
.x_content
kof-loading([isLoading]="isLoading")
form.form-horizontal.form-label-left.css-form(*ngIf="shop", novalidate, (ngSubmit)="updateShop(form)", name="form", #form="ngForm")
.form-group([ngClass]="{'has-error': hasError(shopName)}")
.col-xs-12.col-sm-3
label.text-left Название магазина в системе *
.col-xs-12.col-sm-9.col-md-6
input.form-control(type="text", [ngModel]="shop.details.name", (ngModelChange)="onFieldChange('details.name', $event)", name="shopName", #shopName="ngModel", required)
.form-group
.col-xs-12.col-sm-3
label.text-left Категория *
.col-xs-12.col-sm-9.col-md-6
kof-select([ngModel]="shop.categoryID", (onChange)="onSelectCategory($event)", [items]="categoryItems", name='categoryID')
.form-group
.col-xs-12.col-sm-3
label.text-left Описание магазина
.col-xs-12.col-sm-9.col-md-6
input.form-control(type="text", [ngModel]="shop.details.description", (ngModelChange)="onFieldChange('details.description', $event)", name="shopDescription")
.form-group
.col-xs-12.col-sm-3
label.text-left Адрес
.col-xs-12.col-sm-9.col-md-6
input.form-control(type="text", [ngModel]="shop.details.location ? shop.details.location.url : null", placeholder="https://example.com", (ngModelChange)="onFieldChange('details.location.url', $event)", name="shopLocation")
.form-group
.col-xs-12.col-sm-3
label.text-left Callback handler URL
.col-xs-12.col-sm-9.col-md-6
input.form-control(type="text", [ngModel]="shop.callbackHandler ? shop.callbackHandler.url : null", placeholder="https://example.com", (ngModelChange)="onFieldChange('callbackUrl', $event)", name="callbackHandlerUrl")
.form-group
.col-xs-12.col-sm-3
label.text-left Контракт
.col-xs-12.col-sm-9.col-md-6
kof-select([ngModel]="shop.contractID", (onChange)="onSelectContract($event)", [items]="contractItems", name='contractID')
.form-group
.col-xs-12.col-sm-9.col-md-6.col-sm-offset-3
kof-contract-view([contract]="selectedContract")
.form-group
.col-xs-12.col-sm-3
label.text-left Средство вывода
.col-xs-12.col-sm-9.col-md-6(*ngIf="payoutToolItems.length")
kof-select([ngModel]="selectedPayoutTool.id", (onChange)="onSelectPayoutTool($event)", [items]="payoutToolItems", name='payoutToolID')
.col-xs-12.col-sm-9.col-md-6(*ngIf="!payoutToolItems.length") Нет средств вывода
.form-group(*ngIf="selectedPayoutTool")
.col-xs-12.col-sm-9.col-md-6.col-sm-offset-3
kof-payout-tool-view([payoutTool]="selectedPayoutTool")
.ln_solid
.form-group
.col-xs-12.col-sm-9.col-md-6.col-sm-offset-3
a.btn.btn-default(type="reset", [routerLink]=["/management"]) Назад
button.btn.btn-primary.pull-right(type="submit", [disabled]="form.invalid || form.pristine || !shopEditing.payoutToolID") Создать заявку

View File

@ -3,8 +3,11 @@ div(*ngIf="!shop.isBlocked")
a.btn.btn-xs.btn-danger.pull-right(data-toggle="modal", data-target=".suspend-modal", data-backdrop="false") Заморозить магазин
div(*ngIf="shop.isSuspended")
button.btn.btn-success.btn-xs.pull-right((click)="activateShop()") Активировать
a.btn.btn-default.btn-xs.pull-right([routerLink]="['/', 'shops', shop.id, 'edit']") Изменить данные
dl(*ngIf="shop.details && shop.details.description")
a.btn.btn-default.btn-xs.pull-right(
*ngIf="!claimFound",
[routerLink]="['/', 'shops', shop.id, 'edit']"
) Изменить данные
dl(*ngIf="shop?.details?.description")
dt Описание
dd {{shop.details.description}}
div(*ngIf="shop.callbackHandler")

View File

@ -17,6 +17,9 @@ export class ShopDetailsPanelComponent {
@Input()
public shop: Shop;
@Input()
public claimFound: boolean = false;
@Output()
public onChange = new EventEmitter();

View File

@ -0,0 +1,49 @@
.x_panel.tile
.x_title
h4 Изменение данных магазина
.x_content
kof-loading([isLoading]="isLoading")
form.form-horizontal.form-label-left.css-form(*ngIf="shop", novalidate, name="form", #form="ngForm")
.form-group([ngClass]="{'has-error': hasError(shopName)}")
.col-xs-12.col-sm-3
label.text-left Название магазина *
.col-xs-12.col-sm-6
input.form-control(type="text", [ngModel]="shop.details.name", (ngModelChange)="onFieldChange('details.name', $event)", name="shopName", #shopName="ngModel", required)
.form-group
.col-xs-12.col-sm-3
label.text-left Описание магазина
.col-xs-12.col-sm-6
input.form-control(type="text", [ngModel]="shop.details.description", (ngModelChange)="onFieldChange('details.description', $event)", name="shopDescription")
.form-group
.col-xs-12.col-sm-3
label.text-left Адрес
.col-xs-12.col-sm-6
input.form-control(type="text", [ngModel]="shop.details.location ? shop.details.location.url : null", placeholder="https://example.com", (ngModelChange)="onFieldChange('details.location.url', $event)", name="shopLocation")
.form-group
.col-xs-12.col-sm-3
label.text-left Callback handler URL
.col-xs-12.col-sm-6
input.form-control(type="text", [ngModel]="shop.callbackHandler ? shop.callbackHandler.url : null", placeholder="https://example.com", (ngModelChange)="onFieldChange('callbackUrl', $event)", name="callbackHandlerUrl")
.form-group
.col-xs-12.col-sm-3
label.text-left Категория
.col-xs-12.col-sm-6
kof-select([ngModel]="shop.categoryID", (onChange)="onSelectCategory($event)", [items]="categoryItems", name='category')
.form-group
.col-xs-12.col-sm-3
label.text-left Контракт
.col-xs-12.col-sm-6
kof-select([ngModel]="shop.contractID", [items]="contractItems", (onChange)="onSelectContract($event)", name='contractID')
.form-group
.col-xs-12.col-sm-3
.col-xs-12.col-sm-6
kof-contract-view([contract]="shopContract")
.form-group
.col-xs-12.col-sm-3
label.text-left Средство вывода
.col-xs-12.col-sm-6
kof-select([ngModel]="shop.payoutToolID", (onChange)="onSelectPayoutTool($event)", [items]="payoutToolItems", name='payoutToolID')
.form-group
.col-xs-12.col-sm-3
.col-xs-12.col-sm-6
kof-payout-tool-view([payoutTool]="shopPayoutTool")

View File

@ -1,56 +1,87 @@
import { Component, OnInit } from '@angular/core';
import { Router, ActivatedRoute } from '@angular/router';
import { Component, OnInit, Input, EventEmitter, Output, ViewChild, AfterViewInit } from '@angular/core';
import * as _ from 'lodash';
import { CategoryService } from 'koffing/backend/backend.module';
import { ShopService } from 'koffing/backend/backend.module';
import { Shop } from 'koffing/backend/classes/shop.class';
import { Contract } from 'koffing/backend/classes/contract.class';
import { PayoutTool } from 'koffing/backend/classes/payout-tool.class';
import { ContractService } from 'koffing/backend/services/contract.service';
import { Category } from 'koffing/backend/classes/category.class';
import { SelectItem } from 'koffing/common/common.module';
import { CreateShopArgs } from 'koffing/backend/classes/create-shop-args.class';
import { ShopDetail } from 'koffing/backend/classes/shop-detail.class';
import { ShopParams } from 'koffing/backend/classes/shop-params.class';
import { ShopDetails } from 'koffing/backend/backend.module';
import { ShopLocationUrl } from 'koffing/backend/classes/shop-location-url.class';
import { ShopEditingTransfer } from './shop-editing-transfer.class';
import { NgForm } from '@angular/forms';
@Component({
selector: 'kof-edit-shop',
templateUrl: 'edit-shop.component.pug',
})
export class EditShopComponent implements OnInit {
export class EditShopComponent implements OnInit, AfterViewInit {
public shopID: number = Number(this.route.snapshot.params['shopID']);
public shopEditing: CreateShopArgs;
@Input()
public shop: Shop;
@Input()
public defaultShopChanges: ShopParams;
public shopEditing: ShopParams;
public selectedContract: Contract;
public selectedPayoutTool: PayoutTool;
public contracts: Contract[] = [];
public payoutTools: PayoutTool[] = [];
@Output()
public onChange = new EventEmitter();
@ViewChild('form')
public form: NgForm;
public contractItems: SelectItem[] = [];
public payoutToolItems: SelectItem[] = [];
public categoryItems: SelectItem[] = [];
public isLoading: boolean = false;
constructor(
private route: ActivatedRoute,
private router: Router,
private categoryService: CategoryService,
private shopService: ShopService,
private contractService: ContractService
) {}
) { }
public ngOnInit() {
this.isLoading = true;
Promise.all([
this.loadCategories(),
this.loadShop()
this.loadShopContracts(),
this.loadShopPayoutTools(this.shop.contractID)
]).then(() => {
this.isLoading = false;
this.shopEditing = this.getInstance(this.shop.details);
});
}
public ngAfterViewInit() {
this.form.statusChanges.subscribe((data) => {
this.onFormStatusChanges(data);
});
}
public onFormStatusChanges(formStatus: string) {
this.emitData();
}
public emitData() {
const transfer = new ShopEditingTransfer(this.shopEditing, this.form.valid, this.form.dirty);
this.onChange.emit(transfer);
}
public onFieldChange(path: string, value: any) {
if (_.startsWith(path, 'details')) {
this.shopEditing.details = this.shop.details;
}
if (_.startsWith(path, 'details.location')) {
this.shopEditing.details.location = new ShopLocationUrl();
}
_.set(this.shopEditing, path, value);
}
public loadCategories(): Promise<Category[]> {
return new Promise((resolve) => {
this.categoryService.getCategories().then((categories: Category[]) => {
@ -60,20 +91,6 @@ export class EditShopComponent implements OnInit {
});
}
public loadShop(): Promise<Shop> {
return new Promise((resolve) => {
this.shopService.getShop(this.shopID).then((shop: Shop) => {
this.shop = shop;
Promise.all([
this.loadShopContracts(),
this.loadShopPayoutTools(shop.contractID)
]).then(() => {
resolve(shop);
});
});
});
}
public loadShopContracts(): Promise<Contract[]> {
return new Promise((resolve) => {
this.contractService.getContracts().then((contracts: Contract[]) => {
@ -114,30 +131,10 @@ export class EditShopComponent implements OnInit {
this.selectedPayoutTool = this.findPayoutTool(id);
}
public onFieldChange(path: string, value: any) {
if (_.startsWith(path, 'details')) {
this.shopEditing.details = this.shop.details;
}
if (_.startsWith(path, 'details.location')) {
this.shopEditing.details.location = new ShopLocationUrl();
}
_.set(this.shopEditing, path, value);
}
public hasError(field: any): boolean {
return field.dirty && field.invalid;
}
public updateShop(form: any) {
if (form.valid) {
this.isLoading = true;
this.shopService.updateShop(this.shopID, this.shopEditing).then(() => {
this.isLoading = false;
this.router.navigate(['/management']);
});
}
}
public onSelectCategory(categoryID: string) {
this.shopEditing.categoryID = _.toNumber(categoryID);
}
@ -150,9 +147,12 @@ export class EditShopComponent implements OnInit {
return _.find(this.contracts, (contract) => contract.id === contractID);
}
private getInstance(details: ShopDetail): CreateShopArgs {
const instance = new CreateShopArgs();
private getInstance(details: ShopDetails): ShopParams {
const instance = new ShopParams();
instance.details = details;
if (this.defaultShopChanges) {
instance.update(this.defaultShopChanges);
}
return instance;
}
}

View File

@ -0,0 +1,13 @@
import { ShopParams } from 'koffing/backend/classes/shop-params.class';
export class ShopEditingTransfer {
public shopEditing: ShopParams;
public valid: boolean;
public dirty: boolean;
constructor(shopEditing: ShopParams, valid: boolean, dirty: boolean) {
this.shopEditing = shopEditing;
this.valid = valid;
this.dirty = dirty;
}
}

View File

@ -0,0 +1,16 @@
.x_panel.tile
.x_content
kof-loading([isLoading]="isLoading")
kof-edit-shop(
*ngIf="!isLoading",
[shop]="shop",
(onChange)="onShopEditingChange($event)"
)
.form-group
.col-xs-12.col-sm-6.col-sm-offset-3
a.btn.btn-default(type="reset", [routerLink]=["/management"]) Назад
button.btn.btn-primary.pull-right(
type="submit",
(click)="updateShop()",
[disabled]="!shopEditingReady"
) Создать заявку

View File

@ -0,0 +1,54 @@
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { ShopService } from 'koffing/backend/services/shop.service';
import { Shop } from 'koffing/backend/classes/shop.class';
import { ShopParams } from 'koffing/backend/classes/shop-params.class';
import { ShopEditingTransfer } from 'koffing/management/components/management-container/shops/shop-editing/edit-shop/shop-editing-transfer.class';
@Component({
selector: 'kof-shop-editing',
templateUrl: 'shop-editing.component.pug'
})
export class ShopEditingComponent implements OnInit {
public shopID: number = Number(this.route.snapshot.params['shopID']);
public isLoading: boolean = false;
public shop: Shop;
public shopEditing: ShopParams;
public shopEditingReady: boolean = false;
constructor(
private route: ActivatedRoute,
private router: Router,
private shopService: ShopService
) { }
public ngOnInit() {
this.loadShop();
}
public loadShop() {
this.isLoading = true;
this.shopService.getShop(this.shopID).then((shop: Shop) => {
this.shop = shop;
this.isLoading = false;
});
}
public updateShop() {
if (this.shopEditingReady) {
this.isLoading = true;
this.shopService.updateShop(this.shopID, this.shopEditing).then(() => {
this.isLoading = false;
this.router.navigate(['/management']);
});
}
}
public onShopEditingChange(transfer: ShopEditingTransfer) {
this.shopEditing = transfer.shopEditing;
this.shopEditingReady = transfer.valid && transfer.dirty;
}
}

View File

@ -21,5 +21,12 @@
span.pull-right Заблокирован
tr(*ngIf="isDetailsPanelVisible(i)")
td(colspan=6)
kof-shop-details-panel([shop]="shop", (onChange)="loadData()")
a.btn.btn-primary.pull-right([routerLink]="['/shops/create']") Создать магазин
kof-shop-details-panel(
[shop]="shop",
[claimFound]="claimFound",
(onChange)="loadData()"
)
a.btn.btn-primary.pull-right(
*ngIf="!claimFound",
[routerLink]="['/shops/create']"
) Создать магазин

View File

@ -1,10 +1,12 @@
import { Component, OnInit } from '@angular/core';
import * as _ from 'lodash';
import { Category } from 'koffing/backend/backend.module';
import { CategoryService } from 'koffing/backend/backend.module';
import { ShopService } from 'koffing/backend/backend.module';
import { Shop } from 'koffing/backend/classes/shop.class';
import { ClaimService } from 'koffing/backend/services/claim.service';
import { ClaimRevokeBroadcaster } from 'koffing/broadcaster/services/claim-revoke-broadcaster.service';
import { Claim } from 'koffing/backend/classes/claim/claim.class';
@Component({
templateUrl: 'shops.component.pug',
@ -16,21 +18,31 @@ export class ShopsComponent implements OnInit {
public categories: Category[] = [];
public isLoading: boolean;
public panelsVisibilities: {[key: number]: boolean} = {};
public claimFound: boolean = false;
constructor(
private shopService: ShopService,
private categoryService: CategoryService
private categoryService: CategoryService,
private claimService: ClaimService,
private claimRevokeBroadcaster: ClaimRevokeBroadcaster
) {}
public ngOnInit() {
this.loadData();
this.claimRevokeBroadcaster.on().subscribe(() => {
this.isLoading = true;
this.checkClaim().then(() => {
this.isLoading = false;
});
});
}
public loadData() {
this.isLoading = true;
Promise.all([
this.loadShops(),
this.loadCategories()
this.loadCategories(),
this.checkClaim()
]).then(() => {
this.isLoading = false;
});
@ -71,4 +83,13 @@ export class ShopsComponent implements OnInit {
return (_.find(this.categories, (category: Category) => category.categoryID === categoryID)).name;
}
}
private checkClaim(): Promise<Claim[]> {
return new Promise((resolve) => {
this.claimService.getClaim({status: 'pending'}).then((claims: Claim[]) => {
this.claimFound = claims.length > 0;
resolve();
});
});
}
}

View File

@ -19,7 +19,7 @@ import { CreatePayoutToolComponent } from './components/management-container/sho
import { SelectContractComponent } from './components/management-container/shops/create-shop-wizard/selection-contract/select-contract/select-contract.component';
import { SelectPaytoolComponent } from './components/management-container/shops/create-shop-wizard/selection-paytool/select-paytool/select-paytool.component';
import { AddShopComponent } from './components/management-container/shops/create-shop-wizard/selection-shop-fields/add-shop/add-shop.component';
import { EditShopComponent } from './components/management-container/shops/edit-shop/edit-shop.component';
import { EditShopComponent } from './components/management-container/shops/shop-editing/edit-shop/edit-shop.component';
import { ContractViewComponent } from './components/management-container/contracts/contract-view/contract-view.component';
import { ContractCreateComponent } from './components/management-container/contracts/contract-create/contract-create.component';
import { PayoutToolsComponent } from './components/management-container/contracts/payout-tools/payout-tools.component';
@ -32,6 +32,10 @@ import { SelectionShopComponent } from './components/management-container/shops/
import { ShopDetailsPanelComponent } from 'koffing/management/components/management-container/shops/shop-details-panel/shop-details-panel.component';
import { PaytoolDecisionService } from 'koffing/management/components/management-container/shops/create-shop-wizard/selection-paytool/paytool-decision.service';
import { SuggestionsModule } from 'koffing/suggestions/suggestions.module';
import { ClaimsEditComponent } from 'koffing/management/components/management-container/claims-edit/claims-edit.component';
import { ShopEditingComponent } from 'koffing/management/components/management-container/shops/shop-editing/shop-editing.component';
import { ClaimsEditService } from 'koffing/management/services/claims-edit.service';
import { ClaimDataService } from 'koffing/management/services/claim-data.service';
@NgModule({
imports: [
@ -71,14 +75,24 @@ import { SuggestionsModule } from 'koffing/suggestions/suggestions.module';
SelectionContractComponent,
SelectionPaytoolComponent,
SelectionShopComponent,
ShopDetailsPanelComponent
ShopDetailsPanelComponent,
ClaimsEditComponent,
ShopEditingComponent
],
providers: [PaytoolDecisionService]
providers: [
PaytoolDecisionService,
ClaimsEditService,
ClaimDataService
]
})
export class ManagementModule { }
export * from '../suggestions/classes/suggestion-settings.const';
export * from './components/management-container/shops/edit-shop/edit-shop.component';
export * from './components/management-container/shops/shop-editing/edit-shop/edit-shop.component';
export * from './components/management-container/shops/create-shop-wizard/create-shop-wizard.component';
export * from './components/management-container/contracts/contract-create/contract-create.component';
export * from './components/management-container/contracts/payout-tool-create/payout-tool-create.component';
export * from './components/management-container/claims-edit/claims-edit.component';
export * from './services/claims-edit.service';
export * from './classes/claim-data.class';

View File

@ -0,0 +1,53 @@
import { Injectable } from '@angular/core';
import * as _ from 'lodash';
import { ClaimData } from 'koffing/management/classes/claim-data.class';
import { ContractCreation } from 'koffing/backend/classes/claim/contract-creation.class';
import { ContractPayoutToolCreation } from 'koffing/backend/classes/claim/contract-payout-tool-creation.class';
import { ShopCreation } from 'koffing/backend/classes/claim/shop-creation.class';
import { ShopService } from 'koffing/backend/services/shop.service';
import { ShopUpdate } from 'koffing/backend/classes/claim/shop-update.class';
import { ShopEditingParams } from 'koffing/management/components/management-container/claims-edit/shop-editing-params.class';
import { Shop } from 'koffing/backend/classes/shop.class';
@Injectable()
export class ClaimDataService {
constructor(
private shopService: ShopService
) { }
public handleContractCreation(claimData: ClaimData, setItem: ContractCreation): Promise<any> {
return new Promise((resolve) => {
claimData.contractor = setItem.contract.contractor;
resolve();
});
}
public handleContractPayoutToolCreation(claimData: ClaimData, setItem: ContractPayoutToolCreation): Promise<any> {
return new Promise((resolve) => {
claimData.payoutToolContractId = setItem.contractID;
claimData.payoutToolParams = setItem.payoutTool.params;
resolve();
});
}
public handleShopCreation(claimData: ClaimData, setItem: ShopCreation): Promise<any> {
return new Promise((resolve) => {
claimData.shop = setItem.shop;
resolve();
});
}
public handleShopUpdate(claimData: ClaimData, setItem: ShopUpdate): Promise<any> {
return new Promise((resolve) => {
claimData.shopEditingParams = new ShopEditingParams();
claimData.shopEditingParams.claimShopChanges = setItem.details;
this.shopService.getShop(setItem.shopID).then((shop: Shop) => {
_.assign(claimData.shopEditingParams.shop, shop);
claimData.shopEditingParams.shop.update(setItem.details);
resolve();
});
});
}
}

View File

@ -0,0 +1,159 @@
import { Injectable } from '@angular/core';
import { ClaimData } from 'koffing/management/classes/claim-data.class';
import { Claim } from 'koffing/backend/classes/claim/claim.class';
import { ContractCreation } from 'koffing/backend/classes/claim/contract-creation.class';
import { Contractor } from 'koffing/backend/classes/contractor.class';
import { ContractModification } from 'koffing/backend/classes/claim/contract-modification.class';
import { ContractPayoutToolCreation } from 'koffing/backend/classes/claim/contract-payout-tool-creation.class';
import { ShopCreation } from 'koffing/backend/classes/claim/shop-creation.class';
import { Shop } from 'koffing/backend/classes/shop.class';
import { ShopModification } from 'koffing/backend/classes/claim/shop-modification.class';
import { ShopUpdate } from 'koffing/backend/classes/claim/shop-update.class';
import { ClaimService } from 'koffing/backend/services/claim.service';
import { ShopService } from 'koffing/backend/services/shop.service';
import { ShopParams } from 'koffing/backend/classes/shop-params.class';
import { PaytoolDecision } from 'koffing/management/components/management-container/shops/create-shop-wizard/selection-paytool/paytool-decision.class';
import { PayoutToolParams } from 'koffing/backend/classes/payout-tool-params.class';
import { PaytoolDecisionService } from 'koffing/management/components/management-container/shops/create-shop-wizard/selection-paytool/paytool-decision.service';
import { ClaimDataService } from 'koffing/management/services/claim-data.service';
@Injectable()
export class ClaimsEditService {
constructor(
private claimService: ClaimService,
private shopService: ShopService,
private paytoolDecisionService: PaytoolDecisionService,
private claimDataService: ClaimDataService
) { }
public getClaimData(): Promise<ClaimData> {
return new Promise((resolve) => {
this.claimService.getClaim({status: 'pending'}).then((claims: Claim[]) => {
if (claims.length > 0) {
this.handleClaim(claims[0]).then((claimData: ClaimData) => {
resolve(claimData);
});
}
});
});
}
public saveChanges(claimData: ClaimData): Promise<any> {
return new Promise((resolve, reject) => {
this.claimService.revokeClaim(claimData.claimID, {
reason: 'edit claim'
}).then(() => {
if (claimData.contractor && claimData.payoutToolParams && !claimData.shop) {
return this.createContract(claimData.contractor, claimData.payoutToolParams).then(() => {
resolve();
});
} else if (claimData.contractor && claimData.payoutToolParams && claimData.shop) {
return this.createContractAndShop(claimData.contractor, claimData.payoutToolParams, claimData.shop).then(() => {
resolve();
});
} else if (claimData.payoutToolParams && !claimData.contractor && !claimData.shop) {
return this.createPayoutTool(claimData.payoutToolContractId, claimData.payoutToolParams).then(() => {
resolve();
});
} else if (claimData.payoutToolParams && claimData.shop && !claimData.contractor) {
return this.createPayoutToolAndShop(claimData.payoutToolContractId, claimData.payoutToolParams, claimData.shop).then(() => {
resolve();
});
} else if (claimData.shopEditingParams && !claimData.shop && !claimData.contractor) {
return this.updateShop(claimData.shopEditingParams.shop.id, claimData.shopEditingParams.updatedShopParams).then(() => {
resolve();
});
} else {
reject();
}
});
});
}
private createContract(contractor: Contractor, payoutToolParams: PayoutToolParams): Promise<PaytoolDecision> {
return this.paytoolDecisionService.createContract(contractor, payoutToolParams);
}
private createContractAndShop(contractor: Contractor, payoutToolParams: PayoutToolParams, shop: Shop): Promise<any> {
return this.paytoolDecisionService.createContract(contractor, payoutToolParams).then((decision: PaytoolDecision) => {
return this.shopService.createShop(new ShopParams(
shop.categoryID,
shop.details,
decision.contractID,
decision.payoutToolID,
shop.callbackHandler ? shop.callbackHandler.url : undefined
));
});
}
private createPayoutTool(contractID: number, payoutToolsParams: PayoutToolParams): Promise<PaytoolDecision> {
return this.paytoolDecisionService.createPayoutTool(contractID, payoutToolsParams);
}
private createPayoutToolAndShop(contractID: number, payoutToolsParams: PayoutToolParams, shop: Shop): Promise<string> {
return this.createPayoutTool(contractID, payoutToolsParams).then((decision: PaytoolDecision) => {
return this.shopService.createShop(new ShopParams(
shop.categoryID,
shop.details,
decision.contractID,
decision.payoutToolID,
shop.callbackHandler ? shop.callbackHandler.url : undefined
));
});
}
private updateShop(shopID: number, updatedShopParams: ShopParams): Promise<string> {
return this.shopService.updateShop(shopID, updatedShopParams);
}
private handleClaim(claim: Claim): Promise<ClaimData> {
return new Promise((resolve) => {
const claimData = new ClaimData();
const handlersPromises = [];
claimData.claimID = claim.id;
for (let setItem of claim.changeset) {
switch (setItem.partyModificationType) {
case 'ContractCreation': {
handlersPromises.push(
this.claimDataService.handleContractCreation(claimData, <ContractCreation> setItem)
);
break;
}
case 'ContractModification': {
if ((<ContractModification> setItem).contractModificationType === 'ContractPayoutToolCreation') {
handlersPromises.push(
this.claimDataService.handleContractPayoutToolCreation(claimData, <ContractPayoutToolCreation> setItem)
);
}
break;
}
case 'ShopCreation': {
handlersPromises.push(
this.claimDataService.handleShopCreation(claimData, <ShopCreation> setItem)
);
break;
}
case 'ShopModification': {
if ((<ShopModification> setItem).shopModificationType === 'ShopUpdate') {
handlersPromises.push(
this.claimDataService.handleShopUpdate(claimData, <ShopUpdate> setItem)
);
}
break;
}
default: {
break;
}
}
}
Promise.all(handlersPromises).then(() => {
resolve(claimData);
});
});
}
}

View File

@ -1,10 +1,11 @@
import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';
import { EditShopComponent } from 'koffing/management/management.module';
import { CreateShopWizardComponent } from 'koffing/management/management.module';
import { ContractCreateComponent } from 'koffing/management/components/management-container/contracts/contract-create/contract-create.component';
import { PayoutToolCreateComponent } from 'koffing/management/components/management-container/contracts/payout-tool-create/payout-tool-create.component';
import { ClaimsEditComponent } from 'koffing/management/management.module';
import { ShopEditingComponent } from 'koffing/management/components/management-container/shops/shop-editing/shop-editing.component';
@NgModule({
imports: [
@ -20,7 +21,7 @@ import { PayoutToolCreateComponent } from 'koffing/management/components/managem
},
{
path: 'shops/:shopID/edit',
component: EditShopComponent
component: ShopEditingComponent
},
{
path: 'shops/:shopID/edit/contract/create',
@ -29,6 +30,10 @@ import { PayoutToolCreateComponent } from 'koffing/management/components/managem
{
path: 'shops/:shopID/edit/contract/:contractID/payoutTool/create',
component: PayoutToolCreateComponent
},
{
path: 'claims/edit',
component: ClaimsEditComponent
}
])
],