Browse Source

Merge branch 'main' into 11949-Moving-Files

pull/96/head
malik masis 4 years ago
parent
commit
ebeae7af9d
  1. 31
      apps/angular/angular.json
  2. 3
      apps/angular/package.json
  3. 1
      apps/angular/projects/catalog/tsconfig.lib.json
  4. 1
      apps/angular/projects/catalog/tsconfig.lib.prod.json
  5. 24
      apps/angular/projects/ordering/README.md
  6. 7
      apps/angular/projects/ordering/config/ng-package.json
  7. 2
      apps/angular/projects/ordering/config/src/enums/index.ts
  8. 6
      apps/angular/projects/ordering/config/src/enums/policy-names.ts
  9. 3
      apps/angular/projects/ordering/config/src/enums/route-names.ts
  10. 12
      apps/angular/projects/ordering/config/src/ordering-config.module.ts
  11. 1
      apps/angular/projects/ordering/config/src/providers/index.ts
  12. 23
      apps/angular/projects/ordering/config/src/providers/route.provider.ts
  13. 3
      apps/angular/projects/ordering/config/src/public-api.ts
  14. 44
      apps/angular/projects/ordering/karma.conf.js
  15. 7
      apps/angular/projects/ordering/ng-package.json
  16. 11
      apps/angular/projects/ordering/package.json
  17. 3
      apps/angular/projects/ordering/src/lib/index.ts
  18. 5
      apps/angular/projects/ordering/src/lib/order-view-model.ts
  19. 17
      apps/angular/projects/ordering/src/lib/proxy/README.md
  20. 2377
      apps/angular/projects/ordering/src/lib/proxy/generate-proxy.json
  21. 2
      apps/angular/projects/ordering/src/lib/proxy/index.ts
  22. 3
      apps/angular/projects/ordering/src/lib/proxy/orders/index.ts
  23. 58
      apps/angular/projects/ordering/src/lib/proxy/orders/models.ts
  24. 10
      apps/angular/projects/ordering/src/lib/proxy/orders/order-status.enum.ts
  25. 74
      apps/angular/projects/ordering/src/lib/proxy/orders/order.service.ts
  26. 8
      apps/angular/projects/ordering/src/lib/to-order-view-model.ts
  27. 13
      apps/angular/projects/ordering/src/ordering-routing.module.ts
  28. 9
      apps/angular/projects/ordering/src/ordering.module.ts
  29. 1
      apps/angular/projects/ordering/src/pages/index.ts
  30. 3
      apps/angular/projects/ordering/src/pages/orders/index.ts
  31. 20
      apps/angular/projects/ordering/src/pages/orders/order-detail/order-detail-item/order-detail-item.component.ts
  32. 78
      apps/angular/projects/ordering/src/pages/orders/order-detail/order-detail.component.html
  33. 17
      apps/angular/projects/ordering/src/pages/orders/order-detail/order-detail.component.ts
  34. 11
      apps/angular/projects/ordering/src/pages/orders/orders-routing.module.ts
  35. 87
      apps/angular/projects/ordering/src/pages/orders/orders.component.html
  36. 25
      apps/angular/projects/ordering/src/pages/orders/orders.component.spec.ts
  37. 83
      apps/angular/projects/ordering/src/pages/orders/orders.component.ts
  38. 16
      apps/angular/projects/ordering/src/pages/orders/orders.module.ts
  39. 7
      apps/angular/projects/ordering/src/public-api.ts
  40. 28
      apps/angular/projects/ordering/src/test.ts
  41. 19
      apps/angular/projects/ordering/tsconfig.lib.json
  42. 9
      apps/angular/projects/ordering/tsconfig.lib.prod.json
  43. 17
      apps/angular/projects/ordering/tsconfig.spec.json
  44. 4
      apps/angular/src/app/app-routing.module.ts
  45. 4
      apps/angular/src/app/app.module.ts
  46. 10
      apps/angular/src/environments/environment.prod.ts
  47. 13
      apps/angular/src/environments/environment.ts
  48. 5
      apps/angular/src/environments/my-environment.ts
  49. 8
      apps/angular/tsconfig.json
  50. 2
      apps/public-web/src/EShopOnAbp.PublicWeb/Components/UserOrders/Default.cshtml
  51. 4
      services/administration/src/EShopOnAbp.AdministrationService.Application.Contracts/AdministrationServiceApplicationContractsModule.cs
  52. 2
      services/administration/src/EShopOnAbp.AdministrationService.Application.Contracts/EShopOnAbp.AdministrationService.Application.Contracts.csproj
  53. 30
      services/identity/src/EShopOnAbp.IdentityService.HttpApi.Host/DbMigrations/IdentityServerDataSeeder.cs
  54. 7
      services/ordering/src/EShopOnAbp.OrderingService.Application.Contracts/Orders/GetOrdersInput.cs
  55. 6
      services/ordering/src/EShopOnAbp.OrderingService.Application.Contracts/Orders/IOrderAppService.cs
  56. 6
      services/ordering/src/EShopOnAbp.OrderingService.Application.Contracts/Permissions/OrderingServicePermissionDefinitionProvider.cs
  57. 9
      services/ordering/src/EShopOnAbp.OrderingService.Application.Contracts/Permissions/OrderingServicePermissions.cs
  58. 41
      services/ordering/src/EShopOnAbp.OrderingService.Application/Orders/OrderAppService.cs
  59. 35
      services/ordering/src/EShopOnAbp.OrderingService.Domain.Shared/Localization/OrderingService/en.json
  60. 35
      services/ordering/src/EShopOnAbp.OrderingService.Domain.Shared/Localization/OrderingService/tr.json
  61. 8
      services/ordering/src/EShopOnAbp.OrderingService.Domain.Shared/Localization/OrderingService/zh-Hans.json
  62. 17
      services/ordering/src/EShopOnAbp.OrderingService.Domain.Shared/Orders/OrderCancelledEto.cs
  63. 5
      services/ordering/src/EShopOnAbp.OrderingService.Domain/Orders/IOrderRepository.cs
  64. 16
      services/ordering/src/EShopOnAbp.OrderingService.Domain/Orders/Order.cs
  65. 25
      services/ordering/src/EShopOnAbp.OrderingService.Domain/Orders/OrderManager.cs
  66. 12
      services/ordering/src/EShopOnAbp.OrderingService.EntityFrameworkCore/Orders/EfCoreOrderRepository.cs
  67. 87
      services/ordering/src/EShopOnAbp.OrderingService.HttpApi.Client/ClientProxies/OrderClientProxy.Generated.cs
  68. 172
      services/ordering/src/EShopOnAbp.OrderingService.HttpApi.Client/ClientProxies/ordering-generate-proxy.json
  69. 2
      services/ordering/src/EShopOnAbp.OrderingService.HttpApi.Host/appsettings.json
  70. 33
      services/ordering/test/EShopOnAbp.OrderingService.Application.Tests/Orders/OrderApplication_Tests.cs
  71. 5
      services/payment/src/EShopOnAbp.PaymentService.Domain/EShopOnAbp.PaymentService.Domain.csproj
  72. 26
      services/payment/src/EShopOnAbp.PaymentService.Domain/EventHandlers/OrderCancelledEventHandler.cs

31
apps/angular/angular.json

@ -187,6 +187,37 @@
} }
} }
} }
},
"ordering": {
"projectType": "library",
"root": "projects/ordering",
"sourceRoot": "projects/ordering/src",
"prefix": "lib",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:ng-packagr",
"options": {
"project": "projects/ordering/ng-package.json"
},
"configurations": {
"production": {
"tsConfig": "projects/ordering/tsconfig.lib.prod.json"
},
"development": {
"tsConfig": "projects/ordering/tsconfig.lib.json"
}
},
"defaultConfiguration": "production"
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"main": "projects/ordering/src/test.ts",
"tsConfig": "projects/ordering/tsconfig.spec.json",
"karmaConfig": "projects/ordering/karma.conf.js"
}
}
}
} }
}, },
"defaultProject": "EShopOnAbp", "defaultProject": "EShopOnAbp",

3
apps/angular/package.json

@ -52,9 +52,10 @@
"karma-jasmine": "~4.0.0", "karma-jasmine": "~4.0.0",
"karma-jasmine-html-reporter": "^1.5.0", "karma-jasmine-html-reporter": "^1.5.0",
"ng-packagr": "^12.2.2", "ng-packagr": "^12.2.2",
"prettier": "^2.6.0",
"protractor": "~7.0.0", "protractor": "~7.0.0",
"ts-node": "~8.3.0", "ts-node": "~8.3.0",
"tslint": "~6.1.0", "tslint": "~6.1.0",
"typescript": "~4.3.5" "typescript": "~4.3.5"
} }
} }

1
apps/angular/projects/catalog/tsconfig.lib.json

@ -1,4 +1,3 @@
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{ {
"extends": "../../tsconfig.json", "extends": "../../tsconfig.json",
"compilerOptions": { "compilerOptions": {

1
apps/angular/projects/catalog/tsconfig.lib.prod.json

@ -1,4 +1,3 @@
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{ {
"extends": "./tsconfig.lib.json", "extends": "./tsconfig.lib.json",
"compilerOptions": { "compilerOptions": {

24
apps/angular/projects/ordering/README.md

@ -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.

7
apps/angular/projects/ordering/config/ng-package.json

@ -0,0 +1,7 @@
{
"$schema": "../../../node_modules/ng-packagr/ng-package.schema.json",
"dest": "../../dist/ordering/config",
"lib": {
"entryFile": "src/public-api.ts"
}
}

2
apps/angular/projects/ordering/config/src/enums/index.ts

@ -0,0 +1,2 @@
export * from './policy-names';
export * from './route-names';

6
apps/angular/projects/ordering/config/src/enums/policy-names.ts

@ -0,0 +1,6 @@
export const enum eOrderingPolicyNames {
ordering = 'OrderingService.Orders',
detail = 'OrderingService.Orders',
setAsShipped = 'OrderingService.SetAsShipped',
setAsCancelled = 'OrderingService.SetAsCancelled',
}

3
apps/angular/projects/ordering/config/src/enums/route-names.ts

@ -0,0 +1,3 @@
export const enum eOrderingRouteNames {
ordering = 'OrderingService::Menu:OrderManagement'
}

12
apps/angular/projects/ordering/config/src/ordering-config.module.ts

@ -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],
};
}
}

1
apps/angular/projects/ordering/config/src/providers/index.ts

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

23
apps/angular/projects/ordering/config/src/providers/route.provider.ts

@ -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',
},
]);
};
}

3
apps/angular/projects/ordering/config/src/public-api.ts

@ -0,0 +1,3 @@
export * from './enums';
export * from './providers';
export * from './ordering-config.module';

44
apps/angular/projects/ordering/karma.conf.js

@ -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
});
};

7
apps/angular/projects/ordering/ng-package.json

@ -0,0 +1,7 @@
{
"$schema": "../../node_modules/ng-packagr/ng-package.schema.json",
"dest": "../../dist/ordering",
"lib": {
"entryFile": "src/public-api.ts"
}
}

11
apps/angular/projects/ordering/package.json

@ -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"
}
}

3
apps/angular/projects/ordering/src/lib/index.ts

@ -0,0 +1,3 @@
export * from './order-view-model';
export * from './proxy';
export * from './to-order-view-model';

5
apps/angular/projects/ordering/src/lib/order-view-model.ts

@ -0,0 +1,5 @@
import { OrderDto } from './proxy/orders';
export interface OrderViewModel extends OrderDto {
orderTotal: number;
}

17
apps/angular/projects/ordering/src/lib/proxy/README.md

@ -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.

2377
apps/angular/projects/ordering/src/lib/proxy/generate-proxy.json

File diff suppressed because it is too large

2
apps/angular/projects/ordering/src/lib/proxy/index.ts

@ -0,0 +1,2 @@
import * as Orders from './orders';
export { Orders };

3
apps/angular/projects/ordering/src/lib/proxy/orders/index.ts

@ -0,0 +1,3 @@
export * from './models';
export * from './order-status.enum';
export * from './order.service';

58
apps/angular/projects/ordering/src/lib/proxy/orders/models.ts

@ -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;
}

10
apps/angular/projects/ordering/src/lib/proxy/orders/order-status.enum.ts

@ -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);

74
apps/angular/projects/ordering/src/lib/proxy/orders/order.service.ts

@ -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) {}
}

8
apps/angular/projects/ordering/src/lib/to-order-view-model.ts

@ -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);

13
apps/angular/projects/ordering/src/ordering-routing.module.ts

@ -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 {}

9
apps/angular/projects/ordering/src/ordering.module.ts

@ -0,0 +1,9 @@
import { NgModule } from '@angular/core';
import { OrderingRoutingModule } from './ordering-routing.module';
@NgModule({
declarations: [],
imports: [OrderingRoutingModule],
exports: [],
})
export class OrderingModule {}

1
apps/angular/projects/ordering/src/pages/index.ts

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

3
apps/angular/projects/ordering/src/pages/orders/index.ts

@ -0,0 +1,3 @@
export * from './orders-routing.module';
export * from './orders.component';
export * from './orders.module';

20
apps/angular/projects/ordering/src/pages/orders/order-detail/order-detail-item/order-detail-item.component.ts

@ -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 = '';
}

78
apps/angular/projects/ordering/src/pages/orders/order-detail/order-detail.component.html

@ -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>

17
apps/angular/projects/ordering/src/pages/orders/order-detail/order-detail.component.ts

@ -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>();
}

11
apps/angular/projects/ordering/src/pages/orders/orders-routing.module.ts

@ -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 { }

87
apps/angular/projects/ordering/src/pages/orders/orders.component.html

@ -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>

25
apps/angular/projects/ordering/src/pages/orders/orders.component.spec.ts

@ -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();
});
});

83
apps/angular/projects/ordering/src/pages/orders/orders.component.ts

@ -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();
});
});
}
}

16
apps/angular/projects/ordering/src/pages/orders/orders.module.ts

@ -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 {}

7
apps/angular/projects/ordering/src/public-api.ts

@ -0,0 +1,7 @@
/*
* Public API Surface of ordering
*/
export * from './pages/index';
export * from './ordering.module';
export * from './lib/proxy/index';

28
apps/angular/projects/ordering/src/test.ts

@ -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);

19
apps/angular/projects/ordering/tsconfig.lib.json

@ -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"
]
}

9
apps/angular/projects/ordering/tsconfig.lib.prod.json

@ -0,0 +1,9 @@
{
"extends": "./tsconfig.lib.json",
"compilerOptions": {
"declarationMap": false
},
"angularCompilerOptions": {
"compilationMode": "partial"
}
}

17
apps/angular/projects/ordering/tsconfig.spec.json

@ -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"
]
}

4
apps/angular/src/app/app-routing.module.ts

@ -29,6 +29,10 @@ const routes: Routes = [
path: 'catalog', path: 'catalog',
loadChildren: () => import('@eshoponabp/catalog').then(m => m.CatalogModule), loadChildren: () => import('@eshoponabp/catalog').then(m => m.CatalogModule),
}, },
{
path: 'ordering',
loadChildren: () => import('@eshoponabp/ordering').then(m => m.OrderingModule),
},
]; ];
@NgModule({ @NgModule({

4
apps/angular/src/app/app.module.ts

@ -16,6 +16,7 @@ import { environment } from '../environments/environment';
import { AppRoutingModule } from './app-routing.module'; import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component'; import { AppComponent } from './app.component';
import { APP_ROUTE_PROVIDER } from './route.provider'; import { APP_ROUTE_PROVIDER } from './route.provider';
import { OrderingConfigModule } from '@eshoponabp/ordering/config';
@NgModule({ @NgModule({
imports: [ imports: [
@ -34,7 +35,8 @@ import { APP_ROUTE_PROVIDER } from './route.provider';
ThemeLeptonXModule.forRoot(), ThemeLeptonXModule.forRoot(),
SideMenuLayoutModule.forRoot(), SideMenuLayoutModule.forRoot(),
AccountLayoutModule.forRoot(), AccountLayoutModule.forRoot(),
CatalogConfigModule.forRoot() CatalogConfigModule.forRoot(),
OrderingConfigModule.forRoot()
], ],
declarations: [AppComponent], declarations: [AppComponent],
providers: [APP_ROUTE_PROVIDER], providers: [APP_ROUTE_PROVIDER],

10
apps/angular/src/environments/environment.prod.ts

@ -1,4 +1,4 @@
import { Environment } from '@abp/ng.core'; import { MyEnvironment } from './my-environment';
const baseUrl = 'http://localhost:4200'; const baseUrl = 'http://localhost:4200';
@ -22,8 +22,8 @@ export const environment = {
rootNamespace: 'EShopOnAbp', rootNamespace: 'EShopOnAbp',
}, },
}, },
remoteEnv:{ remoteEnv: {
url: "/getEnvConfig", url: '/getEnvConfig',
mergeStrategy:'deepmerge' mergeStrategy: 'deepmerge'
} }
} as Environment; } as MyEnvironment;

13
apps/angular/src/environments/environment.ts

@ -1,4 +1,4 @@
import { Environment } from '@abp/ng.core'; import { MyEnvironment } from './my-environment';
const baseUrl = 'http://localhost:4200'; const baseUrl = 'http://localhost:4200';
@ -13,7 +13,7 @@ export const environment = {
redirectUri: baseUrl, redirectUri: baseUrl,
clientId: 'Web', clientId: 'Web',
//responseType: 'code', //responseType: 'code',
scope: 'offline_access openid profile email phone AccountService IdentityService AdministrationService CatalogService', scope: 'offline_access openid profile email phone AccountService IdentityService AdministrationService CatalogService OrderingService',
//requireHttps: true, //requireHttps: true,
}, },
apis: { apis: {
@ -25,5 +25,12 @@ export const environment = {
url: 'https://localhost:44354', url: 'https://localhost:44354',
rootNamespace: 'EShopOnAbp.CatalogService', rootNamespace: 'EShopOnAbp.CatalogService',
}, },
Ordering: {
url: "https://localhost:44356",
rootNamespace: 'EShopOnAbp.OrderingService',
}
}, },
} as Environment; mediaServerUrl:'https://localhost:44335'
} as MyEnvironment;

5
apps/angular/src/environments/my-environment.ts

@ -0,0 +1,5 @@
import { Environment } from '@abp/ng.core';
export interface MyEnvironment extends Environment {
mediaServerUrl?: string;
}

8
apps/angular/tsconfig.json

@ -22,6 +22,14 @@
"node_modules/@eshoponabp/catalog", "node_modules/@eshoponabp/catalog",
"projects/catalog/src/public-api.ts", "projects/catalog/src/public-api.ts",
], ],
"@eshoponabp/ordering/config": [
"node_modules/@eshoponabp/ordering/config",
"projects/ordering/config/src/public-api.ts",
],
"@eshoponabp/ordering": [
"node_modules/@eshoponabp/ordering",
"projects/ordering/src/public-api.ts",
],
} }
}, },
"angularCompilerOptions": { "angularCompilerOptions": {

2
apps/public-web/src/EShopOnAbp.PublicWeb/Components/UserOrders/Default.cshtml

@ -13,7 +13,7 @@
</abp-row> </abp-row>
@foreach (var order in Model.UserOrders) @foreach (var order in Model.UserOrders)
{ {
var orderTotalString = order.Items.Sum(q => q.UnitPrice).ToString("C", new CultureInfo("en-US")); var orderTotalString = order.Items.Sum(q => q.UnitPrice * q.Units).ToString("C", new CultureInfo("en-US"));
string addressString = $"{order.Address.Street} {order.Address.ZipCode} \n {order.Address.City}/{order.Address.Country}"; string addressString = $"{order.Address.Street} {order.Address.ZipCode} \n {order.Address.City}/{order.Address.Country}";
<div class="card"> <div class="card">
<div class="card-header"> <div class="card-header">

4
services/administration/src/EShopOnAbp.AdministrationService.Application.Contracts/AdministrationServiceApplicationContractsModule.cs

@ -2,6 +2,7 @@
using Volo.Abp.PermissionManagement; using Volo.Abp.PermissionManagement;
using Volo.Abp.SettingManagement; using Volo.Abp.SettingManagement;
using EShopOnAbp.CatalogService; using EShopOnAbp.CatalogService;
using EShopOnAbp.OrderingService;
namespace EShopOnAbp.AdministrationService namespace EShopOnAbp.AdministrationService
{ {
@ -9,7 +10,8 @@ namespace EShopOnAbp.AdministrationService
typeof(CatalogServiceApplicationContractsModule), typeof(CatalogServiceApplicationContractsModule),
typeof(AdministrationServiceDomainSharedModule), typeof(AdministrationServiceDomainSharedModule),
typeof(AbpPermissionManagementApplicationContractsModule), typeof(AbpPermissionManagementApplicationContractsModule),
typeof(AbpSettingManagementApplicationContractsModule) typeof(AbpSettingManagementApplicationContractsModule),
typeof(OrderingServiceApplicationContractsModule)
)] )]
public class AdministrationServiceApplicationContractsModule : AbpModule public class AdministrationServiceApplicationContractsModule : AbpModule
{ {

2
services/administration/src/EShopOnAbp.AdministrationService.Application.Contracts/EShopOnAbp.AdministrationService.Application.Contracts.csproj

@ -8,6 +8,8 @@
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\EShopOnAbp.AdministrationService.Domain.Shared\EShopOnAbp.AdministrationService.Domain.Shared.csproj" /> <ProjectReference Include="..\EShopOnAbp.AdministrationService.Domain.Shared\EShopOnAbp.AdministrationService.Domain.Shared.csproj" />
<ProjectReference Include="..\..\..\catalog\src\EShopOnAbp.CatalogService.Application.Contracts\EShopOnAbp.CatalogService.Application.Contracts.csproj" /> <ProjectReference Include="..\..\..\catalog\src\EShopOnAbp.CatalogService.Application.Contracts\EShopOnAbp.CatalogService.Application.Contracts.csproj" />
<ProjectReference Include="..\..\..\ordering\src\EShopOnAbp.OrderingService.Application.Contracts\EShopOnAbp.OrderingService.Application.Contracts.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

30
services/identity/src/EShopOnAbp.IdentityService.HttpApi.Host/DbMigrations/IdentityServerDataSeeder.cs

@ -108,9 +108,13 @@ public class IdentityServerDataSeeder : IDataSeedContributor, ITransientDependen
await CreateWebGatewaySwaggerClientAsync("WebGateway", await CreateWebGatewaySwaggerClientAsync("WebGateway",
new[] new[]
{ {
"AccountService", "IdentityService", "AdministrationService", "AccountService",
"CatalogService", "BasketService", "IdentityService",
"PaymentService", "OrderingService" "AdministrationService",
"CatalogService",
"BasketService",
"PaymentService",
"OrderingService"
}); });
} }
@ -125,7 +129,7 @@ public class IdentityServerDataSeeder : IDataSeedContributor, ITransientDependen
"phone", "phone",
"address" "address"
}; };
scopes ??= new[] {name}; scopes ??= new[] { name };
// Swagger Client // Swagger Client
var swaggerClientId = $"{name}_Swagger"; var swaggerClientId = $"{name}_Swagger";
@ -144,7 +148,7 @@ public class IdentityServerDataSeeder : IDataSeedContributor, ITransientDependen
await CreateClientAsync( await CreateClientAsync(
name: swaggerClientId, name: swaggerClientId,
scopes: commonScopes.Union(scopes), scopes: commonScopes.Union(scopes),
grantTypes: new[] {"authorization_code"}, grantTypes: new[] { "authorization_code" },
secret: "1q2w3e*".Sha256(), secret: "1q2w3e*".Sha256(),
requireClientSecret: false, requireClientSecret: false,
redirectUris: new List<string> redirectUris: new List<string>
@ -245,12 +249,12 @@ public class IdentityServerDataSeeder : IDataSeedContributor, ITransientDependen
"PaymentService", "PaymentService",
"OrderingService" "OrderingService"
}), }),
grantTypes: new[] {"hybrid"}, grantTypes: new[] { "hybrid" },
secret: "1q2w3e*".Sha256(), secret: "1q2w3e*".Sha256(),
redirectUris: new List<string>{ $"{publicWebClientRootUrl}signin-oidc" }, redirectUris: new List<string> { $"{publicWebClientRootUrl}signin-oidc" },
postLogoutRedirectUri: $"{publicWebClientRootUrl}signout-callback-oidc", postLogoutRedirectUri: $"{publicWebClientRootUrl}signout-callback-oidc",
frontChannelLogoutUri: $"{publicWebClientRootUrl}Account/FrontChannelLogout", frontChannelLogoutUri: $"{publicWebClientRootUrl}Account/FrontChannelLogout",
corsOrigins: new[] {publicWebClientRootUrl.RemovePostFix("/")} corsOrigins: new[] { publicWebClientRootUrl.RemovePostFix("/") }
); );
//Angular Client //Angular Client
@ -266,13 +270,13 @@ public class IdentityServerDataSeeder : IDataSeedContributor, ITransientDependen
"CatalogService", "CatalogService",
"OrderingService" "OrderingService"
}), }),
grantTypes: new[] {"authorization_code", "LinkLogin", "password"}, grantTypes: new[] { "authorization_code", "LinkLogin", "password" },
secret: "1q2w3e*".Sha256(), secret: "1q2w3e*".Sha256(),
requirePkce: true, requirePkce: true,
requireClientSecret: false, requireClientSecret: false,
redirectUris: new List<string>{ $"{angularClientRootUrl}" }, redirectUris: new List<string> { $"{angularClientRootUrl}" },
postLogoutRedirectUri: $"{angularClientRootUrl}", postLogoutRedirectUri: $"{angularClientRootUrl}",
corsOrigins: new[] {angularClientRootUrl} corsOrigins: new[] { angularClientRootUrl }
); );
//Administration Service Client //Administration Service Client
@ -282,9 +286,9 @@ public class IdentityServerDataSeeder : IDataSeedContributor, ITransientDependen
{ {
"IdentityService" "IdentityService"
}), }),
grantTypes: new[] {"client_credentials"}, grantTypes: new[] { "client_credentials" },
secret: "1q2w3e*".Sha256(), secret: "1q2w3e*".Sha256(),
permissions: new[] {IdentityPermissions.Users.Default} permissions: new[] { IdentityPermissions.Users.Default }
); );
} }

7
services/ordering/src/EShopOnAbp.OrderingService.Application.Contracts/Orders/GetOrdersInput.cs

@ -0,0 +1,7 @@
namespace EShopOnAbp.OrderingService.Orders
{
public class GetOrdersInput
{
public string Filter { get; set; }
}
}

6
services/ordering/src/EShopOnAbp.OrderingService.Application.Contracts/Orders/IOrderAppService.cs

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services; using Volo.Abp.Application.Services;
namespace EShopOnAbp.OrderingService.Orders; namespace EShopOnAbp.OrderingService.Orders;
@ -10,5 +11,10 @@ public interface IOrderAppService : IApplicationService
Task<OrderDto> CreateAsync(OrderCreateDto input); Task<OrderDto> CreateAsync(OrderCreateDto input);
Task<OrderDto> GetAsync(Guid id); Task<OrderDto> GetAsync(Guid id);
Task<List<OrderDto>> GetMyOrdersAsync(GetMyOrdersInput input); Task<List<OrderDto>> GetMyOrdersAsync(GetMyOrdersInput input);
Task<List<OrderDto>> GetOrdersAsync(GetOrdersInput input);
Task<OrderDto> GetByOrderNoAsync(int orderNo); Task<OrderDto> GetByOrderNoAsync(int orderNo);
Task SetAsCancelledAsync(Guid id);
Task SetAsShippedAsync(Guid id);
Task<PagedResultDto<OrderDto>> GetListPagedAsync(PagedAndSortedResultRequestDto input);
} }

6
services/ordering/src/EShopOnAbp.OrderingService.Application.Contracts/Permissions/OrderingServicePermissionDefinitionProvider.cs

@ -8,7 +8,11 @@ namespace EShopOnAbp.OrderingService.Permissions
{ {
public override void Define(IPermissionDefinitionContext context) public override void Define(IPermissionDefinitionContext context)
{ {
var myGroup = context.AddGroup(OrderingServicePermissions.GroupName, L("Permission:OrderingService")); var orderManagmentGroup = context.AddGroup(OrderingServicePermissions.GroupName, L("Permission:OrderingService"));
var oders = orderManagmentGroup.AddPermission(OrderingServicePermissions.Orders.Default, L("Permission:Orders"));
oders.AddChild(OrderingServicePermissions.Orders.SetAsCancelled, L("Permission:Orders.SetAsCancelled"));
oders.AddChild(OrderingServicePermissions.Orders.SetAsShipped, L("Permission:Orders.SetAsShipped"));
} }
private static LocalizableString L(string name) private static LocalizableString L(string name)

9
services/ordering/src/EShopOnAbp.OrderingService.Application.Contracts/Permissions/OrderingServicePermissions.cs

@ -2,10 +2,17 @@
namespace EShopOnAbp.OrderingService.Permissions namespace EShopOnAbp.OrderingService.Permissions
{ {
public class OrderingServicePermissions public static class OrderingServicePermissions
{ {
public const string GroupName = "OrderingService"; public const string GroupName = "OrderingService";
public static class Orders
{
public const string Default = GroupName + ".Orders";
public const string SetAsCancelled = GroupName + ".SetAsCancelled";
public const string SetAsShipped = GroupName + ".SetAsShipped";
}
public static string[] GetAll() public static string[] GetAll()
{ {
return ReflectionHelper.GetPublicConstantsRecursively(typeof(OrderingServicePermissions)); return ReflectionHelper.GetPublicConstantsRecursively(typeof(OrderingServicePermissions));

41
services/ordering/src/EShopOnAbp.OrderingService.Application/Orders/OrderAppService.cs

@ -1,15 +1,19 @@
using EShopOnAbp.OrderingService.Localization; using EShopOnAbp.OrderingService.Localization;
using EShopOnAbp.OrderingService.Orders.Specifications; using EShopOnAbp.OrderingService.Orders.Specifications;
using EShopOnAbp.OrderingService.Permissions;
using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services; using Volo.Abp.Application.Services;
using Volo.Abp.Specifications; using Volo.Abp.Specifications;
using Volo.Abp.Users; using Volo.Abp.Users;
namespace EShopOnAbp.OrderingService.Orders; namespace EShopOnAbp.OrderingService.Orders;
[Authorize(OrderingServicePermissions.Orders.Default)]
public class OrderAppService : ApplicationService, IOrderAppService public class OrderAppService : ApplicationService, IOrderAppService
{ {
private readonly OrderManager _orderManager; private readonly OrderManager _orderManager;
@ -31,15 +35,33 @@ public class OrderAppService : ApplicationService, IOrderAppService
return CreateOrderDtoMapping(order); return CreateOrderDtoMapping(order);
} }
[AllowAnonymous]
public async Task<List<OrderDto>> GetMyOrdersAsync(GetMyOrdersInput input) public async Task<List<OrderDto>> GetMyOrdersAsync(GetMyOrdersInput input)
{ {
ISpecification<Order> specification = SpecificationFactory.Create(input.Filter); ISpecification<Order> specification = SpecificationFactory.Create(input.Filter);
var orders = await _orderRepository.GetOrdersByUserId(CurrentUser.GetId(), specification, true); var orders = await _orderRepository.GetOrdersByUserId(CurrentUser.GetId(), specification, true);
return CreateOrderDtoMapping(orders);
}
public async Task<List<OrderDto>> GetOrdersAsync(GetOrdersInput input)
{
ISpecification<Order> specification = SpecificationFactory.Create(input.Filter);
var orders = await _orderRepository.GetOrdersAsync(specification, true);
return CreateOrderDtoMapping(orders); return CreateOrderDtoMapping(orders);
} }
public async Task<PagedResultDto<OrderDto>> GetListPagedAsync(PagedAndSortedResultRequestDto input)
{
var orders = await _orderRepository.GetPagedListAsync(input.SkipCount, input.MaxResultCount, input.Sorting ?? "OrderDate", true);
var totalCount = await _orderRepository.GetCountAsync();
return new PagedResultDto<OrderDto>(
totalCount,
CreateOrderDtoMapping(orders)
);
}
[AllowAnonymous]
public async Task<OrderDto> GetByOrderNoAsync(int orderNo) public async Task<OrderDto> GetByOrderNoAsync(int orderNo)
{ {
var order = await _orderRepository.GetByOrderNoAsync(orderNo); var order = await _orderRepository.GetByOrderNoAsync(orderNo);
@ -47,6 +69,22 @@ public class OrderAppService : ApplicationService, IOrderAppService
return CreateOrderDtoMapping(order); return CreateOrderDtoMapping(order);
} }
[Authorize(OrderingServicePermissions.Orders.SetAsCancelled)]
public async Task SetAsCancelledAsync(Guid id)
{
await _orderManager.CancelOrderAsync(id);
}
[Authorize(OrderingServicePermissions.Orders.SetAsShipped)]
public async Task SetAsShippedAsync(Guid id)
{
var order = await _orderRepository.GetAsync(id);
order.SetOrderAsShipped();
await _orderRepository.UpdateAsync(order);
}
[AllowAnonymous]
public async Task<OrderDto> CreateAsync(OrderCreateDto input) public async Task<OrderDto> CreateAsync(OrderCreateDto input)
{ {
var orderItems = GetProductListTuple(input.Products); var orderItems = GetProductListTuple(input.Products);
@ -68,6 +106,7 @@ public class OrderAppService : ApplicationService, IOrderAppService
return CreateOrderDtoMapping(placedOrder); return CreateOrderDtoMapping(placedOrder);
} }
private List<(Guid productId, string productName, string productCode, decimal unitPrice, decimal discount, string private List<(Guid productId, string productName, string productCode, decimal unitPrice, decimal discount, string
pictureUrl, int units pictureUrl, int units
)> GetProductListTuple(List<OrderItemCreateDto> products) )> GetProductListTuple(List<OrderItemCreateDto> products)

35
services/ordering/src/EShopOnAbp.OrderingService.Domain.Shared/Localization/OrderingService/en.json

@ -1,12 +1,43 @@
{ {
"culture": "en", "culture": "en",
"texts": { "texts": {
"MyAccount": "My account", "MyAccount": "My account",
"SamplePageMessage": "A sample page for the OrderingService module", "SamplePageMessage": "A sample page for the OrderingService module",
"Ordering:00001": "Possible values for Order status: {OrderStatus}", "Ordering:00001": "Possible values for Order status: {OrderStatus}",
"Ordering:00002": "Invalid number of units", "Ordering:00002": "Invalid number of units",
"Ordering:00003": "Invalid discount", "Ordering:00003": "Invalid discount",
"Ordering:00004": "The total of order item is lower than applied 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"
} }
} }

35
services/ordering/src/EShopOnAbp.OrderingService.Domain.Shared/Localization/OrderingService/tr.json

@ -1,12 +1,43 @@
{ {
"culture": "tr", "culture": "tr",
"texts": { "texts": {
"MyAccount": "Hesabım", "MyAccount": "Hesabım",
"SamplePageMessage": "OrderingService modulünden örnek bir sayfa", "SamplePageMessage": "OrderingService modulünden örnek bir sayfa",
"Ordering:00001": "Muhtemel Sipariş durum değerleri: {OrderStatus}", "Ordering:00001": "Muhtemel Sipariş durum değerleri: {OrderStatus}",
"Ordering:00002": "Ürün adedi negatif olamaz", "Ordering:00002": "Ürün adedi negatif olamaz",
"Ordering:00003": "Geçersiz indirim", "Ordering:00003": "Geçersiz indirim",
"Ordering:00004": "Ürünlerin toplam bedeli, uygulanan indirimden daha az olamaz", "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"
} }
} }

8
services/ordering/src/EShopOnAbp.OrderingService.Domain.Shared/Localization/OrderingService/zh-Hans.json

@ -8,6 +8,12 @@
"Ordering:00002": "无效的单位数量", "Ordering:00002": "无效的单位数量",
"Ordering:00003": "无效的折扣", "Ordering:00003": "无效的折扣",
"Ordering:00004": "订单项的总额低于申请的折扣", "Ordering:00004": "订单项的总额低于申请的折扣",
"Ordering:01001": "无法找到 id 为 {0} 的订单!" "Ordering:01001": "无法找到 id 为 {0} 的订单!",
"Permission:Orders": "命令",
"Permission:OrderingService": "订购服务",
"Menu:Orders": "命令",
"Menu:OrderManagement": "订单管理",
"Permission:Orders.SetAsCancelled": "设置为取消",
"Permission:Orders.SetAsShipped": "设置为发货"
} }
} }

17
services/ordering/src/EShopOnAbp.OrderingService.Domain.Shared/Orders/OrderCancelledEto.cs

@ -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();
}

5
services/ordering/src/EShopOnAbp.OrderingService.Domain/Orders/IOrderRepository.cs

@ -15,6 +15,11 @@ public interface IOrderRepository : IRepository<Order, Guid>
bool includeDetails = true, bool includeDetails = true,
CancellationToken cancellationToken = default); CancellationToken cancellationToken = default);
Task<List<Order>> GetOrdersAsync(
ISpecification<Order> spec,
bool includeDetails = true,
CancellationToken cancellationToken = default);
Task<Order> GetByOrderNoAsync(int orderNo, Task<Order> GetByOrderNoAsync(int orderNo,
bool includeDetails = true, bool includeDetails = true,
CancellationToken cancellationToken = default); CancellationToken cancellationToken = default);

16
services/ordering/src/EShopOnAbp.OrderingService.Domain/Orders/Order.cs

@ -57,6 +57,12 @@ public class Order : AggregateRoot<Guid>
return this; return this;
} }
public Order SetOrderCancelled()
{
OrderStatus = OrderStatus.Cancelled;
return this;
}
public Order AddOrderItem(Guid id, Guid productId, string productName, string productCode, decimal unitPrice, public Order AddOrderItem(Guid id, Guid productId, string productName, string productCode, decimal unitPrice,
decimal discount, string pictureUrl, int units = 1) decimal discount, string pictureUrl, int units = 1)
{ {
@ -85,4 +91,14 @@ public class Order : AggregateRoot<Guid>
{ {
return OrderItems.Sum(o => o.Units * o.UnitPrice); return OrderItems.Sum(o => o.Units * o.UnitPrice);
} }
public Order SetOrderAsShipped()
{
if (OrderStatus == OrderStatus.Cancelled)
{
return this;
}
OrderStatus = OrderStatus.Shipped;
return this;
}
} }

25
services/ordering/src/EShopOnAbp.OrderingService.Domain/Orders/OrderManager.cs

@ -91,6 +91,31 @@ public class OrderManager : DomainService
return await _orderRepository.UpdateAsync(order, autoSave: true); return await _orderRepository.UpdateAsync(order, autoSave: true);
} }
public async Task<Order> CancelOrderAsync(Guid orderId)
{
var order = await _orderRepository.GetAsync(orderId);
if (order == null)
{
throw new BusinessException(OrderingServiceErrorCodes.OrderWithIdNotFound)
.WithData("OrderId", orderId);
}
order.SetOrderCancelled();
// Publish order cancelled event
await _distributedEventBus.PublishAsync(new OrderCancelledEto
{
PaymentRequestId = order.PaymentRequestId.GetValueOrDefault(),
OrderId = order.Id,
OrderDate = order.OrderDate,
OrderNo = order.OrderNo,
Buyer = GetBuyerEto(order.Buyer),
Items = GetProductItemEtoList(order.OrderItems)
});
return await _orderRepository.UpdateAsync(order, autoSave: true);
}
private BuyerEto GetBuyerEto(Buyer buyer) private BuyerEto GetBuyerEto(Buyer buyer)
{ {
return new BuyerEto return new BuyerEto

12
services/ordering/src/EShopOnAbp.OrderingService.EntityFrameworkCore/Orders/EfCoreOrderRepository.cs

@ -34,6 +34,18 @@ public class EfCoreOrderRepository : EfCoreRepository<OrderingServiceDbContext,
.ToListAsync(GetCancellationToken(cancellationToken)); .ToListAsync(GetCancellationToken(cancellationToken));
} }
public async Task<List<Order>> GetOrdersAsync(
ISpecification<Order> spec,
bool includeDetails = false,
CancellationToken cancellationToken = default)
{
return await (await GetDbSetAsync())
.IncludeDetails(includeDetails)
.Where(spec.ToExpression())
.OrderByDescending(o => o.OrderDate)
.ToListAsync(GetCancellationToken(cancellationToken));
}
public async Task<Order> GetByOrderNoAsync( public async Task<Order> GetByOrderNoAsync(
int orderNo, int orderNo,
bool includeDetails = true, bool includeDetails = true,

87
services/ordering/src/EShopOnAbp.OrderingService.HttpApi.Client/ClientProxies/OrderClientProxy.Generated.cs

@ -10,42 +10,73 @@ using EShopOnAbp.OrderingService.Orders;
using System.Collections.Generic; using System.Collections.Generic;
// ReSharper disable once CheckNamespace // ReSharper disable once CheckNamespace
namespace EShopOnAbp.OrderingService.Orders.ClientProxies namespace EShopOnAbp.OrderingService.Orders.ClientProxies;
[Dependency(ReplaceServices = true)]
[ExposeServices(typeof(IOrderAppService), typeof(OrderClientProxy))]
public partial class OrderClientProxy : ClientProxyBase<IOrderAppService>, IOrderAppService
{ {
[Dependency(ReplaceServices = true)] public virtual async Task<OrderDto> GetAsync(Guid id)
[ExposeServices(typeof(IOrderAppService), typeof(OrderClientProxy))] {
public partial class OrderClientProxy : ClientProxyBase<IOrderAppService>, IOrderAppService return await RequestAsync<OrderDto>(nameof(GetAsync), new ClientProxyRequestTypeValue
{
{ typeof(Guid), id }
});
}
public virtual async Task<List<OrderDto>> GetMyOrdersAsync(GetMyOrdersInput input)
{ {
public virtual async Task<OrderDto> GetAsync(Guid id) return await RequestAsync<List<OrderDto>>(nameof(GetMyOrdersAsync), new ClientProxyRequestTypeValue
{ {
return await RequestAsync<OrderDto>(nameof(GetAsync), new ClientProxyRequestTypeValue { typeof(GetMyOrdersInput), input }
{ });
{ typeof(Guid), id } }
});
}
public virtual async Task<List<OrderDto>> GetMyOrdersAsync(GetMyOrdersInput input) public virtual async Task<List<OrderDto>> GetOrdersAsync(GetOrdersInput input)
{
return await RequestAsync<List<OrderDto>>(nameof(GetOrdersAsync), new ClientProxyRequestTypeValue
{ {
return await RequestAsync<List<OrderDto>>(nameof(GetMyOrdersAsync), new ClientProxyRequestTypeValue { typeof(GetOrdersInput), input }
{ });
{ typeof(GetMyOrdersInput), input } }
});
}
public virtual async Task<OrderDto> GetByOrderNoAsync(int orderNo) public virtual async Task<PagedResultDto<OrderDto>> GetListPagedAsync(PagedAndSortedResultRequestDto input)
{
return await RequestAsync<PagedResultDto<OrderDto>>(nameof(GetListPagedAsync), new ClientProxyRequestTypeValue
{ {
return await RequestAsync<OrderDto>(nameof(GetByOrderNoAsync), new ClientProxyRequestTypeValue { typeof(PagedAndSortedResultRequestDto), input }
{ });
{ typeof(int), orderNo } }
});
}
public virtual async Task<OrderDto> CreateAsync(OrderCreateDto input) public virtual async Task<OrderDto> GetByOrderNoAsync(int orderNo)
{
return await RequestAsync<OrderDto>(nameof(GetByOrderNoAsync), new ClientProxyRequestTypeValue
{
{ typeof(int), orderNo }
});
}
public virtual async Task SetAsCancelledAsync(Guid id)
{
await RequestAsync(nameof(SetAsCancelledAsync), new ClientProxyRequestTypeValue
{
{ typeof(Guid), id }
});
}
public virtual async Task SetAsShippedAsync(Guid id)
{
await RequestAsync(nameof(SetAsShippedAsync), new ClientProxyRequestTypeValue
{
{ typeof(Guid), id }
});
}
public virtual async Task<OrderDto> CreateAsync(OrderCreateDto input)
{
return await RequestAsync<OrderDto>(nameof(CreateAsync), new ClientProxyRequestTypeValue
{ {
return await RequestAsync<OrderDto>(nameof(CreateAsync), new ClientProxyRequestTypeValue { typeof(OrderCreateDto), input }
{ });
{ typeof(OrderCreateDto), input }
});
}
} }
} }

172
services/ordering/src/EShopOnAbp.OrderingService.HttpApi.Client/ClientProxies/ordering-generate-proxy.json

@ -97,6 +97,104 @@
"allowAnonymous": null, "allowAnonymous": null,
"implementFrom": "EShopOnAbp.OrderingService.Orders.IOrderAppService" "implementFrom": "EShopOnAbp.OrderingService.Orders.IOrderAppService"
}, },
"GetOrdersAsyncByInput": {
"uniqueName": "GetOrdersAsyncByInput",
"name": "GetOrdersAsync",
"httpMethod": "GET",
"url": "api/ordering/order/orders",
"supportedVersions": [],
"parametersOnMethod": [
{
"name": "input",
"typeAsString": "EShopOnAbp.OrderingService.Orders.GetOrdersInput, EShopOnAbp.OrderingService.Application.Contracts",
"type": "EShopOnAbp.OrderingService.Orders.GetOrdersInput",
"typeSimple": "EShopOnAbp.OrderingService.Orders.GetOrdersInput",
"isOptional": false,
"defaultValue": null
}
],
"parameters": [
{
"nameOnMethod": "input",
"name": "Filter",
"jsonName": null,
"type": "System.String",
"typeSimple": "string",
"isOptional": false,
"defaultValue": null,
"constraintTypes": null,
"bindingSourceId": "ModelBinding",
"descriptorName": "input"
}
],
"returnValue": {
"type": "System.Collections.Generic.List<EShopOnAbp.OrderingService.Orders.OrderDto>",
"typeSimple": "[EShopOnAbp.OrderingService.Orders.OrderDto]"
},
"allowAnonymous": false,
"implementFrom": "EShopOnAbp.OrderingService.Orders.IOrderAppService"
},
"GetListPagedAsyncByInput": {
"uniqueName": "GetListPagedAsyncByInput",
"name": "GetListPagedAsync",
"httpMethod": "GET",
"url": "api/ordering/order/paged",
"supportedVersions": [],
"parametersOnMethod": [
{
"name": "input",
"typeAsString": "Volo.Abp.Application.Dtos.PagedAndSortedResultRequestDto, Volo.Abp.Ddd.Application.Contracts",
"type": "Volo.Abp.Application.Dtos.PagedAndSortedResultRequestDto",
"typeSimple": "Volo.Abp.Application.Dtos.PagedAndSortedResultRequestDto",
"isOptional": false,
"defaultValue": null
}
],
"parameters": [
{
"nameOnMethod": "input",
"name": "Sorting",
"jsonName": null,
"type": "System.String",
"typeSimple": "string",
"isOptional": false,
"defaultValue": null,
"constraintTypes": null,
"bindingSourceId": "ModelBinding",
"descriptorName": "input"
},
{
"nameOnMethod": "input",
"name": "SkipCount",
"jsonName": null,
"type": "System.Int32",
"typeSimple": "number",
"isOptional": false,
"defaultValue": null,
"constraintTypes": null,
"bindingSourceId": "ModelBinding",
"descriptorName": "input"
},
{
"nameOnMethod": "input",
"name": "MaxResultCount",
"jsonName": null,
"type": "System.Int32",
"typeSimple": "number",
"isOptional": false,
"defaultValue": null,
"constraintTypes": null,
"bindingSourceId": "ModelBinding",
"descriptorName": "input"
}
],
"returnValue": {
"type": "Volo.Abp.Application.Dtos.PagedResultDto<EShopOnAbp.OrderingService.Orders.OrderDto>",
"typeSimple": "Volo.Abp.Application.Dtos.PagedResultDto<EShopOnAbp.OrderingService.Orders.OrderDto>"
},
"allowAnonymous": false,
"implementFrom": "EShopOnAbp.OrderingService.Orders.IOrderAppService"
},
"GetByOrderNoAsyncByOrderNo": { "GetByOrderNoAsyncByOrderNo": {
"uniqueName": "GetByOrderNoAsyncByOrderNo", "uniqueName": "GetByOrderNoAsyncByOrderNo",
"name": "GetByOrderNoAsync", "name": "GetByOrderNoAsync",
@ -134,6 +232,80 @@
"allowAnonymous": null, "allowAnonymous": null,
"implementFrom": "EShopOnAbp.OrderingService.Orders.IOrderAppService" "implementFrom": "EShopOnAbp.OrderingService.Orders.IOrderAppService"
}, },
"SetAsCancelledAsyncById": {
"uniqueName": "SetAsCancelledAsyncById",
"name": "SetAsCancelledAsync",
"httpMethod": "POST",
"url": "api/ordering/order/{id}/set-as-cancelled",
"supportedVersions": [],
"parametersOnMethod": [
{
"name": "id",
"typeAsString": "System.Guid, System.Private.CoreLib",
"type": "System.Guid",
"typeSimple": "string",
"isOptional": false,
"defaultValue": null
}
],
"parameters": [
{
"nameOnMethod": "id",
"name": "id",
"jsonName": null,
"type": "System.Guid",
"typeSimple": "string",
"isOptional": false,
"defaultValue": null,
"constraintTypes": [],
"bindingSourceId": "Path",
"descriptorName": ""
}
],
"returnValue": {
"type": "System.Void",
"typeSimple": "System.Void"
},
"allowAnonymous": false,
"implementFrom": "EShopOnAbp.OrderingService.Orders.IOrderAppService"
},
"SetAsShippedAsyncById": {
"uniqueName": "SetAsShippedAsyncById",
"name": "SetAsShippedAsync",
"httpMethod": "POST",
"url": "api/ordering/order/{id}/set-as-shipped",
"supportedVersions": [],
"parametersOnMethod": [
{
"name": "id",
"typeAsString": "System.Guid, System.Private.CoreLib",
"type": "System.Guid",
"typeSimple": "string",
"isOptional": false,
"defaultValue": null
}
],
"parameters": [
{
"nameOnMethod": "id",
"name": "id",
"jsonName": null,
"type": "System.Guid",
"typeSimple": "string",
"isOptional": false,
"defaultValue": null,
"constraintTypes": [],
"bindingSourceId": "Path",
"descriptorName": ""
}
],
"returnValue": {
"type": "System.Void",
"typeSimple": "System.Void"
},
"allowAnonymous": false,
"implementFrom": "EShopOnAbp.OrderingService.Orders.IOrderAppService"
},
"CreateAsyncByInput": { "CreateAsyncByInput": {
"uniqueName": "CreateAsyncByInput", "uniqueName": "CreateAsyncByInput",
"name": "CreateAsync", "name": "CreateAsync",

2
services/ordering/src/EShopOnAbp.OrderingService.HttpApi.Host/appsettings.json

@ -1,7 +1,7 @@
{ {
"App": { "App": {
"SelfUrl": "https://localhost:44356", "SelfUrl": "https://localhost:44356",
"CorsOrigins": "https://localhost:44372,https://localhost:44373" "CorsOrigins": "https://localhost:44372,https://localhost:44373,https://localhost:4200"
}, },
"AuthServer": { "AuthServer": {
"Authority": "https://localhost:44330", "Authority": "https://localhost:44330",

33
services/ordering/test/EShopOnAbp.OrderingService.Application.Tests/Orders/OrderApplication_Tests.cs

@ -1,15 +1,15 @@
using System; using Microsoft.Extensions.DependencyInjection;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using NSubstitute; using NSubstitute;
using Shouldly; using Shouldly;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.Users; using Volo.Abp.Users;
using Xunit; using Xunit;
namespace EShopOnAbp.OrderingService.Orders; namespace EShopOnAbp.OrderingService.Orders;
public class OrderApplication_Tests:OrderingServiceApplicationTestBase public class OrderApplication_Tests : OrderingServiceApplicationTestBase
{ {
private readonly IOrderAppService _orderAppService; private readonly IOrderAppService _orderAppService;
private readonly TestData _testData; private readonly TestData _testData;
@ -38,8 +38,13 @@ public class OrderApplication_Tests:OrderingServiceApplicationTestBase
{ {
new OrderItemCreateDto() new OrderItemCreateDto()
{ {
Discount = 0, Units = 2, PictureUrl = "", ProductCode = "Test-001", ProductId = Guid.NewGuid(), Discount = 0,
ProductName = "Test product", UnitPrice = 150 Units = 2,
PictureUrl = string.Empty,
ProductCode = "Test-001",
ProductId = Guid.NewGuid(),
ProductName = "Test product",
UnitPrice = 150
} }
}; };
@ -48,14 +53,24 @@ public class OrderApplication_Tests:OrderingServiceApplicationTestBase
PaymentMethod = "paypal", PaymentMethod = "paypal",
Address = new OrderAddressDto() Address = new OrderAddressDto()
{ {
City = "Test City", Country = "Test Country", Description = "No Description", Street = "Test Street", City = "Test City",
Country = "Test Country",
Description = "No Description",
Street = "Test Street",
ZipCode = "Test ZipCode" ZipCode = "Test ZipCode"
}, },
Products = orderItems Products = orderItems
}); });
// Get Order by OrderNo; // Get Order by OrderNo;
var myOrder = await _orderAppService.GetByOrderNoAsync(placedOrder.OrderNo); var myOrder = await _orderAppService.GetByOrderNoAsync(placedOrder.OrderNo);
myOrder.ShouldNotBeNull(); myOrder.ShouldNotBeNull();
// Get all orders
var orders = await _orderAppService.GetOrdersAsync(new GetOrdersInput()
{
Filter = string.Empty,
});
orders.ShouldNotBeNull();
} }
} }

5
services/payment/src/EShopOnAbp.PaymentService.Domain/EShopOnAbp.PaymentService.Domain.csproj

@ -12,4 +12,9 @@
<ProjectReference Include="..\EShopOnAbp.PaymentService.Domain.Shared\EShopOnAbp.PaymentService.Domain.Shared.csproj" /> <ProjectReference Include="..\EShopOnAbp.PaymentService.Domain.Shared\EShopOnAbp.PaymentService.Domain.Shared.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\ordering\src\EShopOnAbp.OrderingService.Domain.Shared\EShopOnAbp.OrderingService.Domain.Shared.csproj" />
<ProjectReference Include="..\..\..\..\shared\EShopOnAbp.Shared.Hosting\EShopOnAbp.Shared.Hosting.csproj" />
</ItemGroup>
</Project> </Project>

26
services/payment/src/EShopOnAbp.PaymentService.Domain/EventHandlers/OrderCancelledEventHandler.cs

@ -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}");
}
}
}
Loading…
Cancel
Save