This commit is contained in:
Sankit chandel 2022-02-14 20:47:25 +05:30
Родитель 275c16dce4
Коммит 63e4d364f9
106 изменённых файлов: 7099 добавлений и 37 удалений

21
LICENSE.md Normal file
Просмотреть файл

@ -0,0 +1,21 @@
MIT License
Copyright (c) Microsoft Corporation.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE

16
NOTICE.md Normal file
Просмотреть файл

@ -0,0 +1,16 @@
## NOTICES AND INFORMATION
Do Not Translate or Localize
This software incorporates material from third parties.
Microsoft makes certain open source code available at https://3rdpartysource.microsoft.com,
or you may send a check or money order for US $5.00, including the product name,
the open source component name, platform, and version number, to:
Source Code Compliance Team
Microsoft Corporation
One Microsoft Way
Redmond, WA 98052
USA
Notwithstanding any other terms, you may reverse engineer this software to the extent
required to debug changes to any libraries licensed under the GNU Lesser General Public License.

23
PRIVACY.md Normal file
Просмотреть файл

@ -0,0 +1,23 @@
# Privacy
When you deploy this template, Microsoft is able to identify the installation of the software with the Azure resources that are deployed. Microsoft is able to correlate the Azure resources that are used to support the software. Microsoft collects this information to provide the best experiences with their products and to operate their business. The data is collected and governed by Microsoft's privacy policies, which can be found at [Microsoft Privacy Statement](https://go.microsoft.com/fwlink/?LinkID=824704).
To disable this, simply remove the following section from [main.json](/deployments/ARMTemplates/Json/main.json) before deploying the resources to Azure:
```json
{
"type": "Microsoft.Resources/deployments",
"apiVersion": "2021-04-01",
"name": "pid-b467f153-9bc9-5631-adb5-3eefa231a547",
"properties": {
"mode": "Incremental",
"template": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"resources": []
}
}
}
```
You can see more information on this at https://docs.microsoft.com/en-us/azure/marketplace/azure-partner-customer-usage-attribution.

213
README.md
Просмотреть файл

@ -1,59 +1,123 @@
# Digital Documentation Shipping Industry Solution Accelerator Guide
# Digital Shipping Documentation Solution Accelerator
## About this repository
This accelerator was built to provide developers with all of the resources needed to quickly build an initial Digital Documentation Shipping Quote system. Use this accelerator to jump start your development efforts with Blockchain in Azure.
## About this Repository
Todays supply chains depend on a growing list of international and domestic partners.
To better meet customer demand and keep the increasingly complex systems running smoothly leaders are turning to intelligent shipping documentation.
Digital documentation solutions that leverage the unique advantages of blockchain technology deliver improved speed and agility, while also providing transparency and traceability to internal and external stakeholders.
The Digital Shipping Documentation Solution Accelerator shows you how to complete shipping agreements faster, with improved security, when transacting with new and existing customers all over the world.
The solution uses a private blockchain network to document every step of the order process in a way that improves the overall experience for everyone involved.
Through the use of a secure, distributed, immutable, and automatable network of blockchain platforms, every business transaction between shippers and carriers is tokenized and shared.
Use of blockchain technology practically eilminates the risk of data tampering in the shipment order process, between quotation and booking, as every business participant can access the shared ledger of transaction events.
This solution accellerator is focused on the shipping industry, though with a little imagination it can serve as model for any number of use cases in a multitude of industries.
### Traditional Shipping Process
---
Traditional shipping industry processes are fragmented, with limited data sharing between quotation and booking workflows.
![Quotation Process](./documents/media/QuotationProcess.png)
![Booking Process](./documents/media/BookingProcess.png)
### Unified Shipping Process
---
The Digital Shipping Documentation Solution Accelerator shows how the traditional order and quotation processes can be made more agile within full and/or semi-trusted business relationships.
This new technology can reduce the time needed to complete business deals and empowers companies to easily and securely negotiate rates with new customers all over the world.
While this Solution Accelerator was built to improve transparency within the shipping industry, it is applicable to almost any business process that requires transparency and traceability among participants.
The diagram below shows how traditional processes can be consolidated and managed as a single process using NFT Tokens.
![Unified Process](./documents/media/UnifyProcessWithToken.png)
This screenshot summarizes how NFT tokens can be used to efficiently manage quoting and order confirmation for shipping companies,
making contract conditions and related information available to all participants. It is easy to see how this solution can be extended to provide visiblity on the entire delivery process.
![Manage BookingOrder](./documents/media/ManageBookingOrder.png)
This repository contains the steps, scripts, code, and tools to create a Blockchain application.
- 00_Resource_Deployment will create the solution resources in Azure (Functions, Blockchain Service, and Cosmos DB).
- 01_Source_Code_Deployment will configure and deploy the client app as well as the functions to the Azure resource.
- 02_Token_Service_Deployment will configure and deploy the blockchain token service to an Azure Container Registry.
- 03_Application_Deployment will deploy and configure and run your solution.
## Prerequisites
In order to successfully complete your solution, you will need to have access to or provisioned the following:
1. Access to an Azure subscription
2. Visual Studio 2017 or 2019
3. Azure CLI installed
4. Access to Azure Pipelines
5. (_for local deployment only_) Azure Storage Explorer, Azure Functions Core Tools
In order to successfully complete your solution, you will need to have access to or provision the following:
1. [Access to an Azure Subscription](http://portal.azure.com), with required permissions - Required to deploy compute resources
2. [Visual Studio 2019 or newer version](https://visualstudio.microsoft.com/downloads/)
3. [Azure CLI](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli) installed - Required for deployment scripts to be run
5. [Azure Functions Core Tools](https://docs.microsoft.com/en-us/azure/azure-functions/functions-run-local?tabs=v4%2Cwindows%2Ccsharp%2Cportal%2Cbash#v2)
## Architectural Overview
After completion of all steps, you will have a working end-to-end solution with the following architecture:
![Microservices Architecture](./documents/media/architecture_w_NFT_SA.png)
## Azure and Blockchain
The directions provided in this repository assume fundamental working knowledge of Azure. The resources needed for the solution are Cosmos DB, Azure Fuctions, Azure Blockchain Service, and Azure Pipelines. To host the blockchain endpoint, Azure Container Registry, Azure Kubernetes Service, and Azure Key Vault will also be required.
The directions provided in this repository assume a fundamental working knowledge of Azure. The resources needed for this solution are Cosmos DB, and Azure Functions.
This SA leverages [Azure Non-Fungible Token Solution Accelerator](https://github.com/microsoft/Azure-Non-Fungible-Token-Solution-Accelerator) for implementing NFT transactions more quickly. Please review Azure Non-Fungible Token Solution Accelerator before you begin this project.
For additional training and support, please see:
1. [Azure Cosmos DB](https://docs.microsoft.com/en-us/azure/cosmos-db/introduction)
2. [Azure Functions](https://azure.microsoft.com/en-us/services/functions/)
3. [Azure Blockchain Service](https://azure.microsoft.com/en-us/services/blockchain-service/)
4. [Azure Container Registry](https://azure.microsoft.com/en-us/services/container-registry/)
5. [Azure Kubernetes Service](https://azure.microsoft.com/en-us/services/kubernetes-service/)
6. [Azure Key Vault](https://azure.microsoft.com/en-us/services/key-vault/)
7. [Service Principal](https://docs.microsoft.com/en-us/azure/active-directory/develop/app-objects-and-service-principals)
8. [Azure Pipelines](https://azure.microsoft.com/en-us/services/devops/pipelines/)
3. [Azure Non-Fungible Token Solution Accelerator](https://github.com/microsoft/Azure-Non-Fungible-Token-Solution-Accelerator)
## Getting Started
## Getting Started and Process Overview
Clone/download this repo onto your computer and then walk through each of these folders in order, following the steps outlined in each of the README files. After completion of all steps, you will have a working end-to-end solution with the following architecture:
1. Clone/download this repo onto your computer and then walk through each of these steps in order, following the steps outlined in each of the README files.
![Microservices Architecture](./References/architecture.png)
1. Deploy the needed [resources](./deployments/ARMTemplates/README.md)
- The resources in this folder can be used to deploy the required cloud services into your Azure Subscription. This can be done either via the [Azure Portal](https://portal.azure.com) or by using the [PowerShell script](./deployments/ARMTemplates/Bicep/resourcedeployment.ps1) included in the deployment folder.
- After resource deployment, you will have an Azure Function App, Azure App Service Plan, Azure Storage Account, Azure Cosmos DB Account, and Azure Managed Identity.
- Resources can also be deployed into your Azure Subscription by using one of these Deploy Azure links:
[![Deploy to Azure](https://raw.githubusercontent.com/Azure/azure-quickstart-templates/master/1-CONTRIBUTION-GUIDE/images/deploytoazure.svg?sanitize=true)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2Fmicrosoft%2FDDSI-SA-Dev%2Fmain%2Fdeployments%2FARMTemplates%2FJson%2Fmain.json%3Ftoken%3DGHSAT0AAAAAABQNU3BZSIJE5L2NH6NYOYAEYQOBT5Q)   
[![Deploy To Azure US Gov](https://raw.githubusercontent.com/Azure/azure-quickstart-templates/master/1-CONTRIBUTION-GUIDE/images/deploytoazuregov.svg?sanitize=true)](https://portal.azure.us/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2Fmicrosoft%2FDDSI-SA-Dev%2Fmain%2Fdeployments%2FARMTemplates%2FJson%2Fmain.json%3Ftoken%3DGHSAT0AAAAAABQNU3BZSIJE5L2NH6NYOYAEYQOBT5Q)   
**Note: Follow "Step 3" in [Azure Resources Deployment](./deployments/ARMTemplates/README.md#step-3-configure-and-assign-managed-identity) to configure managed identity permission if you have deployed resources using above Azure links.**
1. Deploy the [Azure Functions](./deployments/AzureFunctions/README.md) using a [PowerShell script](./deployments/AzureFunctions/deployazurefunction.ps1) that will deploy source code from the repo to Azure Functions.
1. Deploy the [sample client application](./documents/README.md) to test and demonstrate the solution.
## Folders
### [00 - Resource Deployment](./00_Resource_Deployment)
The resources in this folder can be used to deploy the required resources into your Azure Subscription. This can be done either via the [Azure Portal](https://portal.azure.com) or by using the [PowerShell script](./00_Resource_Deployment/deploy.ps1) included in the resource deployment folder.
### [Resource Deployment](./deployments/ARMTemplates)
Contains resource deployment scripts to deploy the resources required to complete this project.
After deployed, you will have a Cosmos DB account, Azure Function (including an App Service Plan and Storage), and Blockchain Service deployed in your specified resource group.
### [Application Deployment](./deployments/AzureFunctions)
This folder contains deployment scripts need to setup the token API
### [01 - Source Code Deployment](./01_Source_Code_Deployment)
This folder contains a YAML pipeline and the source code. The [pipeline](./01_Source_Code_Deployment/azure-pipelines.yml) will deploy the source code to the Azure Functions resource.
### [Source](./src)
This folder contains all source code for Contoso Cargo sample application.
This pipeline will help you deploy the functions needed to handle the API calls for the quote and booking transactions.
### [02 - Token Service Deployment](./02_Token_Service_Deployment)
This folder contains a YAML pipeline and the blockchain token service source code. The [pipeline](./02_Token_Service_Deployment/azure-pipelines.yml) will deploy the source code to a docker container.
### [03 - Application Deployment](./03_Application_Deployment)
This folder contains the documentation of how to configure the solution to your provisioned Azure resources and how to use the application.
## Microsoft Open Source Code of Conduct
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
Resources:
- [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/)
- [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/)
- Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns
## License
Copyright (c) Microsoft Corporation
All rights reserved.
@ -64,7 +128,44 @@ Permission is hereby granted, free of charge, to any person obtaining a copy of
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE
THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT, OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE
## Security
Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/).
If you believe you have found a security vulnerability in any Microsoft-owned repository
that meets Microsoft's [Microsoft's definition of a security vulnerability](https://docs.microsoft.com/en-us/previous-versions/tn-archive/cc751383(v=technet.10)),
please report it to us as described here: [Reporting Security Issues](./SECURITY.md)
**Please do not report security vulnerabilities through public GitHub issues or any other public forumn.**
## Privacy
When you deploy this template, Microsoft is able to identify the installation of the software with the Azure resources that are deployed. Microsoft is able to correlate the Azure resources that are used to support the software. Microsoft collects this information to provide the best experiences with their products and to operate their business. The data is collected and governed by Microsoft's privacy policies, which can be found at [Microsoft Privacy Statement](https://go.microsoft.com/fwlink/?LinkID=824704).
To disable this, simply remove the following section from [main.json](/deployments/ARMTemplates/Json/main.json) before deploying the resources to Azure:
```json
{
"type": "Microsoft.Resources/deployments",
"apiVersion": "2021-04-01",
"name": "pid-b467f153-9bc9-5631-adb5-3eefa231a547",
"properties": {
"mode": "Incremental",
"template": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"resources": []
}
}
}
```
You can see more information on this at https://docs.microsoft.com/en-us/azure/marketplace/azure-partner-customer-usage-attribution.
## Contributing
@ -78,4 +179,44 @@ provided by the bot. You will only need to do this once across all repos using o
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or
contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
## Support
### How to file issues and get help
This project uses GitHub Issues to track bugs and feature requests. Please search the existing
issues before filing new issues to avoid duplicates. For new issues, file your bug or
feature request as a new Issue.
### Microsoft Support Policy
Support for this project is limited to the resources listed above.
## Trademarks
This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft
trademarks or logos is subject to and must follow
[Microsoft's Trademark & Brand Guidelines](https://www.microsoft.com/en-us/legal/intellectualproperty/trademarks/usage/general).
Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship.
Any use of third-party trademarks or logos are subject to those third-party's policies.
## Notices
Do Not Translate or Localize
This software incorporates material from third parties.
Microsoft makes certain open source code available at https://3rdpartysource.microsoft.com,
or you may send a check or money order for US $5.00, including the product name,
the open source component name, platform, and version number, to:
Source Code Compliance Team
Microsoft Corporation
One Microsoft Way
Redmond, WA 98052
USA
Notwithstanding any other terms, you may reverse engineer this software to the extent
required to debug changes to any libraries licensed under the GNU Lesser General Public License.

Просмотреть файл

@ -8,7 +8,7 @@ If you believe you have found a security vulnerability in any Microsoft-owned re
## Reporting Security Issues
**Please do not report security vulnerabilities through public GitHub issues.**
**Please do not report security vulnerabilities through public GitHub issues or any other public forumn.**
Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://msrc.microsoft.com/create-report).

12
SUPPORT.md Normal file
Просмотреть файл

@ -0,0 +1,12 @@
# Support
## How to file issues and get help
This project uses GitHub Issues to track bugs and feature requests. Please search the existing
issues before filing new issues to avoid duplicates. For new issues, file your bug or
feature request as a new Issue.
## Microsoft Support Policy
Support for this **PROJECT or PRODUCT** is limited to the resources listed above.

Просмотреть файл

@ -0,0 +1,133 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
@description('Provide a location to deploy your resources')
var location = resourceGroup().location
@description('Cosmos DB account name, can only contain lowercase letters, numbers, and the hyphen (-) character. It must be between 3-44 characters in length')
var cosmosAccountName = 'cosmos-contosocargo-${take(uniqueString(resourceGroup().id),5)}'
@description('Provide a name for function app')
var funcAppName = 'func-contosocargo-${take(uniqueString(resourceGroup().id),5)}'
@description('Storage account name, only lowercase letters and numbers, Name must be between 3 and 24 characters')
var funcStorageName = 'stcontosocargo${take(uniqueString(resourceGroup().id),5)}'
@description('Provide a name for the app service plan')
var serverFarmName = 'plan-contosocargo-${take(uniqueString(resourceGroup().id),5)}'
@description('Managed Idenity name')
var DigitShipUserIdentity = 'DShipUserIdentity-${take(uniqueString(resourceGroup().id),5)}'
resource cosmosAccountName_resource 'Microsoft.DocumentDB/databaseAccounts@2021-10-15' = {
name: cosmosAccountName
location: location
kind:'MongoDB'
properties: {
enableAutomaticFailover: false
enableMultipleWriteLocations: false
isVirtualNetworkFilterEnabled: false
virtualNetworkRules: []
databaseAccountOfferType: 'Standard'
consistencyPolicy: {
defaultConsistencyLevel: 'Session'
maxIntervalInSeconds: 5
maxStalenessPrefix: 100
}
locations: [
{
locationName: location
failoverPriority:0
isZoneRedundant:false
}
]
capabilities:[
{
name: 'EnableMongo'
}
]
}
}
resource funcStorageName_resource 'Microsoft.Storage/storageAccounts@2021-06-01' = {
name: funcStorageName
location: location
sku: {
name: 'Standard_LRS'
}
kind: 'StorageV2'
}
resource funcAppName_resource 'Microsoft.Web/sites@2021-02-01' = {
name: funcAppName
location: location
kind: 'functionapp'
properties: {
serverFarmId: serverFarmName_resource.id
siteConfig: {
appSettings: [
{
name: 'AzureWebJobsStorage'
value: 'DefaultEndpointsProtocol=https;AccountName=${funcStorageName};AccountKey=${listKeys(funcStorageName, '2021-04-01').keys[0].value}'
}
{
name: 'WEBSITE_CONTENTAZUREFILECONNECTIONSTRING'
value: 'DefaultEndpointsProtocol=https;AccountName=${funcStorageName};AccountKey=${listKeys(funcStorageName, '2021-04-01').keys[0].value}'
}
{
name: 'WEBSITE_CONTENTSHARE'
value: funcAppName
}
{
name: 'FUNCTIONS_EXTENSION_VERSION'
value: '~4'
}
{
name: 'FUNCTIONS_WORKER_RUNTIME'
value: 'dotnet'
}
{
name: 'WEBSITE_ENABLE_SYNC_UPDATE_SITE'
value: 'true'
}
{
name: 'WEBSITE_RUN_FROM_PACKAGE'
value: '1'
}
]
}
}
dependsOn: [
funcStorageName_resource
]
}
resource serverFarmName_resource 'Microsoft.Web/serverfarms@2021-02-01' = {
name: serverFarmName
location: location
sku: {
name: 'Y1'
tier: 'Dynamic'
}
}
resource DShipUserIdentity_resource 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = {
name: DigitShipUserIdentity
location: location
}
resource traceTag_resource 'Microsoft.Resources/deployments@2021-04-01' = {
name: 'pid-b467f153-9bc9-5631-adb5-3eefa231a547'
properties:{
mode: 'Incremental'
template:{
'$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#'
contentVersion: '1.0.0.0'
resources: []
}
}
}
output DShipUserIdentityID string = DShipUserIdentity_resource.properties.clientId
output cosmosName string = cosmosAccountName_resource.name

Просмотреть файл

@ -0,0 +1,51 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT license.
param(
[Parameter(Mandatory= $True,
HelpMessage='Enter the Azure subscription ID to deploy your resources')]
[string]
$subscriptionID = '',
[Parameter(Mandatory= $True,
HelpMessage='Enter the Azure Data Center Region to deploy your resources')]
[string]
$location = ''
)
Write-Host "Log in to Azure.....`r`n" -ForegroundColor Yellow
az login
az account set --subscription $subscriptionID
Write-Host "Switched subscription to '$subscriptionID' `r`n" -ForegroundColor Yellow
$deploymentName = 'DigitalShippingDeploy-' + ([string][guid]::NewGuid()).Substring(0,5)
$resourceGroupName = 'digitalshipping-' + ([string][guid]::NewGuid()).Substring(0,5)
$resourceGroup = az group exists -n $resourcegroupName
if ($resourceGroup -eq $false) {
#create resource group
az group create `
--location $location `
--name $resourceGroupName `
--subscription $subscriptionID
}
Write-Host "Started deploying Digital Shipping resources.....`r`n" -ForegroundColor Yellow
$deploymentResult = az deployment group create -g $resourceGroupName --template-file .\main.bicep -n $deploymentName
$joinedString = $deploymentResult -join ""
$jsonString = ConvertFrom-Json $joinedString
$DShipUserIdentityID = $jsonString.properties.outputs.DShipUserIdentityID.value
$cosmosName = $jsonString.properties.outputs.cosmosName.value
Write-Host "--------------------------------------------`r`n" -ForegroundColor White
Write-Host "Deployment output: `r`n" -ForegroundColor White
Write-Host "Subscription Id: $subscriptionID `r`n" -ForegroundColor Yellow
Write-Host "Digital Shipping resource group: $resourcegroupName `r`n" -ForegroundColor Yellow
Write-Host "Cosmos DB Account: $cosmosName" -ForegroundColor Yellow
Write-Host "User Assigned Identity Client Id: $DShipUserIdentityID " -ForegroundColor Yellow
Write-Host "--------------------------------------------`r`n" -ForegroundColor White
Write-Host "All resources are deployed successfully.....`r`n" -ForegroundColor Green

Просмотреть файл

@ -0,0 +1,147 @@
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"metadata": {
"_generator": {
"name": "bicep",
"version": "0.4.1124.51302",
"templateHash": "17409979608818972943"
}
},
"variables": {
"location": "[resourceGroup().location]",
"cosmosAccountName": "[format('cosmos-contosocargo-{0}', take(uniqueString(resourceGroup().id), 5))]",
"funcAppName": "[format('func-contosocargo-{0}', take(uniqueString(resourceGroup().id), 5))]",
"funcStorageName": "[format('stcontosocargo{0}', take(uniqueString(resourceGroup().id), 5))]",
"serverFarmName": "[format('plan-contosocargo-{0}', take(uniqueString(resourceGroup().id), 5))]",
"DigitShipUserIdentity": "[format('DShipUserIdentity-{0}', take(uniqueString(resourceGroup().id), 5))]"
},
"resources": [
{
"type": "Microsoft.DocumentDB/databaseAccounts",
"apiVersion": "2021-10-15",
"name": "[variables('cosmosAccountName')]",
"location": "[variables('location')]",
"kind": "MongoDB",
"properties": {
"enableAutomaticFailover": false,
"enableMultipleWriteLocations": false,
"isVirtualNetworkFilterEnabled": false,
"virtualNetworkRules": [],
"databaseAccountOfferType": "Standard",
"consistencyPolicy": {
"defaultConsistencyLevel": "Session",
"maxIntervalInSeconds": 5,
"maxStalenessPrefix": 100
},
"locations": [
{
"locationName": "[variables('location')]",
"failoverPriority": 0,
"isZoneRedundant": false
}
],
"capabilities": [
{
"name": "EnableMongo"
}
]
}
},
{
"type": "Microsoft.Storage/storageAccounts",
"apiVersion": "2021-06-01",
"name": "[variables('funcStorageName')]",
"location": "[variables('location')]",
"sku": {
"name": "Standard_LRS"
},
"kind": "StorageV2"
},
{
"type": "Microsoft.Web/sites",
"apiVersion": "2021-02-01",
"name": "[variables('funcAppName')]",
"location": "[variables('location')]",
"kind": "functionapp",
"properties": {
"serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('serverFarmName'))]",
"siteConfig": {
"appSettings": [
{
"name": "AzureWebJobsStorage",
"value": "[format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1}', variables('funcStorageName'), listKeys(variables('funcStorageName'), '2021-04-01').keys[0].value)]"
},
{
"name": "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING",
"value": "[format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1}', variables('funcStorageName'), listKeys(variables('funcStorageName'), '2021-04-01').keys[0].value)]"
},
{
"name": "WEBSITE_CONTENTSHARE",
"value": "[variables('funcAppName')]"
},
{
"name": "FUNCTIONS_EXTENSION_VERSION",
"value": "~4"
},
{
"name": "FUNCTIONS_WORKER_RUNTIME",
"value": "dotnet"
},
{
"name": "WEBSITE_ENABLE_SYNC_UPDATE_SITE",
"value": "true"
},
{
"name": "WEBSITE_RUN_FROM_PACKAGE",
"value": "1"
}
]
}
},
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts', variables('funcStorageName'))]",
"[resourceId('Microsoft.Web/serverfarms', variables('serverFarmName'))]"
]
},
{
"type": "Microsoft.Web/serverfarms",
"apiVersion": "2021-02-01",
"name": "[variables('serverFarmName')]",
"location": "[variables('location')]",
"sku": {
"name": "Y1",
"tier": "Dynamic"
}
},
{
"type": "Microsoft.ManagedIdentity/userAssignedIdentities",
"apiVersion": "2018-11-30",
"name": "[variables('DigitShipUserIdentity')]",
"location": "[variables('location')]"
},
{
"type": "Microsoft.Resources/deployments",
"apiVersion": "2021-04-01",
"name": "pid-b467f153-9bc9-5631-adb5-3eefa231a547",
"properties": {
"mode": "Incremental",
"template": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"resources": []
}
}
}
],
"outputs": {
"DShipUserIdentityID": {
"type": "string",
"value": "[reference(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', variables('DigitShipUserIdentity'))).clientId]"
},
"cosmosName": {
"type": "string",
"value": "[variables('cosmosAccountName')]"
}
}
}

Просмотреть файл

@ -0,0 +1,109 @@
## Resource Deployment
The [PowerShell script](./Bicep/resourcedeployment.ps1) can be used to provision the Azure resources required to deploy this Digital Documentation for Shipping Industry Solution Accelerator.
You may skip this section if you prefer to provision your resources via the Azure Portal, using the Azure Resource Manager(ARM) Template provided, or one of the Deploy to Azure buttons on the main documentation page.
The PowerShell script will provision the following resources to your Azure subscription:
- Azure Cosmos DB API for MongoDB account
- Azure Function App
- Azure App Service Plan
- Azure Storage Account
- Azure Managed Identity
## Prerequisites
1. [Azure Subscription](http://portal.azure.com) - Required to deploy compute resources
2. [PowerShell 7.1](https://docs.microsoft.com/en-us/powershell/scripting/install/installing-powershell?view=powershell-7.1) - Required to run deployment scripts
3. [Azure CLI](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli) installed - Required to run deployment scripts
4. [User Access Administrator](https://docs.microsoft.com/en-us/azure/role-based-access-control/built-in-roles#user-access-administrator) Role - Assigned to Azure Subscription user
Execute the following steps to deploy Azure resources:
## Step 1. Download Files
Clone or download this repository, if you have not already done so.
Check here for more information on [cloning a repository](https://docs.github.com/en/repositories/creating-and-managing-repositories/cloning-a-repository).
## Step 2. Deploy Digital Shipping Resources
1. Run [PowerShell 7.1](https://docs.microsoft.com/en-us/powershell/scripting/install/installing-powershell?view=powershell-7.1)
2. Run the Change Directory command to navigate to the location where **resourcedeployment.ps1** is located
```console
PS C:\Users\>CD <directory path>
```
3. Run the **resourcedeployment.ps1** with the following parameters:
```.\resourcedeployment.ps1 <SubscriptionId> <location>```
```
SubscriptionId: The subscription ID for where you want to manage your resources
location: Azure Data Center Region where resources will be deployed
```
- If you see this error message when running the PowerShell script:
![alt text](/documents/media/ResourceDeploymentError.png)
- Resolve it by running the following command:
```Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass```
- Then run ```.\resourcedeployment.ps1 <SubscriptionId> <location>```
After the completion of the script, check to see that all of the Azure resources deployed successfully. Your resource groups should look similar to the image below.
![alt text](/documents/media/Resources.png)
## Step 3. Configure and Assign Managed Identity
- **Reminder:** The managed identity name will differ by deployment. Your managed identity name will be different. Ex. DShipUserIdentity-XXXXX
#### Assign Managed Identity to Azure Function
1. Step into the Azure Function app
![alt text](/documents/media/FunctionApp.png)
2. Under the settings click on the identity
![alt text](/documents/media/FunctionAppIdentity.png)
3. Click on the User Assigned tab and click on add and select DShipUserIdentity-XXXXX
![alt text](/documents/media/FunctionAppIdentityAdd.png)
4. Refresh to confirm identity assignment
![alt text](/documents/media/FunctionAppIdentityVerify.png)
#### Assign Managed Identity to Azure Cosmos DB
1. Step into the Azure Cosmos DB account
![alt text](/documents/media/CosmosDb.png)
2. Click on the Access control and click on add and select Add role assignment
![alt text](/documents/media/CosmosDbAccess.png)
3. Search for the "DocumentDB Account Contributor" in the search box given. Select the "DocumentDB Account Contributor" role and click Next
![alt text](/documents/media/CosmosDbSelect.png)
4. Select "Managed Identity," and click on the "Selected members," and select the identity you configured the steps above
![alt text](/documents/media/CosmosDbIdentitySelect.png)
5. Click on "Review + assign" to add the role assignment
![alt text](/documents/media/CosmosDbIdentityAssign.png)
6. Refresh to confirm role assignment
![alt text](/documents/media/CosmosDbIdentityVerify.png)
**Remember to write down all of the output values printed on the screen. These will be required in the next step (when deploying Azure Function code).**
**You've successfully deployed all the resources!**
For the next step, go to [Application Deployment](/deployments/AzureFunctions/README.md).

Просмотреть файл

@ -0,0 +1,94 @@
# Application Deployment
## Prerequisites
To successfully deploy the digital shipping industry azure functions, you will need to have deployed the following resources.
1. Azure Storage Account
2. Azure Cosmos DB API for Mongo DB Account
3. Azure Function App
4. Azure App Service Plan
5. Azure Managed Identity
6. Azure CLI installed
7. [Azure Core Tool installed](https://docs.microsoft.com/en-us/azure/azure-functions/functions-run-local?tabs=v4%2Cwindows%2Ccsharp%2Cportal%2Cbash#v2)
8. Azure Non-Fungible Token Solution Accelerator
If these are not available, please follow the [resource deployment](../ARMTemplates/ResourceDeployment.md) steps.
## Steps for Azure Functions Deployment via PowerShell
### Step 1. Setup Azure core tool globally. (Required first time only)
1. Open the PowerShell tool and run the below command.
```
npm install -g azure-functions-core-tools@4
```
### Step 2. Execute the PowerShell deployment script.
1. Run [PowerShell 7.1](https://docs.microsoft.com/en-us/powershell/scripting/install/installing-powershell?view=powershell-7.1)
2. Run the Change Directory command to navigate to the location where **deployazurefunction.ps1** is located
```console
PS C:\Users\>CD <directory path>
```
3. Provide the following detail in deployazurefunction.ps1 from the previous script(resourcedeployment.ps1) output
```
SubscriptionId: The Subscription ID for where you want to manage your resources
ResourcegroupName: Resource group name where the resources are deployed
DatabaseAccountName : Azure Cosmos DB account name
serviceEndpointUrl: NFT service endpoint URL received after deployment of Azure Non Fungible Token Solution Accelerator.
ManagedIdentityId: User Assigned Identity Client Id
FunctionAppName: Name of app that requires Azure Functions support
```
4. Run the .\deployazurefunction.ps1
```console
PS <directory path> \deployments\AzureFunctions>Powershell.exe -executionpolicy remotesigned -File .\deployazurefunction.ps1
```
5. Accept the log-in request through your browser
6. After the successful execution of the script, the Azure Functions will be deployed.
**You've successfully deployed Azure Functions!**
**Note:** Azure function URL and Hostkey will be received after successful deployment. Copy this detail as it will be required in next step.
![alt text](/documents/media/AzureFunctionURLandHostkey.png)
For next steps, please go to [**Setup Console Application**](/documents/README.md).
---
## Detail of the deployment script
1. Log in to the Azure portal
```
az login
```
2. Set the Azure account Subscription ID
```
az account set --subscription mysubscriptionid
```
3. Set Up Azure function application
```
Set-location "..\..\src"
((Get-Content -path ContosoCargo.DigitalDocument.TokenService.Host\application.settings.json -Raw) -replace '{ServiceEndpoint}', $serviceEndpointUrl) | Set-Content -Path ContosoCargo.DigitalDocument.TokenService.Host\application.settings.json
((Get-Content -path ContosoCargo.DigitalDocument.TokenService.Host\application.settings.json -Raw) -replace '{SubscriptionId}', $subscriptionId) | Set-Content -Path ContosoCargo.DigitalDocument.TokenService.Host\application.settings.json
((Get-Content -path ContosoCargo.DigitalDocument.TokenService.Host\application.settings.json -Raw) -replace '{ResourceGroupName}', $resourcegroupName) | Set-Content -Path ContosoCargo.DigitalDocument.TokenService.Host\application.settings.json
((Get-Content -path ContosoCargo.DigitalDocument.TokenService.Host\application.settings.json -Raw) -replace '{DatabaseAccountName}', $databaseAccountName) | Set-Content -Path ContosoCargo.DigitalDocument.TokenService.Host\application.settings.json
((Get-Content -path ContosoCargo.DigitalDocument.TokenService.Host\application.settings.json -Raw) -replace '{ManagedIdentityId}', $ManagedIdentityId) | Set-Content -Path ContosoCargo.DigitalDocument.TokenService.Host\application.settings.json
```
5. Deploy Azure Functions
```
Set-location "ContosoCargo.DigitalDocument.TokenService.Host"
func azure functionapp publish $FunctionAppName --csharp --force
Set-Location "..\..\deployments\AzureFunctions"
```
6. Update function App configuration
```
az functionapp config appsettings set --name $FunctionAppName --resource-group $resourcegroupName --settings "FUNCTIONS_WORKER_RUNTIME=dotnet-isolated"
```

Просмотреть файл

@ -0,0 +1,49 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT license.
#login azure
Write-Host "Log in to Azure"
az Login
$subscriptionId = Read-Host "subscription Id"
$resourcegroupName = Read-Host "resource group name"
$databaseAccountName = Read-Host "azure cosmos db account name"
$serviceEndpointUrl = Read-Host "NFT service end point URL"
$ManagedIdentityId = Read-Host "user assigned identity client id"
$FunctionAppName = Read-Host "function app name"
Write-Host "Setup subscription Id...`r`n"
az account set --subscription $subscriptionId
$resourceGroup = az group exists -n $resourcegroupName
if ($resourceGroup -eq $false) {
throw "The Resource group '$resourcegroupName' is not exist`r`n Please check resource name and try it again"
}
Write-Host "Setup Azure Functions Appsetting.....`r`n"
Set-location "..\..\src"
((Get-Content -path ContosoCargo.DigitalDocument.TokenService.Host\application.settings.json -Raw) -replace '{ServiceEndpoint}', $serviceEndpointUrl) | Set-Content -Path ContosoCargo.DigitalDocument.TokenService.Host\application.settings.json
((Get-Content -path ContosoCargo.DigitalDocument.TokenService.Host\application.settings.json -Raw) -replace '{SubscriptionId}', $subscriptionId) | Set-Content -Path ContosoCargo.DigitalDocument.TokenService.Host\application.settings.json
((Get-Content -path ContosoCargo.DigitalDocument.TokenService.Host\application.settings.json -Raw) -replace '{ResourceGroupName}', $resourcegroupName) | Set-Content -Path ContosoCargo.DigitalDocument.TokenService.Host\application.settings.json
((Get-Content -path ContosoCargo.DigitalDocument.TokenService.Host\application.settings.json -Raw) -replace '{DatabaseAccountName}', $databaseAccountName) | Set-Content -Path ContosoCargo.DigitalDocument.TokenService.Host\application.settings.json
((Get-Content -path ContosoCargo.DigitalDocument.TokenService.Host\application.settings.json -Raw) -replace '{ManagedIdentityId}', $ManagedIdentityId) | Set-Content -Path ContosoCargo.DigitalDocument.TokenService.Host\application.settings.json
Write-Host "Deploy Azure Functions `r`n"
Set-location "ContosoCargo.DigitalDocument.TokenService.Host"
func azure functionapp publish $FunctionAppName --csharp --force
Set-Location "..\..\deployments\AzureFunctions"
Write-Host "Update function App configuration.....`r`n"
az functionapp config appsettings set --name $FunctionAppName --resource-group $resourcegroupName --settings "FUNCTIONS_WORKER_RUNTIME=dotnet-isolated"
Write-Host "**You've successfully deployed the Azure Functions!**" -ForegroundColor Green
az functionapp list --query "[?name == '$FunctionAppName'].{HostName: defaultHostName}" --output table
Write-Host "";
az functionapp keys list --name $FunctionAppName -g $resourcegroupName --query "{FunctionKey : functionKeys.default }" --output table

57
documents/README.md Normal file
Просмотреть файл

@ -0,0 +1,57 @@
# Setup and Deploy Sample Console Application
This folder contains documentation on how to run the sample application to demonstrate the Digital Shipping Documentation solution.
## Prerequisites
1. Access to an Azure subscription
1. Fundamental knowledge and access to [Visual Studio](https://visualstudio.microsoft.com/)
## How to run Console Application in Azure
To run the [source code](../src):
1. Clone/download the [source code](../src) onto your computer and open the folder in Visual Studio.
2. Open the [ContosoCargo.DigitalDocument.TokenService.sln](../src/ContosoCargo.DigitalDocument.TokenService.sln).
3. Navgate to ContosoCargo.DigitalDocument.Setup > appsettings.json
4. Replace TokenServiceEndpoint and BlockchainNetworkTxNode which it is recevied during [azure non fungible token solution accelerator](https://github.com/microsoft/Azure-Non-Fungible-Token-Solution-Accelerator) deployment.
5. Set the ContosoCargo.DigitalDocument.Setup as your start up project and run the solution.
6. Once the application runs successfully, at the end following values will be received.
- Contoso Cargo Id : 324ee982-a87d-43c8-affb-07758e732044
- Shipper A Id : de5f8ad5-2130-47e3-84f6-4f703b687233
- Shipper B Id : 44eef836-0292-4d84-94b3-665c7079011b
- **Note: Above given value will be different everytime we the run ContosoCargo.DigitalDocument.Setup application.**
7. Copy the detail received as they will be need for next applicaiton. Now stop the running application.
8. Navigate to ContosoCargo.DigitalDocument.Application.WindowsClient > App.config.
9. Replace HostKey and ServiceEndpoint with your Azure Functions
- When [azure functions deployed](../deployments/AzureFunctions/README.md) at the end of deployemnt HostKey and ServiceEndpoint has been received.
![alt text](./media/AzureFunctionURLandHostkey.png)
- If not coppied after deployemnt, it can get from azure portal.
- Copy ServiceEndpoint from azure portal.
![alt text](./media/AzureFunctionURL.PNG)
- Copy HostKey from azure portal.
![alt text](./media/AzureFunctionKey.PNG)
-**Note:** Don't forget **/api** on the end! (e.g. _https://contosocargo.azurewebsites.net/api_)
10. Replace ContosoCargo_Id, ShipperA_Id and ShipperB_Id which is received while running Setup application.
10. Set the Application.WindowsClient as your start up project and run the solution.
## How to use the Application
The first time the client app will open up to 'Contoso Cargo' as the Party and there should be no quotes created yet. Once there are shipping quotes, the client should look like this:
![Step 0](./media/Step_0.JPG)
### 1. Start with a shipper creating a quote request:
![Step 1](./media/Step_1.JPG)
### 2. The carrier will respond with a quotation:
![Step 2](./media/Step_2.JPG)
### 3. The shipper will book the request:
![Step 3](./media/Step_3.JPG)
### 4. The carrier will confirm the request:
![Step 4](./media/Step_4.JPG)

Двоичные данные
documents/media/AzureFunctionKey.PNG Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 89 KiB

Двоичные данные
documents/media/AzureFunctionURL.PNG Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 80 KiB

Двоичные данные
documents/media/AzureFunctionURLandHostkey.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 5.1 KiB

Двоичные данные
documents/media/BookingProcess.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 166 KiB

Двоичные данные
documents/media/CosmosDb.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 107 KiB

Двоичные данные
documents/media/CosmosDbAccess.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 115 KiB

Двоичные данные
documents/media/CosmosDbIdentityAssign.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 46 KiB

Двоичные данные
documents/media/CosmosDbIdentitySelect.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 94 KiB

Двоичные данные
documents/media/CosmosDbIdentityVerify.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 106 KiB

Двоичные данные
documents/media/CosmosDbSelect.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 56 KiB

Двоичные данные
documents/media/FunctionApp.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 107 KiB

Двоичные данные
documents/media/FunctionAppIdentity.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 108 KiB

Двоичные данные
documents/media/FunctionAppIdentityAdd.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 134 KiB

Двоичные данные
documents/media/FunctionAppIdentityVerify.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 116 KiB

Двоичные данные
documents/media/ManageBookingOrder.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 80 KiB

Двоичные данные
documents/media/QuotationProcess.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 186 KiB

Двоичные данные
documents/media/ResourceDeploymentError.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 18 KiB

Двоичные данные
documents/media/Resources.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 105 KiB

Двоичные данные
documents/media/Step_0.JPG Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 98 KiB

Двоичные данные
documents/media/Step_1.JPG Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 137 KiB

Двоичные данные
documents/media/Step_2.JPG Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 132 KiB

Двоичные данные
documents/media/Step_3.JPG Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 134 KiB

Двоичные данные
documents/media/Step_4.JPG Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 142 KiB

Двоичные данные
documents/media/UnifyProcessWithToken.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 149 KiB

Двоичные данные
documents/media/architecture.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 37 KiB

Двоичные данные
documents/media/architecture_function.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 77 KiB

Двоичные данные
documents/media/architecture_w_NFT_SA.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 70 KiB

Просмотреть файл

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
</startup>
<appSettings>
<add key="ServiceEndpoint" value=""/>
<add key="HostKey" value=""/>
<add key="ContosoCargo_Id" value=""/>
<add key="ShipperA_Id" value=""/>
<add key="ShipperB_Id" value=""/>
</appSettings>
</configuration>

Просмотреть файл

@ -0,0 +1,9 @@
<Application x:Class="CargoSmart.Windows.Booking.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:CargoSmart.Windows.Booking"
Startup="Application_StartUp">
<Application.Resources>
</Application.Resources>
</Application>

Просмотреть файл

@ -0,0 +1,52 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace CargoSmart.Windows.Booking
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
public App()
{
}
private void Application_StartUp(object sender, StartupEventArgs e)
{
this.ShutdownMode = ShutdownMode.OnMainWindowClose;
OrderManager orderManager = new OrderManager();
orderManager.Show();
}
}
public class WaitCursor : IDisposable
{
private ProgressBar _progressBar = null;
private Cursor _previousCursor;
public void Dispose()
{
Mouse.OverrideCursor = _previousCursor;
if (_progressBar != null) { _progressBar.IsIndeterminate = false; }
}
public WaitCursor()
{
_previousCursor = Mouse.OverrideCursor;
Mouse.OverrideCursor = Cursors.Wait;
}
public WaitCursor(ProgressBar progressBar) : this()
{
_progressBar = progressBar;
progressBar.IsIndeterminate = true;
}
}
}

Просмотреть файл

@ -0,0 +1,116 @@
<Window x:Class="CargoSmart.Windows.Booking.BookingConfirmation"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:converter="clr-namespace:CargoSmart.Windows.Booking.FieldConverter"
xmlns:local="clr-namespace:CargoSmart.Windows.Booking"
mc:Ignorable="d"
Title="BookingConfirmation" Height="582.472" Width="800">
<Window.Resources>
<converter:CustomerNameConverter x:Key="CustomerNameTypeConverter"/>
<converter:ContainerSizeValueConverter x:Key="ContainerSizeValueConveter"/>
<converter:ContainerTypeValueConverter x:Key="ContainerTypeValueConverter"/>
<converter:CargoNatureValueTypeConverter x:Key="CargoNatureValueTypeConverter"/>
<converter:PlaceValueTypeConverter x:Key="PlaceValueTypeConverter"/>
<Style x:Key="LabelStyle" TargetType="{x:Type Label}">
<Setter Property="Padding" Value="0,0,0,0"/>
<Setter Property="Margin" Value="0,0,0,0"/>
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<Setter Property="VerticalAlignment" Value="Stretch"/>
<Setter Property="HorizontalAlignment" Value="Left"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
</Style>
<Style x:Key="TextBoxStyle" TargetType="{x:Type TextBox}">
<Setter Property="Margin" Value="3,3,10,3"/>
</Style>
<Style x:Key="TextBlockStyle" TargetType="TextBlock">
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="TextWrapping" Value="Wrap"/>
</Style>
</Window.Resources>
<Grid x:Name="grdBookingConfirmation">
<Grid.RowDefinitions>
<RowDefinition Height="20"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20"></ColumnDefinition>
<ColumnDefinition Width="184"></ColumnDefinition>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Label Content="Title :" Grid.Row="1" Grid.Column="1" Style="{StaticResource LabelStyle}"/>
<TextBox x:Name="txtTitle" Grid.Row="1" Grid.Column="2" Style="{StaticResource TextBoxStyle}" />
<Label Content="Description :" Grid.Row="2" Grid.Column="1" Style="{StaticResource LabelStyle}"/>
<TextBox x:Name="txtDescription" Grid.Row="2" Grid.Column="2" Style="{StaticResource TextBoxStyle}" TextWrapping="Wrap" AcceptsReturn="True" Grid.RowSpan="2" />
<Label Content="CY Cut Off :" Grid.Row="4" Grid.Column="1" Style="{StaticResource LabelStyle}" />
<TextBox x:Name="txtCYCutOff" Grid.Row="4" Grid.Column="2" Style="{StaticResource TextBoxStyle}"/>
<Label Content="CI Cut Off :" Grid.Row="5" Grid.Column="1" Style="{StaticResource LabelStyle}" />
<TextBox x:Name="txtCICutOff" Grid.Row="5" Grid.Column="2" Style="{StaticResource TextBoxStyle}"/>
<Label Content="Empty Container Pickup Location :" Grid.Row="6" Grid.Column="1" Style="{StaticResource LabelStyle}" />
<TextBox x:Name="txtEmptyContainerPickupLocation" Grid.Row="6" Grid.Column="2" Style="{StaticResource TextBoxStyle}"/>
<Label Content="Laden Container Pickup Location :" Grid.Row="7" Grid.Column="1" Style="{StaticResource LabelStyle}" />
<TextBox x:Name="txtLadenContainerPickupLocation" Grid.Row="7" Grid.Column="2" Style="{StaticResource TextBoxStyle}"/>
<Label Content="Shipper :" Grid.Row="8" Grid.Column="1" Style="{StaticResource LabelStyle}" Width="47"/>
<WrapPanel x:Name="pnlCustomerName" Grid.Column="2" VerticalAlignment="Center" Grid.Row="8" >
<TextBlock Text="{Binding Contractee, Converter={StaticResource CustomerNameTypeConverter}}" Style="{StaticResource TextBlockStyle}"/>
<TextBlock TextWrapping="Wrap" Text=" ( " Style="{StaticResource TextBlockStyle}"/>
<TextBlock TextWrapping="Wrap" Text="{Binding Contractee}" Style="{StaticResource TextBlockStyle}"/>
<TextBlock TextWrapping="Wrap" Text=" )" Style="{StaticResource TextBlockStyle}"/>
</WrapPanel>
<Label Content="From :" Grid.Row="9" Grid.Column="1" Style="{StaticResource LabelStyle}" Width="33"/>
<Label Content="{Binding From}" Grid.Row="9" Grid.Column="2" Style="{StaticResource LabelStyle}"/>
<Label Content="To :" Grid.Row="10" Grid.Column="1" Style="{StaticResource LabelStyle}" Width="18"/>
<Label Content="{Binding To}" Grid.Row="10" Grid.Column="2" Style="{StaticResource LabelStyle}" />
<Label Content="Container Size :" Grid.Row="11" Grid.Column="1" Style="{StaticResource LabelStyle}" Width="82"/>
<Label Content="{Binding ContainerSize, Converter={StaticResource ContainerSizeValueConveter}}" Grid.Row="11" Grid.Column="2" Style="{StaticResource LabelStyle}" />
<Label Content="Container Type :" Grid.Row="12" Grid.Column="1" Style="{StaticResource LabelStyle}" Width="86"/>
<Label Content="{Binding ContainerType, Converter={StaticResource ContainerTypeValueConverter}}" Grid.Row="12" Grid.Column="2" Style="{StaticResource LabelStyle}" />
<Label Content="Quantity :" Grid.Row="13" Grid.Column="1" Style="{StaticResource LabelStyle}" Width="51"/>
<Label x:Name="txtQuantity" Content="{Binding Quantity}" Grid.Row="13" Grid.Column="2" Style="{StaticResource LabelStyle}" />
<Label Content="Shipping Place :" Grid.Row="14" Grid.Column="1" Style="{StaticResource LabelStyle}" Width="84"/>
<Label Content="{Binding Place, Converter={StaticResource PlaceValueTypeConverter} }" Grid.Row="14" Grid.Column="2" Style="{StaticResource LabelStyle}" />
<Label Content="Weight :" Grid.Row="15" Grid.Column="1" Style="{StaticResource LabelStyle}" Width="44"/>
<Label Content="{Binding Weight}" Grid.Row="15" Grid.Column="2" Style="{StaticResource LabelStyle}"/>
<Label Content="Cargo Nature :" Grid.Row="16" Grid.Column="1" Style="{StaticResource LabelStyle}" Width="77"/>
<Label Content="{Binding CargoNature, Converter={StaticResource CargoNatureValueTypeConverter}}" Grid.Row="16" Grid.Column="2" Style="{StaticResource LabelStyle}" Width="173"/>
<Button Content="Create Booking Request" Grid.Row="17" Grid.Column="2" HorizontalAlignment="Left" Margin="3,10,0,0" VerticalAlignment="Top" Width="151" Height="20" Click="Button_Click"/>
</Grid>
</Window>

Просмотреть файл

@ -0,0 +1,75 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using CargoSmart.Windows.Booking.ServiceProxy;
using Newtonsoft.Json;
using System.Diagnostics;
using System.Threading.Tasks;
using System.Windows;
namespace CargoSmart.Windows.Booking
{
/// <summary>
/// Interaction logic for BookingConfirmation.xaml
/// </summary>
public partial class BookingConfirmation : Window
{
private OrderManager _motherForm;
private CargoTokenShipment _Shipment;
public BookingConfirmation()
{
InitializeComponent();
}
public BookingConfirmation(OrderManager motherForm, CargoTokenShipment ShipmentInfo) : this()
{
_motherForm = motherForm;
_Shipment = ShipmentInfo;
ServiceProxy.BookingRequest bookingRequest =
JsonConvert.DeserializeObject<ServiceProxy.BookingRequest>(_Shipment.BookingRequestTokenInfo.BusinessMetaData);
pnlCustomerName.DataContext = _Shipment;
grdBookingConfirmation.DataContext = bookingRequest;
}
private async Task<CargoTokenShipment> CreateBookingConfirmation()
{
HttpServiceProxy proxy = HttpServiceLocator.GetHttpServiceProxy();
BookingConfirmationRequestMessage bookingConfirmationRequestMessage = new BookingConfirmationRequestMessage()
{
ShipmentID = _Shipment.Id.ToString(),
CallerID = _Shipment.Contracter,
CustomerID = _Shipment.Contractee,
BookingConfirmationTitle = txtTitle.Text,
BookingConfirmationDescription = txtDescription.Text,
BookingConfirmationInfo = new BookingConfirmationInfo()
{
CyCutOff = txtCYCutOff.Text,
SiCutOff = txtCICutOff.Text,
EmptyContainerPickupLocation = txtEmptyContainerPickupLocation.Text,
LadenContainerReturnLocation = txtLadenContainerPickupLocation.Text,
BookingRequest = (ServiceProxy.BookingRequest)grdBookingConfirmation.DataContext
}
};
var result = await proxy.CreateBookingConfirmationAsync(_Shipment.Id.ToString(), bookingConfirmationRequestMessage);
Debug.WriteLine(result);
return result;
}
private async void Button_Click(object sender, RoutedEventArgs e)
{
using (new WaitCursor(_motherForm.pgbProgress))
{
await CreateBookingConfirmation();
await _motherForm.GetMyShipment(true);
}
this.Close();
}
}
}

Просмотреть файл

@ -0,0 +1,100 @@
<Window x:Class="CargoSmart.Windows.Booking.BookingRequest"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:CargoSmart.Windows.Booking"
mc:Ignorable="d"
x:Name="frmBookingRequest"
xmlns:converter="clr-namespace:CargoSmart.Windows.Booking.FieldConverter"
Title="BookingRequest" Height="473.54" Width="505">
<Window.Resources>
<converter:ContainerSizeValueConverter x:Key="ContainerSizeValueConveter"/>
<converter:ContainerTypeValueConverter x:Key="ContainerTypeValueConverter"/>
<converter:CargoNatureValueTypeConverter x:Key="CargoNatureValueTypeConverter"/>
<converter:CustomerNameConverter x:Key="CustomerNameTypeConverter"/>
<Style x:Key="LabelStyle" TargetType="{x:Type Label}">
<Setter Property="Padding" Value="0,0,0,0"/>
<Setter Property="Margin" Value="0,0,0,0"/>
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<Setter Property="VerticalAlignment" Value="Stretch"/>
<Setter Property="HorizontalAlignment" Value="Left"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
</Style>
<Style x:Key="TextBoxStyle" TargetType="{x:Type TextBox}">
<Setter Property="Margin" Value="3,3,10,3"/>
</Style>
<Style x:Key="TextBlockStyle" TargetType="TextBlock">
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="TextWrapping" Value="Wrap"/>
</Style>
</Window.Resources>
<Grid x:Name="grdBookingRequest">
<Grid.RowDefinitions>
<RowDefinition Height="20"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20"></ColumnDefinition>
<ColumnDefinition Width="140"></ColumnDefinition>
<ColumnDefinition Width="635*"/>
</Grid.ColumnDefinitions>
<Label Content="Title :" Grid.Row="1" Grid.Column="1" Style="{StaticResource LabelStyle}"/>
<TextBox x:Name="txtTitle" Grid.Row="1" Grid.Column="2" Style="{StaticResource TextBoxStyle}" />
<Label Content="Description :" Grid.Row="2" Grid.Column="1" Style="{StaticResource LabelStyle}"/>
<TextBox x:Name="txtDescription" Grid.Row="2" Grid.Column="2" Style="{StaticResource TextBoxStyle}" TextWrapping="Wrap" AcceptsReturn="True" Grid.RowSpan="2" />
<Label Content="Shipper :" Grid.Row="4" Grid.Column="1" Style="{StaticResource LabelStyle}"/>
<WrapPanel x:Name="pnlCustomerName" Grid.Column="2" VerticalAlignment="Center" Height="16" Grid.Row="4" Margin="0,7" Grid.ColumnSpan="2">
<TextBlock Text="{Binding Contractee, Converter={StaticResource CustomerNameTypeConverter}}" Style="{StaticResource TextBlockStyle}"/>
<TextBlock TextWrapping="Wrap" Text=" ( " Style="{StaticResource TextBlockStyle}"/>
<TextBlock TextWrapping="Wrap" Text="{Binding Contractee}" Style="{StaticResource TextBlockStyle}"/>
<TextBlock TextWrapping="Wrap" Text=" )" Style="{StaticResource TextBlockStyle}"/>
</WrapPanel>
<!--<Label x:Name="lblAccount" Content="{Binding Contracter}" Grid.Row="1" Grid.Column="2" Style="{StaticResource LabelStyle}"/>-->
<Label Content="From :" Grid.Row="5" Grid.Column="1" Style="{StaticResource LabelStyle}"/>
<Label Content="{Binding From}" Grid.Row="5" Grid.Column="2" Style="{StaticResource LabelStyle}"/>
<Label Content="To :" Grid.Row="6" Grid.Column="1" Style="{StaticResource LabelStyle}"/>
<Label Content="{Binding To}" Grid.Row="6" Grid.Column="2" Style="{StaticResource LabelStyle}"/>
<Label Content="Container Size :" Grid.Row="7" Grid.Column="1" Style="{StaticResource LabelStyle}"/>
<Label x:Name="lblContainerSize" Content="{Binding ContainerSize, Converter={StaticResource ContainerSizeValueConveter}}" Grid.Row="7" Grid.Column="2" Style="{StaticResource LabelStyle}"/>
<Label Content="Container Type :" Grid.Row="8" Grid.Column="1" Style="{StaticResource LabelStyle}"/>
<Label x:Name="lblContainerType" Content="{Binding ContainerType, Converter={StaticResource ContainerTypeValueConverter}}" Grid.Row="8" Grid.Column="2" Style="{StaticResource LabelStyle}"/>
<Label Content="Quantity :" Grid.Row="9" Grid.Column="1" Style="{StaticResource LabelStyle}"/>
<TextBox x:Name="txtQuantity" Grid.Row="9" Grid.Column="2" Style="{StaticResource TextBoxStyle}"/>
<Label Content="Shipping Place :" Grid.Row="10" Grid.Column="1" Style="{StaticResource LabelStyle}"/>
<ComboBox x:Name="cboShippingplace" Grid.Row="10" Grid.Column="2" Margin="3,3,10,3" HorizontalAlignment="Left" VerticalAlignment="Center" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" Width="300"/>
<Label Content="Weight :" Grid.Row="11" Grid.Column="1" Style="{StaticResource LabelStyle}"/>
<TextBox x:Name="txtWeight" Grid.Row="11" Grid.Column="2" Style="{StaticResource TextBoxStyle}"/>
<Label Content="Cargo Nature :" Grid.Row="12" Grid.Column="1" Style="{StaticResource LabelStyle}"/>
<Label Content="{Binding CargoNature}" Grid.Row="12" Grid.Column="2" Style="{StaticResource LabelStyle}"/>
<Button Content="Create Booking Request" Grid.Row="13" Grid.Column="2" HorizontalAlignment="Left" Margin="3,10,0,0" VerticalAlignment="Top" Width="151" Click="Button_Click"/>
</Grid>
</Window>

Просмотреть файл

@ -0,0 +1,93 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using CargoSmart.Windows.Booking.FieldConverter;
using CargoSmart.Windows.Booking.ServiceProxy;
using Newtonsoft.Json;
using System.Diagnostics;
using System.Threading.Tasks;
using System.Windows;
namespace CargoSmart.Windows.Booking
{
/// <summary>
/// Interaction logic for BookingRequest.xaml
/// </summary>
public partial class BookingRequest : Window
{
private OrderManager _motherForm;
private CargoTokenShipment _Shipment;
public string ShipperAccount { get; set; }
public BookingRequest()
{
InitializeComponent();
}
public BookingRequest(OrderManager motherForm, CargoTokenShipment ShipmentInfo) : this()
{
_motherForm = motherForm;
_Shipment = ShipmentInfo;
pnlCustomerName.DataContext = _Shipment;
//this.ShipperAccount = _Shipment.Contracter;
grdBookingRequest.DataContext = JsonConvert.DeserializeObject<QuoteInfo>(ShipmentInfo.QuotedTokenInfo.BusinessMetaData);
SetupShippingPlaceCombo();
}
private void SetupShippingPlaceCombo()
{
cboShippingplace.Items.Add("Yard");
cboShippingplace.Items.Add("Door");
cboShippingplace.SelectedIndex = 0;
}
private async void Button_Click(object sender, RoutedEventArgs e)
{
using (new WaitCursor(_motherForm.pgbProgress))
{
await CreateBookingRequest();
await _motherForm.GetMyShipment(true);
}
this.Close();
}
private async Task CreateBookingRequest()
{
HttpServiceProxy httpServiceProxy = HttpServiceLocator.GetHttpServiceProxy();
QuoteInfo quoteInfo = JsonConvert.DeserializeObject<QuoteInfo>(_Shipment.QuotedTokenInfo.BusinessMetaData);
BookingRequestMessage bookingRequestInfo = new BookingRequestMessage()
{
ShipmentID = _Shipment.Id.ToString(),
BookingRequestTitle = txtTitle.Text,
BookingRequestDescription = txtDescription.Text,
CallerID = _Shipment.Contracter,
CustomerID = _Shipment.Contractee,
BookingRequestInfo = new BookingRequestInfo()
{
From = quoteInfo.From,
To = quoteInfo.To,
ContainerSize = (BookingRequestInfoContainerSize)(quoteInfo.ContainerSize.GetValueOrDefault()),
ContainerType = (BookingRequestInfoContainerType)(quoteInfo.ContainerType.GetValueOrDefault()),
CargoNature = (BookingRequestInfoCargoNature)(new CargoNatureValueTypeConverter()).ConvertBack(quoteInfo.CargoNature, typeof(BookingRequestInfoCargoNature), null, null),
Place = (BookingRequestInfoPlace)(cboShippingplace.SelectedIndex),
Quantity = int.Parse(txtQuantity.Text),
Shipper = _Shipment.Contractee,
Weight = int.Parse(txtWeight.Text)
}
};
var result = await httpServiceProxy.CreateBookingRequestAsync(_Shipment.Id.ToString(), bookingRequestInfo);
Debug.WriteLine(JsonConvert.SerializeObject(result));
}
}
}

Просмотреть файл

@ -0,0 +1,136 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{BDA70AC9-EBFB-4626-A3F5-697C03411E67}</ProjectGuid>
<OutputType>WinExe</OutputType>
<RootNamespace>CargoSmart.Windows.Booking</RootNamespace>
<AssemblyName>CargoSmartTokenApp</AssemblyName>
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<WarningLevel>4</WarningLevel>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<Deterministic>true</Deterministic>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Configuration" />
<Reference Include="System.Data" />
<Reference Include="System.Runtime.Serialization" />
<Reference Include="System.Xml" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xaml">
<RequiredTargetFramework>4.0</RequiredTargetFramework>
</Reference>
<Reference Include="WindowsBase" />
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
</ItemGroup>
<ItemGroup>
<ApplicationDefinition Include="App.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</ApplicationDefinition>
<Page Include="BookingConfirmation.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="BookingRequest.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="OrderManagement.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Compile Include="App.xaml.cs">
<DependentUpon>App.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Compile Include="BookingConfirmation.xaml.cs">
<DependentUpon>BookingConfirmation.xaml</DependentUpon>
</Compile>
<Compile Include="BookingRequest.xaml.cs">
<DependentUpon>BookingRequest.xaml</DependentUpon>
</Compile>
<Compile Include="Entities\User.cs" />
<Compile Include="FieldConverter\CargoNatureValueConverter.cs" />
<Compile Include="FieldConverter\ContainerSizeValueConverter.cs" />
<Compile Include="FieldConverter\ContainerTypeValueConverter.cs" />
<Compile Include="FieldConverter\CurrentStatusConverter.cs" />
<Compile Include="FieldConverter\CustomerNameConverter.cs" />
<Compile Include="FieldConverter\PlaceValueConverter.cs" />
<Compile Include="Quotation.xaml.cs">
<DependentUpon>Quotation.xaml</DependentUpon>
</Compile>
<Compile Include="ServiceProxy\HttpServiceLocator.cs" />
<Compile Include="ServiceProxy\HttpServiceProxy.cs" />
<Compile Include="OrderManagement.xaml.cs">
<DependentUpon>OrderManagement.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Page Include="Quotation.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<Compile Include="Properties\Settings.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
<Compile Include="ServiceProxy\HttpServiceProxy.Partial.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json">
<Version>12.0.3</Version>
</PackageReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

Просмотреть файл

@ -0,0 +1,37 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using System.Collections.Generic;
using System.Configuration;
namespace CargoSmart.Windows.Booking.Entities
{
public class User
{
public string UserName { get; set; }
public string Address { get; set; }
public Role Role { get; set; }
private static List<User> _users;
public static List<User> GetUserAccounts()
{
if (User._users != null && _users.Count > 0) return _users;
User._users = new List<User>();
User._users.Add(new User() { UserName = "Contoso Cargo", Address = ConfigurationManager.AppSettings["ContosoCargo_Id"], Role = Role.Carrier });
User._users.Add(new User() { UserName = "Shipper A", Address = ConfigurationManager.AppSettings["ShipperA_Id"], Role = Role.Shipper });
User._users.Add(new User() { UserName = "Shipper B", Address = ConfigurationManager.AppSettings["ShipperB_Id"], Role = Role.Shipper });
return User._users;
}
}
public enum Role
{
Shipper,
Carrier,
Trucker
}
}

Просмотреть файл

@ -0,0 +1,44 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using CargoSmart.Windows.Booking.ServiceProxy;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Data;
namespace CargoSmart.Windows.Booking.FieldConverter
{
public class CargoNatureValueTypeConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
switch (value)
{
case BookingRequestCargoNature._0:
return "Normal";
case BookingRequestCargoNature._1:
return "Dangerous";
default:
return null;
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
switch (value)
{
case "Normal":
return BookingRequestCargoNature._0;
case "Dangerous":
return BookingRequestCargoNature._1;
default:
return null;
}
}
}
}

Просмотреть файл

@ -0,0 +1,67 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using CargoSmart.Windows.Booking.ServiceProxy;
using System;
using System.CodeDom;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Data;
namespace CargoSmart.Windows.Booking.FieldConverter
{
public class ContainerSizeValueConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
switch (value)
{
case QuoteInfoContainerSize._0:
case BookingRequestContainerSize._0:
return "Large";
case QuoteInfoContainerSize._1:
case BookingRequestContainerSize._1:
return "Medium";
case QuoteInfoContainerSize._2:
case BookingRequestContainerSize._2:
return "Small";
default:
return null;
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
//throw new NotImplementedException();
switch (value)
{
case "Large":
if (targetType == typeof(BookingRequestInfoContainerSize))
{
return BookingRequestInfoContainerSize._0;
}
return null;
case "Medium":
if (targetType == typeof(BookingRequestInfoContainerSize))
{
return BookingRequestInfoContainerSize._1;
}
return null;
case "Small":
//return "Small";
if (targetType == typeof(BookingRequestInfoContainerSize))
{
return BookingRequestInfoContainerSize._2;
}
return null;
default:
return null;
}
}
}
}

Просмотреть файл

@ -0,0 +1,65 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using CargoSmart.Windows.Booking.ServiceProxy;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Data;
namespace CargoSmart.Windows.Booking.FieldConverter
{
public class ContainerTypeValueConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
switch (value)
{
case QuoteInfoContainerType._0:
case BookingRequestContainerType._0:
return "Type A";
case QuoteInfoContainerType._1:
case BookingRequestContainerType._1:
return "Type B";
case QuoteInfoContainerType._2:
case BookingRequestContainerType._2:
return "Type C";
default:
return null;
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
switch (value)
{
case "Type A":
if (targetType == typeof(BookingRequestContainerType))
{
return BookingRequestContainerType._0;
}
return null;
case "Type B":
if (targetType == typeof(BookingRequestContainerType))
{
return BookingRequestContainerType._1;
}
return null;
case "Type C":
if (targetType == typeof(BookingRequestContainerType))
{
return BookingRequestContainerType._2;
}
return null;
default:
return null;
}
}
}
}

Просмотреть файл

@ -0,0 +1,51 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using System;
using System.Globalization;
using System.Windows.Data;
using CargoSmart.Windows.Booking.ServiceProxy;
namespace CargoSmart.Windows.Booking.FieldConverter
{
public class CurrentStatusConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
switch (value)
{
case CargoTokenShipmentCurrentStatus._0:
return "Quotation Requested";
case CargoTokenShipmentCurrentStatus._1:
return "Quoted";
case CargoTokenShipmentCurrentStatus._2:
return "Booking Reuqest";
case CargoTokenShipmentCurrentStatus._3:
return "Booking Confirmed";
case CargoTokenShipmentCurrentStatus._4:
return "Job Order Sent";
default:
return "";
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
switch (value)
{
case "Quotation Requested":
return CargoTokenShipmentCurrentStatus._0;
case "Quoted":
return CargoTokenShipmentCurrentStatus._1;
case "Booking Reuqest":
return CargoTokenShipmentCurrentStatus._2;
case "Booking Confirmed":
return CargoTokenShipmentCurrentStatus._3;
case "Job Order Sent":
return CargoTokenShipmentCurrentStatus._4;
default:
return null;
}
}
}
}

Просмотреть файл

@ -0,0 +1,33 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using CargoSmart.Windows.Booking.Entities;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Data;
namespace CargoSmart.Windows.Booking.FieldConverter
{
public class CustomerNameConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var user =
User.GetUserAccounts().Where<User>(x => x.Address == value.ToString()).FirstOrDefault();
return (user != null) ? user.UserName : "";
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
var user =
User.GetUserAccounts().Where<User>(x => x.UserName == value.ToString()).FirstOrDefault();
return (user != null) ? user.Address : "";
}
}
}

Просмотреть файл

@ -0,0 +1,41 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using CargoSmart.Windows.Booking.ServiceProxy;
using System;
using System.Globalization;
using System.Windows.Data;
namespace CargoSmart.Windows.Booking.FieldConverter
{
public class PlaceValueTypeConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
switch (value)
{
case BookingRequestPlace._0:
return "Yard";
case BookingRequestPlace._1:
return "Door";
default:
return null;
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
//throw new NotImplementedException();
switch (value)
{
case "Yard":
return BookingRequestPlace._0;
case "Door":
return BookingRequestPlace._1;
default:
return null;
}
}
}
}

Просмотреть файл

@ -0,0 +1,520 @@
<Window x:Class="CargoSmart.Windows.Booking.OrderManager"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:CargoSmart.Windows.Booking"
xmlns:converter="clr-namespace:CargoSmart.Windows.Booking.FieldConverter"
mc:Ignorable="d"
Title="Managing Booking Order" Height="777.667" Width="800">
<Window.Resources>
<converter:CurrentStatusConverter x:Key="CurrentStatusConverter"/>
<converter:CustomerNameConverter x:Key="CustomerNameConverter"/>
<converter:ContainerSizeValueConverter x:Key="ContainerSizeValueConverter"/>
<converter:ContainerTypeValueConverter x:Key="ContainerTypeValueConverter"/>
<converter:PlaceValueTypeConverter x:Key="PlaceValueTypeConverter"/>
<converter:CargoNatureValueTypeConverter x:Key="CargoNatureValueTypeConverter"/>
<DataTemplate x:Key="ListViewControlTemplate_Shipment">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="65"></ColumnDefinition>
<ColumnDefinition Width="385"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="40"></RowDefinition>
<RowDefinition Height="40"></RowDefinition>
</Grid.RowDefinitions>
<WrapPanel Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" VerticalAlignment="Center">
<TextBlock Text="{Binding Contractee, Converter={StaticResource CustomerNameConverter}}"/>
<TextBlock Text="- Contract Time : "/>
<TextBlock Text="{Binding CreatedTime}"/>
</WrapPanel>
<TextBlock Grid.Row="1" Grid.Column="0" Text="Status :" Margin="0,0,23,0" VerticalAlignment="Center" />
<TextBlock Grid.Row="1" Grid.Column="1" Text="{Binding CurrentStatus, Converter={StaticResource CurrentStatusConverter}}" VerticalAlignment="Center" />
</Grid>
</DataTemplate>
<Style x:Key="TextBlockStyle" TargetType="TextBlock">
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="TextWrapping" Value="Wrap"/>
</Style>
<Style x:Key="LabelStyle" TargetType="{x:Type Label}">
<Setter Property="Padding" Value="10,0,0,0"/>
<Setter Property="Margin" Value="0,0,0,0"/>
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<Setter Property="VerticalAlignment" Value="Stretch"/>
<Setter Property="HorizontalAlignment" Value="Left"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
</Style>
<Style x:Key="TextBoxStyle" TargetType="{x:Type TextBox}">
<Setter Property="Margin" Value="3,3,10,3"/>
</Style>
<Style x:Key="alternatingListViewItemStyle" TargetType="{x:Type ListViewItem}">
<Style.Triggers>
<!-- setting up triggers for alternate background colors -->
<Trigger Property="ItemsControl.AlternationIndex" Value="1">
<Setter Property="Background" Value="AliceBlue"></Setter>
</Trigger>
<Trigger Property="ItemsControl.AlternationIndex" Value="2">
<Setter Property="Background" Value="White"></Setter>
</Trigger>
</Style.Triggers>
<!-- setting row height here -->
<!--
<Setter Property="Height" Value="30" />-->
</Style>
</Window.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="343*"/>
<ColumnDefinition Width="5"/>
<ColumnDefinition Width="451*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="0"/>
<RowDefinition Height="42"/>
<RowDefinition Height="42"/>
<RowDefinition/>
<RowDefinition Height="20"/>
</Grid.RowDefinitions>
<Grid Grid.Row="1" Grid.Column="0" Grid.RowSpan="2">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="48*"/>
<ColumnDefinition Width="100"/>
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.Column="0" Content="Party : " Style="{StaticResource LabelStyle}" Width="45"/>
<ComboBox Grid.Row="0" Grid.Column="1" x:Name="cboUser" SelectionChanged="cboUser_SelectionChanged" VerticalAlignment="Center" HorizontalAlignment="Stretch" Margin="5,10" Height="22"/>
<Button x:Name="btnCreateQuoteRequest" Grid.Row="0" Grid.Column="2" Margin="3,10" Content="Request Quote" Click="btnCreateQuoteRequest_Click"/>
<Label Grid.Row="1" Grid.Column="0" Content="Booking Status :" Style="{StaticResource LabelStyle}" Width="139" />
<ComboBox Grid.Row="1" Grid.Column="1" x:Name="cboFilter" SelectionChanged="cboFilter_SelectionChanged" VerticalAlignment="Center" HorizontalAlignment="Stretch" Margin="5,10" Height="22" />
<Button x:Name="btnRefresh" Grid.Column="2" Grid.Row="1" Content="Refresh" Margin="3,10" Click="btnRefresh_Click" />
</Grid>
<GridSplitter Grid.Column="1" Width="5" HorizontalAlignment="Stretch" />
<ListView x:Name="lstShipments" Grid.Row="3" SelectionChanged="lstShipments_SelectionChanged" ItemContainerStyle="{StaticResource alternatingListViewItemStyle}" AlternationCount="2" ItemTemplate="{DynamicResource ListViewControlTemplate_Shipment}" Margin="5,5"/>
<TabControl Grid.Row="1" Grid.Column="2" Margin="0,7,10,10" Grid.RowSpan="3" x:Name="tabProcess">
<TabItem Header="Quotation Request Information" x:Name="tabQuoteRequest">
<Grid Background="#FFE5E5E5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20"/>
<ColumnDefinition Width="119*"/>
<ColumnDefinition Width="210*"/>
<ColumnDefinition Width="82*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="15"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition/>
</Grid.RowDefinitions>
<!--<Grid HorizontalAlignment="Left" Height="100" Margin="7,18,0,0" VerticalAlignment="Top" Width="100" Grid.Column="1" Grid.RowSpan="4" Grid.Row="3"/>-->
<!--- Customer Name-->
<TextBlock Grid.Column="1" Text="Shipper :" Grid.Row="1" Style="{StaticResource TextBlockStyle}" Margin="0,7" Height="16" />
<WrapPanel Grid.Column="2" Grid.Row="1" Grid.ColumnSpan="2" VerticalAlignment="Center" Margin="0,7" Height="16">
<TextBlock Text="{Binding Contractee, Converter={StaticResource CustomerNameConverter}}" Style="{StaticResource TextBlockStyle}"/>
<TextBlock TextWrapping="Wrap" Text=" ( " Style="{StaticResource TextBlockStyle}"/>
<TextBlock TextWrapping="Wrap" Text="{Binding Contractee}" Style="{StaticResource TextBlockStyle}"/>
<TextBlock TextWrapping="Wrap" Text=" )" Style="{StaticResource TextBlockStyle}"/>
</WrapPanel>
<!--Carrier-->
<TextBlock Grid.Column="1" Text="Carrier :" Grid.Row="2" Style="{StaticResource TextBlockStyle}" Margin="0,7" Height="16" />
<WrapPanel Grid.Column="2" Grid.Row="2" Grid.ColumnSpan="2" VerticalAlignment="Center" Margin="0,7" Height="16">
<TextBlock Text="{Binding Contracter, Converter={StaticResource CustomerNameConverter}}" Style="{StaticResource TextBlockStyle}"/>
<TextBlock TextWrapping="Wrap" Text=" ( " Style="{StaticResource TextBlockStyle}"/>
<TextBlock TextWrapping="Wrap" Text="{Binding Contracter}" Style="{StaticResource TextBlockStyle}"/>
<TextBlock TextWrapping="Wrap" Text=" )" Style="{StaticResource TextBlockStyle}"/>
</WrapPanel>
<!--- Token ID-->
<TextBlock Grid.Column="1" Grid.Row="3" Text="Token ID :" Style="{StaticResource TextBlockStyle}" Margin="0,7" Height="16" />
<TextBlock Grid.Column="2" Grid.Row="3" Text="{Binding QuoteRequestTokenInfo.TokenID}" Grid.ColumnSpan="2" Style="{StaticResource TextBlockStyle}" Margin="0,7" Height="16" />
<!--Minted Token Title-->
<TextBlock Grid.Column="1" Grid.Row="4" Text="QuoteRequest Token :" Style="{StaticResource TextBlockStyle}" Margin="0,7" Height="16" />
<WrapPanel Grid.Column="2" VerticalAlignment="top" Grid.Row="4" Grid.RowSpan="3" Margin="0,5,0,0" Height="60" Grid.ColumnSpan="2">
<TextBlock Text="{Binding QuoteRequestTokenInfo.MintedTokenTitle}" Style="{StaticResource TextBlockStyle}" />
<TextBlock Text=" - " Style="{StaticResource TextBlockStyle}"/>
<TextBlock Text="{Binding QuoteRequestTokenInfo.MintedTokenDescription}" Style="{StaticResource TextBlockStyle}"/>
</WrapPanel>
<TextBlock Grid.Column="1" Grid.Row="6" Text="Minted Date :" Style="{StaticResource TextBlockStyle}" Margin="0,7" Height="16"/>
<TextBlock Grid.Column="2" Grid.Row="6" Text="{Binding QuoteRequestTokenInfo.TokenMintedDate}" Style="{StaticResource TextBlockStyle}" HorizontalAlignment="Stretch" Grid.ColumnSpan="2" Margin="0,7" Height="16" />
<TextBlock Grid.Column="1" Grid.Row="7" Text="Business Data :" Style="{StaticResource TextBlockStyle}" Margin="0,7" Height="16" />
<Button Content="Validate Business Entity from Ledger" Grid.Column="2" HorizontalAlignment="Left" Margin="1,5,0,0" Grid.Row="7" VerticalAlignment="Top" Width="221" Click="ValidateBusinessEntityButton_Click" Grid.ColumnSpan="2" Height="20"/>
<Grid Grid.Column="1" Grid.Row="8" Margin="0,0,0,0" Grid.RowSpan="6" Grid.ColumnSpan="3" x:Name="QuotationRequestDataEntityGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="123*"/>
<ColumnDefinition Width="293*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
</Grid.RowDefinitions>
<TextBlock Grid.Column="0" Text="From : " Style="{StaticResource TextBlockStyle}" Grid.ColumnSpan="2" Height="16" Margin="0,0,295,0" />
<TextBlock Grid.Column="1" Text="{Binding From}" Style="{StaticResource TextBlockStyle}" Height="16" />
<TextBlock Grid.Column="0" Grid.Row="1" Text="To : " Style="{StaticResource TextBlockStyle}" Grid.ColumnSpan="2" Height="16" Margin="0,0,295,0" />
<TextBlock Grid.Column="1" Grid.Row="1" Text="{Binding To}" Style="{StaticResource TextBlockStyle}" Height="16" />
<TextBlock Grid.Column="0" Grid.Row="2" Text="CargoNature : " Style="{StaticResource TextBlockStyle}" Grid.ColumnSpan="2" Height="16" Margin="0,0,295,0" />
<TextBlock Grid.Column="1" Grid.Row="2" Text="{Binding CargoNature}" Style="{StaticResource TextBlockStyle}" Height="16" />
<TextBlock Grid.Column="0" Grid.Row="3" Text="Container Size : " Style="{StaticResource TextBlockStyle}" Grid.ColumnSpan="2" Height="16" Margin="0,0,295,0" />
<TextBlock Grid.Column="1" Grid.Row="3" Text="{Binding ContainerSize, Converter={StaticResource ContainerSizeValueConverter}}" Style="{StaticResource TextBlockStyle}" Height="16" />
<TextBlock Grid.Column="0" Grid.Row="4" Text="Container Type : " Style="{StaticResource TextBlockStyle}" Grid.ColumnSpan="2" Height="16" Margin="0,0,295,0" />
<TextBlock Grid.Column="1" Grid.Row="4" Text="{Binding ContainerType, Converter={StaticResource ContainerTypeValueConverter}}" Style="{StaticResource TextBlockStyle}" Height="16" />
<TextBlock Grid.Column="0" Grid.Row="5" Text="Cargo Ready Date : " Style="{StaticResource TextBlockStyle}" Grid.ColumnSpan="2" Height="16" Margin="0,0,295,0" />
<TextBlock Grid.Column="1" Grid.Row="5" Text="{Binding CargoReadyDate}" Style="{StaticResource TextBlockStyle}" Height="16" />
<Button Grid.Row="6" x:Name="btnCreateQuotation" Content="Send Quotation" Click="btnCreateQuotation_Click" Margin="0,0,77,0" Grid.Column="1"/>
</Grid>
</Grid>
</TabItem>
<TabItem Header="Quotation Information" x:Name="tabQuote">
<Grid Background="#FFE5E5E5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20"/>
<ColumnDefinition Width="110*"/>
<ColumnDefinition Width="8*"/>
<ColumnDefinition Width="297*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="15"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition/>
</Grid.RowDefinitions>
<!--<Grid HorizontalAlignment="Left" Height="100" Margin="7,18,0,0" VerticalAlignment="Top" Width="100" Grid.Column="1" Grid.RowSpan="4" Grid.Row="3"/>-->
<!--- Customer Name-->
<TextBlock Grid.Column="1" Text="Shipper :" Grid.Row="1" Style="{StaticResource TextBlockStyle}" Margin="0,7" Height="16" />
<WrapPanel Grid.Column="2" Grid.Row="1" Grid.ColumnSpan="2" VerticalAlignment="Center" Margin="0,7" Height="16">
<TextBlock Text="{Binding Contractee, Converter={StaticResource CustomerNameConverter}}" Style="{StaticResource TextBlockStyle}"/>
<TextBlock TextWrapping="Wrap" Text=" ( " Style="{StaticResource TextBlockStyle}"/>
<TextBlock TextWrapping="Wrap" Text="{Binding Contractee}" Style="{StaticResource TextBlockStyle}"/>
<TextBlock TextWrapping="Wrap" Text=" )" Style="{StaticResource TextBlockStyle}"/>
</WrapPanel>
<!--Carrier-->
<TextBlock Grid.Column="1" Text="Carrier :" Grid.Row="2" Style="{StaticResource TextBlockStyle}" Margin="0,7" Height="16" />
<WrapPanel Grid.Column="2" Grid.Row="2" Grid.ColumnSpan="2" VerticalAlignment="Center" Margin="0,7" Height="16">
<TextBlock Text="{Binding Contracter, Converter={StaticResource CustomerNameConverter}}" Style="{StaticResource TextBlockStyle}"/>
<TextBlock TextWrapping="Wrap" Text=" ( " Style="{StaticResource TextBlockStyle}"/>
<TextBlock TextWrapping="Wrap" Text="{Binding Contracter}" Style="{StaticResource TextBlockStyle}"/>
<TextBlock TextWrapping="Wrap" Text=" )" Style="{StaticResource TextBlockStyle}"/>
</WrapPanel>
<!--- Token ID-->
<TextBlock Grid.Column="1" Grid.Row="3" Text="Token ID :" Style="{StaticResource TextBlockStyle}" />
<TextBlock Grid.Column="2" Grid.Row="3" Text="{Binding QuotedTokenInfo.TokenID}" Grid.ColumnSpan="2" Style="{StaticResource TextBlockStyle}"/>
<!--Minted Token Title-->
<TextBlock Grid.Column="1" Grid.Row="4" Text="Quoted Token :" Style="{StaticResource TextBlockStyle}" />
<WrapPanel Grid.Column="2" VerticalAlignment="top" Grid.Row="4" Grid.RowSpan="3" Margin="0,5,0,0" Height="60" Grid.ColumnSpan="2">
<TextBlock Text="{Binding QuotedTokenInfo.MintedTokenTitle}" Style="{StaticResource TextBlockStyle}" />
<TextBlock Text=" - " Style="{StaticResource TextBlockStyle}"/>
<TextBlock Text="{Binding QuotedTokenInfo.MintedTokenDescription}" Style="{StaticResource TextBlockStyle}"/>
</WrapPanel>
<TextBlock Grid.Column="1" Grid.Row="6" Text="Minted Date :" Style="{StaticResource TextBlockStyle}"/>
<TextBlock Grid.Column="2" Grid.Row="6" Text="{Binding QuotedTokenInfo.TokenMintedDate}" Grid.ColumnSpan="2" Style="{StaticResource TextBlockStyle}" />
<TextBlock Grid.Column="1" Grid.Row="7" Text="Business Data :" Style="{StaticResource TextBlockStyle}" />
<Button Content="Validate Business Entity from Ledger" Grid.Column="2" HorizontalAlignment="Left" Margin="5,5,0,0" Grid.Row="7" VerticalAlignment="Top" Width="221" Click="ValidateBusinessEntityButton_Click" Grid.ColumnSpan="2"/>
<Grid Grid.Column="1" Grid.Row="8" Margin="0,0,0,0" Grid.RowSpan="6" Grid.ColumnSpan="3" x:Name="QuotationDataEntityGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="22*"/>
<ColumnDefinition Width="61*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
</Grid.RowDefinitions>
<TextBlock Grid.Column="0" Grid.Row="0" Text="From : " Style="{StaticResource TextBlockStyle}"/>
<TextBlock Grid.Column="1" Grid.Row="0" Text="{Binding From}" Style="{StaticResource TextBlockStyle}" />
<TextBlock Grid.Column="0" Grid.Row="1" Text="To : " Style="{StaticResource TextBlockStyle}" />
<TextBlock Grid.Column="1" Grid.Row="1" Text="{Binding To}" Style="{StaticResource TextBlockStyle}" />
<TextBlock Grid.Column="0" Grid.Row="2" Text="CargoNature : " Style="{StaticResource TextBlockStyle}" />
<TextBlock Grid.Column="1" Grid.Row="2" Text="{Binding CargoNature}" Style="{StaticResource TextBlockStyle}" />
<TextBlock Grid.Column="0" Grid.Row="3" Text="Container Size : " Style="{StaticResource TextBlockStyle}" />
<TextBlock Grid.Column="1" Grid.Row="3" Text="{Binding ContainerSize, Converter={StaticResource ContainerSizeValueConverter}}" Style="{StaticResource TextBlockStyle}" />
<TextBlock Grid.Column="0" Grid.Row="4" Text="Container Type : " Style="{StaticResource TextBlockStyle}" />
<TextBlock Grid.Column="1" Grid.Row="4" Text="{Binding ContainerType, Converter={StaticResource ContainerTypeValueConverter}}" Style="{StaticResource TextBlockStyle}" />
<TextBlock Grid.Column="0" Grid.Row="5" Text="Cargo Ready Date : " Style="{StaticResource TextBlockStyle}" />
<TextBlock Grid.Column="1" Grid.Row="5" Text="{Binding CargoReadyDate}" Style="{StaticResource TextBlockStyle}" />
<Button Grid.Row="6" Grid.Column="1" x:Name="btnCreateBookingRequest" Content="Booking Request" Margin="0,0,77,0" Click="btnCreateBookingRequest_Click"/>
</Grid>
</Grid>
</TabItem>
<TabItem Header="Booking Request Information" x:Name="tabBookingRequest">
<Grid Background="#FFE5E5E5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20"/>
<ColumnDefinition Width="22*"/>
<ColumnDefinition Width="61*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="15"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition/>
</Grid.RowDefinitions>
<!--- Customer Name-->
<TextBlock Grid.Column="1" Text="Shipper :" Grid.Row="1" Style="{StaticResource TextBlockStyle}" Margin="0,7" Height="16" />
<WrapPanel Grid.Column="2" Grid.Row="1" Grid.ColumnSpan="2" VerticalAlignment="Center" Margin="0,7" Height="16">
<TextBlock Text="{Binding Contractee, Converter={StaticResource CustomerNameConverter}}" Style="{StaticResource TextBlockStyle}"/>
<TextBlock TextWrapping="Wrap" Text=" ( " Style="{StaticResource TextBlockStyle}"/>
<TextBlock TextWrapping="Wrap" Text="{Binding Contractee}" Style="{StaticResource TextBlockStyle}"/>
<TextBlock TextWrapping="Wrap" Text=" )" Style="{StaticResource TextBlockStyle}"/>
</WrapPanel>
<!--Carrier-->
<TextBlock Grid.Column="1" Text="Carrier :" Grid.Row="2" Style="{StaticResource TextBlockStyle}" Margin="0,7" Height="16" />
<WrapPanel Grid.Column="2" Grid.Row="2" Grid.ColumnSpan="2" VerticalAlignment="Center" Margin="0,7" Height="16">
<TextBlock Text="{Binding Contracter, Converter={StaticResource CustomerNameConverter}}" Style="{StaticResource TextBlockStyle}"/>
<TextBlock TextWrapping="Wrap" Text=" ( " Style="{StaticResource TextBlockStyle}"/>
<TextBlock TextWrapping="Wrap" Text="{Binding Contracter}" Style="{StaticResource TextBlockStyle}"/>
<TextBlock TextWrapping="Wrap" Text=" )" Style="{StaticResource TextBlockStyle}"/>
</WrapPanel>
<!--- Token ID-->
<TextBlock Grid.Column="1" Grid.Row="3" Text="Token ID :" Style="{StaticResource TextBlockStyle}" />
<TextBlock Grid.Column="2" Grid.Row="3" Text="{Binding BookingRequestTokenInfo.TokenID}" Style="{StaticResource TextBlockStyle}" />
<!--Minted Token Title-->
<TextBlock Grid.Column="1" Grid.Row="4" Text="Quoted Token :" Style="{StaticResource TextBlockStyle}" />
<WrapPanel Grid.Column="2" VerticalAlignment="top" Grid.Row="4" Grid.RowSpan="3" Margin="0,5,0,0" Height="60" Grid.ColumnSpan="2">
<TextBlock Text="{Binding BookingRequestTokenInfo.MintedTokenTitle}" Style="{StaticResource TextBlockStyle}"/>
<TextBlock Text=" - " Style="{StaticResource TextBlockStyle}"/>
<TextBlock Text="{Binding BookingRequestTokenInfo.MintedTokenDescription}" Style="{StaticResource TextBlockStyle}"/>
</WrapPanel>
<TextBlock Grid.Column="1" Grid.Row="6" Text="Minted Date :" Style="{StaticResource TextBlockStyle}" />
<TextBlock Grid.Column="2" Grid.Row="6" Text="{Binding BookingRequestTokenInfo.TokenMintedDate}" Grid.ColumnSpan="2" Style="{StaticResource TextBlockStyle}" />
<TextBlock Grid.Column="1" Grid.Row="7" Text="Business Data :" Style="{StaticResource TextBlockStyle}" />
<Button Content="Validate Business Entity from Ledger" Grid.Column="2" HorizontalAlignment="Left" Margin="5,9,0,0" Grid.Row="7" VerticalAlignment="Top" Width="221" Click="ValidateBusinessEntityButton_Click" Grid.ColumnSpan="2"/>
<Grid Grid.Column="1" Grid.Row="8" Margin="0,0,0,0" Grid.RowSpan="6" Grid.ColumnSpan="3" x:Name="BookingReuqestDataEntityGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="22*"/>
<ColumnDefinition Width="61*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
</Grid.RowDefinitions>
<TextBlock Grid.Column="0" Grid.Row="0" Text="From : " Style="{StaticResource TextBlockStyle}" />
<TextBlock Grid.Column="1" Grid.Row="0" Text="{Binding From}" Style="{StaticResource TextBlockStyle}" />
<TextBlock Grid.Column="0" Grid.Row="1" Text="To : " Style="{StaticResource TextBlockStyle}" />
<TextBlock Grid.Column="1" Grid.Row="1" Text="{Binding To}" Style="{StaticResource TextBlockStyle}" />
<TextBlock Grid.Column="0" Grid.Row="2" Text="CargoNature : " Style="{StaticResource TextBlockStyle}" />
<TextBlock Grid.Column="1" Grid.Row="2" Text="{Binding CargoNature, Converter={StaticResource CargoNatureValueTypeConverter} }" Style="{StaticResource TextBlockStyle}" />
<TextBlock Grid.Column="0" Grid.Row="3" Text="Container Size : " Style="{StaticResource TextBlockStyle}"/>
<TextBlock Grid.Column="1" Grid.Row="3" Text="{Binding ContainerSize, Converter={StaticResource ContainerSizeValueConverter}}" Style="{StaticResource TextBlockStyle}" />
<TextBlock Grid.Column="0" Grid.Row="4" Text="Container Type : " Style="{StaticResource TextBlockStyle}" />
<TextBlock Grid.Column="1" Grid.Row="4" Text="{Binding ContainerType, Converter={StaticResource ContainerTypeValueConverter} }" Style="{StaticResource TextBlockStyle}" />
<TextBlock Grid.Column="0" Grid.Row="5" Text="Quantity : " Style="{StaticResource TextBlockStyle}" />
<TextBlock Grid.Column="1" Grid.Row="5" Text="{Binding Quantity }" Style="{StaticResource TextBlockStyle}" />
<TextBlock Grid.Column="0" Grid.Row="6" Text="Place : " Style="{StaticResource TextBlockStyle}" />
<TextBlock Grid.Column="1" Grid.Row="6" Text="{Binding Place, Converter={StaticResource PlaceValueTypeConverter} }" Style="{StaticResource TextBlockStyle}" />
<TextBlock Grid.Column="0" Grid.Row="7" Text="Weight : " Style="{StaticResource TextBlockStyle}" />
<TextBlock Grid.Column="1" Grid.Row="7" Text="{Binding Weight }" Style="{StaticResource TextBlockStyle}" />
<Button Grid.Row="8" Grid.Column="1" x:Name="btnCreateBookingConfirmation" Content="Booking Confirmation" Margin="6,4" Click="btnCreateBookingConfirmation_Click"/>
</Grid>
</Grid>
</TabItem>
<TabItem Header="Booking Confirmation Information" x:Name="tabBookingConfirmation">
<Grid Background="#FFE5E5E5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20"/>
<ColumnDefinition Width="22*"/>
<ColumnDefinition Width="61*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="15"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition/>
</Grid.RowDefinitions>
<!--- Customer Name-->
<TextBlock Grid.Column="1" Text="Shipper :" Grid.Row="1" Style="{StaticResource TextBlockStyle}" Margin="0,7" Height="16" />
<WrapPanel Grid.Column="2" Grid.Row="1" Grid.ColumnSpan="2" VerticalAlignment="Center" Margin="0,7" Height="16">
<TextBlock Text="{Binding Contractee, Converter={StaticResource CustomerNameConverter}}" Style="{StaticResource TextBlockStyle}"/>
<TextBlock TextWrapping="Wrap" Text=" ( " Style="{StaticResource TextBlockStyle}"/>
<TextBlock TextWrapping="Wrap" Text="{Binding Contractee}" Style="{StaticResource TextBlockStyle}"/>
<TextBlock TextWrapping="Wrap" Text=" )" Style="{StaticResource TextBlockStyle}"/>
</WrapPanel>
<!--Carrier-->
<TextBlock Grid.Column="1" Text="Carrier :" Grid.Row="2" Style="{StaticResource TextBlockStyle}" Margin="0,7" Height="16" />
<WrapPanel Grid.Column="2" Grid.Row="2" Grid.ColumnSpan="2" VerticalAlignment="Center" Margin="0,7" Height="16">
<TextBlock Text="{Binding Contracter, Converter={StaticResource CustomerNameConverter}}" Style="{StaticResource TextBlockStyle}"/>
<TextBlock TextWrapping="Wrap" Text=" ( " Style="{StaticResource TextBlockStyle}"/>
<TextBlock TextWrapping="Wrap" Text="{Binding Contracter}" Style="{StaticResource TextBlockStyle}"/>
<TextBlock TextWrapping="Wrap" Text=" )" Style="{StaticResource TextBlockStyle}"/>
</WrapPanel>
<!--- Token ID-->
<TextBlock Grid.Column="1" Grid.Row="3" Text="Token ID :" Style="{StaticResource TextBlockStyle}" />
<TextBlock Grid.Column="2" Grid.Row="3" Text="{Binding BookedTokenInfo.TokenID}" Grid.ColumnSpan="2" Style="{StaticResource TextBlockStyle}" />
<!--Minted Token Title-->
<TextBlock Grid.Column="1" Grid.Row="4" Text="Quoted Token :" Style="{StaticResource TextBlockStyle}" />
<WrapPanel Grid.Column="2" VerticalAlignment="top" Grid.Row="4" Grid.RowSpan="3" Margin="0,5,0,0" Height="60" Grid.ColumnSpan="2">
<TextBlock Text="{Binding BookedTokenInfo.MintedTokenTitle}" Style="{StaticResource TextBlockStyle}" />
<TextBlock Text=" - " Style="{StaticResource TextBlockStyle}"/>
<TextBlock Text="{Binding BookedTokenInfo.MintedTokenDescription}"/>
</WrapPanel>
<TextBlock Grid.Column="1" Grid.Row="6" Text="Minted Date :" Style="{StaticResource TextBlockStyle}" />
<TextBlock Grid.Column="2" Grid.Row="6" Text="{Binding BookedTokenInfo.TokenMintedDate}" Grid.ColumnSpan="2" Style="{StaticResource TextBlockStyle}" />
<TextBlock Grid.Column="1" Grid.Row="7" Text="Business Data :" Style="{StaticResource TextBlockStyle}" />
<Button Content="Validate Business Entity from Ledger" Grid.Column="2" HorizontalAlignment="Left" Margin="5,9,0,0" Grid.Row="7" VerticalAlignment="Top" Width="221" Click="ValidateBusinessEntityButton_Click" Grid.ColumnSpan="2"/>
<ScrollViewer Grid.Column="1" Grid.Row="8" Margin="0,0,0,0" Grid.RowSpan="6" Grid.ColumnSpan="3">
<Grid Grid.Column="1" Grid.Row="7" Margin="0,0,0,0" Grid.RowSpan="6" Grid.ColumnSpan="3" x:Name="BookingConfirmationDataEntityGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="187*"/>
<ColumnDefinition Width="207*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
</Grid.RowDefinitions>
<TextBlock Grid.Column="0" Grid.Row="0" Text="CyCutOff : " Style="{StaticResource TextBlockStyle}" Height="16" Margin="0,7"/>
<TextBlock Grid.Column="1" Grid.Row="0" Text="{Binding CyCutOff}" Style="{StaticResource TextBlockStyle}" Height="16" Margin="0,7" />
<TextBlock Grid.Column="0" Grid.Row="1" Text="SiCutOff : " Style="{StaticResource TextBlockStyle}" Height="16" Margin="0,7" />
<TextBlock Grid.Column="1" Grid.Row="1" Text="{Binding SiCutOff}" Style="{StaticResource TextBlockStyle}" Height="16" Margin="0,7" />
<TextBlock Grid.Column="0" Grid.Row="1" Text="Empty Container Pickup Location : " Style="{StaticResource TextBlockStyle}" Height="32" Margin="0,29" Grid.RowSpan="3" />
<TextBlock Grid.Column="1" Grid.Row="2" Text="{Binding EmptyContainerPickupLocation}" Style="{StaticResource TextBlockStyle}" Height="16" Margin="0,7" />
<TextBlock Grid.Column="0" Grid.Row="3" Text="Laden Container Return Location : " Style="{StaticResource TextBlockStyle}" />
<TextBlock Grid.Column="1" Grid.Row="3" Text="{Binding LadenContainerReturnLocation}" Style="{StaticResource TextBlockStyle}" />
<TextBlock Grid.Column="0" Grid.Row="4" Text="From : " Style="{StaticResource TextBlockStyle}" />
<TextBlock Grid.Column="1" Grid.Row="4" Text="{Binding BookingRequest.From}" Style="{StaticResource TextBlockStyle}" />
<TextBlock Grid.Column="0" Grid.Row="5" Text="To : " Style="{StaticResource TextBlockStyle}" />
<TextBlock Grid.Column="1" Grid.Row="5" Text="{Binding BookingRequest.To}" Style="{StaticResource TextBlockStyle}" />
<TextBlock Grid.Column="0" Grid.Row="6" Text="CargoNature : " Style="{StaticResource TextBlockStyle}" />
<TextBlock Grid.Column="1" Grid.Row="6" Text="{Binding BookingRequest.CargoNature, Converter={StaticResource CargoNatureValueTypeConverter} }" Style="{StaticResource TextBlockStyle}" />
<TextBlock Grid.Column="0" Grid.Row="7" Text="Container Size : " Style="{StaticResource TextBlockStyle}" />
<TextBlock Grid.Column="1" Grid.Row="7" Text="{Binding BookingRequest.ContainerSize, Converter={StaticResource ContainerSizeValueConverter}}" Style="{StaticResource TextBlockStyle}" />
<TextBlock Grid.Column="0" Grid.Row="8" Text="Container Type : " Style="{StaticResource TextBlockStyle}" />
<TextBlock Grid.Column="1" Grid.Row="8" Text="{Binding BookingRequest.ContainerType, Converter={StaticResource ContainerTypeValueConverter} }" Style="{StaticResource TextBlockStyle}" />
<TextBlock Grid.Column="0" Grid.Row="9" Text="Quantity : " Style="{StaticResource TextBlockStyle}" />
<TextBlock Grid.Column="1" Grid.Row="9" Text="{Binding BookingRequest.Quantity }" Style="{StaticResource TextBlockStyle}" />
<TextBlock Grid.Column="0" Grid.Row="10" Text="Weight : " Style="{StaticResource TextBlockStyle}" />
<TextBlock Grid.Column="1" Grid.Row="10" Text="{Binding BookingRequest.Weight }" Style="{StaticResource TextBlockStyle}" />
<TextBlock Grid.Column="0" Grid.Row="11" Text="Place : " Style="{StaticResource TextBlockStyle}" />
<TextBlock Grid.Column="1" Grid.Row="11" Text="{Binding BookingRequest.Place, Converter={StaticResource PlaceValueTypeConverter} }" Style="{StaticResource TextBlockStyle}" />
</Grid>
</ScrollViewer>
</Grid>
</TabItem>
</TabControl>
<Label x:Name="lblCreateQuoteRequest" Grid.Row="1" Grid.Column="2" Grid.RowSpan="3" VerticalAlignment="Stretch" HorizontalAlignment="Stretch"
VerticalContentAlignment="Center" HorizontalContentAlignment="Center" Content="Try to Create Quotation Request" FontSize="15" FontWeight="Bold" Visibility="Collapsed"/>
<ProgressBar x:Name="pgbProgress" Grid.Row="4" Grid.Column="0" Margin="3"/>
</Grid>
</Window>

Просмотреть файл

@ -0,0 +1,348 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using CargoSmart.Windows.Booking.Entities;
using CargoSmart.Windows.Booking.ServiceProxy;
using Newtonsoft.Json;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
namespace CargoSmart.Windows.Booking
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class OrderManager : Window
{
public OrderManager()
{
InitializeComponent();
InitializeData();
}
private void InitializeData()
{
SetupUserAccountCombo();
SetupFilterCombo();
}
private void SetupFilterCombo()
{
cboFilter.Items.Add("All");
cboFilter.Items.Add("Quote Request");
cboFilter.Items.Add("Quoted");
cboFilter.Items.Add("Booking Request");
cboFilter.Items.Add("Booked");
cboFilter.SelectedIndex = 0;
}
private void SetupUserAccountCombo()
{
cboUser.ItemsSource = User.GetUserAccounts();
cboUser.DisplayMemberPath = "UserName";
cboUser.SelectedValuePath = "Address";
cboUser.SelectedIndex = 0;
}
public async Task GetMyShipment(bool IsRefresh = false)
{
HttpServiceProxy proxy = HttpServiceLocator.GetHttpServiceProxy();
User selectedItem = cboUser.SelectedItem as User;
if (selectedItem != null)
{
var result =
await proxy.GetMyShipmentsAsync(new GetTokenShipmentsRequest() { CallerID = selectedItem.Address, IsContracter = (selectedItem.Role == Role.Carrier) });
lstShipments.ItemsSource = result;
if (result.Count > 0)
{
if (IsRefresh)
{
lstShipments.SelectedIndex = lstShipments.Items.Count - 1;
}
else
{
lstShipments.SelectedIndex = 0;
}
tabProcess.Visibility = Visibility.Visible;
lblCreateQuoteRequest.Visibility = Visibility.Collapsed;
} else
{
tabProcess.Visibility = Visibility.Collapsed;
lblCreateQuoteRequest.Visibility = Visibility.Visible;
}
}
}
private void lstShipments_SelectionChanged(object sender, RoutedEventArgs e)
{
if (lstShipments.SelectedItem == null) return;
CargoTokenShipment Shipment = lstShipments.SelectedItem as CargoTokenShipment;
this.DataContext = Shipment;
//Activate Tab by Current Status
this.tabProcess.SelectedIndex = (int)Shipment.CurrentStatus;
//Control Tab visibility by Status
this.tabQuoteRequest.Visibility = (Shipment.QuoteRequestTokenInfo == null) ? Visibility.Hidden : Visibility.Visible;
this.tabQuote.Visibility = (Shipment.QuotedTokenInfo == null) ? Visibility.Hidden : Visibility.Visible;
this.tabBookingRequest.Visibility = (Shipment.BookingRequestTokenInfo == null) ? Visibility.Hidden : Visibility.Visible;
this.tabBookingConfirmation.Visibility = (Shipment.BookedTokenInfo == null) ? Visibility.Hidden : Visibility.Visible;
if (Shipment.QuoteRequestTokenInfo != null)
{
//just in case
if (string.IsNullOrEmpty(Shipment.QuoteRequestTokenInfo.BusinessMetaData)) return;
//Deserialize business entity and set as DataContext
QuoteInfo quoteRequest = JsonConvert.DeserializeObject<QuoteInfo>(Shipment.QuoteRequestTokenInfo.BusinessMetaData, new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore });
this.QuotationRequestDataEntityGrid.DataContext = quoteRequest;
//Control button's visibility
//CreateQuotation button need to show to Contracter
//Shoudn't be seen in post status
if (Shipment.Contracter == (cboUser.SelectedItem as User).Address)
{
btnCreateQuotation.Visibility = Visibility.Visible;
_ = (Shipment.CurrentStatus > CargoTokenShipmentCurrentStatus._0) ? btnCreateQuotation.Visibility = Visibility.Collapsed
: btnCreateQuotation.Visibility = Visibility.Visible;
}
else
{
btnCreateQuotation.Visibility = Visibility.Collapsed;
}
}
if (Shipment.QuotedTokenInfo != null)
{
if (string.IsNullOrEmpty(Shipment.QuotedTokenInfo.BusinessMetaData)) return;
QuoteInfo quoteInfo = JsonConvert.DeserializeObject<QuoteInfo>(Shipment.QuotedTokenInfo.BusinessMetaData, new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore });
this.QuotationDataEntityGrid.DataContext = quoteInfo;
//show button to Contractee
if (Shipment.Contractee == (cboUser.SelectedItem as User).Address)
{
btnCreateBookingRequest.Visibility = Visibility.Visible;
_ = (Shipment.CurrentStatus > CargoTokenShipmentCurrentStatus._1) ? btnCreateBookingRequest.Visibility = Visibility.Collapsed
: btnCreateBookingRequest.Visibility = Visibility.Visible;
}
else
{
btnCreateBookingRequest.Visibility = Visibility.Collapsed;
}
}
if (Shipment.BookingRequestTokenInfo != null)
{
if (string.IsNullOrEmpty(Shipment.BookingRequestTokenInfo.BusinessMetaData)) return;
ServiceProxy.BookingRequest bookingRequest = JsonConvert.DeserializeObject<ServiceProxy.BookingRequest>(Shipment.BookingRequestTokenInfo.BusinessMetaData, new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore });
this.BookingReuqestDataEntityGrid.DataContext = bookingRequest;
if (Shipment.Contracter == (cboUser.SelectedItem as User).Address)
{
btnCreateBookingConfirmation.Visibility = Visibility.Visible;
_ = (Shipment.CurrentStatus > CargoTokenShipmentCurrentStatus._2) ? btnCreateBookingConfirmation.Visibility = Visibility.Collapsed
: btnCreateBookingConfirmation.Visibility = Visibility.Visible;
}
else
{
btnCreateBookingConfirmation.Visibility = Visibility.Collapsed;
}
}
if (Shipment.BookedTokenInfo != null)
{
if (string.IsNullOrEmpty(Shipment.BookedTokenInfo.BusinessMetaData)) return;
BookingConfirmationInfo bookingConfirmation = JsonConvert.DeserializeObject<BookingConfirmationInfo>(Shipment.BookedTokenInfo.BusinessMetaData, new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore });
this.BookingConfirmationDataEntityGrid.DataContext = bookingConfirmation;
}
}
private async void cboUser_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
await QueryMyShipment();
_ = (((User)cboUser.SelectedItem).Role != Role.Carrier) ? btnCreateQuoteRequest.Visibility = Visibility.Visible : btnCreateQuoteRequest.Visibility = Visibility.Collapsed;
}
private async Task QueryMyShipment()
{
using (new WaitCursor(this.pgbProgress))
{
await GetMyShipment();
}
}
private async void ValidateBusinessEntityButton_Click(object sender, RoutedEventArgs e)
{
bool isValid = false;
using (new WaitCursor(this.pgbProgress))
{
isValid = await ValidateBusinessEntity();
}
_ = isValid
? MessageBox.Show(this, "Validated!", "Digital Document Token Service App", MessageBoxButton.OK, MessageBoxImage.Information)
: MessageBox.Show(this, "Invalid Business Entity\n Something seems to be wrong....", "Digital Document Token Service App", MessageBoxButton.OK, MessageBoxImage.Warning);
}
private async Task<bool> ValidateBusinessEntity()
{
CargoTokenShipment cargoTokenShipment = this.DataContext as CargoTokenShipment;
HttpServiceProxy proxy = HttpServiceLocator.GetHttpServiceProxy();
TokenMintedInfo mintedToken = null;
switch (tabProcess.SelectedIndex)
{
case 0: //QuoteRequest
mintedToken = await proxy.GetQuotationRequestTokenAsync(cargoTokenShipment.Id.ToString(), new GetTokenMetaDataRequest()
{
CallerID = cargoTokenShipment.Contracter,
TokenID = cargoTokenShipment.TokenId,
TokenSequence = tabProcess.SelectedIndex.ToString()
});
return cargoTokenShipment.QuoteRequestTokenInfo.BusinessMetaData.Equals(mintedToken.BusinessMetaData) ? true : false;
case 1: //Quoted
mintedToken = await proxy.GetQuotationTokenAsync(cargoTokenShipment.Id.ToString(), new GetTokenMetaDataRequest()
{
CallerID = cargoTokenShipment.Contracter,
TokenID = cargoTokenShipment.TokenId,
TokenSequence = tabProcess.SelectedIndex.ToString()
});
return cargoTokenShipment.QuotedTokenInfo.BusinessMetaData.Equals(mintedToken.BusinessMetaData) ? true : false;
case 2: //BookingRequest
mintedToken = await proxy.GetBookingRequestTokenAsync(cargoTokenShipment.Id.ToString(), new GetTokenMetaDataRequest()
{
CallerID = cargoTokenShipment.Contracter,
TokenID = cargoTokenShipment.TokenId,
TokenSequence = tabProcess.SelectedIndex.ToString()
});
return cargoTokenShipment.BookingRequestTokenInfo.BusinessMetaData.Equals(mintedToken.BusinessMetaData) ? true : false;
case 3: //BookingConfirmed
mintedToken = await proxy.GetBookingConfirmationTokenAsync(cargoTokenShipment.Id.ToString(), new GetTokenMetaDataRequest()
{
CallerID = cargoTokenShipment.Contracter,
TokenID = cargoTokenShipment.TokenId,
TokenSequence = tabProcess.SelectedIndex.ToString()
});
return cargoTokenShipment.BookedTokenInfo.BusinessMetaData.Equals(mintedToken.BusinessMetaData) ? true : false;
default:
return false;
}
}
private void cboFilter_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (lstShipments.ItemsSource == null) return;
CollectionView view = ((CollectionView)CollectionViewSource.GetDefaultView(lstShipments.ItemsSource));
view.Filter = UserFilter;
if (view.Count > 0) lstShipments.SelectedIndex = 0;
}
private bool UserFilter(object item)
{
if (cboFilter.SelectedIndex == 0)
{
return true;
}
else
{
return ((int)(item as CargoTokenShipment).CurrentStatus == cboFilter.SelectedIndex - 1) ? true : false;
}
}
private void ShowCreateQuoteReuqestWindow()
{
Quotation frmQuotation = new Quotation(this, (cboUser.SelectedItem as User).Address, true);
frmQuotation.WindowStartupLocation = WindowStartupLocation.CenterOwner;
frmQuotation.Owner = this;
frmQuotation.Show();
}
private void ShowCreateBookingRequestWindow()
{
BookingRequest frmBookingRequest = new BookingRequest(this, (CargoTokenShipment)this.DataContext);
frmBookingRequest.WindowStartupLocation = WindowStartupLocation.CenterOwner;
frmBookingRequest.Owner = this;
frmBookingRequest.Show();
}
private void ShowCreateQuotationWindow()
{
Quotation frmQuotation = new Quotation(this, (cboUser.SelectedItem as User).Address);
frmQuotation.WindowStartupLocation = WindowStartupLocation.CenterOwner;
frmQuotation.Owner = this;
frmQuotation.Show();
}
private void ShowCreateBookingConfirmationWindow()
{
BookingConfirmation frmBookingConfirmation = new BookingConfirmation(this, (CargoTokenShipment)this.DataContext);
frmBookingConfirmation.WindowStartupLocation = WindowStartupLocation.CenterOwner;
frmBookingConfirmation.Owner = this;
frmBookingConfirmation.Show();
}
private void btnCreateBookingRequest_Click(object sender, RoutedEventArgs e)
{
ShowCreateBookingRequestWindow();
}
private void btnCreateQuotation_Click(object sender, RoutedEventArgs e)
{
ShowCreateQuotationWindow();
}
private void btnCreateBookingConfirmation_Click(object sender, RoutedEventArgs e)
{
ShowCreateBookingConfirmationWindow();
}
private async void btnRefresh_Click(object sender, RoutedEventArgs e)
{
await QueryMyShipment();
}
private void btnCreateQuoteRequest_Click(object sender, RoutedEventArgs e)
{
ShowCreateQuoteReuqestWindow();
}
}
}

Просмотреть файл

@ -0,0 +1,55 @@
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Windows;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("CargoSmart Token App")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("CargoSmart Token App")]
[assembly: AssemblyCopyright("Copyright © 2019")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
//In order to begin building localizable applications, set
//<UICulture>CultureYouAreCodingWith</UICulture> in your .csproj file
//inside a <PropertyGroup>. For example, if you are using US english
//in your source files, set the <UICulture> to en-US. Then uncomment
//the NeutralResourceLanguage attribute below. Update the "en-US" in
//the line below to match the UICulture setting in the project file.
//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
[assembly: ThemeInfo(
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
//(used if a resource is not found in the page,
// or application resource dictionaries)
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
//(used if a resource is not found in the page,
// app, or any theme specific resource dictionaries)
)]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

Просмотреть файл

@ -0,0 +1,63 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace CargoSmart.Windows.Booking.Properties {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("CargoSmart.Windows.Booking.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
}
}

Просмотреть файл

@ -0,0 +1,117 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

Просмотреть файл

@ -0,0 +1,26 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace CargoSmart.Windows.Booking.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.3.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default {
get {
return defaultInstance;
}
}
}
}

Просмотреть файл

@ -0,0 +1,7 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="uri:settings" CurrentProfile="(Default)">
<Profiles>
<Profile Name="(Default)" />
</Profiles>
<Settings />
</SettingsFile>

Просмотреть файл

@ -0,0 +1,74 @@
<Window x:Class="CargoSmart.Windows.Booking.Quotation"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:CargoSmart.Windows.Booking"
mc:Ignorable="d"
Title="Send Quotation Request" Height="450" Width="622">
<Window.Resources>
<Style x:Key="LabelStyle" TargetType="{x:Type Label}">
<Setter Property="Padding" Value="0,0,0,0"/>
<Setter Property="Margin" Value="0,0,0,0"/>
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<Setter Property="VerticalAlignment" Value="Stretch"/>
<Setter Property="HorizontalAlignment" Value="Left"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
</Style>
<Style x:Key="TextBoxStyle" TargetType="{x:Type TextBox}">
<Setter Property="Margin" Value="3,3,10,3"/>
</Style>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="20"></RowDefinition>
<RowDefinition Height="32"></RowDefinition>
<RowDefinition Height="32"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="10"></ColumnDefinition>
<ColumnDefinition Width="180"></ColumnDefinition>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Label Content="Carrier :" Grid.Row="1" Grid.Column="1" Style="{StaticResource LabelStyle}" Margin="0,0.333" Width="41"/>
<ComboBox x:Name="cboCustomer" Grid.Row="1" Grid.Column="2" Margin="3,5.333,0,5.333" HorizontalAlignment="Left" VerticalAlignment="Center" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" Width="300" Height="22"/>
<Label x:Name="lblQuotationRequestTitle" Content="Quotation Request Title :" Grid.Row="1" Grid.Column="1" Style="{StaticResource LabelStyle}" Margin="0,32.333,0,0" Grid.RowSpan="2" Width="131"/>
<TextBox x:Name="txtQuotationTitle" Grid.Row="2" Grid.Column="2" Style="{StaticResource TextBoxStyle}" Margin="3,2.667,10,3"/>
<Label x:Name="lblQuotationDescription" Content="Quotation Request Description :" Grid.Row="3" Grid.Column="1" Style="{StaticResource LabelStyle}" Margin="0,0,0,0.333" Width="169" />
<TextBox x:Name="txtQuotationDescription" Grid.Row="3" Grid.Column="2" Grid.RowSpan="2" VerticalScrollBarVisibility="Auto" Style="{StaticResource TextBoxStyle}" TextWrapping="Wrap" AcceptsReturn="True" Margin="3,3,10,3.333" />
<Label Content="From :" Grid.Row="4" Grid.Column="1" Style="{StaticResource LabelStyle}" Margin="0,30.333,0,0" Grid.RowSpan="2" Width="33" />
<TextBox x:Name="txtFrom" Grid.Row="5" Grid.Column="2" Style="{StaticResource TextBoxStyle}" Margin="3,2.667,10,3"/>
<Label Content="To :" Grid.Row="6" Grid.Column="1" Style="{StaticResource LabelStyle}" Margin="0,0,0,30.333" Grid.RowSpan="2" Width="18" />
<TextBox x:Name="txtTo" Grid.Row="6" Grid.Column="2" Style="{StaticResource TextBoxStyle}" Margin="3,3,10,2.667"/>
<Label Content="Cargo Ready Date :" Grid.Row="7" Grid.Column="1" Style="{StaticResource LabelStyle}" Margin="0,0.333" Width="101" />
<DatePicker x:Name="dpCargoReadyDate" Grid.Column="2" HorizontalAlignment="Left" Grid.Row="7" Margin="3,3.333,0,3.333" Width="222"/>
<Label Content="Cargo Nature :" Grid.Row="7" Grid.Column="1" Style="{StaticResource LabelStyle}" Margin="0,30.333,0,0" Grid.RowSpan="2" Width="77" />
<ComboBox x:Name="cboCargoNature" Grid.Row="8" Grid.Column="2" Margin="3,4.667,0,4" HorizontalAlignment="Left" VerticalAlignment="Center" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" Width="300" Height="22"/>
<Label Content="Container Size :" Grid.Row="9" Grid.Column="1" Style="{StaticResource LabelStyle}" Margin="0,0,0,30.333" Grid.RowSpan="2" Width="82" />
<ComboBox x:Name="cboContainerSize" Grid.Row="9" Grid.Column="2" Margin="3,4,0,4.667" HorizontalAlignment="Left" VerticalAlignment="Center" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" Width="300" Height="22"/>
<Label Content="Container Type :" Grid.Row="10" Grid.Column="1" Style="{StaticResource LabelStyle}" Margin="0,0.333" Width="85" />
<ComboBox x:Name="cboContainerType" Grid.Row="10" Grid.Column="2" Margin="3,4.333,0,4.333" HorizontalAlignment="Left" VerticalAlignment="Center" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" Width="300" Height="22"/>
<Button Content="Create Quotation" Grid.Column="2" HorizontalAlignment="Left" Margin="3,9.667,0,0" Grid.Row="11" VerticalAlignment="Top" Width="151" Click="Button_Click" Height="20"/>
</Grid>
</Window>

Просмотреть файл

@ -0,0 +1,158 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using CargoSmart.Windows.Booking.ServiceProxy;
using CargoSmart.Windows.Booking.Entities;
using System;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using System.Diagnostics;
using Newtonsoft.Json;
namespace CargoSmart.Windows.Booking
{
/// <summary>
/// Interaction logic for Quotation.xaml
/// </summary>
public partial class Quotation : Window
{
private string _userAccount;
private OrderManager _motherForm;
private bool _isQuotationRequest;
public Quotation(OrderManager motherForm, string userAccount, bool isQuotationRequest = false)
{
InitializeComponent();
InitializeCombos();
_userAccount = userAccount;
_motherForm = motherForm;
_isQuotationRequest = isQuotationRequest;
CargoTokenShipment Shipment = motherForm.DataContext as CargoTokenShipment;
if (!isQuotationRequest)
{
this.lblQuotationRequestTitle.Content = "Quotation Title :";
this.lblQuotationDescription.Content = "Quotation Description : ";
this.Title = "Send Quotation";
QuoteInfo quoteInfo = JsonConvert.DeserializeObject<QuoteInfo>(Shipment.QuoteRequestTokenInfo.BusinessMetaData);
txtFrom.Text = quoteInfo.From;
txtTo.Text = quoteInfo.To;
dpCargoReadyDate.SelectedDate = quoteInfo.CargoReadyDate.GetValueOrDefault().UtcDateTime;
cboCargoNature.Text = quoteInfo.CargoNature;
cboContainerSize.SelectedIndex = (int)quoteInfo.ContainerSize; //Enum.GetName//quoteInfo.ContainerSize
cboContainerType.SelectedIndex = (int)quoteInfo.ContainerType;
}
}
public Quotation()
{
InitializeComponent();
InitializeCombos();
}
private void InitializeCombos()
{
SetupUserAccountCombo();
SetupCargoNatureCombo();
SetupcboContainerSize();
SetupcboContainerType();
}
private void SetupCargoNatureCombo()
{
cboCargoNature.Items.Add("Normal");
cboCargoNature.Items.Add("Dangerous");
cboCargoNature.SelectedIndex = 0;
}
private void SetupcboContainerSize()
{
cboContainerSize.Items.Add("Type A");
cboContainerSize.Items.Add("Type B");
cboContainerSize.Items.Add("Type C");
cboContainerType.SelectedIndex = 0;
}
private void SetupcboContainerType()
{
cboContainerType.Items.Add("Large");
cboContainerType.Items.Add("Medium");
cboContainerType.Items.Add("Small");
cboContainerSize.SelectedIndex = 0;
}
private void SetupUserAccountCombo()
{
cboCustomer.ItemsSource = User.GetUserAccounts().Where<User>(x => x.Role.Equals(Role.Carrier));
cboCustomer.DisplayMemberPath = "UserName";
cboCustomer.SelectedValuePath = "Address";
cboCustomer.SelectedIndex = 0;
}
private async Task<CargoTokenShipment> CreateQuotationRequest()
{
HttpServiceProxy proxy = HttpServiceLocator.GetHttpServiceProxy(); //new HttpServiceProxy(new System.Net.Http.HttpClient());
CargoTokenShipment Shipment = null;
if (!_isQuotationRequest) { Shipment = _motherForm.DataContext as CargoTokenShipment; }
QuoteRequestMessage quoteRequestMessage = new QuoteRequestMessage()
{
ShipmentID = _isQuotationRequest ? "" : Shipment.Id.ToString(),
CallerID = ((User)cboCustomer.SelectedItem).Address,
CustomerID = _isQuotationRequest ? _userAccount : Shipment.Contractee,
QuoteTitle = txtQuotationTitle.Text,
QuoteDescription = txtQuotationDescription.Text,
QuoteInfo = new QuoteInfo()
{
From = txtFrom.Text,
To = txtTo.Text,
CargoReadyDate = dpCargoReadyDate.SelectedDate,
CargoNature = cboCargoNature.Text,
ContainerSize = (QuoteInfoContainerSize)Enum.GetValues(typeof(QuoteInfoContainerSize)).GetValue(cboContainerSize.SelectedIndex), //QuoteInfoContainerSize._0,
ContainerType = (QuoteInfoContainerType)Enum.GetValues(typeof(QuoteInfoContainerType)).GetValue(cboContainerType.SelectedIndex)//QuoteInfoContainerType._0
}
};
if (_isQuotationRequest)
{
return await proxy.CreateQuoteRequestAsync(quoteRequestMessage);
}
else
{
return await proxy.CreateQuoteAsync(quoteRequestMessage);
}
}
private async void Button_Click(object sender, RoutedEventArgs e)
{
using (new WaitCursor(_motherForm.pgbProgress))
{
CargoTokenShipment _Shipment = await CreateQuotationRequest();
int lstIndex = 0;
if (!_isQuotationRequest) { lstIndex = _motherForm.lstShipments.SelectedIndex; }
await _motherForm.GetMyShipment(true);
if (!_isQuotationRequest) { _motherForm.lstShipments.SelectedItem = lstIndex; }
Debug.WriteLine(JsonConvert.SerializeObject(_Shipment));
}
this.Close();
}
}
}

Просмотреть файл

@ -0,0 +1,24 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using System.Configuration;
namespace CargoSmart.Windows.Booking.ServiceProxy
{
public class HttpServiceLocator
{
private static string ReadValue(string keyName)
{
return ConfigurationManager.AppSettings[keyName];
}
public static HttpServiceProxy GetHttpServiceProxy()
{
return new HttpServiceProxy(new System.Net.Http.HttpClient()) {
BaseUrl = HttpServiceLocator.ReadValue("ServiceEndPoint"),
HostKey = HttpServiceLocator.ReadValue("HostKey")
};
}
}
}

Просмотреть файл

@ -0,0 +1,18 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
namespace CargoSmart.Windows.Booking.ServiceProxy
{
public partial class HttpServiceProxy
{
public string HostKey { get; set; }
partial void PrepareRequest(System.Net.Http.HttpClient client, System.Net.Http.HttpRequestMessage request, string url)
{
if (url.Contains("localhost")) return;
url += $"?code={HostKey}";
request.RequestUri = new System.Uri(url, System.UriKind.RelativeOrAbsolute);
}
}
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,28 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
<StartupObject>ContosoCargo.DigitalDocument.Setup.Program</StartupObject>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Hosting" Version="5.0.0" />
<PackageReference Include="Microsoft.Extensions.Http" Version="5.0.0" />
<PackageReference Include="Microsoft.Extensions.Http.Polly" Version="5.0.1" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
</ItemGroup>
<ItemGroup>
<Reference Include="Microsoft.Solutions.NFT">
<HintPath>..\TokenServiceSDK\Microsoft.Solutions.NFT.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<None Update="appsettings.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

Просмотреть файл

@ -0,0 +1,55 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using Polly;
using Polly.Extensions.Http;
using System;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
namespace ContosoCargo.DigitalDocument.Setup
{
class Program
{
static async Task Main(string[] args)
{
var host = CreateHostBuilder(args).Build();
await host.RunAsync();
}
static IHostBuilder CreateHostBuilder(string[] args)
{
return Host.CreateDefaultBuilder(args)
.ConfigureServices((hostContext, services) =>
{
services.AddHttpClient<ContosoCargoDigitalDocumentSetup>()
.SetHandlerLifetime(TimeSpan.FromSeconds(5))
.AddPolicyHandler(GetRetryPolicy());
services.AddTransient<ContosoCargoDigitalDocumentSetup>();
services.AddHostedService<SetupApplication>();
}
);
}
static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy()
{
return HttpPolicyExtensions
.HandleTransientHttpError()
.OrResult(msg => msg.StatusCode == System.Net.HttpStatusCode.NotFound)
.WaitAndRetryAsync(3, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2,
retryAttempt)));
}
}
}

Просмотреть файл

@ -0,0 +1,122 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Microsoft.Solutions.NFT;
using System;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
namespace ContosoCargo.DigitalDocument.Setup
{
internal class SetupApplication : IHostedService
{
ContosoCargoDigitalDocumentSetup setup;
public SetupApplication(ContosoCargoDigitalDocumentSetup AppSetup)
{
setup = AppSetup;
}
public async Task StartAsync(CancellationToken cancellationToken)
{
await SetupEnvironment(setup);
}
public Task StopAsync(CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
public async Task SetupEnvironment(ContosoCargoDigitalDocumentSetup setup)
{
Console.WriteLine("\nStart to registering..........");
Console.WriteLine("\nRegistering group.....");
var party = await setup.SetupParty();
Console.WriteLine("====> Done");
Console.WriteLine("\nRegistering blockchian network.....");
var bcNetwork = await setup.SetupBlockChainNetwork();
Console.WriteLine("====> Done");
Console.WriteLine("\nRegistering Contoso Cargo account.....");
var contosoCargo = await setup.SetupContosoUsers("Contoso Cargo", party.Id, bcNetwork.Id);
Console.WriteLine("====> Done");
Console.WriteLine("\nRegistering Shipper A account.....");
var shipperA = await setup.SetupContosoUsers("Shipper A", party.Id, bcNetwork.Id);
Console.WriteLine("====> Done");
Console.WriteLine("\nRegistering Shipper B account.....");
var shipperB = await setup.SetupContosoUsers("Shiper B", party.Id, bcNetwork.Id);
Console.WriteLine("====> Done");
Console.WriteLine("\n\nAll Set process has been completed. " +
"\nUpdate your App.config file with below values in Windows Client Application");
Console.WriteLine("\n=================== Configuration Information =====================");
Console.WriteLine($"Contoso Cargo Id\t: {contosoCargo.Id}");
Console.WriteLine($"Shipper A Id\t\t: {shipperA.Id}");
Console.WriteLine($"Shipper B Id\t\t: {shipperB.Id}");
Console.WriteLine("======================================================================");
Console.WriteLine("==> Copy these values then Hit Enter to close.");
Console.ReadLine();
}
}
public class ContosoCargoDigitalDocumentSetup
{
ServiceClient tokenServiceClient;
IConfiguration config;
public ContosoCargoDigitalDocumentSetup(IConfiguration Config, HttpClient HttpClient)
{
this.config = Config;
tokenServiceClient = new ServiceClient(Config["Settings:TokenServiceEndpoint"], HttpClient);
}
public async Task<BlockchainNetwork> SetupBlockChainNetwork()
{
var result = await tokenServiceClient.RegisterBlockchainNetworkAsync(new BlockchainNetworkInfo()
{
Name = config["Settings:BlockchainNetworkName"],
Description = config["Settings:BlockchainNetworkDescription"],
NodeURL = config["Settings:BlockchainNetworkTxNode"]
});
return result;
}
public async Task<Party> SetupParty()
{
string _partyName = config["Settings:PartyName"];
string _partyDescription = config["Settings:PartyDescription"];
var result = await tokenServiceClient.RegisterPartyAsync(new PartyInfo()
{
PartyName = _partyName,
Description = _partyDescription
});
return result;
}
public async Task<User> SetupContosoUsers(string UserName, Guid PartyID, Guid BlockchainNetworkID)
{
return await tokenServiceClient.RegisterUserAsync(new UserInfo()
{
Name = UserName,
PartyID = PartyID,
BlockchainNetworkID = BlockchainNetworkID
});
}
}
}

Просмотреть файл

@ -0,0 +1,19 @@
{
"Logging": {
"LogLevel": {
"Default": "None",
"Microsoft": "None",
"Microsoft.Hosting.Lifetime": "None"
}
},
"Settings": {
"TokenServiceEndpoint": "{Azure_Non_Fungible_Token_Solution_Accelerator_URL}",
"BlockchainNetworkName": "Contoso Network",
"BlockchainNetworkDescription": "Contoso Blockchain Network",
"BlockchainNetworkTxNode": "{Blockchain_Network_URL}",
"PartyName": "Contoso Shipping",
"PartyDescription": "Contoso Shipping Party"
}
}

Просмотреть файл

@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.Solutions.NFT">
<HintPath>..\TokenServiceSDK\Microsoft.Solutions.NFT.dll</HintPath>
</Reference>
</ItemGroup>
</Project>

Просмотреть файл

@ -0,0 +1,77 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using System.Diagnostics;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.Solutions.NFT;
namespace ContosoCargo.DigitalDocument.TokenService.Client
{
public class TokenServiceWrapper
{
private Microsoft.Solutions.NFT.ServiceClient tokenServiceAPI;
public TokenServiceWrapper(string endpointUrl, HttpClient HttpClient)
{
tokenServiceAPI = new ServiceClient(endpointUrl, HttpClient);
}
public async Task<TransactionReciept> CreateToken(string tokenName, string tokenSymbol, string CallerID)
{
Debug.Assert(tokenServiceAPI != null, "Token Service API should be assigned before invoke it");
return await tokenServiceAPI.DeployNewTokenAsync(CallerID, tokenName, tokenSymbol);
}
public async Task<long?> GetBalance(string ContractAddress, string CallerID)
{
return await tokenServiceAPI.BalanceOfAsync(ContractAddress, CallerID);
}
public async Task<string> GetName(string ContractAddress, string CallerID)
{
return await tokenServiceAPI.NameAsync(ContractAddress, CallerID);
}
public async Task<string> GetSymbol(string ContractAddress, string CallerID)
{
return await tokenServiceAPI.SymbolAsync(ContractAddress, CallerID);
}
public async Task<TransactionReciept> MintToken(string ContractAddress, string minter, string mintee, string metaDataString, long? sequence)
{
return await tokenServiceAPI.MintTokenAsync(ContractAddress,
minter, mintee, sequence, metaDataString);
}
public async Task<string> GetTokenMetaData(string ContractAddress, string caller, long sequence)
{
tokenServiceAPI.ReadResponseAsString = true;
return await tokenServiceAPI.TokenURIAsync(ContractAddress, caller, sequence);
}
public async Task<TransactionReciept> SetApprovalForAll(string ContractAddress, string caller, string approveeId)
{
return await tokenServiceAPI.SetApprovalForAllAsync(ContractAddress, caller, approveeId, true);
}
public async Task<TransactionReciept> TranferToken(string ContractAddress, long sequence, string callerID, string from, string to)
{
return await tokenServiceAPI.TransferAsync(ContractAddress, from, to, sequence);
}
public async Task<TransactionReciept> DeleteToken(string ContractAddress, string callerId, long deletedTokensequence)
{
return await tokenServiceAPI.BurnAsync(ContractAddress, callerId, deletedTokensequence);
}
public async Task<string> WhoisOwner(string ContractAddress, string callerId, long tokenNumber)
{
return await tokenServiceAPI.OwnerOfAsync(ContractAddress, callerId, tokenNumber);
}
}
}

264
src/ContosoCargo.DigitalDocument.TokenService.Host/.gitignore поставляемый Normal file
Просмотреть файл

@ -0,0 +1,264 @@
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
# Azure Functions localsettings file
local.settings.json
# User-specific files
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
# Visual Studio 2015 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUNIT
*.VisualState.xml
TestResult.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# DNX
project.lock.json
project.fragment.lock.json
artifacts/
*_i.c
*_p.c
*_i.h
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# JustCode is a .NET coding add-in
.JustCode
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# TODO: Comment the next line if you want to checkin your web deploy settings
# but database connection strings (with potential passwords) will be unencrypted
#*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# The packages folder can be ignored because of Package Restore
**/packages/*
# except build/, which is used as an MSBuild target.
!**/packages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/packages/repositories.config
# NuGet v3's project.json files produces more ignoreable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
node_modules/
orleans.codegen.cs
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
# SQL Server files
*.mdf
*.ldf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# JetBrains Rider
.idea/
*.sln.iml
# CodeRush
.cr/
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc

Просмотреть файл

@ -0,0 +1,303 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using ContosoCargo.DigitalDocument.TokenService.Models;
using ContosoCargo.DigitalDocument.TokenService.OffChain.Mongo.ModelBase;
using ContosoCargo.DigitalDocument.TokenService.Host.Messages;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Net.Http;
using Microsoft.Solutions.CosmosDB.Security.ManagedIdentity;
using Microsoft.Extensions.Configuration;
using ContosoCargo.DigitalDocument.TokenService.OffChain.Mongo;
using MongoDB.Driver;
namespace ContosoCargo.DigitalDocument.TokenService.Host.Application
{
public class ContosoCargo : IContosoCargoApplication
{
private readonly IRepository<CargoTokenShipment, Guid> ContosoCargoIncidentRepository;
private Client.TokenServiceWrapper TokenServiceClient;
public ContosoCargo(CosmosConnectionStrings Connections, IConfiguration Config, HttpClient httpClient)
{
ContosoCargoIncidentRepository = new BusinessTransactionRepository<CargoTokenShipment, Guid>(new MongoClient(Connections.PrimaryReadWriteKey), "CargoTokenRepository");
TokenServiceClient = new Client.TokenServiceWrapper(Config["App:ServiceEndpoint"], httpClient);
}
public async Task<CargoTokenShipment> CreateQuoteRequest(QuoteRequestMessage quoteRequest)
{
//Create New Token
var TokenName = $"ContosoCargoToken:{Guid.NewGuid().ToString()}";
var CallerID = quoteRequest.CallerID;
var TokenSymbol = $"CS-{Guid.NewGuid().ToString()}-{quoteRequest.CustomerID}";
var creationResponse = await TokenServiceClient.CreateToken(TokenName, TokenSymbol, CallerID);
//Mint Token
var Minter = quoteRequest.CallerID;
var Mintee = quoteRequest.CustomerID;
var TokenID = creationResponse.ContractAddress;
var TokenSequence = 0; //define QuoteRequest TokenID will be 0
var SerializedBusinessMetaData = JsonConvert.SerializeObject(quoteRequest.QuoteInfo);
var mintedResponse = await TokenServiceClient.MintToken(TokenID, Minter, Mintee, SerializedBusinessMetaData, TokenSequence);
CargoTokenShipment newToken = new CargoTokenShipment()
{
TokenMetaInfo = new TokenMeta()
{
TokenID = creationResponse.ContractAddress,
TokenName = TokenName,
TokenSymbol = TokenSymbol,
TokenTemplateID = "8465231b-4919-4498-b6e3-ae5975b7eab2",
TokenCreator = Minter,
TokenCreatedDate = DateTime.Now
},
CurrentStatus = ShipmentStage.OnQuoteRequest,
TokenId = creationResponse.ContractAddress,
Contracter = Minter,
Contractee = Mintee,
QuoteRequestTokenInfo = new TokenMintedInfo()
{
TokenSequence = TokenSequence,
BusinessMetaData = SerializedBusinessMetaData,
TokenMintedDate = System.DateTime.Now,
TokenMintee = Mintee,
TokenMinter = Minter,
TokenID = creationResponse.ContractAddress,
MintedTokenTitle = quoteRequest.QuoteTitle,
MintedTokenDescription = quoteRequest.QuoteDescription
}
};
//Save TokenInfo into Repository
await ContosoCargoIncidentRepository.SaveAsync(newToken);
return newToken;
}
public async Task<CargoTokenShipment> CreateQuote(QuoteRequestMessage quoteRequest)
{
CargoTokenShipment Shipment = ContosoCargoIncidentRepository.Get(Guid.Parse(quoteRequest.ShipmentID));
//Mint Token
var Minter = quoteRequest.CallerID;
var Mintee = quoteRequest.CustomerID;
var TokenID = Shipment.TokenId;
var TokenSequence = 1;//define Quote TokenID will be 1
var SerializedBusinessMetaData = JsonConvert.SerializeObject(quoteRequest.QuoteInfo);
var mintedResponse = await TokenServiceClient.MintToken(TokenID, Minter, Mintee, SerializedBusinessMetaData, TokenSequence);
Shipment.QuotedTokenInfo = new TokenMintedInfo()
{
TokenID = Shipment.TokenId,
TokenSequence = TokenSequence,
BusinessMetaData = SerializedBusinessMetaData,
TokenMintedDate = System.DateTime.Now,
TokenMintee = Mintee,
TokenMinter = Minter,
MintedTokenTitle = quoteRequest.QuoteTitle,
MintedTokenDescription = quoteRequest.QuoteDescription
};
//Save TokenInfo into Repository
Shipment.CurrentStatus = ShipmentStage.Quoted;
await ContosoCargoIncidentRepository.SaveAsync(Shipment);
return Shipment;
}
public IEnumerable<CargoTokenShipment> GetMyShipments(GetTokenShipmentsRequest getTokenShipmentsRequest)
{
string callee = getTokenShipmentsRequest.CallerID;
if (getTokenShipmentsRequest.IsContracter)
{
return ContosoCargoIncidentRepository.FindAll(
new GenericSpecification<CargoTokenShipment>(x =>
x.QuoteRequestTokenInfo.TokenMinter.Equals(callee) ||
x.BookedTokenInfo.TokenMinter.Equals(callee) ||
x.QuotedTokenInfo.TokenMinter.Equals(callee) ||
x.BookingRequestTokenInfo.TokenMinter.Equals(callee)));
}
else
{
return ContosoCargoIncidentRepository.FindAll(
new GenericSpecification<CargoTokenShipment>(x =>
x.QuoteRequestTokenInfo.TokenMintee.Equals(callee) ||
x.BookedTokenInfo.TokenMintee.Equals(callee) ||
x.QuotedTokenInfo.TokenMintee.Equals(callee) ||
x.BookingRequestTokenInfo.TokenMintee.Equals(callee)));
}
}
public async Task<bool> DeleteMyShipment(Guid id, DeleteTokenRequest deleteTokenRequest)
{
var Shipment = ContosoCargoIncidentRepository.Find(new GenericSpecification<CargoTokenShipment>(x =>
x.Id == id));
if ((Shipment != null) && (Shipment.Contracter == deleteTokenRequest.CallerID))
{
//required asyc process burn tokens as parallel.
deleteTokenRequest.TokenSequence = 0;
await TokenServiceClient.DeleteToken(deleteTokenRequest.TokenID, deleteTokenRequest.CallerID, deleteTokenRequest.TokenSequence);
deleteTokenRequest.TokenSequence = 1;
await TokenServiceClient.DeleteToken(deleteTokenRequest.TokenID, deleteTokenRequest.CallerID, deleteTokenRequest.TokenSequence);
deleteTokenRequest.TokenSequence = 2;
await TokenServiceClient.DeleteToken(deleteTokenRequest.TokenID, deleteTokenRequest.CallerID, deleteTokenRequest.TokenSequence);
deleteTokenRequest.TokenSequence = 3;
await TokenServiceClient.DeleteToken(deleteTokenRequest.TokenID, deleteTokenRequest.CallerID, deleteTokenRequest.TokenSequence);
ContosoCargoIncidentRepository.Delete(id);
return true;
}
else
{
return false;
}
}
public CargoTokenShipment GetShipment(Guid id)
{
CargoTokenShipment returnedShipment =
ContosoCargoIncidentRepository.Find(new GenericSpecification<CargoTokenShipment>(x => x.Id.Equals(id)));
return returnedShipment;
}
public async Task<CargoTokenShipment> BookingRequest(BookingRequestMessage bookingRequest)
{
CargoTokenShipment Shipment = ContosoCargoIncidentRepository.Get(Guid.Parse(bookingRequest.ShipmentID));
//Mint Token
var Minter = bookingRequest.CallerID;
var Mintee = bookingRequest.CustomerID;
var TokenID = Shipment.TokenId;
var TokenSequence = 2; //BookingRequest sequence is "2"
var SerializedBusinessMetaData = JsonConvert.SerializeObject(bookingRequest.BookingRequestInfo);//bookingRequest
var mintedResponse = await TokenServiceClient.MintToken(TokenID, Minter, Mintee, SerializedBusinessMetaData, TokenSequence);
//Adding Minted Token Info
Shipment.BookingRequestTokenInfo = new TokenMintedInfo()
{
TokenID = Shipment.TokenId,
TokenSequence = TokenSequence,
BusinessMetaData = SerializedBusinessMetaData,
TokenMintedDate = System.DateTime.Now,
TokenMintee = Mintee,
TokenMinter = Minter,
MintedTokenTitle = bookingRequest.BookingRequestTitle,
MintedTokenDescription = bookingRequest.BookingRequestDescription
};
//Save TokenInfo into Repository
Shipment.CurrentStatus = ShipmentStage.OnBookingRequest;
await ContosoCargoIncidentRepository.SaveAsync(Shipment);
return Shipment;
}
public async Task<CargoTokenShipment> BookingConfimation(BookingConfirmationRequestMessage bookingConfirmationRequest)
{
CargoTokenShipment Shipment = ContosoCargoIncidentRepository.Get(Guid.Parse(bookingConfirmationRequest.ShipmentID));
//Mint Token
var Minter = bookingConfirmationRequest.CallerID;
var Mintee = bookingConfirmationRequest.CustomerID;
var TokenID = Shipment.TokenId;
var TokenSequence = 3; //BookingConfirmation sequence is "3"
var SerializedBusinessMetaData = JsonConvert.SerializeObject(bookingConfirmationRequest.BookingConfirmationInfo); //bookingRequest
var mintedResponse = await TokenServiceClient.MintToken(TokenID, Minter, Mintee, SerializedBusinessMetaData, TokenSequence);
//Adding Minted Token Info
Shipment.BookedTokenInfo = new TokenMintedInfo()
{
TokenID = Shipment.TokenId,
TokenSequence = TokenSequence,
BusinessMetaData = SerializedBusinessMetaData,
TokenMintedDate = System.DateTime.Now,
TokenMintee = Mintee,
TokenMinter = Minter,
MintedTokenTitle = bookingConfirmationRequest.BookingConfirmationTitle,
MintedTokenDescription = bookingConfirmationRequest.BookingConfirmationDescription
};
//Save TokenInfo into Repository
Shipment.CurrentStatus = ShipmentStage.Booked;
await ContosoCargoIncidentRepository.SaveAsync(Shipment);
return Shipment;
}
public async Task<TokenMintedInfo> GetMintedTokenInfoFromChain<T>(Guid id, GetTokenMetaDataRequest getTokenMetaDataRequest)
{
var Shipment = ContosoCargoIncidentRepository.Find(new GenericSpecification<CargoTokenShipment>(
x => x.Id.Equals(id)));
if (!Shipment.Contracter.Equals(getTokenMetaDataRequest.CallerID)) return null;
if (typeof(T).Equals(typeof(Quotation)))
{
TokenMintedInfo mintedTokenInfo = Shipment.QuoteRequestTokenInfo;
getTokenMetaDataRequest.TokenSequence = "0";
var result = await TokenServiceClient.GetTokenMetaData(getTokenMetaDataRequest.TokenID, getTokenMetaDataRequest.CallerID, 0);
mintedTokenInfo.BusinessMetaData = result;
return mintedTokenInfo;
}
else if (typeof(T).Equals(typeof(RateQuotation)))
{
TokenMintedInfo mintedTokenInfo = Shipment.QuotedTokenInfo;
getTokenMetaDataRequest.TokenSequence = "1";
var result = await TokenServiceClient.GetTokenMetaData(getTokenMetaDataRequest.TokenID, getTokenMetaDataRequest.CallerID, 1);
mintedTokenInfo.BusinessMetaData = result;
return mintedTokenInfo;
}
else if (typeof(T).Equals(typeof(BookingRequest)))
{
TokenMintedInfo mintedTokenInfo = Shipment.BookingRequestTokenInfo;
getTokenMetaDataRequest.TokenSequence = "2";
var result = await TokenServiceClient.GetTokenMetaData(getTokenMetaDataRequest.TokenID, getTokenMetaDataRequest.CallerID, 2);
mintedTokenInfo.BusinessMetaData = result;
return mintedTokenInfo;
}
else if (typeof(T).Equals(typeof(BookingConfirmation)))
{
TokenMintedInfo mintedTokenInfo = Shipment.BookingRequestTokenInfo;
getTokenMetaDataRequest.TokenSequence = "3";
var result = await TokenServiceClient.GetTokenMetaData(getTokenMetaDataRequest.TokenID, getTokenMetaDataRequest.CallerID, 3); ;
mintedTokenInfo.BusinessMetaData = result;
return mintedTokenInfo;
}
return null;
}
}
}

Просмотреть файл

@ -0,0 +1,31 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using ContosoCargo.DigitalDocument.TokenService.Models;
using ContosoCargo.DigitalDocument.TokenService.Host.Messages;
namespace ContosoCargo.DigitalDocument.TokenService.Host.Application
{
public interface IContosoCargoApplication
{
Task<CargoTokenShipment> CreateQuote(QuoteRequestMessage quoteRequest);
Task<CargoTokenShipment> CreateQuoteRequest(QuoteRequestMessage quoteRequest);
IEnumerable<CargoTokenShipment> GetMyShipments(GetTokenShipmentsRequest getTokenShipmentsRequest);
Task<bool> DeleteMyShipment(Guid id, DeleteTokenRequest deleteTokenRequest);
CargoTokenShipment GetShipment(Guid id);
Task<CargoTokenShipment> BookingRequest(BookingRequestMessage bookingRequest);
Task<CargoTokenShipment> BookingConfimation(BookingConfirmationRequestMessage bookingConfirmationRequest);
Task<TokenMintedInfo> GetMintedTokenInfoFromChain<T>(Guid id, GetTokenMetaDataRequest getMintedTokenInfoRequest);
}
}

Просмотреть файл

@ -0,0 +1,65 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<OutputType>Exe</OutputType>
<AzureFunctionsVersion>v3</AzureFunctionsVersion>
</PropertyGroup>
<ItemGroup>
<Compile Remove="Messages\Munich\**" />
<EmbeddedResource Remove="Messages\Munich\**" />
<None Remove="Messages\Munich\**" />
</ItemGroup>
<ItemGroup>
<Compile Remove="Application\IMunichApp.cs" />
<Compile Remove="Application\Munich.cs" />
<Compile Remove="Munich.cs" />
<Compile Remove="MunichExtensions.cs" />
<Compile Remove="Startup.cs" />
<Compile Remove="SwaggerRanderer.cs" />
</ItemGroup>
<ItemGroup>
<None Remove="appsettings.json" />
</ItemGroup>
<ItemGroup>
<Resource Include="appsettings.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Resource>
</ItemGroup>
<ItemGroup>
<PackageReference Include="EAE.Solutions.CosmosDB.Security.ManagedIdentity" Version="0.7.3" />
<PackageReference Include="Microsoft.Azure.Core.NewtonsoftJson" Version="1.0.0" />
<PackageReference Include="Microsoft.Azure.Functions.Worker" Version="1.6.0" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Http" Version="3.0.13" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.OpenApi" Version="1.0.0" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Sdk" Version="1.3.0" OutputItemType="Analyzer" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ContosoCargo.DigitalDocument.TokenService.Client\ContosoCargo.DigitalDocument.TokenService.Client.csproj" />
<ProjectReference Include="..\ContosoCargo.DigitalDocument.TokenService.Models\ContosoCargo.DigitalDocument.TokenService.Models.csproj" />
</ItemGroup>
<ItemGroup>
<Reference Include="Microsoft.Solutions.NFT">
<HintPath>..\TokenServiceSDK\Microsoft.Solutions.NFT.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Update="ContosoCargo.cs">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Compile>
</ItemGroup>
<ItemGroup>
<None Update="application.settings.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="host.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="local.settings.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToPublishDirectory>Never</CopyToPublishDirectory>
</None>
</ItemGroup>
</Project>

Просмотреть файл

@ -0,0 +1,250 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using System.Collections.Generic;
using ContosoCargo.DigitalDocument.TokenService.Models;
using ContosoCargo.DigitalDocument.TokenService.Host.Messages;
using ContosoCargo.DigitalDocument.TokenService.Host.Application;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Attributes;
using Microsoft.Azure.Functions.Worker.Http;
using Microsoft.OpenApi.Models;
namespace ContosoCargo.DigitalDocument.TokenService.Host
{
public class ContosoCargo
{
private readonly IContosoCargoApplication _cargoApp;
private ILogger<ContosoCargo> log;
public ContosoCargo(IContosoCargoApplication CargoApp, ILogger<ContosoCargo> Logger)
{
(_cargoApp, log) = (CargoApp, Logger);
}
[Function(nameof(CreateQuoteRequest))]
[OpenApiOperation(operationId: "CreateQuoteRequest",
Description = "Create Shipment and then mint Quotation Token",
Summary = "Create Shipment and mint Quotation Token")]
[OpenApiRequestBody("application/json", typeof(QuoteRequestMessage), Description = "QuotationRequest Information")]
[OpenApiResponseWithBody(System.Net.HttpStatusCode.OK, "application/json", typeof(CargoTokenShipment), Description = "Whole Shipment Document")]
public async Task<IActionResult> CreateQuoteRequest(
[HttpTrigger(AuthorizationLevel.Anonymous, "put", Route = "Shipment/QuoteRequest")] HttpRequestData req)
{
log.LogInformation("C# HTTP trigger function processed a request. - CargoSmart/QuoteRequest");
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
QuoteRequestMessage data = JsonConvert.DeserializeObject<QuoteRequestMessage>(requestBody);
var result = await _cargoApp.CreateQuoteRequest(data);
return new OkObjectResult(result);
}
[Function(nameof(CreateQuote))]
[OpenApiOperation("CreateQuote",
Description = "Mining Quotation Token",
Summary = "when Carrier agreed for Quotation Request, Quotation Token will be minted")]
[OpenApiRequestBody("application/json", typeof(QuoteRequestMessage), Description = "QuotationRequest Information")]
[OpenApiResponseWithBody(System.Net.HttpStatusCode.OK, "application/json", typeof(CargoTokenShipment), Description = "Whole Shipment Document")]
public async Task<IActionResult> CreateQuote(
[HttpTrigger(AuthorizationLevel.Anonymous, "put", Route = "Shipment/Quote")] HttpRequestData req)
{
log.LogInformation("C# HTTP trigger function processed a request. - CargoSmart/Quote");
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
QuoteRequestMessage data = JsonConvert.DeserializeObject<QuoteRequestMessage>(requestBody);
var result = await _cargoApp.CreateQuote(data);
return new OkObjectResult(result);
}
[Function(nameof(CreateBookingRequest))]
[OpenApiOperation("CreateBookingRequest",
Description = "Minting BookingRequest token",
Summary = "when Customer agreed for Quotation, BookingRequest information is updated in Shipment and BookingRequest token is minted to customer.")]
[OpenApiParameter("id", In = Microsoft.OpenApi.Models.ParameterLocation.Path, Description = "Shipment ID", Required = true)]
[OpenApiRequestBody("application/json", typeof(BookingRequestMessage), Description = "BookingRequest Information")]
[OpenApiResponseWithBody(System.Net.HttpStatusCode.OK, "application/json", typeof(CargoTokenShipment), Description = "Whole Shipment Document")]
public async Task<IActionResult> CreateBookingRequest(
[HttpTrigger(AuthorizationLevel.Anonymous, "put", Route = "Shipment/{id}/Booking")] HttpRequestData req)
{
log.LogInformation("C# HTTP trigger function processed a request. - put CargoSmart/Booking");
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
BookingRequestMessage data = JsonConvert.DeserializeObject<BookingRequestMessage>(requestBody);
var result = await _cargoApp.BookingRequest(data);
return new OkObjectResult(result);
}
[Function(nameof(CreateBookingConfirmation))]
[OpenApiOperation("CreateBookingConfirmation",
Description = "Minting BookingConfirmation token",
Summary = "when booking request has been confirmed from customer side, BookingConfirmation information is updated in offchaindatbase and BookingConfirmation token is minted.")]
[OpenApiParameter("id", In = Microsoft.OpenApi.Models.ParameterLocation.Path, Description = "Shipment ID", Required = true)]
[OpenApiRequestBody("application/json", typeof(BookingConfirmationRequestMessage), Description = "BookingConfirmation Information")]
[OpenApiResponseWithBody(System.Net.HttpStatusCode.OK, "application/json", typeof(CargoTokenShipment), Description = "Whole Shipment Document")]
public async Task<IActionResult> CreateBookingConfirmation(
[HttpTrigger(AuthorizationLevel.Anonymous, "put", Route = "Shipment/{id}/BookingConfirmation")] HttpRequestData req)
{
log.LogInformation("C# HTTP trigger function processed a request. - CargoSmart/BookingConfirmation");
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
BookingConfirmationRequestMessage data = JsonConvert.DeserializeObject<BookingConfirmationRequestMessage>(requestBody);
var result = await _cargoApp.BookingConfimation(data);
return new OkObjectResult(result);
}
[Function(nameof(GetMyShipments))]
[OpenApiOperation("GetMyShipments",
Description = "Get Shipments what I created or has got from",
Summary = "list up whole Shipments which were created by me or minted token to me")]
[OpenApiRequestBody("application/json", typeof(GetTokenShipmentsRequest), Description = "TokenIncidnentRequest Information")]
[OpenApiResponseWithBody(System.Net.HttpStatusCode.OK, "application/json", typeof(IEnumerable<CargoTokenShipment>), Description = "Get Shipment Document lists")]
public IEnumerable<CargoTokenShipment> GetMyShipments(
[HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "Shipment")] HttpRequestData req)
{
log.LogInformation("C# HTTP trigger function processed a request. - post CargoSmart/Shipment");
string requestBody = new StreamReader(req.Body).ReadToEndAsync().Result;
GetTokenShipmentsRequest data = JsonConvert.DeserializeObject<GetTokenShipmentsRequest>(requestBody);
IEnumerable<CargoTokenShipment> result = _cargoApp.GetMyShipments(data);
return result;
}
[Function(nameof(DeleteMyShipment))]
[OpenApiOperation("DeleteMyShipment",
Description = "delete Shipment that I created",
Summary = "Delete Shipment record and burn tokens from offchain and chain both")]
[OpenApiParameter("id", Type = typeof(Guid) ,In = Microsoft.OpenApi.Models.ParameterLocation.Path, Description = "Shipment ID", Required = true)]
[OpenApiRequestBody("application/json", typeof(DeleteTokenRequest), Description = "DeleteToken request Information")]
[OpenApiResponseWithBody(System.Net.HttpStatusCode.OK, "application/json", typeof(System.Boolean), Description = "Delete process result")]
public async Task<IActionResult> DeleteMyShipment(
[HttpTrigger(AuthorizationLevel.Anonymous, "delete", Route = "Shipment/{id}")] HttpRequestData req, Guid id)
{
log.LogInformation($"C# HTTP trigger function processed a request. - delete CargoSmart/Shipment/{id}");
string requestBody = new StreamReader(req.Body).ReadToEndAsync().Result;
DeleteTokenRequest data = JsonConvert.DeserializeObject<DeleteTokenRequest>(requestBody);
var result = await _cargoApp.DeleteMyShipment(id, data);
return new OkObjectResult(result);
}
[Function(nameof(GetShipment))]
[OpenApiOperation("GetShipment",
Description = "get specific Shipment data by Shipment ID",
Summary = "Get Shipment Data by Shipment ID")]
[OpenApiParameter("id", Type = typeof(Guid), In = Microsoft.OpenApi.Models.ParameterLocation.Path, Description = "Shipment ID", Required = true)]
[OpenApiResponseWithBody(System.Net.HttpStatusCode.OK, "application/json", typeof(CargoTokenShipment), Description = "Whole Shipment Document")]
public CargoTokenShipment GetShipment(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "Shipment/{id}")] HttpRequestData req,
Guid id)
{
log.LogInformation($"C# HTTP trigger function processed a request. - get CargoSmart/Shipment/{id}");
var result = _cargoApp.GetShipment(id);
return result;
}
[Function("GetQuotationRequestToken")]
[OpenApiOperation("GetQuotationRequestToken",
Description = "Return QuotationRequest Token Information by Shipment ID",
Summary = "Get QuotationRequest Token by Shipment ID")]
[OpenApiParameter("id", Type = typeof(Guid), In = Microsoft.OpenApi.Models.ParameterLocation.Path, Description = "Shipment ID", Required = true)]
[OpenApiRequestBody("application/json", typeof(GetTokenMetaDataRequest), Description = "QuotationRequest token request Information")]
[OpenApiResponseWithBody(System.Net.HttpStatusCode.OK, "application/json", typeof(TokenMintedInfo), Description = "QuoteRequest Token Information")]
public async Task<TokenMintedInfo> GetQuoteRequestTokenFromChain(
[HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "Shipment/{id}/QuoteRequestToken")] HttpRequestData req, Guid id)
{
log.LogInformation($"C# HTTP trigger function processed a request. - get GetQuoteTokenFromChain CargoSmart/Shipment/{id}");
string requestBody = new StreamReader(req.Body).ReadToEndAsync().Result;
GetTokenMetaDataRequest data = JsonConvert.DeserializeObject<GetTokenMetaDataRequest>(requestBody);
var result = await _cargoApp.GetMintedTokenInfoFromChain<Quotation>(id, data);
return result;
}
[Function("GetQuotationToken")]
[OpenApiOperation("GetQuotationToken",
Description = "Return Quotation Token Information by Shipment ID",
Summary = "Get Quotation Token by Shipment ID")]
[OpenApiParameter("id", Type = typeof(Guid), In = Microsoft.OpenApi.Models.ParameterLocation.Path, Description = "Shipment ID", Required = true)]
[OpenApiRequestBody("application/json", typeof(GetTokenMetaDataRequest), Description = "Quotation token request Information")]
[OpenApiResponseWithBody(System.Net.HttpStatusCode.OK, "application/json", typeof(TokenMintedInfo), Description = "Quote Token Information")]
public async Task<TokenMintedInfo> GetQuoteTokenFromChain(
[HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "Shipment/{id}/QuoteToken")] HttpRequestData req, Guid id)
{
log.LogInformation($"C# HTTP trigger function processed a request. - get GetQuoteTokenFromChain CargoSmart/Shipment/{id}");
string requestBody = new StreamReader(req.Body).ReadToEndAsync().Result;
GetTokenMetaDataRequest data = JsonConvert.DeserializeObject<GetTokenMetaDataRequest>(requestBody);
var result = await _cargoApp.GetMintedTokenInfoFromChain<RateQuotation>(id, data);
return result;
}
[Function("GetBookingRequestToken")]
[OpenApiOperation("GetBookingRequestToken",
Description = "Return BookingRequest Token Information by Shipment ID",
Summary = "Get BookingRequest Token by Shipment ID")]
[OpenApiParameter("id", Type = typeof(Guid), In = Microsoft.OpenApi.Models.ParameterLocation.Path, Description = "Shipment ID", Required = true)]
[OpenApiRequestBody("application/json", typeof(GetTokenMetaDataRequest), Description = "BookingRequest token request Information")]
[OpenApiResponseWithBody(System.Net.HttpStatusCode.OK, "application/json", typeof(TokenMintedInfo), Description = "BookingRequest Token Information")]
public async Task<TokenMintedInfo> GetBookingRequestTokenFromChain(
[HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "Shipment/{id}/BookingToken")] HttpRequestData req, Guid id)
{
log.LogInformation($"C# HTTP trigger function processed a request. - get GetBookingRequestToken CargoSmart/Shipment/{id}");
string requestBody = new StreamReader(req.Body).ReadToEndAsync().Result;
GetTokenMetaDataRequest data = JsonConvert.DeserializeObject<GetTokenMetaDataRequest>(requestBody);
var result = await _cargoApp.GetMintedTokenInfoFromChain<BookingRequest>(id, data);
return result;
}
[Function("GetBookingConfirmationToken")]
[OpenApiOperation("GetBookingConfirmationToken",
Description = "Return BookingConfirmation Token Information by Shipment ID",
Summary = "Get BookingConfirmation Token by Shipment ID")]
[OpenApiParameter("id", Type = typeof(Guid), In = Microsoft.OpenApi.Models.ParameterLocation.Path, Description = "Shipment ID", Required = true)]
[OpenApiRequestBody("application/json", typeof(GetTokenMetaDataRequest), Description = "BookingConfirmation token request Information")]
[OpenApiResponseWithBody(System.Net.HttpStatusCode.OK, "application/json", typeof(TokenMintedInfo), Description = "BookingConfirmation Token Information")]
public async Task<TokenMintedInfo> GetBookingConfirmationTokenFromChain(
[HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "Shipment/{id}/BookingConfirmationToken")] HttpRequestData req, Guid id)
{
log.LogInformation($"C# HTTP trigger function processed a request. - get GetBookingConfirmationToken CargoSmart/Shipment/{id}");
string requestBody = new StreamReader(req.Body).ReadToEndAsync().Result;
GetTokenMetaDataRequest data = JsonConvert.DeserializeObject<GetTokenMetaDataRequest>(requestBody);
var result = await _cargoApp.GetMintedTokenInfoFromChain<BookingConfirmation>(id, data);
return result;
}
}
}

Просмотреть файл

@ -0,0 +1,22 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using ContosoCargo.DigitalDocument.TokenService.Models;
using System;
using System.Collections.Generic;
using System.Text;
namespace ContosoCargo.DigitalDocument.TokenService.Host.Messages
{
public class BookingConfirmationRequestMessage
{
public string CallerID { get; set; }
public string ShipmentID { get; set; }
public string BookingConfirmationTitle { get; set; }
public string BookingConfirmationDescription { get; set; }
public string CustomerID { get; set; }
public BookingConfirmation BookingConfirmationInfo { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,20 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using System;
using System.Collections.Generic;
using System.Text;
using ContosoCargo.DigitalDocument.TokenService.Models;
namespace ContosoCargo.DigitalDocument.TokenService.Host.Messages
{
public class BookingRequestMessage
{
public string CallerID { get; set; }
public string ShipmentID { get; set; }
public string BookingRequestTitle { get; set; }
public string BookingRequestDescription { get; set; }
public string CustomerID { get; set; }
public BookingRequest BookingRequestInfo { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,16 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using System;
using System.Collections.Generic;
using System.Text;
namespace ContosoCargo.DigitalDocument.TokenService.Host.Messages
{
public class DeleteTokenRequest
{
public string TokenID { get; set; }
public string CallerID { get; set; }
public long TokenSequence { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,16 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using System;
using System.Collections.Generic;
using System.Text;
namespace ContosoCargo.DigitalDocument.TokenService.Host.Messages
{
public class GetMintedTokenInfoRequestMessage
{
public string TokenID { get; set; }
public string CallerID { get; set; }
public string TokenSequence { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,16 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using System;
using System.Collections.Generic;
using System.Text;
namespace ContosoCargo.DigitalDocument.TokenService.Host.Messages
{
public class GetTokenMetaDataRequest
{
public string TokenID { get; set; }
public string CallerID { get; set; }
public string TokenSequence { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,15 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using System;
using System.Collections.Generic;
using System.Text;
namespace ContosoCargo.DigitalDocument.TokenService.Host.Messages
{
public class GetTokenShipmentsRequest
{
public string CallerID { get; set; }
public bool IsContracter { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,20 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using ContosoCargo.DigitalDocument.TokenService.Models;
using System;
using System.Collections.Generic;
using System.Text;
namespace ContosoCargo.DigitalDocument.TokenService.Host.Messages
{
public class QuoteRequestMessage
{
public string ShipmentID { get; set; }
public string QuoteTitle { get; set; }
public string QuoteDescription { get; set; }
public string CallerID { get; set; }
public string CustomerID { get; set; }
public RateQuotation QuoteInfo { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,63 @@
using System;
using System.IO;
using System.Net.Http;
using System.Reflection;
using System.Threading.Tasks;
using ContosoCargo.DigitalDocument.TokenService.Host.Application;
using Microsoft.Azure.Functions.Worker.Extensions.OpenApi.Extensions;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using Microsoft.Extensions.Hosting;
using Microsoft.Solutions.CosmosDB.Security.ManagedIdentity;
using Polly;
using Polly.Extensions.Http;
namespace ContosoCargo.DigitalDocument.TokenService.Host
{
public class Program
{
public async static Task Main()
{
var host = new HostBuilder()
.ConfigureFunctionsWorkerDefaults(worker => worker.UseNewtonsoftJson())
.ConfigureOpenApi()
.ConfigureAppConfiguration(appConfiguration =>
{
var fileInfo = new FileInfo(Assembly.GetExecutingAssembly().Location);
appConfiguration.AddJsonFile(Path.Combine(fileInfo.Directory.FullName,"application.settings.json"), false, false).Build();
})
.ConfigureServices((context, services) =>
{
services.AddSingleton<CosmosConnectionStrings>(x =>
{
return ConnectionStringAccessor.Create(context.Configuration["App:SubscriptionId"], context.Configuration["App:ResourceGroupName"], context.Configuration["App:DatabaseAccountName"])
.GetConnectionStringsAsync(context.Configuration["App:ManagedIdentityId"]).GetAwaiter().GetResult();
});
services.AddHttpClient<IContosoCargoApplication, Application.ContosoCargo>()
.SetHandlerLifetime(TimeSpan.FromSeconds(5))
.AddPolicyHandler(GetRetryPolicy());
services.AddTransient<IContosoCargoApplication, Application.ContosoCargo>();
services.AddLogging();
})
.Build();
await host.RunAsync();
}
static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy()
{
return HttpPolicyExtensions
.HandleTransientHttpError()
.OrResult(msg => msg.StatusCode == System.Net.HttpStatusCode.NotFound)
.WaitAndRetryAsync(3, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2,
retryAttempt)));
}
}
}

Просмотреть файл

@ -0,0 +1,175 @@
{
"$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"metadata": {
"_dependencyType": "compute.function.windows.appService"
},
"parameters": {
"resourceGroupName": {
"type": "string",
"defaultValue": "ShippingTokenSA",
"metadata": {
"description": "Name of the resource group for the resource. It is recommended to put resources under same resource group for better tracking."
}
},
"resourceGroupLocation": {
"type": "string",
"defaultValue": "",
"metadata": {
"description": "Location of the resource group. Resource groups could have different location than resources, however by default we use API versions from latest hybrid profile which support all locations for resource types we support."
}
},
"resourceName": {
"type": "string",
"defaultValue": "ContosoCargoDigitalDocumentTokenService",
"metadata": {
"description": "Name of the main resource to be created by this template."
}
},
"resourceLocation": {
"type": "string",
"defaultValue": "[parameters('resourceGroupLocation')]",
"metadata": {
"description": "Location of the resource. By default use resource group's location, unless the resource provider is not supported there."
}
}
},
"resources": [
{
"type": "Microsoft.Resources/resourceGroups",
"name": "[parameters('resourceGroupName')]",
"location": "[parameters('resourceGroupLocation')]",
"apiVersion": "2019-10-01"
},
{
"type": "Microsoft.Resources/deployments",
"name": "[concat(parameters('resourceGroupName'), 'Deployment', uniqueString(concat(parameters('resourceName'), subscription().subscriptionId)))]",
"resourceGroup": "[parameters('resourceGroupName')]",
"apiVersion": "2019-10-01",
"dependsOn": [
"[parameters('resourceGroupName')]"
],
"properties": {
"mode": "Incremental",
"expressionEvaluationOptions": {
"scope": "inner"
},
"parameters": {
"resourceGroupName": {
"value": "[parameters('resourceGroupName')]"
},
"resourceGroupLocation": {
"value": "[parameters('resourceGroupLocation')]"
},
"resourceName": {
"value": "[parameters('resourceName')]"
},
"resourceLocation": {
"value": "[parameters('resourceLocation')]"
}
},
"template": {
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"resourceGroupName": {
"type": "string"
},
"resourceGroupLocation": {
"type": "string"
},
"resourceName": {
"type": "string"
},
"resourceLocation": {
"type": "string"
}
},
"variables": {
"storage_name": "[toLower(concat('storage', uniqueString(concat(parameters('resourceName'), subscription().subscriptionId))))]",
"appServicePlan_name": "[concat('Plan', uniqueString(concat(parameters('resourceName'), subscription().subscriptionId)))]",
"storage_ResourceId": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', parameters('resourceGroupName'), '/providers/Microsoft.Storage/storageAccounts/', variables('storage_name'))]",
"appServicePlan_ResourceId": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', parameters('resourceGroupName'), '/providers/Microsoft.Web/serverFarms/', variables('appServicePlan_name'))]",
"function_ResourceId": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', parameters('resourceGroupName'), '/providers/Microsoft.Web/sites/', parameters('resourceName'))]"
},
"resources": [
{
"location": "[parameters('resourceLocation')]",
"name": "[parameters('resourceName')]",
"type": "Microsoft.Web/sites",
"apiVersion": "2015-08-01",
"tags": {
"[concat('hidden-related:', variables('appServicePlan_ResourceId'))]": "empty"
},
"dependsOn": [
"[variables('appServicePlan_ResourceId')]",
"[variables('storage_ResourceId')]"
],
"kind": "functionapp",
"properties": {
"name": "[parameters('resourceName')]",
"kind": "functionapp",
"httpsOnly": true,
"reserved": false,
"serverFarmId": "[variables('appServicePlan_ResourceId')]",
"siteConfig": {
"alwaysOn": true
}
},
"identity": {
"type": "SystemAssigned"
},
"resources": [
{
"name": "appsettings",
"type": "config",
"apiVersion": "2015-08-01",
"dependsOn": [
"[variables('function_ResourceId')]"
],
"properties": {
"AzureWebJobsDashboard": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storage_name'), ';AccountKey=', listKeys(variables('storage_ResourceId'), '2017-10-01').keys[0].value, ';EndpointSuffix=', 'core.windows.net')]",
"AzureWebJobsStorage": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storage_name'), ';AccountKey=', listKeys(variables('storage_ResourceId'), '2017-10-01').keys[0].value, ';EndpointSuffix=', 'core.windows.net')]",
"FUNCTIONS_EXTENSION_VERSION": "~3",
"FUNCTIONS_WORKER_RUNTIME": "dotnet"
}
}
]
},
{
"location": "[parameters('resourceGroupLocation')]",
"name": "[variables('storage_name')]",
"type": "Microsoft.Storage/storageAccounts",
"apiVersion": "2017-10-01",
"tags": {
"[concat('hidden-related:', concat('/providers/Microsoft.Web/sites/', parameters('resourceName')))]": "empty"
},
"properties": {
"supportsHttpsTrafficOnly": true
},
"sku": {
"name": "Standard_LRS"
},
"kind": "Storage"
},
{
"location": "[parameters('resourceGroupLocation')]",
"name": "[variables('appServicePlan_name')]",
"type": "Microsoft.Web/serverFarms",
"apiVersion": "2015-08-01",
"sku": {
"name": "S1",
"tier": "Standard",
"family": "S",
"size": "S1"
},
"properties": {
"name": "[variables('appServicePlan_name')]"
}
}
]
}
}
}
]
}

Просмотреть файл

@ -0,0 +1,11 @@
{
"profiles": {
"newProfile1": {
"commandName": "Snapshot Debugger"
},
"Profile 1": {
"commandName": "Project",
"commandLineArgs": "host start --verbose"
}
}
}

Просмотреть файл

@ -0,0 +1,77 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
{
"App": {
"ServiceEndpoint": "{ServiceEndpoint}",
"SubscriptionId": "{SubscriptionId}",
"ResourceGroupName": "{ResourceGroupName}",
"DatabaseAccountName": "{DatabaseAccountName}",
"ManagedIdentityId": "{ManagedIdentityId}"
}
}

Просмотреть файл

@ -0,0 +1,18 @@
{
"version": "2.0",
"logging": {
"applicationInsights": {
"samplingSettings": {
"isEnabled": true,
"excludedTypes": "Request"
}
},
"fileLoggingMode": "debugOnly",
"logLevel": {
"default": "Information",
"Host.Results": "Error",
"Function": "Error",
"Host.Aggregator": "Trace"
}
}
}

Просмотреть файл

@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Library</OutputType>
<TargetFramework>net5.0</TargetFramework>
<StartupObject></StartupObject>
<RunAnalyzersDuringBuild>false</RunAnalyzersDuringBuild>
<RunAnalyzersDuringLiveAnalysis>false</RunAnalyzersDuringLiveAnalysis>
<ApplicationIcon />
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ContosoCargo.DigitalDocument.TokenService.OffChain.Mongo\ContosoCargo.DigitalDocument.TokenService.OffChain.Mongo.csproj" />
</ItemGroup>
</Project>

Просмотреть файл

@ -0,0 +1,18 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using System;
using System.Collections.Generic;
using System.Text;
namespace ContosoCargo.DigitalDocument.TokenService.Models
{
public class BookingConfirmation
{
public string CYCutOff { get; set; }
public string SICutOff { get; set; }
public string EmptyContainerPickupLocation { get; set; }
public string LadenContainerReturnLocation { get; set; }
public BookingRequest BookingRequest { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,34 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using System;
using System.Collections.Generic;
using System.Text;
namespace ContosoCargo.DigitalDocument.TokenService.Models
{
public class BookingRequest
{
public string Shipper { get; set; }
public string From { get; set; }
public string To { get; set; }
public ContainerSize ContainerSize { get; set; }
public ContainerType ContainerType { get; set; }
public int Quantity { get; set; }
public ShippingPlace Place { get; set; }
public int Weight { get; set; }
public CargoNature CargoNature { get; set; }
}
public enum ShippingPlace
{
Yard,
Door
}
public enum CargoNature
{
Normal,
Dangerous
}
}

Просмотреть файл

@ -0,0 +1,54 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using ContosoCargo.DigitalDocument.TokenService.OffChain.Mongo.ModelBase;
using Newtonsoft.Json;
using System;
namespace ContosoCargo.DigitalDocument.TokenService.Models
{
public class CargoTokenShipment : IEntityModel<Guid>
{
public Guid Id { get; set; }
public string TokenId { get; set; }
public TokenMeta TokenMetaInfo { get; set; }
public string Contracter { get; set; }
public string Contractee { get; set; }
public DateTime CreatedTime { get { return QuoteRequestTokenInfo.TokenMintedDate; } }
public CargoTokenShipment()
{
Id = Guid.NewGuid();
}
//Current Status of Shipment
public ShipmentStage CurrentStatus { get; set; }
public TokenMintedInfo QuoteRequestTokenInfo { get; set; }
//QuotedDate => ShipmentStage : Quoted
public TokenMintedInfo QuotedTokenInfo { get; set; }
//BookingRequestedDate => ShipmentStage : OnBookingRequest
public TokenMintedInfo BookingRequestTokenInfo { get; set; }
//BookedDate => ShipmentStage : Booked
public TokenMintedInfo BookedTokenInfo { get; set; }
//BookedDate => ShipmentStage : JobOrdered
public TokenMintedInfo JobOrderTokenInfo { get; set; }
}
public enum ShipmentStage
{
OnQuoteRequest,
Quoted,
OnBookingRequest,
Booked,
JobOrdered
}
}

Просмотреть файл

@ -0,0 +1,27 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Text;
namespace ContosoCargo.DigitalDocument.TokenService.Models
{
public class Quotation
{
public Quotation()
{
this.ID = Guid.NewGuid();
}
public Guid ID { get; }
public string CargoNature { get; set; }
public string From { get; set; }
public string To { get; set; }
public ContainerSize ContainerSize { get; set; }
public ContainerType ContainerType { get; set; }
public DateTime CargoReadyDate { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,42 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Text;
namespace ContosoCargo.DigitalDocument.TokenService.Models
{
public class RateQuotation
{
public RateQuotation()
{
this.ID = Guid.NewGuid();
}
public Guid ID { get; }
public string CargoNature { get; set; }
public string From { get; set; }
public string To { get; set; }
public ContainerSize ContainerSize { get; set; }
public ContainerType ContainerType { get; set; }
public DateTime CargoReadyDate { get; set; }
}
public enum ContainerType
{
TypeA,
TypeB,
TypeC
}
public enum ContainerSize
{
Large,
Medium,
Small
}
}

Просмотреть файл

@ -0,0 +1,19 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using System;
using System.Collections.Generic;
using System.Text;
namespace ContosoCargo.DigitalDocument.TokenService.Models
{
public class TokenMeta
{
public string TokenTemplateID { get; set; }
public string TokenID { get; set; }
public string TokenName { get; set; }
public string TokenSymbol { get; set; }
public string TokenCreator { get; set; }
public DateTime TokenCreatedDate { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,21 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using System;
using System.Collections.Generic;
using System.Text;
namespace ContosoCargo.DigitalDocument.TokenService.Models
{
public class TokenMintedInfo
{
public string TokenID { get; set; }
public long? TokenSequence { get; set; }
public string TokenMintee { get; set; }
public string TokenMinter { get; set; }
public DateTime TokenMintedDate { get; set; }
public string BusinessMetaData { get; set; }
public string MintedTokenDescription { get; set; }
public string MintedTokenTitle { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,115 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using ContosoCargo.DigitalDocument.TokenService.OffChain.Mongo.ModelBase;
using MongoDB.Bson;
using MongoDB.Bson.Serialization;
using MongoDB.Driver;
namespace ContosoCargo.DigitalDocument.TokenService.OffChain.Mongo
{
public class BusinessTransactionRepository<TEntity, TIdentifier> : IRepository<TEntity, TIdentifier> where TEntity : class, IEntityModel<TIdentifier>
{
private readonly IMongoDatabase _database;
public BusinessTransactionRepository(IMongoClient client, string DatabaseName)
{
_database = client.GetDatabase(DatabaseName);
if (!BsonClassMap.IsClassMapRegistered(typeof(TEntity)))
BsonClassMap.RegisterClassMap<TEntity>();
}
public TEntity Get(TIdentifier id)
{
return _database.GetCollection<TEntity>(typeof(TEntity).Name.ToLowerInvariant()).Find(x => x.Id.Equals(id)).FirstOrDefault();
}
public TEntity Find(ISpecification<TEntity> specification)
{
var collection = _database.GetCollection<TEntity>(typeof(TEntity).Name.ToLowerInvariant());
return collection.Find(specification.Predicate).FirstOrDefaultAsync().Result;
}
public IEnumerable<TEntity> GetAll()
{
return _database.GetCollection<TEntity>(typeof(TEntity).Name.ToLowerInvariant()).Find(new BsonDocument()).ToList();
}
/// <summary>
/// Not actually used or part of the IRepository interface.
/// </summary>
/// <param name="builders"></param>
/// <returns></returns>
public IEnumerable<TEntity> FindAll(FilterDefinition<TEntity> builders)
{
var collection = _database.GetCollection<TEntity>(typeof(TEntity).Name.ToLowerInvariant());
var list = collection.Find(builders).ToList();
return list;
}
public IEnumerable<TEntity> FindAll(ISpecification<TEntity> specification)
{
var collection = _database.GetCollection<TEntity>(typeof(TEntity).Name.ToLowerInvariant());
var list = collection.Find(specification.Predicate).ToList();
return list;
}
/// <summary>
/// Gets all entities for the passed <param name="identifiers"></param> variable.
/// </summary>
/// <param name="identifiers">Guids of type TIdentifier to find."</param>
/// <returns></returns>
public IEnumerable<TEntity> GetAll(IEnumerable<TIdentifier> identifiers)
{
List<TEntity> results = new List<TEntity>();
IMongoCollection<TEntity> collection = _database.GetCollection<TEntity>(typeof(TEntity).Name.ToLowerInvariant());
foreach (var i in identifiers)
results.Add(collection.Find(x => x.Id.Equals(i)).FirstOrDefault());
return results;
}
public TEntity Save(TEntity entity)
{
var collection = _database.GetCollection<TEntity>(typeof(TEntity).Name.ToLowerInvariant());
collection.ReplaceOne(x => x.Id.Equals(entity.Id), entity, new ReplaceOptions
{
IsUpsert = true
});
return entity;
}
public async Task<TEntity> SaveAsync(TEntity entity)
{
var collection = _database.GetCollection<TEntity>(typeof(TEntity).Name.ToLowerInvariant());
await collection.ReplaceOneAsync(x => x.Id.Equals(entity.Id), entity, new ReplaceOptions
{
IsUpsert = true
});
return entity;
}
public void Delete(TIdentifier address)
{
var collection = _database.GetCollection<TEntity>(typeof(TEntity).Name.ToLowerInvariant());
collection.DeleteOne(x => x.Id.Equals(address));
}
public void Delete(TEntity entity)
{
var collection = _database.GetCollection<TEntity>(typeof(TEntity).Name.ToLowerInvariant());
collection.DeleteOne(x => x.Id.Equals(entity.Id));
}
}
}

Просмотреть файл

@ -0,0 +1,28 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<RunAnalyzersDuringBuild>false</RunAnalyzersDuringBuild>
<RunAnalyzersDuringLiveAnalysis>false</RunAnalyzersDuringLiveAnalysis>
</PropertyGroup>
<ItemGroup>
<Compile Remove="Model\**" />
<EmbeddedResource Remove="Model\**" />
<None Remove="Model\**" />
</ItemGroup>
<ItemGroup>
<Compile Remove="TokensMetaRepository.cs" />
</ItemGroup>
<ItemGroup>
<Folder Include="ModelBase\" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="MongoDB.Driver" Version="2.14.1" />
<PackageReference Include="MongoDB.Driver.Core" Version="2.14.1" />
</ItemGroup>
</Project>

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше