@ -0,0 +1,24 @@ |
|||
# Ordering |
|||
|
|||
This library was generated with [Angular CLI](https://github.com/angular/angular-cli) version 12.2.0. |
|||
|
|||
## Code scaffolding |
|||
|
|||
Run `ng generate component component-name --project ordering` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module --project ordering`. |
|||
> Note: Don't forget to add `--project ordering` or else it will be added to the default project in your `angular.json` file. |
|||
|
|||
## Build |
|||
|
|||
Run `ng build ordering` to build the project. The build artifacts will be stored in the `dist/` directory. |
|||
|
|||
## Publishing |
|||
|
|||
After building your library with `ng build ordering`, go to the dist folder `cd dist/ordering` and run `npm publish`. |
|||
|
|||
## Running unit tests |
|||
|
|||
Run `ng test ordering` to execute the unit tests via [Karma](https://karma-runner.github.io). |
|||
|
|||
## Further help |
|||
|
|||
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page. |
|||
@ -0,0 +1,7 @@ |
|||
{ |
|||
"$schema": "../../../node_modules/ng-packagr/ng-package.schema.json", |
|||
"dest": "../../dist/ordering/config", |
|||
"lib": { |
|||
"entryFile": "src/public-api.ts" |
|||
} |
|||
} |
|||
@ -0,0 +1,2 @@ |
|||
export * from './policy-names'; |
|||
export * from './route-names'; |
|||
@ -0,0 +1,6 @@ |
|||
export const enum eOrderingPolicyNames { |
|||
ordering = 'OrderingService.Orders', |
|||
detail = 'OrderingService.Orders', |
|||
setAsShipped = 'OrderingService.SetAsShipped', |
|||
setAsCancelled = 'OrderingService.SetAsCancelled', |
|||
} |
|||
@ -0,0 +1,3 @@ |
|||
export const enum eOrderingRouteNames { |
|||
ordering = 'OrderingService::Menu:OrderManagement' |
|||
} |
|||
@ -0,0 +1,12 @@ |
|||
import { ModuleWithProviders, NgModule } from '@angular/core'; |
|||
import { ORDERING_ROUTE_PROVIDERS } from './providers/route.provider'; |
|||
|
|||
@NgModule() |
|||
export class OrderingConfigModule { |
|||
static forRoot(): ModuleWithProviders<OrderingConfigModule> { |
|||
return { |
|||
ngModule: OrderingConfigModule, |
|||
providers: [ORDERING_ROUTE_PROVIDERS], |
|||
}; |
|||
} |
|||
} |
|||
@ -0,0 +1 @@ |
|||
export * from './route.provider'; |
|||
@ -0,0 +1,23 @@ |
|||
import { eLayoutType, RoutesService } from '@abp/ng.core'; |
|||
import { APP_INITIALIZER } from '@angular/core'; |
|||
import { eOrderingPolicyNames } from '../enums/policy-names'; |
|||
import { eOrderingRouteNames } from '../enums/route-names'; |
|||
|
|||
export const ORDERING_ROUTE_PROVIDERS = [ |
|||
{ provide: APP_INITIALIZER, useFactory: configureRoutes, deps: [RoutesService], multi: true }, |
|||
]; |
|||
|
|||
export function configureRoutes(routesService: RoutesService) { |
|||
return () => { |
|||
routesService.add([ |
|||
{ |
|||
path: '/ordering', |
|||
name: eOrderingRouteNames.ordering, |
|||
layout: eLayoutType.application, |
|||
requiredPolicy: eOrderingPolicyNames.ordering, |
|||
parentName: null, |
|||
iconClass: 'bi bi-collection-fill', |
|||
}, |
|||
]); |
|||
}; |
|||
} |
|||
@ -0,0 +1,3 @@ |
|||
export * from './enums'; |
|||
export * from './providers'; |
|||
export * from './ordering-config.module'; |
|||
@ -0,0 +1,44 @@ |
|||
// Karma configuration file, see link for more information
|
|||
// https://karma-runner.github.io/1.0/config/configuration-file.html
|
|||
|
|||
module.exports = function (config) { |
|||
config.set({ |
|||
basePath: '', |
|||
frameworks: ['jasmine', '@angular-devkit/build-angular'], |
|||
plugins: [ |
|||
require('karma-jasmine'), |
|||
require('karma-chrome-launcher'), |
|||
require('karma-jasmine-html-reporter'), |
|||
require('karma-coverage'), |
|||
require('@angular-devkit/build-angular/plugins/karma') |
|||
], |
|||
client: { |
|||
jasmine: { |
|||
// you can add configuration options for Jasmine here
|
|||
// the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html
|
|||
// for example, you can disable the random execution with `random: false`
|
|||
// or set a specific seed with `seed: 4321`
|
|||
}, |
|||
clearContext: false // leave Jasmine Spec Runner output visible in browser
|
|||
}, |
|||
jasmineHtmlReporter: { |
|||
suppressAll: true // removes the duplicated traces
|
|||
}, |
|||
coverageReporter: { |
|||
dir: require('path').join(__dirname, '../../coverage/ordering'), |
|||
subdir: '.', |
|||
reporters: [ |
|||
{ type: 'html' }, |
|||
{ type: 'text-summary' } |
|||
] |
|||
}, |
|||
reporters: ['progress', 'kjhtml'], |
|||
port: 9876, |
|||
colors: true, |
|||
logLevel: config.LOG_INFO, |
|||
autoWatch: true, |
|||
browsers: ['Chrome'], |
|||
singleRun: false, |
|||
restartOnFileChange: true |
|||
}); |
|||
}; |
|||
@ -0,0 +1,7 @@ |
|||
{ |
|||
"$schema": "../../node_modules/ng-packagr/ng-package.schema.json", |
|||
"dest": "../../dist/ordering", |
|||
"lib": { |
|||
"entryFile": "src/public-api.ts" |
|||
} |
|||
} |
|||
@ -0,0 +1,11 @@ |
|||
{ |
|||
"name": "@eshoponabp/ordering", |
|||
"version": "0.0.1", |
|||
"peerDependencies": { |
|||
"@angular/common": "^12.2.0", |
|||
"@angular/core": "^12.2.0" |
|||
}, |
|||
"dependencies": { |
|||
"tslib": "^2.3.0" |
|||
} |
|||
} |
|||
@ -0,0 +1,3 @@ |
|||
export * from './order-view-model'; |
|||
export * from './proxy'; |
|||
export * from './to-order-view-model'; |
|||
@ -0,0 +1,5 @@ |
|||
import { OrderDto } from './proxy/orders'; |
|||
|
|||
export interface OrderViewModel extends OrderDto { |
|||
orderTotal: number; |
|||
} |
|||
@ -0,0 +1,17 @@ |
|||
# Proxy Generation Output |
|||
|
|||
This directory includes the output of the latest proxy generation. |
|||
The files and folders in it will be overwritten when proxy generation is run again. |
|||
Therefore, please do not place your own content in this folder. |
|||
|
|||
In addition, `generate-proxy.json` works like a lock file. |
|||
It includes information used by the proxy generator, so please do not delete or modify it. |
|||
|
|||
Finally, the name of the files and folders should not be changed for two reasons: |
|||
- Proxy generator will keep creating them at those paths and you will have multiple copies of the same content. |
|||
- ABP Suite generates files which include imports from this folder. |
|||
|
|||
> **Important Notice:** If you are building a module and are planning to publish to npm, |
|||
> some of the generated proxies are likely to be exported from public-api.ts file. In such a case, |
|||
> please make sure you export files directly and not from barrel exports. In other words, |
|||
> do not include index.ts exports in your public-api.ts exports. |
|||
@ -0,0 +1,2 @@ |
|||
import * as Orders from './orders'; |
|||
export { Orders }; |
|||
@ -0,0 +1,3 @@ |
|||
export * from './models'; |
|||
export * from './order-status.enum'; |
|||
export * from './order.service'; |
|||
@ -0,0 +1,58 @@ |
|||
import type { EntityDto } from '@abp/ng.core'; |
|||
import type { OrderStatus } from './order-status.enum'; |
|||
|
|||
export interface BuyerDto extends EntityDto<string> { |
|||
name?: string; |
|||
email?: string; |
|||
} |
|||
|
|||
export interface GetMyOrdersInput { |
|||
filter?: string; |
|||
} |
|||
|
|||
export interface GetOrdersInput { |
|||
filter?: string; |
|||
} |
|||
|
|||
export interface OrderAddressDto { |
|||
description?: string; |
|||
street: string; |
|||
city: string; |
|||
country: string; |
|||
zipCode: string; |
|||
} |
|||
|
|||
export interface OrderCreateDto { |
|||
paymentMethod?: string; |
|||
address: OrderAddressDto; |
|||
products: OrderItemCreateDto[]; |
|||
} |
|||
|
|||
export interface OrderDto extends EntityDto<string> { |
|||
orderDate?: string; |
|||
orderNo: number; |
|||
orderStatus: OrderStatus; |
|||
paymentMethod?: string; |
|||
buyer: BuyerDto; |
|||
address: OrderAddressDto; |
|||
items: OrderItemDto[]; |
|||
} |
|||
|
|||
export interface OrderItemCreateDto { |
|||
productId?: string; |
|||
productCode?: string; |
|||
productName?: string; |
|||
pictureUrl?: string; |
|||
unitPrice: number; |
|||
discount: number; |
|||
units: number; |
|||
} |
|||
|
|||
export interface OrderItemDto extends EntityDto<string> { |
|||
productId?: string; |
|||
productName?: string; |
|||
pictureUrl?: string; |
|||
unitPrice: number; |
|||
discount: number; |
|||
units: number; |
|||
} |
|||
@ -0,0 +1,10 @@ |
|||
import { mapEnumToOptions } from '@abp/ng.core'; |
|||
|
|||
export enum OrderStatus { |
|||
Placed = 0, |
|||
Paid = 1, |
|||
Shipped = 2, |
|||
Cancelled = 3, |
|||
} |
|||
|
|||
export const orderStatusOptions = mapEnumToOptions(OrderStatus); |
|||
@ -0,0 +1,74 @@ |
|||
import type { GetMyOrdersInput, GetOrdersInput, OrderCreateDto, OrderDto } from './models'; |
|||
import { RestService } from '@abp/ng.core'; |
|||
import type { PagedAndSortedResultRequestDto, PagedResultDto } from '@abp/ng.core'; |
|||
import { Injectable } from '@angular/core'; |
|||
|
|||
@Injectable({ |
|||
providedIn: 'root', |
|||
}) |
|||
export class OrderService { |
|||
apiName = 'Ordering'; |
|||
|
|||
create = (input: OrderCreateDto) => |
|||
this.restService.request<any, OrderDto>({ |
|||
method: 'POST', |
|||
url: '/api/ordering/order', |
|||
body: input, |
|||
}, |
|||
{ apiName: this.apiName }); |
|||
|
|||
get = (id: string) => |
|||
this.restService.request<any, OrderDto>({ |
|||
method: 'GET', |
|||
url: `/api/ordering/order/${id}`, |
|||
}, |
|||
{ apiName: this.apiName }); |
|||
|
|||
getByOrderNo = (orderNo: number) => |
|||
this.restService.request<any, OrderDto>({ |
|||
method: 'GET', |
|||
url: '/api/ordering/order/by-order-no', |
|||
params: { orderNo }, |
|||
}, |
|||
{ apiName: this.apiName }); |
|||
|
|||
getListPaged = (input: PagedAndSortedResultRequestDto) => |
|||
this.restService.request<any, PagedResultDto<OrderDto>>({ |
|||
method: 'GET', |
|||
url: '/api/ordering/order/paged', |
|||
params: { sorting: input.sorting, skipCount: input.skipCount, maxResultCount: input.maxResultCount }, |
|||
}, |
|||
{ apiName: this.apiName }); |
|||
|
|||
getMyOrders = (input: GetMyOrdersInput) => |
|||
this.restService.request<any, OrderDto[]>({ |
|||
method: 'GET', |
|||
url: '/api/ordering/order/my-orders', |
|||
params: { filter: input.filter }, |
|||
}, |
|||
{ apiName: this.apiName }); |
|||
|
|||
getOrders = (input: GetOrdersInput) => |
|||
this.restService.request<any, OrderDto[]>({ |
|||
method: 'GET', |
|||
url: '/api/ordering/order/orders', |
|||
params: { filter: input.filter }, |
|||
}, |
|||
{ apiName: this.apiName }); |
|||
|
|||
setAsCancelled = (id: string) => |
|||
this.restService.request<any, void>({ |
|||
method: 'POST', |
|||
url: `/api/ordering/order/${id}/set-as-cancelled`, |
|||
}, |
|||
{ apiName: this.apiName }); |
|||
|
|||
setAsShipped = (id: string) => |
|||
this.restService.request<any, void>({ |
|||
method: 'POST', |
|||
url: `/api/ordering/order/${id}/set-as-shipped`, |
|||
}, |
|||
{ apiName: this.apiName }); |
|||
|
|||
constructor(private restService: RestService) {} |
|||
} |
|||
@ -0,0 +1,8 @@ |
|||
import { OrderDto } from './proxy/orders'; |
|||
import { OrderViewModel } from './order-view-model'; |
|||
|
|||
const mapItem = (x: OrderDto): OrderViewModel => { |
|||
const orderTotal = x.items?.reduce((acc, curr) => ( acc + (curr.unitPrice * curr.units)), 0) || 0; |
|||
return {...x, orderTotal}; |
|||
}; |
|||
export const toOrderViewModel = (orders: OrderDto[]) => orders.map(mapItem); |
|||
@ -0,0 +1,13 @@ |
|||
import { NgModule } from '@angular/core'; |
|||
import { RouterModule, Routes } from '@angular/router'; |
|||
|
|||
const routes: Routes = [ |
|||
{ path: '', redirectTo: 'orders', pathMatch: 'full' }, |
|||
{ path: 'orders', loadChildren: () => import('./pages/orders/orders.module').then(m => m.OrdersModule) }, |
|||
]; |
|||
|
|||
@NgModule({ |
|||
imports: [RouterModule.forChild(routes)], |
|||
exports: [RouterModule], |
|||
}) |
|||
export class OrderingRoutingModule {} |
|||
@ -0,0 +1,9 @@ |
|||
import { NgModule } from '@angular/core'; |
|||
import { OrderingRoutingModule } from './ordering-routing.module'; |
|||
|
|||
@NgModule({ |
|||
declarations: [], |
|||
imports: [OrderingRoutingModule], |
|||
exports: [], |
|||
}) |
|||
export class OrderingModule {} |
|||
@ -0,0 +1 @@ |
|||
export * from './orders'; |
|||
@ -0,0 +1,3 @@ |
|||
export * from './orders-routing.module'; |
|||
export * from './orders.component'; |
|||
export * from './orders.module'; |
|||
@ -0,0 +1,20 @@ |
|||
import { Component, Input } from '@angular/core'; |
|||
|
|||
@Component({ |
|||
selector: 'lib-order-detail-item', |
|||
template: ` |
|||
<div class="row"> |
|||
<div class="col-3"> |
|||
{{ label | abpLocalization }} |
|||
</div> |
|||
<b class="col-9"> |
|||
<ng-content></ng-content> |
|||
</b> |
|||
</div> |
|||
`,
|
|||
styles: [], |
|||
}) |
|||
export class OrderDetailItemComponent { |
|||
@Input() |
|||
label = ''; |
|||
} |
|||
@ -0,0 +1,78 @@ |
|||
<abp-modal [visible]="visible" (visibleChange)="visibleChange.emit($event)" [options]="modalOption"> |
|||
<ng-template #abpHeader> |
|||
<h3>{{ 'OrderingService::ModalTitle' }}</h3> |
|||
</ng-template> |
|||
|
|||
<ng-template #abpBody> |
|||
<div *ngIf="order"> |
|||
<div class="container"> |
|||
<lib-order-detail-item label="OrderingService::DisplayName:OrderNo" |
|||
>#{{ order.orderNo }}</lib-order-detail-item |
|||
> |
|||
<lib-order-detail-item label="OrderingService::DisplayName:OrderStatus">{{ |
|||
order.orderStatus |
|||
}}</lib-order-detail-item> |
|||
<lib-order-detail-item label="OrderingService::DisplayName:BuyerName">{{ |
|||
order.buyer.name |
|||
}}</lib-order-detail-item> |
|||
<lib-order-detail-item label="OrderingService::DisplayName:BuyerEmail">{{ |
|||
order.buyer.email |
|||
}}</lib-order-detail-item> |
|||
|
|||
<lib-order-detail-item label="OrderingService::DisplayName:Address"> |
|||
<span *ngIf="order.address as address"> |
|||
{{ address.description }} <br /> |
|||
{{ address.street }} <br /> |
|||
{{ address.zipCode }} <br /> |
|||
{{ address.city }} / {{ address.country }} <br /> |
|||
</span> |
|||
</lib-order-detail-item> |
|||
<lib-order-detail-item label="OrderingService::DisplayName:PaymentMethod">{{ |
|||
order.paymentMethod |
|||
}}</lib-order-detail-item> |
|||
<lib-order-detail-item label="OrderingService::DisplayName:Total">{{ |
|||
order.orderTotal | currency |
|||
}}</lib-order-detail-item> |
|||
</div> |
|||
<br /><br /><br /> |
|||
|
|||
<ngx-datatable [rows]="order.items" default> |
|||
<!-- TODO: localize column headers --> |
|||
<ngx-datatable-column |
|||
[name]="'OrderingService::DisplayName:ProductId'" |
|||
prop="productId" |
|||
></ngx-datatable-column> |
|||
<ngx-datatable-column [name]="'OrderingService::DisplayName:PictureUrl'" prop="pictureUrl"> |
|||
<ng-template let-value="value" ngx-datatable-cell-template> |
|||
<img [src]="mediaServerUrl + '/product-images/' + value" width="80" alt="" /> |
|||
</ng-template> |
|||
</ngx-datatable-column> |
|||
<ngx-datatable-column |
|||
[name]="'OrderingService::DisplayName:ProductName'" |
|||
prop="productName" |
|||
></ngx-datatable-column> |
|||
<ngx-datatable-column [name]="'OrderingService::DisplayName:UnitPrice'" prop="unitPrice"> |
|||
<ng-template let-value="value" ngx-datatable-cell-template> |
|||
{{ value | currency }} |
|||
</ng-template> |
|||
</ngx-datatable-column> |
|||
<ngx-datatable-column |
|||
[name]="'OrderingService::DisplayName:Units'" |
|||
prop="units" |
|||
></ngx-datatable-column> |
|||
<ngx-datatable-column [name]="'OrderingService::DisplayName:Discount'" prop="discount"> |
|||
<ng-template let-value="value" ngx-datatable-cell-template> {{ value }} % </ng-template> |
|||
</ngx-datatable-column> |
|||
<ngx-datatable-column [name]="'OrderingService::DisplayName:TotalPrice'"> |
|||
<ng-template let-row="row" ngx-datatable-cell-template> |
|||
{{ row.units * row.unitPrice | currency }} |
|||
</ng-template> |
|||
</ngx-datatable-column> |
|||
</ngx-datatable> |
|||
</div> |
|||
</ng-template> |
|||
|
|||
<ng-template #abpFooter> |
|||
<button type="button" class="btn btn-secondary" abpClose>{{ 'AbpUi::Close' }}</button> |
|||
</ng-template> |
|||
</abp-modal> |
|||
@ -0,0 +1,17 @@ |
|||
import { Component, EventEmitter, Input, Output } from '@angular/core'; |
|||
import { OrderViewModel } from '../../../lib/order-view-model'; |
|||
import { environment } from '../../../../../../src/environments/environment'; |
|||
|
|||
@Component({ |
|||
selector: 'lib-order-detail', |
|||
templateUrl: './order-detail.component.html', |
|||
}) |
|||
export class OrderDetailComponent { |
|||
modalOption = { size: 'xl' }; |
|||
@Input() |
|||
visible: boolean; |
|||
@Input() |
|||
order: OrderViewModel | undefined; |
|||
mediaServerUrl = environment.mediaServerUrl; |
|||
@Output() readonly visibleChange = new EventEmitter<boolean>(); |
|||
} |
|||
@ -0,0 +1,11 @@ |
|||
import { NgModule } from '@angular/core'; |
|||
import { RouterModule, Routes } from '@angular/router'; |
|||
import { OrdersComponent } from './orders.component'; |
|||
|
|||
const routes: Routes = [{ path: '', component: OrdersComponent }]; |
|||
|
|||
@NgModule({ |
|||
imports: [RouterModule.forChild(routes)], |
|||
exports: [RouterModule] |
|||
}) |
|||
export class OrdersRoutingModule { } |
|||
@ -0,0 +1,87 @@ |
|||
<div class="card"> |
|||
<div class="card-header"> |
|||
<div class="row"> |
|||
<div class="col col-md-6"> |
|||
<h5 class="card-title">{{ 'AbpOrdering::Orders' | abpLocalization }}</h5> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="card-body"> |
|||
<ngx-datatable [rows]="items" [count]="count" [list]="list" default> |
|||
<!-- TODO: localize column headers --> |
|||
<ngx-datatable-column name="" [sortable]="false" prop="id"> |
|||
<ng-template let-row="row" ngx-datatable-cell-template> |
|||
<div ngbDropdown container="body" class="d-inline-block"> |
|||
<button |
|||
class="btn btn-primary btn-sm dropdown-toggle" |
|||
data-toggle="dropdown" |
|||
aria-haspopup="true" |
|||
ngbDropdownToggle |
|||
> |
|||
<i class="mr-1 fa fa-cog"></i>{{ 'AbpUi::Actions' | abpLocalization }} |
|||
</button> |
|||
<div ngbDropdownMenu> |
|||
<button |
|||
class="dropdown-item" |
|||
(click)="openModal(row)" |
|||
*abpPermission="permissions.detail" |
|||
> |
|||
{{ 'AbpUi::Detail' | abpLocalization }} |
|||
</button> |
|||
<button |
|||
class="dropdown-item" |
|||
(click)="setAsShipped(row)" |
|||
*abpPermission="permissions.setAsShipped" |
|||
> |
|||
{{ 'OrderingService::Permission:Orders.SetAsShipped' | abpLocalization }} |
|||
</button> |
|||
<!-- Todo: Add permissions --> |
|||
<button |
|||
class="dropdown-item" |
|||
*abpPermission="permissions.setAsCancelled" |
|||
(click)="setAsCancelled(row)" |
|||
> |
|||
{{ 'OrderingService::Permission:Orders.SetAsCancelled' | abpLocalization }} |
|||
</button> |
|||
</div> |
|||
</div> |
|||
</ng-template> |
|||
</ngx-datatable-column> |
|||
<ngx-datatable-column |
|||
[name]="'OrderingService::DisplayName:OrderNo' | abpLocalization" |
|||
prop="orderNo" |
|||
></ngx-datatable-column> |
|||
<ngx-datatable-column |
|||
[name]="'OrderingService::DisplayName:OrderDate' | abpLocalization" |
|||
prop="orderDate" |
|||
> |
|||
<ng-template let-value="value" ngx-datatable-cell-template> |
|||
<span>{{ value | date }}</span> |
|||
</ng-template> |
|||
</ngx-datatable-column> |
|||
<ngx-datatable-column |
|||
[name]="'OrderingService::DisplayName:OrderTotal' | abpLocalization" |
|||
prop="orderTotal" |
|||
> |
|||
<ng-template let-value="value" ngx-datatable-cell-template> |
|||
<span>{{ value | currency }}</span> |
|||
</ng-template> |
|||
</ngx-datatable-column> |
|||
<ngx-datatable-column |
|||
[name]="'OrderingService::DisplayName:OrderStatus' | abpLocalization" |
|||
prop="orderStatus" |
|||
> |
|||
<ng-template let-value="value" ngx-datatable-cell-template> |
|||
{{ 'OrderingService::Enum:OrderStatus:' + value | abpLocalization }} |
|||
</ng-template> |
|||
</ngx-datatable-column> |
|||
</ngx-datatable> |
|||
</div> |
|||
</div> |
|||
|
|||
<lib-order-detail |
|||
[visible]="isModalVisible" |
|||
(visibleChange)="closeModal($event)" |
|||
[order]="selectedOrder" |
|||
> |
|||
</lib-order-detail> |
|||
@ -0,0 +1,25 @@ |
|||
import { ComponentFixture, TestBed } from '@angular/core/testing'; |
|||
|
|||
import { OrdersComponent } from './orders.component'; |
|||
|
|||
describe('OrdersComponent', () => { |
|||
let component: OrdersComponent; |
|||
let fixture: ComponentFixture<OrdersComponent>; |
|||
|
|||
beforeEach(async () => { |
|||
await TestBed.configureTestingModule({ |
|||
declarations: [ OrdersComponent ] |
|||
}) |
|||
.compileComponents(); |
|||
}); |
|||
|
|||
beforeEach(() => { |
|||
fixture = TestBed.createComponent(OrdersComponent); |
|||
component = fixture.componentInstance; |
|||
fixture.detectChanges(); |
|||
}); |
|||
|
|||
it('should create', () => { |
|||
expect(component).toBeTruthy(); |
|||
}); |
|||
}); |
|||
@ -0,0 +1,83 @@ |
|||
import { Component, OnInit } from '@angular/core'; |
|||
import { OrderService } from '../../lib/proxy/orders'; |
|||
import { OrderViewModel, toOrderViewModel } from '../../lib'; |
|||
import { Confirmation, ConfirmationService } from '@abp/ng.theme.shared'; |
|||
import { ListService } from '@abp/ng.core'; |
|||
import { eOrderingPolicyNames } from '@eshoponabp/ordering/config'; |
|||
|
|||
@Component({ |
|||
selector: 'lib-orders', |
|||
templateUrl: './orders.component.html', |
|||
providers: [ListService], |
|||
}) |
|||
export class OrdersComponent implements OnInit { |
|||
constructor( |
|||
private service: OrderService, |
|||
public list: ListService, |
|||
private confirmationService: ConfirmationService |
|||
) {} |
|||
|
|||
selectedOrder: OrderViewModel | undefined; |
|||
isModalVisible = false; |
|||
items: OrderViewModel[]; |
|||
count = 0; |
|||
permissions = { |
|||
detail: eOrderingPolicyNames.ordering, |
|||
setAsShipped: eOrderingPolicyNames.setAsShipped, |
|||
setAsCancelled: eOrderingPolicyNames.setAsCancelled, |
|||
}; |
|||
|
|||
ngOnInit(): void { |
|||
const ordersStreamCreator = query => this.service.getListPaged(query); |
|||
|
|||
this.list.hookToQuery(ordersStreamCreator).subscribe(response => { |
|||
this.items = toOrderViewModel(response.items); |
|||
this.count = response.totalCount; |
|||
}); |
|||
} |
|||
|
|||
openModal(order: OrderViewModel) { |
|||
if (!order) { |
|||
return; |
|||
} |
|||
this.selectedOrder = order; |
|||
this.isModalVisible = true; |
|||
} |
|||
|
|||
closeModal(isVisible: boolean) { |
|||
if (isVisible) { |
|||
return; |
|||
} |
|||
this.selectedOrder = null; |
|||
this.isModalVisible = false; |
|||
} |
|||
|
|||
setAsShipped(row: OrderViewModel) { |
|||
this.confirmationService |
|||
.warn('AbpOrdering::WillSetAsShipped', { key: '::AreYouSure', defaultValue: 'Are you sure?' }) |
|||
.subscribe(status => { |
|||
if (status !== Confirmation.Status.confirm) { |
|||
return; |
|||
} |
|||
this.service.setAsShipped(row.id).subscribe(() => { |
|||
this.list.get(); |
|||
}); |
|||
}); |
|||
} |
|||
|
|||
setAsCancelled(row: OrderViewModel) { |
|||
this.confirmationService |
|||
.warn('AbpOrdering::WillSetAsCancelled', { |
|||
key: '::AreYouSure', |
|||
defaultValue: 'Are you sure?', |
|||
}) |
|||
.subscribe(status => { |
|||
if (status !== Confirmation.Status.confirm) { |
|||
return; |
|||
} |
|||
this.service.setAsCancelled(row.id).subscribe(() => { |
|||
this.list.get(); |
|||
}); |
|||
}); |
|||
} |
|||
} |
|||
@ -0,0 +1,16 @@ |
|||
import { NgModule } from '@angular/core'; |
|||
import { CommonModule } from '@angular/common'; |
|||
|
|||
import { OrdersRoutingModule } from './orders-routing.module'; |
|||
import { OrdersComponent } from './orders.component'; |
|||
import { ThemeSharedModule } from '@abp/ng.theme.shared'; |
|||
import { CoreModule } from '@abp/ng.core'; |
|||
import { OrderDetailComponent } from './order-detail/order-detail.component'; |
|||
import { OrderDetailItemComponent } from './order-detail/order-detail-item/order-detail-item.component'; |
|||
import { NgbDropdownModule } from '@ng-bootstrap/ng-bootstrap'; |
|||
|
|||
@NgModule({ |
|||
declarations: [OrdersComponent, OrderDetailComponent, OrderDetailItemComponent], |
|||
imports: [CommonModule, NgbDropdownModule, OrdersRoutingModule, ThemeSharedModule, CoreModule], |
|||
}) |
|||
export class OrdersModule {} |
|||
@ -0,0 +1,7 @@ |
|||
/* |
|||
* Public API Surface of ordering |
|||
*/ |
|||
|
|||
export * from './pages/index'; |
|||
export * from './ordering.module'; |
|||
export * from './lib/proxy/index'; |
|||
@ -0,0 +1,28 @@ |
|||
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
|
|||
|
|||
import 'zone.js'; |
|||
import 'zone.js/testing'; |
|||
import { getTestBed } from '@angular/core/testing'; |
|||
import { |
|||
BrowserDynamicTestingModule, |
|||
platformBrowserDynamicTesting |
|||
} from '@angular/platform-browser-dynamic/testing'; |
|||
|
|||
declare const require: { |
|||
context(path: string, deep?: boolean, filter?: RegExp): { |
|||
keys(): string[]; |
|||
<T>(id: string): T; |
|||
}; |
|||
}; |
|||
|
|||
// First, initialize the Angular testing environment.
|
|||
getTestBed().initTestEnvironment( |
|||
BrowserDynamicTestingModule, |
|||
platformBrowserDynamicTesting(), |
|||
{ teardown: { destroyAfterEach: true }}, |
|||
); |
|||
|
|||
// Then we find all the tests.
|
|||
const context = require.context('./', true, /\.spec\.ts$/); |
|||
// And load the modules.
|
|||
context.keys().map(context); |
|||
@ -0,0 +1,19 @@ |
|||
{ |
|||
"extends": "../../tsconfig.json", |
|||
"compilerOptions": { |
|||
"outDir": "../../out-tsc/lib", |
|||
"target": "es2015", |
|||
"declaration": true, |
|||
"declarationMap": true, |
|||
"inlineSources": true, |
|||
"types": [], |
|||
"lib": [ |
|||
"dom", |
|||
"es2018" |
|||
] |
|||
}, |
|||
"exclude": [ |
|||
"src/test.ts", |
|||
"**/*.spec.ts" |
|||
] |
|||
} |
|||
@ -0,0 +1,9 @@ |
|||
{ |
|||
"extends": "./tsconfig.lib.json", |
|||
"compilerOptions": { |
|||
"declarationMap": false |
|||
}, |
|||
"angularCompilerOptions": { |
|||
"compilationMode": "partial" |
|||
} |
|||
} |
|||
@ -0,0 +1,17 @@ |
|||
/* To learn more about this file see: https://angular.io/config/tsconfig. */ |
|||
{ |
|||
"extends": "../../tsconfig.json", |
|||
"compilerOptions": { |
|||
"outDir": "../../out-tsc/spec", |
|||
"types": [ |
|||
"jasmine" |
|||
] |
|||
}, |
|||
"files": [ |
|||
"src/test.ts" |
|||
], |
|||
"include": [ |
|||
"**/*.spec.ts", |
|||
"**/*.d.ts" |
|||
] |
|||
} |
|||
@ -0,0 +1,5 @@ |
|||
import { Environment } from '@abp/ng.core'; |
|||
|
|||
export interface MyEnvironment extends Environment { |
|||
mediaServerUrl?: string; |
|||
} |
|||
@ -1,100 +0,0 @@ |
|||
{ |
|||
"GlobalConfiguration": { |
|||
"BaseUrl": "https://localhost:44373" |
|||
}, |
|||
"Routes": [ |
|||
{ |
|||
"ServiceKey": "Account Service", |
|||
"DownstreamPathTemplate": "/api/account/{everything}", |
|||
"DownstreamScheme": "https", |
|||
"DownstreamHostAndPorts": [ |
|||
{ |
|||
"Host": "localhost", |
|||
"Port": 44330 |
|||
} |
|||
], |
|||
"UpstreamPathTemplate": "/api/account/{everything}", |
|||
"UpstreamHttpMethod": [ "Put", "Delete", "Get", "Post" ] |
|||
}, |
|||
{ |
|||
"ServiceKey": "Administration Service", |
|||
"DownstreamPathTemplate": "/api/abp/{everything}", |
|||
"DownstreamScheme": "https", |
|||
"DownstreamHostAndPorts": [ |
|||
{ |
|||
"Host": "localhost", |
|||
"Port": 44353 |
|||
} |
|||
], |
|||
"UpstreamPathTemplate": "/api/abp/{everything}", |
|||
"UpstreamHttpMethod": [ "Put", "Delete", "Get", "Post" ], |
|||
"QoSOptions": { |
|||
"ExceptionsAllowedBeforeBreaking": 3, |
|||
"DurationOfBreak": 3000, |
|||
"TimeoutValue": 2500 |
|||
} |
|||
}, |
|||
{ |
|||
"ServiceKey": "Catalog Service", |
|||
"DownstreamPathTemplate": "/api/catalog/{everything}", |
|||
"DownstreamScheme": "https", |
|||
"DownstreamHostAndPorts": [ |
|||
{ |
|||
"Host": "localhost", |
|||
"Port": 44354 |
|||
} |
|||
], |
|||
"UpstreamPathTemplate": "/api/catalog/{everything}", |
|||
"UpstreamHttpMethod": [ "Put", "Delete", "Get", "Post" ], |
|||
"QoSOptions": { |
|||
"ExceptionsAllowedBeforeBreaking": 3, |
|||
"DurationOfBreak": 3000, |
|||
"TimeoutValue": 2500 |
|||
} |
|||
}, |
|||
{ |
|||
"ServiceKey": "Basket Service", |
|||
"DownstreamPathTemplate": "/api/basket/{everything}", |
|||
"DownstreamScheme": "https", |
|||
"DownstreamHostAndPorts": [ |
|||
{ |
|||
"Host": "localhost", |
|||
"Port": 44355 |
|||
} |
|||
], |
|||
"UpstreamPathTemplate": "/api/basket/{everything}", |
|||
"UpstreamHttpMethod": [ "Put", "Delete", "Get", "Post" ], |
|||
"QoSOptions": { |
|||
"ExceptionsAllowedBeforeBreaking": 3, |
|||
"DurationOfBreak": 3000, |
|||
"TimeoutValue": 2500 |
|||
} |
|||
}, |
|||
{ |
|||
"ServiceKey": "Ordering Service", |
|||
"DownstreamPathTemplate": "/api/ordering/{everything}", |
|||
"DownstreamScheme": "https", |
|||
"DownstreamHostAndPorts": [ |
|||
{ |
|||
"Host": "localhost", |
|||
"Port": 44356 |
|||
} |
|||
], |
|||
"UpstreamPathTemplate": "/api/ordering/{everything}", |
|||
"UpstreamHttpMethod": [ "Put", "Delete", "Get", "Post" ] |
|||
}, |
|||
{ |
|||
"ServiceKey": "Payment Service", |
|||
"DownstreamPathTemplate": "/api/payment/{everything}", |
|||
"DownstreamScheme": "https", |
|||
"DownstreamHostAndPorts": [ |
|||
{ |
|||
"Host": "localhost", |
|||
"Port": 44357 |
|||
} |
|||
], |
|||
"UpstreamPathTemplate": "/api/payment/{everything}", |
|||
"UpstreamHttpMethod": [ "Put", "Delete", "Get", "Post" ] |
|||
} |
|||
] |
|||
} |
|||
@ -0,0 +1,100 @@ |
|||
{ |
|||
"ReverseProxy": { |
|||
"Routes": { |
|||
"Account Service": { |
|||
"ClusterId": "account-cluster", |
|||
"Match": { |
|||
"Path": "/api/account/{**everything}" |
|||
} |
|||
}, |
|||
"Administration Service": { |
|||
"ClusterId": "administration-cluster", |
|||
"Match": { |
|||
"Path": "/api/abp/{**everything}" |
|||
} |
|||
}, |
|||
"Catalog Service": { |
|||
"ClusterId": "catalog-cluster", |
|||
"Match": { |
|||
"Path": "/api/catalog/{**everything}" |
|||
} |
|||
}, |
|||
"Basket Service": { |
|||
"ClusterId": "basket-cluster", |
|||
"Match": { |
|||
"Path": "/api/basket/{**everything}" |
|||
} |
|||
}, |
|||
"Ordering Service": { |
|||
"ClusterId": "ordering-cluster", |
|||
"Match": { |
|||
"Path": "/api/ordering/{**everything}" |
|||
} |
|||
}, |
|||
"Payment Service": { |
|||
"ClusterId": "payment-cluster", |
|||
"Match": { |
|||
"Path": "/api/payment/{**everything}" |
|||
} |
|||
}, |
|||
"product-picture-route": { |
|||
"ClusterId": "product-picture-cluster", |
|||
"Match": { |
|||
"Path": "/product-images/{**everything}", |
|||
"Methods" : [ "GET" ] |
|||
} |
|||
} |
|||
}, |
|||
"Clusters": { |
|||
"account-cluster": { |
|||
"Destinations": { |
|||
"destination1": { |
|||
"Address": "https://localhost:44330" |
|||
} |
|||
} |
|||
}, |
|||
"administration-cluster": { |
|||
"Destinations": { |
|||
"destination1": { |
|||
"Address": "https://localhost:44353" |
|||
} |
|||
} |
|||
}, |
|||
"catalog-cluster": { |
|||
"Destinations": { |
|||
"destination1": { |
|||
"Address": "https://localhost:44354" |
|||
} |
|||
} |
|||
}, |
|||
"product-picture-cluster": { |
|||
"Destinations": { |
|||
"destination1": { |
|||
"Address": "https://localhost:44354" |
|||
} |
|||
} |
|||
}, |
|||
"basket-cluster": { |
|||
"Destinations": { |
|||
"destination1": { |
|||
"Address": "https://localhost:44355" |
|||
} |
|||
} |
|||
}, |
|||
"ordering-cluster": { |
|||
"Destinations": { |
|||
"destination1": { |
|||
"Address": "https://localhost:44356" |
|||
} |
|||
} |
|||
}, |
|||
"payment-cluster": { |
|||
"Destinations": { |
|||
"destination1": { |
|||
"Address": "https://localhost:44357" |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -1,90 +0,0 @@ |
|||
{ |
|||
"GlobalConfiguration": { |
|||
"BaseUrl": "https://localhost:44372" |
|||
}, |
|||
"Routes": [ |
|||
{ |
|||
"ServiceKey": "Identity Service", |
|||
"DownstreamPathTemplate": "/api/identity/{everything}", |
|||
"DownstreamScheme": "https", |
|||
"DownstreamHostAndPorts": [ |
|||
{ |
|||
"Host": "localhost", |
|||
"Port": 44351 |
|||
} |
|||
], |
|||
"UpstreamPathTemplate": "/api/identity/{everything}", |
|||
"UpstreamHttpMethod": [ "Put", "Delete", "Get", "Post" ] |
|||
}, |
|||
{ |
|||
"ServiceKey": "Account Service", |
|||
"DownstreamPathTemplate": "/api/account/{everything}", |
|||
"DownstreamScheme": "https", |
|||
"DownstreamHostAndPorts": [ |
|||
{ |
|||
"Host": "localhost", |
|||
"Port": 44330 |
|||
} |
|||
], |
|||
"UpstreamPathTemplate": "/api/account/{everything}", |
|||
"UpstreamHttpMethod": [ "Put", "Delete", "Get", "Post" ] |
|||
}, |
|||
{ |
|||
"ServiceKey": "Administration Service", |
|||
"DownstreamPathTemplate": "/api/abp/{everything}", |
|||
"DownstreamScheme": "https", |
|||
"DownstreamHostAndPorts": [ |
|||
{ |
|||
"Host": "localhost", |
|||
"Port": 44353 |
|||
} |
|||
], |
|||
"UpstreamPathTemplate": "/api/abp/{everything}", |
|||
"UpstreamHttpMethod": [ "Put", "Delete", "Get", "Post" ], |
|||
"QoSOptions": { |
|||
"ExceptionsAllowedBeforeBreaking": 3, |
|||
"DurationOfBreak": 5000, |
|||
"TimeoutValue": 2500 |
|||
} |
|||
}, |
|||
{ |
|||
"ServiceKey": "Administration Service", |
|||
"DownstreamPathTemplate": "/api/feature-management/{everything}", |
|||
"DownstreamScheme": "https", |
|||
"DownstreamHostAndPorts": [ |
|||
{ |
|||
"Host": "localhost", |
|||
"Port": 44353 |
|||
} |
|||
], |
|||
"UpstreamPathTemplate": "/api/feature-management/{everything}", |
|||
"UpstreamHttpMethod": [ "Put", "Delete", "Get", "Post" ] |
|||
}, |
|||
{ |
|||
"ServiceKey": "Administration Service", |
|||
"DownstreamPathTemplate": "/api/permission-management/{everything}", |
|||
"DownstreamScheme": "https", |
|||
"DownstreamHostAndPorts": [ |
|||
{ |
|||
"Host": "localhost", |
|||
"Port": 44353 |
|||
} |
|||
], |
|||
"UpstreamPathTemplate": "/api/permission-management/{everything}", |
|||
"UpstreamHttpMethod": [ "Put", "Delete", "Get", "Post" ] |
|||
}, |
|||
{ |
|||
"ServiceKey": "Administration Service", |
|||
"DownstreamPathTemplate": "/api/setting-management/{everything}", |
|||
"DownstreamScheme": "https", |
|||
"DownstreamHostAndPorts": [ |
|||
{ |
|||
"Host": "localhost", |
|||
"Port": 44353 |
|||
} |
|||
], |
|||
"UpstreamPathTemplate": "/api/setting-management/{everything}", |
|||
"UpstreamHttpMethod": [ "Put", "Delete", "Get", "Post" ] |
|||
} |
|||
] |
|||
} |
|||
@ -0,0 +1,86 @@ |
|||
{ |
|||
"ReverseProxy": { |
|||
"Routes": { |
|||
"Account Service": { |
|||
"ClusterId": "account-cluster", |
|||
"Match": { |
|||
"Path": "/api/account/{**everything}" |
|||
} |
|||
}, |
|||
"Identity Service": { |
|||
"ClusterId": "identity-cluster", |
|||
"Match": { |
|||
"Path": "/api/identity/{**everything}" |
|||
} |
|||
}, |
|||
"Administration Service": { |
|||
"ClusterId": "administration-cluster", |
|||
"Match": { |
|||
"Path": "/api/abp/{**everything}" |
|||
} |
|||
}, |
|||
"feature-management-route": { |
|||
"ClusterId": "feature-management-cluster", |
|||
"Match": { |
|||
"Path": "/api/feature-management/{**everything}" |
|||
} |
|||
}, |
|||
"permission-management-route": { |
|||
"ClusterId": "permission-management-cluster", |
|||
"Match": { |
|||
"Path": "/api/permission-management/{**everything}" |
|||
} |
|||
}, |
|||
"setting-management-route": { |
|||
"ClusterId": "setting-management-cluster", |
|||
"Match": { |
|||
"Path": "/api/setting-management/{**everything}" |
|||
} |
|||
} |
|||
}, |
|||
"Clusters": { |
|||
"account-cluster": { |
|||
"Destinations": { |
|||
"destination1": { |
|||
"Address": "https://localhost:44330" |
|||
} |
|||
} |
|||
}, |
|||
"identity-cluster": { |
|||
"Destinations": { |
|||
"destination1": { |
|||
"Address": "https://localhost:44351" |
|||
} |
|||
} |
|||
}, |
|||
"administration-cluster": { |
|||
"Destinations": { |
|||
"destination1": { |
|||
"Address": "https://localhost:44353" |
|||
} |
|||
} |
|||
}, |
|||
"feature-management-cluster": { |
|||
"Destinations": { |
|||
"destination1": { |
|||
"Address": "https://localhost:44353" |
|||
} |
|||
} |
|||
}, |
|||
"permission-management-cluster": { |
|||
"Destinations": { |
|||
"destination1": { |
|||
"Address": "https://localhost:44353" |
|||
} |
|||
} |
|||
}, |
|||
"setting-management-cluster": { |
|||
"Destinations": { |
|||
"destination1": { |
|||
"Address": "https://localhost:44353" |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 94 KiB After Width: | Height: | Size: 94 KiB |
|
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 47 KiB |
|
Before Width: | Height: | Size: 9.4 KiB After Width: | Height: | Size: 9.4 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 66 KiB After Width: | Height: | Size: 66 KiB |
@ -0,0 +1,7 @@ |
|||
namespace EShopOnAbp.OrderingService.Orders |
|||
{ |
|||
public class GetOrdersInput |
|||
{ |
|||
public string Filter { get; set; } |
|||
} |
|||
} |
|||
@ -1,12 +1,43 @@ |
|||
{ |
|||
"culture": "en", |
|||
"texts": { |
|||
"MyAccount": "My account", |
|||
"MyAccount": "My account", |
|||
"SamplePageMessage": "A sample page for the OrderingService module", |
|||
"Ordering:00001": "Possible values for Order status: {OrderStatus}", |
|||
"Ordering:00002": "Invalid number of units", |
|||
"Ordering:00003": "Invalid discount", |
|||
"Ordering:00004": "The total of order item is lower than applied discount", |
|||
"Ordering:01001": "Order with {0} id could not be found!" |
|||
"Ordering:01001": "Order with {0} id could not be found!", |
|||
"Permission:Orders": "Orders", |
|||
"Permission:OrderingService": "Ordering Service", |
|||
"Menu:Orders": "Orders", |
|||
"Menu:OrderManagement": "Order Management", |
|||
|
|||
"ModalTitle":"Order Detail", |
|||
|
|||
"DisplayName:OrderNo": "Order No", |
|||
"DisplayName:OrderDate": "Order Date", |
|||
"DisplayName:OrderTotal": "Order Total", |
|||
"DisplayName:OrderStatus": "Order Status", |
|||
"DisplayName:ProductId": "Product Id", |
|||
"DisplayName:ProductName": "Product Name", |
|||
"DisplayName:PictureUrl": "Picture", |
|||
"DisplayName:Units": "Unit", |
|||
"DisplayName:UnitPrice": "Unit Price", |
|||
"DisplayName:Discount": "Discount", |
|||
"DisplayName:TotalPrice": "Total Price", |
|||
"DisplayName:BuyerName": "Buyer Name", |
|||
"DisplayName:BuyerEmail": "Buyer E-mail", |
|||
"DisplayName:Address": "Address", |
|||
"DisplayName:PaymentMethod": "Payment Method", |
|||
"DisplayName:Total": "Total", |
|||
|
|||
"Permission:Orders.SetAsCancelled": "Set As Cancelled", |
|||
"Permission:Orders.SetAsShipped": "Set As Shipped", |
|||
|
|||
"Enum:OrderStatus:0":"Placed", |
|||
"Enum:OrderStatus:1":"Paid", |
|||
"Enum:OrderStatus:2":"Shipped", |
|||
"Enum:OrderStatus:3":"Cancelled" |
|||
} |
|||
} |
|||
@ -1,12 +1,43 @@ |
|||
{ |
|||
"culture": "tr", |
|||
"texts": { |
|||
"MyAccount": "Hesabım", |
|||
"MyAccount": "Hesabım", |
|||
"SamplePageMessage": "OrderingService modulünden örnek bir sayfa", |
|||
"Ordering:00001": "Muhtemel Sipariş durum değerleri: {OrderStatus}", |
|||
"Ordering:00002": "Ürün adedi negatif olamaz", |
|||
"Ordering:00003": "Geçersiz indirim", |
|||
"Ordering:00004": "Ürünlerin toplam bedeli, uygulanan indirimden daha az olamaz", |
|||
"Ordering:01001": "{0} ID numaralı ürün bulunamadı!" |
|||
"Ordering:01001": "{0} ID numaralı ürün bulunamadı!", |
|||
"Permission:Orders": "Siparişler", |
|||
"Permission:OrderingService": "Sipariş Servisi", |
|||
"Menu:Orders": "Siparişler", |
|||
"Menu:OrderManagement": "Sipariş Yönetimi", |
|||
|
|||
"ModalTitle": "Sipariş Detayı", |
|||
|
|||
"DisplayName:OrderNo": "Sipariş Numarası", |
|||
"DisplayName:OrderDate": "Sipariş Tarihi", |
|||
"DisplayName:OrderTotal": "Sipariş Toplamı", |
|||
"DisplayName:OrderStatus": "Sipariş Durumu", |
|||
"DisplayName:ProductId": "Ürün Anahtarı", |
|||
"DisplayName:ProductName": "Ürün Adı", |
|||
"DisplayName:PictureUrl": "Resim", |
|||
"DisplayName:Units": "Adet", |
|||
"DisplayName:UnitPrice": "Adet Fiyatı", |
|||
"DisplayName:Discount": "İndirim", |
|||
"DisplayName:TotalPrice": "Toplam Fiyat", |
|||
"DisplayName:BuyerName": "Alan Kişi", |
|||
"DisplayName:BuyerEmail": "Alan Kişi Mail", |
|||
"DisplayName:Address": "Adres", |
|||
"DisplayName:PaymentMethod": "Ödeme Şekli", |
|||
"DisplayName:Total": "Toplam", |
|||
|
|||
"Permission:Orders.SetAsCancelled": "İptal Edildi Olarak İşaretle", |
|||
"Permission:Orders.SetAsShipped": "Sevk Edildi Olarak İşaretle", |
|||
|
|||
"Enum:OrderStatus:0": "Oluşturuldu", |
|||
"Enum:OrderStatus:1": "Ödendi", |
|||
"Enum:OrderStatus:2": "Sevk Edildi", |
|||
"Enum:OrderStatus:3": "İptal Edildi" |
|||
} |
|||
} |
|||
@ -0,0 +1,17 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using Volo.Abp.Domain.Entities.Events.Distributed; |
|||
using Volo.Abp.EventBus; |
|||
|
|||
namespace EShopOnAbp.OrderingService.Orders; |
|||
|
|||
[EventName("EShopOnAbp.Order.Cancelled")] |
|||
public class OrderCancelledEto : EtoBase |
|||
{ |
|||
public Guid PaymentRequestId { get; set; } |
|||
public Guid OrderId { get; set; } |
|||
public int OrderNo { get; set; } |
|||
public DateTime OrderDate { get; set; } |
|||
public BuyerEto Buyer { get; set; } |
|||
public List<OrderItemEto> Items { get; set; } = new(); |
|||
} |
|||
@ -0,0 +1,26 @@ |
|||
using EShopOnAbp.OrderingService.Orders; |
|||
using EShopOnAbp.PaymentService.PaymentRequests; |
|||
using Serilog; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.DependencyInjection; |
|||
using Volo.Abp.EventBus.Distributed; |
|||
|
|||
|
|||
namespace EShopOnAbp.PaymentService.EventHandlers |
|||
{ |
|||
public class OrderCancelledEventHandler : IDistributedEventHandler<OrderCancelledEto>, ITransientDependency |
|||
{ |
|||
private readonly IPaymentRequestRepository _paymentRepository; |
|||
|
|||
public OrderCancelledEventHandler(IPaymentRequestRepository paymenRepository) |
|||
{ |
|||
_paymentRepository = paymenRepository; |
|||
} |
|||
|
|||
public async Task HandleEventAsync(OrderCancelledEto eventData) |
|||
{ |
|||
var payment = await _paymentRepository.GetAsync(eventData.PaymentRequestId); |
|||
Log.Information($"Cancelled the order: {payment.OrderId} payment:{payment.Id}"); |
|||
} |
|||
} |
|||
} |
|||
@ -1,24 +1,20 @@ |
|||
using EShopOnAbp.Shared.Hosting.AspNetCore; |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Ocelot.DependencyInjection; |
|||
using Ocelot.Provider.Polly; |
|||
using Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy; |
|||
using Volo.Abp.Modularity; |
|||
|
|||
namespace EShopOnAbp.Shared.Hosting.Gateways |
|||
{ |
|||
[DependsOn( |
|||
typeof(EShopOnAbpSharedHostingAspNetCoreModule), |
|||
typeof(AbpAspNetCoreMvcUiMultiTenancyModule) |
|||
typeof(EShopOnAbpSharedHostingAspNetCoreModule) |
|||
)] |
|||
public class EShopOnAbpSharedHostingGatewaysModule : AbpModule |
|||
{ |
|||
public override void ConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
var configuration = context.Services.GetConfiguration(); |
|||
|
|||
context.Services.AddOcelot(configuration) |
|||
.AddPolly(); |
|||
|
|||
context.Services.AddReverseProxy() |
|||
.LoadFromConfig(configuration.GetSection("ReverseProxy")); |
|||
} |
|||
} |
|||
} |
|||
@ -1,20 +0,0 @@ |
|||
using System.Collections.Generic; |
|||
|
|||
namespace EShopOnAbp.Shared.Hosting.Gateways |
|||
{ |
|||
public class OcelotConfiguration |
|||
{ |
|||
public string ServiceKey { get; set; } |
|||
public string DownstreamPathTemplate { get; set; } |
|||
public string DownstreamScheme { get; set; } |
|||
public string UpstreamPathTemplate { get; set; } |
|||
public List<string> UpstreamHttpMethod { get; set; } |
|||
public List<HostAndPort> DownstreamHostAndPorts { get; set; } |
|||
} |
|||
|
|||
public class HostAndPort |
|||
{ |
|||
public string Host { get; set; } |
|||
public int Port { get; set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,52 @@ |
|||
using System.Linq; |
|||
using Microsoft.AspNetCore.Builder; |
|||
using Microsoft.Extensions.Configuration; |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Microsoft.Extensions.Logging; |
|||
using Volo.Abp; |
|||
using Yarp.ReverseProxy.Configuration; |
|||
|
|||
namespace EShopOnAbp.Shared.Hosting.Gateways; |
|||
|
|||
public static class YarpSwaggerUIBuilderExtensions |
|||
{ |
|||
public static IApplicationBuilder ConfigureSwaggerUIWithYarp(this IApplicationBuilder app, |
|||
ApplicationInitializationContext context) |
|||
{ |
|||
app.UseSwagger(); |
|||
app.UseSwaggerUI(options => |
|||
{ |
|||
var configuration = context.ServiceProvider.GetRequiredService<IConfiguration>(); |
|||
var logger = context.ServiceProvider.GetRequiredService<ILogger<ApplicationInitializationContext>>(); |
|||
var proxyConfigProvider = context.ServiceProvider.GetRequiredService<IProxyConfigProvider>(); |
|||
var yarpConfig = proxyConfigProvider.GetConfig(); |
|||
|
|||
var routedClusters = yarpConfig.Clusters |
|||
.SelectMany(t => t.Destinations, |
|||
(clusterId, destination) => new {clusterId.ClusterId, destination.Value}); |
|||
|
|||
var groupedClusters = routedClusters |
|||
.GroupBy(q => q.Value.Address) |
|||
.Select(t => t.First()) |
|||
.Distinct() |
|||
.ToList(); |
|||
|
|||
foreach (var clusterGroup in groupedClusters) |
|||
{ |
|||
var routeConfig = yarpConfig.Routes.FirstOrDefault(q => |
|||
q.ClusterId == clusterGroup.ClusterId); |
|||
if (routeConfig == null) |
|||
{ |
|||
logger.LogWarning($"Swagger UI: Couldn't find route configuration for {clusterGroup.ClusterId}..."); |
|||
continue; |
|||
} |
|||
|
|||
options.SwaggerEndpoint($"{clusterGroup.Value.Address}/swagger/v1/swagger.json", $"{routeConfig.RouteId} API"); |
|||
options.OAuthClientId(configuration["AuthServer:SwaggerClientId"]); |
|||
options.OAuthClientSecret(configuration["AuthServer:SwaggerClientSecret"]); |
|||
} |
|||
}); |
|||
|
|||
return app; |
|||
} |
|||
} |
|||