release/9.30 - Commerce Sample Update

This commit is contained in:
Dynamics 365 Commerce 2021-05-24 22:07:53 +00:00
Родитель 02c8e5632a
Коммит e49e747e81
45 изменённых файлов: 1950 добавлений и 380 удалений

433
.gitignore поставляемый
Просмотреть файл

@ -1,350 +1,123 @@
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
# User-specific files
*.rsuser
*.suo
_ReSharper*
[Bb]in
obj
objd
bin
bld
pkg
/schemas/
out/
target/
tmp/
.vs
App_Data
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Mono auto generated files
mono_crash.*
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
[Ll]ogs/
# Visual Studio 2015/2017 cache/options directory
*.sln.cache
*.suo
TestResults
[Tt]humbs.db
buildd.*
build.(err|log|wrn|trc|prf|evt|dbb)
*.log
*.bak
OACRTemp/
build_logs/
lock
/public/inc/bldver.*
/public/inc/sources.ver
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
/Symbols
/drop
/.corext/.pkg/
/.corext/gen/
/.corext/cache
versionsmk.inc
Logs
# Visual Studio 2017 auto generated files
Generated\ Files/
# Weird MSBuild output folders
[0-9]
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# msbuild logs
msbuild.log
msbuild.err
msbuild.wrn
# NUnit
*.VisualState.xml
TestResult.xml
nunit-*.xml
# bad tlb/chm generators in nmake tree
*.tlb
*.chm
# The following file is a part of the sdk and must be an exception to the above rule, meaning it will be included.
!CommerceRuntimeMessages.chm
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# dumb silverlight
ClientBin/
# Benchmark Results
BenchmarkDotNet.Artifacts/
# dumb azure
*.build.csdef
csx/
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
# Generated C# files
*.g.cs
!src/SampleExtensions/ShoppingApp/**/*.g.cs
*.projhash
*.projhash.userData
*.projhash.userData.assemblies
*.slnhash
*.slnhash.userData
*.slnhash.userData.assemblies
# Ignore other generated file types, too
*.g.ts
*.g.xml
# StyleCop
StyleCopReport.xml
StyleCop.Cache
# Files built by Visual Studio
*_i.c
*_p.c
*_h.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
# Configs and transient build assets
.config/.inc/bldver.cpp
.config/.inc/bldver.cs
.config/.inc/bldver.h
.config/.inc/bldver.vb
.config/.inc/sources.ver
.config/.inc/version.htm
.config/.inc/version.sql
.config/.inc/version.json
.config/.inc/version.txt
.gen/
build/.gen_oacr/
build/oacr_exclude.ini
*.tslint
*.d.ts
*.map
*.generated
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*_wpftmp.csproj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
*.js
/src/OnlineStore/Ecommerce.Sdk.Controls/Common/Scripts.js
# Chutzpah Test files
_Chutzpah*
# Build and development artifiacts
/VersionGeneration
tslint.out
TypeScripttslintFileListArgs.txt
/.config/dev.packages.props
/src/Provisioning/ProvisioningDatabase/ProvisioningDatabase.refactorlog
.packages
phantomjs-license.txt
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# Visual Studio Trace Files
*.e2e
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json
# Visual Studio code coverage results
*.coverage
*.coveragexml
# 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
# Note: 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
# NuGet Symbol Packages
*.snupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
# POS Build Artifacts
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
*.appxbundle
*.appxupload
bld/
schemas/
dist/
devDependencies/
# 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
# Certificate files
*.pfx
*.publishsettings
orleans.codegen.cs
# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk
# Nuget package cache
/src/References
/ComponentScenarios/Pos/Dependencies/
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# Nuget package creation temps
/nu/t
# 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
ServiceFabricBackup/
*.rptproj.bak
# SQL Server files
*.mdf
*.ldf
*.ndf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
*- [Bb]ackup.rdl
*- [Bb]ackup ([0-9]).rdl
*- [Bb]ackup ([0-9][0-9]).rdl
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# 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/
# CodeRush personal settings
.cr/personal
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Tabs Studio
*.tss
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs
# OpenCover UI analysis results
OpenCover/
# Azure Stream Analytics local run output
ASALocalRun/
# MSBuild Binary and Structured Log
*.binlog
# NVidia Nsight GPU debugger configuration file
*.nvuser
# MFractors (Xamarin productivity tool) working folder
.mfractor/
# Local History for Visual Studio
.localhistory/
# BeatPulse healthcheck temp database
healthchecksdb
# Backup folder for Package Reference Convert tool in Visual Studio 2017
MigrationBackup/
# Ionide (cross platform F# VS Code tools) working folder
.ionide/
# Ignore generated nuget packages
*.nupkg

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

@ -1,9 +0,0 @@
# 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

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

@ -0,0 +1,11 @@
param(
[string]$AzureKeyVaultURI,
[string]$ApplicationId,
[string]$ApplicationSecretValue,
[string]$CertificateName,
[string]$Timestamp,
[string]$Files,
[string]$TimestampDigest = "sha256"
)
AzureSignTool.exe sign -kvu "$AzureKeyVaultURI" -kvi "$ApplicationId" -kvs "$ApplicationSecretValue" -kvc "$CertificateName" -tr "$Timestamp" -td "$TimestampDigest" (-split $Files)

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

@ -0,0 +1,13 @@
param(
[string]$RelativePath,
[string]$File,
[string]$DestinationFullName
)
$searchFile = Get-ChildItem -Path $RelativePath -Filter $File -Recurse
if (-NOT $searchFile) {
throw "$File file was not found."
}
else {
Copy-Item $searchFile.FullName -Destination "$DestinationFullName"
}

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

@ -0,0 +1,6 @@
write-host "Executing pre-build scripts"
# Any additional scripts to be executed during pipeline should be referenced in this file
# Link for reference: https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/invoke-expression?view=powershell-7.1
# Invoke-Expression -Command "C:\ps-test\testscript.ps1"

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

@ -0,0 +1,40 @@
pr: none
trigger: none
pool:
vmImage: 'windows-latest'
steps:
- task: PowerShell@2
displayName: 'Pre-Build steps'
inputs:
targetType: filePath
filePath: ./Pipeline/PowershellScripts/Pre-Build.ps1
failOnStderr: true
- task: NuGetToolInstaller@1
displayName: 'Use NuGet 5.4.0'
inputs:
versionSpec: '5.4.0'
- task: NuGetCommand@2
displayName: 'NuGet restore'
inputs:
feedsToUse: config
nugetConfigPath: nuget.config
- task: VSBuild@1
displayName: 'Build solution **\*.sln'
inputs:
solution: '**\*.sln'
- task: PowerShell@2
displayName: 'Copy CloudScaleUnitExtensionPackage package to artifact directory'
inputs:
targetType: filePath
filePath: ./Pipeline/PowershellScripts/CopyFileToDestination.ps1
arguments: '-RelativePath "$(Build.SourcesDirectory)\src\ScaleUnitSample" -File "CloudScaleUnitExtensionPackage.zip" -DestinationFullName "$(Build.ArtifactStagingDirectory)\ScaleUnitPackage_$(Build.BuildNumber).zip"'
failOnStderr: true
- task: PublishBuildArtifacts@1
displayName: 'Publish Artifact: drop'

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

@ -1,3 +1,13 @@
---
page_type: sample
languages:
- csharp
products:
- Dynamics 365 Commerce
name: Extend Headless commerce engine (CRT/RS)
description: This repo contains the sample code on how to extend the Dynamics 365 Headless Commerce engine - Retail Server, Commerce runtime and Database.
---
**Download Retail SDK samples and Reference packages from GitHub and NuGet feed:**
This document explains to how to get Retail SDK samples from GitHub and reference package from the public NuGet feed.

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

@ -1,41 +0,0 @@
<!-- BEGIN MICROSOFT SECURITY.MD V0.0.5 BLOCK -->
## 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 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 below.
## Reporting Security Issues
**Please do not report security vulnerabilities through public GitHub issues.**
Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://msrc.microsoft.com/create-report).
If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://www.microsoft.com/en-us/msrc/pgp-key-msrc).
You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc).
Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue:
* Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)
* Full paths of source file(s) related to the manifestation of the issue
* The location of the affected source code (tag/branch/commit or direct URL)
* Any special configuration required to reproduce the issue
* Step-by-step instructions to reproduce the issue
* Proof-of-concept or exploit code (if possible)
* Impact of the issue, including how an attacker might exploit the issue
This information will help us triage your report more quickly.
If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://microsoft.com/msrc/bounty) page for more details about our active programs.
## Preferred Languages
We prefer all communications to be in English.
## Policy
Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://www.microsoft.com/en-us/msrc/cvd).
<!-- END MICROSOFT SECURITY.MD BLOCK -->

11
nuget.config Normal file
Просмотреть файл

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<packageSources>
<clear />
<add key="dynamics365-commerce" value="https://pkgs.dev.azure.com/commerce-partner/Registry/_packaging/dynamics365-commerce/nuget/v3/index.json" />
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
</packageSources>
<disabledPackageSources>
<clear />
</disabledPackageSources>
</configuration>

14
repo.props Normal file
Просмотреть файл

@ -0,0 +1,14 @@
<Project>
<PropertyGroup>
<BuildNumber Condition="'$(BuildNumber)' == ''">0.0</BuildNumber>
<MajorVersion>9.30</MajorVersion>
<Version>$(MajorVersion).$(BuildNumber)</Version>
</PropertyGroup>
<PropertyGroup>
<Publisher Condition="'$(Publisher)' == ''">CN=Contoso Ltd.</Publisher>
<PublisherDisplayName Condition="'$(PublisherDisplayName)' == ''">Contoso Ltd.</PublisherDisplayName>
</PropertyGroup>
<PropertyGroup>
<CommerceSdkPackagesVersion>[9.30.21144.7-preview,9.31)</CommerceSdkPackagesVersion>
</PropertyGroup>
</Project>

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

@ -0,0 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\CustomizationPackage.props" />
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Dynamics.Commerce.Sdk.ChannelDatabase" Version="$(CommerceSdkPackagesVersion)" />
</ItemGroup>
</Project>

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

@ -0,0 +1,138 @@
/**
* SAMPLE CODE NOTICE
*
* THIS SAMPLE CODE IS MADE AVAILABLE AS IS. MICROSOFT MAKES NO WARRANTIES, WHETHER EXPRESS OR IMPLIED,
* OF FITNESS FOR A PARTICULAR PURPOSE, OF ACCURACY OR COMPLETENESS OF RESPONSES, OF RESULTS, OR CONDITIONS OF MERCHANTABILITY.
* THE ENTIRE RISK OF THE USE OR THE RESULTS FROM THE USE OF THIS SAMPLE CODE REMAINS WITH THE USER.
* NO TECHNICAL SUPPORT IS PROVIDED. YOU MAY NOT DISTRIBUTE THIS CODE UNLESS YOU HAVE A LICENSE AGREEMENT WITH MICROSOFT THAT ALLOWS YOU TO DO SO.
*/
-- Create the extension table to store the custom fields.
IF (SELECT OBJECT_ID('[ext].[CONTOSO_EXAMPLETABLE]')) IS NULL
BEGIN
CREATE TABLE
[ext].[CONTOSO_EXAMPLETABLE]
(
[EXAMPLEID] BIGINT IDENTITY(1,1) NOT NULL,
[EXAMPLEINT] INT NOT NULL DEFAULT ((0)),
[EXAMPLESTRING] NVARCHAR(64) NOT NULL DEFAULT (('')),
CONSTRAINT [I_EXAMPLETABLE_EXAMPLEID] PRIMARY KEY CLUSTERED
(
[EXAMPLEID] ASC
) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
ALTER TABLE [ext].[CONTOSO_EXAMPLETABLE] WITH CHECK ADD CHECK (([EXAMPLEID]<>(0)))
END
GO
GRANT SELECT, INSERT, UPDATE, DELETE ON OBJECT::[ext].[CONTOSO_EXAMPLETABLE] TO [DataSyncUsersRole]
GO
-- Create a stored procedure CRT can use to add entries to the custom table.
IF OBJECT_ID(N'[ext].[CONTOSO_INSERTEXAMPLE]', N'P') IS NOT NULL
DROP PROCEDURE [ext].[CONTOSO_INSERTEXAMPLE]
GO
CREATE PROCEDURE [ext].[CONTOSO_INSERTEXAMPLE]
@i_ExampleInt INT,
@s_ExampleString NVARCHAR(64)
AS
BEGIN
SET NOCOUNT ON
INSERT INTO
ext.CONTOSO_EXAMPLETABLE
(EXAMPLEINT, EXAMPLESTRING)
OUTPUT
INSERTED.EXAMPLEID
VALUES
(@i_ExampleInt, @s_ExampleString)
END;
GO
GRANT EXECUTE ON [ext].[CONTOSO_INSERTEXAMPLE] TO [UsersRole];
GO
GRANT EXECUTE ON [ext].[CONTOSO_INSERTEXAMPLE] TO [DeployExtensibilityRole];
GO
-- Create the custom view that can query a complete Example Entity.
IF (SELECT OBJECT_ID('[ext].[CONTOSO_EXAMPLEVIEW]')) IS NOT NULL
DROP VIEW [ext].[CONTOSO_EXAMPLEVIEW]
GO
CREATE VIEW [ext].[CONTOSO_EXAMPLEVIEW] AS
(
SELECT
et.EXAMPLEINT,
et.EXAMPLESTRING,
et.EXAMPLEID
FROM
[ext].[CONTOSO_EXAMPLETABLE] et
)
GO
GRANT SELECT ON OBJECT::[ext].[CONTOSO_EXAMPLEVIEW] TO [UsersRole];
GO
GRANT SELECT ON OBJECT::[ext].[CONTOSO_EXAMPLEVIEW] TO [DeployExtensibilityRole];
GO
-- Create a stored procedure CRT can use to perform updates.
IF OBJECT_ID(N'[ext].[CONTOSO_UPDATEEXAMPLE]', N'P') IS NOT NULL
DROP PROCEDURE [ext].[CONTOSO_UPDATEEXAMPLE]
GO
CREATE PROCEDURE [ext].[CONTOSO_UPDATEEXAMPLE]
@bi_Id BIGINT,
@i_ExampleInt INT,
@s_ExampleString NVARCHAR(64)
AS
BEGIN
SET NOCOUNT ON
UPDATE
ext.CONTOSO_EXAMPLETABLE
SET
EXAMPLEINT = @i_ExampleInt,
EXAMPLESTRING = @s_ExampleString
WHERE
EXAMPLEID = @bi_Id
END;
GO
GRANT EXECUTE ON [ext].[CONTOSO_UPDATEEXAMPLE] TO [UsersRole];
GO
GRANT EXECUTE ON [ext].[CONTOSO_UPDATEEXAMPLE] TO [DeployExtensibilityRole];
GO
-- Create a stored procedure CRT can use to delete Example Entities.
IF OBJECT_ID(N'[ext].[CONTOSO_DELETEEXAMPLE]', N'P') IS NOT NULL
DROP PROCEDURE [ext].CONTOSO_DELETEEXAMPLE
GO
CREATE PROCEDURE [ext].CONTOSO_DELETEEXAMPLE
@bi_Id BIGINT
AS
BEGIN
SET NOCOUNT ON
DELETE FROM
ext.CONTOSO_EXAMPLETABLE
WHERE
EXAMPLEID = @bi_Id
END;
GO
GRANT EXECUTE ON [ext].CONTOSO_DELETEEXAMPLE TO [UsersRole];
GO
GRANT EXECUTE ON [ext].CONTOSO_DELETEEXAMPLE TO [DeployExtensibilityRole];
GO

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

@ -0,0 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\CustomizationPackage.props" />
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Dynamics.Commerce.Sdk.Runtime" Version="$(CommerceSdkPackagesVersion)" />
</ItemGroup>
</Project>

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

@ -0,0 +1,63 @@
/**
* SAMPLE CODE NOTICE
*
* THIS SAMPLE CODE IS MADE AVAILABLE AS IS. MICROSOFT MAKES NO WARRANTIES, WHETHER EXPRESS OR IMPLIED,
* OF FITNESS FOR A PARTICULAR PURPOSE, OF ACCURACY OR COMPLETENESS OF RESPONSES, OF RESULTS, OR CONDITIONS OF MERCHANTABILITY.
* THE ENTIRE RISK OF THE USE OR THE RESULTS FROM THE USE OF THIS SAMPLE CODE REMAINS WITH THE USER.
* NO TECHNICAL SUPPORT IS PROVIDED. YOU MAY NOT DISTRIBUTE THIS CODE UNLESS YOU HAVE A LICENSE AGREEMENT WITH MICROSOFT THAT ALLOWS YOU TO DO SO.
*/
namespace Contoso.CommerceRuntime.Controllers
{
using System.Threading.Tasks;
using Microsoft.Dynamics.Commerce.Runtime;
using Microsoft.Dynamics.Commerce.Runtime.DataModel;
using Microsoft.Dynamics.Commerce.Runtime.Hosting.Contracts;
/// <summary>
/// An extension controller to handle requests to the StoreHours entity set.
/// </summary>
[RoutePrefix("BoundController")]
[BindEntity(typeof(Entities.DataModel.ExampleEntity))]
public class BoundController : IController
{
[HttpGet]
[Authorization(CommerceRoles.Anonymous, CommerceRoles.Application, CommerceRoles.Customer, CommerceRoles.Device, CommerceRoles.Employee, CommerceRoles.Storefront)]
public async Task<PagedResult<Entities.DataModel.ExampleEntity>> GetAllExampleEntities(IEndpointContext context)
{
var queryResultSettings = QueryResultSettings.SingleRecord;
queryResultSettings.Paging = new PagingInfo(10);
var request = new Messages.ExampleEntityDataRequest() { QueryResultSettings = queryResultSettings };
var response = await context.ExecuteAsync<Messages.ExampleEntityDataResponse>(request).ConfigureAwait(false);
return response.ExampleEntities;
}
[HttpPost]
[Authorization(CommerceRoles.Customer, CommerceRoles.Device, CommerceRoles.Employee)]
public async Task<long> CreateExampleEntity(IEndpointContext context, CommerceRuntime.Entities.DataModel.ExampleEntity entityData)
{
var request = new Messages.CreateExampleEntityDataRequest(entityData);
var response = await context.ExecuteAsync<Messages.CreateExampleEntityDataResponse>(request).ConfigureAwait(false);
return response.CreatedId;
}
[HttpPost]
[Authorization(CommerceRoles.Customer, CommerceRoles.Device, CommerceRoles.Employee)]
public async Task<bool> UpdateExampleEntity(IEndpointContext context, [EntityKey] long key, CommerceRuntime.Entities.DataModel.ExampleEntity updatedEntity)
{
var request = new Messages.UpdateExampleEntityDataRequest(key, updatedEntity);
var response = await context.ExecuteAsync<Messages.UpdateExampleEntityDataResponse>(request).ConfigureAwait(false);
return response.Success;
}
[HttpPost]
[Authorization(CommerceRoles.Customer, CommerceRoles.Device, CommerceRoles.Employee)]
public async Task<bool> DeleteExampleEntity(IEndpointContext context, [EntityKey] long key)
{
var request = new Messages.DeleteExampleEntityDataRequest(key);
var response = await context.ExecuteAsync<Messages.DeleteExampleEntityDataResponse>(request).ConfigureAwait(false);
return response.Success;
}
}
}

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

@ -0,0 +1,43 @@
/**
* SAMPLE CODE NOTICE
*
* THIS SAMPLE CODE IS MADE AVAILABLE AS IS. MICROSOFT MAKES NO WARRANTIES, WHETHER EXPRESS OR IMPLIED,
* OF FITNESS FOR A PARTICULAR PURPOSE, OF ACCURACY OR COMPLETENESS OF RESPONSES, OF RESULTS, OR CONDITIONS OF MERCHANTABILITY.
* THE ENTIRE RISK OF THE USE OR THE RESULTS FROM THE USE OF THIS SAMPLE CODE REMAINS WITH THE USER.
* NO TECHNICAL SUPPORT IS PROVIDED. YOU MAY NOT DISTRIBUTE THIS CODE UNLESS YOU HAVE A LICENSE AGREEMENT WITH MICROSOFT THAT ALLOWS YOU TO DO SO.
*/
namespace Contoso.CommerceRuntime.Controllers
{
using System.Threading.Tasks;
using Microsoft.Dynamics.Commerce.Runtime.DataModel;
using Microsoft.Dynamics.Commerce.Runtime.Hosting.Contracts;
/// <summary>
/// An extension controller to handle requests to the StoreHours entity set.
/// </summary>
public class UnboundController : IController
{
/// <summary>
/// A simple GET endpoint to demonstrate GET endpoints on an unbound controller.
/// </summary>
/// <returns>A simple true value to indicate the endpoint was reached.</returns>
[HttpGet]
[Authorization(CommerceRoles.Anonymous, CommerceRoles.Application, CommerceRoles.Customer, CommerceRoles.Device, CommerceRoles.Employee, CommerceRoles.Storefront)]
public Task<bool> SimplePingGet()
{
return Task.FromResult(true);
}
/// <summary>
/// A simple POST endpoint to demonstrate POST endpoints on an unbound controller.
/// </summary>
/// <returns>A simple true value to indicate the endpoint was reached.</returns>
[HttpPost]
[Authorization(CommerceRoles.Customer, CommerceRoles.Device, CommerceRoles.Employee)]
public Task<bool> SimplePingPost()
{
return Task.FromResult(true);
}
}
}

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

@ -0,0 +1,73 @@
/**
* SAMPLE CODE NOTICE
*
* THIS SAMPLE CODE IS MADE AVAILABLE AS IS. MICROSOFT MAKES NO WARRANTIES, WHETHER EXPRESS OR IMPLIED,
* OF FITNESS FOR A PARTICULAR PURPOSE, OF ACCURACY OR COMPLETENESS OF RESPONSES, OF RESULTS, OR CONDITIONS OF MERCHANTABILITY.
* THE ENTIRE RISK OF THE USE OR THE RESULTS FROM THE USE OF THIS SAMPLE CODE REMAINS WITH THE USER.
* NO TECHNICAL SUPPORT IS PROVIDED. YOU MAY NOT DISTRIBUTE THIS CODE UNLESS YOU HAVE A LICENSE AGREEMENT WITH MICROSOFT THAT ALLOWS YOU TO DO SO.
*/
namespace Contoso.CommerceRuntime.Entities.DataModel
{
using System.Runtime.Serialization;
using Microsoft.Dynamics.Commerce.Runtime.ComponentModel.DataAnnotations;
using Microsoft.Dynamics.Commerce.Runtime.DataModel;
using SystemAnnotations = System.ComponentModel.DataAnnotations;
/// <summary>
/// Defines a simple class that holds information about opening and closing times for a particular day.
/// </summary>
public class ExampleEntity : CommerceEntity
{
private const string ExampleIntColumn = "EXAMPLEINT";
private const string ExampleStringColumn = "EXAMPLESTRING";
private const string IdColumn = "EXAMPLEID";
/// <summary>
/// Initializes a new instance of the <see cref="ExampleEntity"/> class.
/// </summary>
public ExampleEntity()
: base("Example")
{
}
/// <summary>
/// Gets or sets a property containing an int value.
/// </summary>
[DataMember]
[Column(ExampleIntColumn)]
public int IntData
{
get { return (int)this[ExampleIntColumn]; }
set { this[ExampleIntColumn] = value; }
}
/// <summary>
/// Gets or sets a property containing a string value.
/// </summary>
[DataMember]
[Column(ExampleStringColumn)]
public string StringData
{
get { return (string)this[ExampleStringColumn]; }
set { this[ExampleStringColumn] = value; }
}
/// <summary>
/// Gets or sets the id.
/// </summary>
/// <remarks>
/// Fields named "Id" are automatically treated as the entity key.
/// If a name other than Id is preferred, <see cref="System.ComponentModel.DataAnnotations.KeyAttribute"/>
/// can be used like it is here to annotate a given field as the entity key.
/// </remarks>
[SystemAnnotations.Key]
[DataMember]
[Column(IdColumn)]
public long UnusualEntityId
{
get { return (long)this[IdColumn]; }
set { this[IdColumn] = value; }
}
}
}

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

@ -0,0 +1,37 @@
/**
* SAMPLE CODE NOTICE
*
* THIS SAMPLE CODE IS MADE AVAILABLE AS IS. MICROSOFT MAKES NO WARRANTIES, WHETHER EXPRESS OR IMPLIED,
* OF FITNESS FOR A PARTICULAR PURPOSE, OF ACCURACY OR COMPLETENESS OF RESPONSES, OF RESULTS, OR CONDITIONS OF MERCHANTABILITY.
* THE ENTIRE RISK OF THE USE OR THE RESULTS FROM THE USE OF THIS SAMPLE CODE REMAINS WITH THE USER.
* NO TECHNICAL SUPPORT IS PROVIDED. YOU MAY NOT DISTRIBUTE THIS CODE UNLESS YOU HAVE A LICENSE AGREEMENT WITH MICROSOFT THAT ALLOWS YOU TO DO SO.
*/
namespace Contoso.CommerceRuntime.Messages
{
using System.Runtime.Serialization;
using Contoso.CommerceRuntime.Entities.DataModel;
using Microsoft.Dynamics.Commerce.Runtime.Messages;
/// <summary>
/// A simple request class to create an Example Entity in the database.
/// </summary>
[DataContract]
public sealed class CreateExampleEntityDataRequest : Request
{
/// <summary>
/// Initializes a new instance of the <see cref="CreateExampleEntityDataRequest"/> class.
/// </summary>
/// <param name="entityData">An example entity with its fields populated with the values to be stored.</param>
public CreateExampleEntityDataRequest(ExampleEntity entityData)
{
this.EntityData = entityData;
}
/// <summary>
/// Gets an Example Entity instance with its fields set with the values to be stored.
/// </summary>
[DataMember]
public ExampleEntity EntityData { get; private set; }
}
}

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

@ -0,0 +1,35 @@
/**
* SAMPLE CODE NOTICE
*
* THIS SAMPLE CODE IS MADE AVAILABLE AS IS. MICROSOFT MAKES NO WARRANTIES, WHETHER EXPRESS OR IMPLIED,
* OF FITNESS FOR A PARTICULAR PURPOSE, OF ACCURACY OR COMPLETENESS OF RESPONSES, OF RESULTS, OR CONDITIONS OF MERCHANTABILITY.
* THE ENTIRE RISK OF THE USE OR THE RESULTS FROM THE USE OF THIS SAMPLE CODE REMAINS WITH THE USER.
* NO TECHNICAL SUPPORT IS PROVIDED. YOU MAY NOT DISTRIBUTE THIS CODE UNLESS YOU HAVE A LICENSE AGREEMENT WITH MICROSOFT THAT ALLOWS YOU TO DO SO.
*/
namespace Contoso.CommerceRuntime.Messages
{
using System.Runtime.Serialization;
using Microsoft.Dynamics.Commerce.Runtime.Messages;
/// <summary>
/// A simple response class to indicate whether creating a new entity succeeded or not.
/// </summary>
[DataContract]
public sealed class CreateExampleEntityDataResponse : Response
{
/// <summary>
/// Initializes a new instance of the <see cref="CreateExampleEntityDataResponse"/> class.
/// </summary>
/// <param name="createdId">The ID of the newly saved entity instance, 0 in the event of failure.</param>
public CreateExampleEntityDataResponse(long createdId)
{
this.CreatedId = createdId;
}
/// <summary>
/// Gets the ID of the newly saved entity instance, or 0 in the event of failure.
/// </summary>
public long CreatedId { get; private set; }
}
}

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

@ -0,0 +1,35 @@
/**
* SAMPLE CODE NOTICE
*
* THIS SAMPLE CODE IS MADE AVAILABLE AS IS. MICROSOFT MAKES NO WARRANTIES, WHETHER EXPRESS OR IMPLIED,
* OF FITNESS FOR A PARTICULAR PURPOSE, OF ACCURACY OR COMPLETENESS OF RESPONSES, OF RESULTS, OR CONDITIONS OF MERCHANTABILITY.
* THE ENTIRE RISK OF THE USE OR THE RESULTS FROM THE USE OF THIS SAMPLE CODE REMAINS WITH THE USER.
* NO TECHNICAL SUPPORT IS PROVIDED. YOU MAY NOT DISTRIBUTE THIS CODE UNLESS YOU HAVE A LICENSE AGREEMENT WITH MICROSOFT THAT ALLOWS YOU TO DO SO.
*/
namespace Contoso.CommerceRuntime.Messages
{
using System.Runtime.Serialization;
using Microsoft.Dynamics.Commerce.Runtime.Messages;
/// <summary>
/// A simple request used to delete an example entity from the database.
/// </summary>
[DataContract]
public sealed class DeleteExampleEntityDataRequest : Request
{
/// <summary>
/// Initializes a new instance of the <see cref="DeleteExampleEntityDataRequest"/> class.
/// </summary>
/// <param name="entityKey">A unique key identifying an Example Entity record to delete.</param>
public DeleteExampleEntityDataRequest(long entityKey)
{
this.ExampleEntityKey = entityKey;
}
/// <summary>
/// Gets the unique ID specifying the Example Entity record to delete.
/// </summary>
public long ExampleEntityKey { get; private set; }
}
}

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

@ -0,0 +1,35 @@
/**
* SAMPLE CODE NOTICE
*
* THIS SAMPLE CODE IS MADE AVAILABLE AS IS. MICROSOFT MAKES NO WARRANTIES, WHETHER EXPRESS OR IMPLIED,
* OF FITNESS FOR A PARTICULAR PURPOSE, OF ACCURACY OR COMPLETENESS OF RESPONSES, OF RESULTS, OR CONDITIONS OF MERCHANTABILITY.
* THE ENTIRE RISK OF THE USE OR THE RESULTS FROM THE USE OF THIS SAMPLE CODE REMAINS WITH THE USER.
* NO TECHNICAL SUPPORT IS PROVIDED. YOU MAY NOT DISTRIBUTE THIS CODE UNLESS YOU HAVE A LICENSE AGREEMENT WITH MICROSOFT THAT ALLOWS YOU TO DO SO.
*/
namespace Contoso.CommerceRuntime.Messages
{
using System.Runtime.Serialization;
using Microsoft.Dynamics.Commerce.Runtime.Messages;
/// <summary>
/// A simple response class to indicate whether a delete succeeded or not.
/// </summary>
[DataContract]
public sealed class DeleteExampleEntityDataResponse : Response
{
/// <summary>
/// Creates a new instance of the <see cref="DeleteExampleEntityDataResponse"/> class.
/// </summary>
/// <param name="success">Whether the delete succeeded.</param>
public DeleteExampleEntityDataResponse(bool success)
{
this.Success = success;
}
/// <summary>
/// Gets a value indicating whether the delete succeeded.
/// </summary>
public bool Success { get; private set; }
}
}

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

@ -0,0 +1,21 @@
/**
* SAMPLE CODE NOTICE
*
* THIS SAMPLE CODE IS MADE AVAILABLE AS IS. MICROSOFT MAKES NO WARRANTIES, WHETHER EXPRESS OR IMPLIED,
* OF FITNESS FOR A PARTICULAR PURPOSE, OF ACCURACY OR COMPLETENESS OF RESPONSES, OF RESULTS, OR CONDITIONS OF MERCHANTABILITY.
* THE ENTIRE RISK OF THE USE OR THE RESULTS FROM THE USE OF THIS SAMPLE CODE REMAINS WITH THE USER.
* NO TECHNICAL SUPPORT IS PROVIDED. YOU MAY NOT DISTRIBUTE THIS CODE UNLESS YOU HAVE A LICENSE AGREEMENT WITH MICROSOFT THAT ALLOWS YOU TO DO SO.
*/
namespace Contoso.CommerceRuntime.Messages
{
using System.Runtime.Serialization;
using Microsoft.Dynamics.Commerce.Runtime.Messages;
/// <summary>
/// A simple request class to get all Example Entities.
/// </summary>
[DataContract]
public sealed class ExampleEntityDataRequest : Request
{
}
}

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

@ -0,0 +1,38 @@
/**
* SAMPLE CODE NOTICE
*
* THIS SAMPLE CODE IS MADE AVAILABLE AS IS. MICROSOFT MAKES NO WARRANTIES, WHETHER EXPRESS OR IMPLIED,
* OF FITNESS FOR A PARTICULAR PURPOSE, OF ACCURACY OR COMPLETENESS OF RESPONSES, OF RESULTS, OR CONDITIONS OF MERCHANTABILITY.
* THE ENTIRE RISK OF THE USE OR THE RESULTS FROM THE USE OF THIS SAMPLE CODE REMAINS WITH THE USER.
* NO TECHNICAL SUPPORT IS PROVIDED. YOU MAY NOT DISTRIBUTE THIS CODE UNLESS YOU HAVE A LICENSE AGREEMENT WITH MICROSOFT THAT ALLOWS YOU TO DO SO.
*/
namespace Contoso.CommerceRuntime.Messages
{
using System.Runtime.Serialization;
using Contoso.CommerceRuntime.Entities.DataModel;
using Microsoft.Dynamics.Commerce.Runtime;
using Microsoft.Dynamics.Commerce.Runtime.Messages;
/// <summary>
/// Defines a simple response class that holds a collection of Example Entities.
/// </summary>
[DataContract]
public sealed class ExampleEntityDataResponse : Response
{
/// <summary>
/// Initializes a new instance of the <see cref="ExampleEntityDataResponse"/> class.
/// </summary>
/// <param name="exampleEntities">The collection of Example Entities.</param>
public ExampleEntityDataResponse(PagedResult<ExampleEntity> exampleEntities)
{
this.ExampleEntities = exampleEntities;
}
/// <summary>
/// Gets the retrieved Example Entities as a paged result.
/// </summary>
[DataMember]
public PagedResult<ExampleEntity> ExampleEntities { get; private set; }
}
}

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

@ -0,0 +1,44 @@
/**
* SAMPLE CODE NOTICE
*
* THIS SAMPLE CODE IS MADE AVAILABLE AS IS. MICROSOFT MAKES NO WARRANTIES, WHETHER EXPRESS OR IMPLIED,
* OF FITNESS FOR A PARTICULAR PURPOSE, OF ACCURACY OR COMPLETENESS OF RESPONSES, OF RESULTS, OR CONDITIONS OF MERCHANTABILITY.
* THE ENTIRE RISK OF THE USE OR THE RESULTS FROM THE USE OF THIS SAMPLE CODE REMAINS WITH THE USER.
* NO TECHNICAL SUPPORT IS PROVIDED. YOU MAY NOT DISTRIBUTE THIS CODE UNLESS YOU HAVE A LICENSE AGREEMENT WITH MICROSOFT THAT ALLOWS YOU TO DO SO.
*/
namespace Contoso.CommerceRuntime.Messages
{
using System.Runtime.Serialization;
using Contoso.CommerceRuntime.Entities.DataModel;
using Microsoft.Dynamics.Commerce.Runtime.Messages;
/// <summary>
/// A simple request class to update the values on an example entity.
/// </summary>
[DataContract]
public sealed class UpdateExampleEntityDataRequest : Request
{
/// <summary>
/// Initializes a new instance of the <see cref="UpdateExampleEntityDataRequest"/> class.
/// </summary>
/// <param name="entityKey">A unique key identifying an Example Entity record to update.</param>
/// <param name="updatedEntity">An example entity with update fields.</param>
public UpdateExampleEntityDataRequest(long entityKey, ExampleEntity updatedEntity)
{
this.ExampleEntityKey = entityKey;
this.UpdatedExampleEntity = updatedEntity;
}
/// <summary>
/// Gets the unique ID specifying the Example Entity record to update.
/// </summary>
public long ExampleEntityKey { get; private set; }
/// <summary>
/// Gets an Example Entity instance with any updates applied to it.
/// </summary>
[DataMember]
public ExampleEntity UpdatedExampleEntity { get; private set; }
}
}

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

@ -0,0 +1,35 @@
/**
* SAMPLE CODE NOTICE
*
* THIS SAMPLE CODE IS MADE AVAILABLE AS IS. MICROSOFT MAKES NO WARRANTIES, WHETHER EXPRESS OR IMPLIED,
* OF FITNESS FOR A PARTICULAR PURPOSE, OF ACCURACY OR COMPLETENESS OF RESPONSES, OF RESULTS, OR CONDITIONS OF MERCHANTABILITY.
* THE ENTIRE RISK OF THE USE OR THE RESULTS FROM THE USE OF THIS SAMPLE CODE REMAINS WITH THE USER.
* NO TECHNICAL SUPPORT IS PROVIDED. YOU MAY NOT DISTRIBUTE THIS CODE UNLESS YOU HAVE A LICENSE AGREEMENT WITH MICROSOFT THAT ALLOWS YOU TO DO SO.
*/
namespace Contoso.CommerceRuntime.Messages
{
using System.Runtime.Serialization;
using Microsoft.Dynamics.Commerce.Runtime.Messages;
/// <summary>
/// A simple response class to indicate whether an update succeeded or not.
/// </summary>
[DataContract]
public sealed class UpdateExampleEntityDataResponse : Response
{
/// <summary>
/// Initializes a new instance of the <see cref="UpdateExampleEntityDataResponse"/> class.
/// </summary>
/// <param name="success">Whether the update succeeded.</param>
public UpdateExampleEntityDataResponse(bool success)
{
this.Success = success;
}
/// <summary>
/// Gets a value indicating whether the update succeeded.
/// </summary>
public bool Success { get; private set; }
}
}

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

@ -0,0 +1,174 @@
/**
* SAMPLE CODE NOTICE
*
* THIS SAMPLE CODE IS MADE AVAILABLE AS IS. MICROSOFT MAKES NO WARRANTIES, WHETHER EXPRESS OR IMPLIED,
* OF FITNESS FOR A PARTICULAR PURPOSE, OF ACCURACY OR COMPLETENESS OF RESPONSES, OF RESULTS, OR CONDITIONS OF MERCHANTABILITY.
* THE ENTIRE RISK OF THE USE OR THE RESULTS FROM THE USE OF THIS SAMPLE CODE REMAINS WITH THE USER.
* NO TECHNICAL SUPPORT IS PROVIDED. YOU MAY NOT DISTRIBUTE THIS CODE UNLESS YOU HAVE A LICENSE AGREEMENT WITH MICROSOFT THAT ALLOWS YOU TO DO SO.
*/
namespace Contoso.CommerceRuntime.RequestHandlers
{
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Dynamics.Commerce.Runtime;
using Microsoft.Dynamics.Commerce.Runtime.Data;
using Microsoft.Dynamics.Commerce.Runtime.Messages;
using Contoso.CommerceRuntime.Entities.DataModel;
using Contoso.CommerceRuntime.Messages;
/// <summary>
/// Sample service to demonstrate managing a collection of entities.
/// </summary>
public class ExampleDataService : IRequestHandlerAsync
{
/// <summary>
/// Gets the collection of supported request types by this handler.
/// </summary>
public IEnumerable<Type> SupportedRequestTypes
{
get
{
return new[]
{
typeof(CreateExampleEntityDataRequest),
typeof(ExampleEntityDataRequest),
typeof(UpdateExampleEntityDataRequest),
typeof(DeleteExampleEntityDataRequest),
};
}
}
/// <summary>
/// Entry point to StoreHoursDataService service.
/// </summary>
/// <param name="request">The request to execute.</param>
/// <returns>Result of executing request, or null object for void operations.</returns>
public Task<Response> Execute(Request request)
{
if (request == null)
{
throw new ArgumentNullException("request");
}
Type reqType = request.GetType();
if (reqType == typeof(CreateExampleEntityDataRequest))
{
return this.CreateExampleEntity((CreateExampleEntityDataRequest)request);
}
else if (reqType == typeof(ExampleEntityDataRequest))
{
return this.GetExampleEntities((ExampleEntityDataRequest)request);
}
else if (reqType == typeof(UpdateExampleEntityDataRequest))
{
return this.UpdateExampleEntity((UpdateExampleEntityDataRequest)request);
}
else if (reqType == typeof(DeleteExampleEntityDataRequest))
{
return this.DeleteExampleEntity((DeleteExampleEntityDataRequest)request);
}
else
{
string message = string.Format(CultureInfo.InvariantCulture, "Request '{0}' is not supported.", reqType);
throw new NotSupportedException(message);
}
}
private async Task<Response> CreateExampleEntity(CreateExampleEntityDataRequest request)
{
ThrowIf.Null(request, nameof(request));
ThrowIf.Null(request.EntityData, nameof(request.EntityData));
long insertedId = 0;
using (var databaseContext = new DatabaseContext(request.RequestContext))
{
ParameterSet parameters = new ParameterSet();
parameters["@i_ExampleInt"] = request.EntityData.IntData;
parameters["@s_ExampleString"] = request.EntityData.StringData;
var result = await databaseContext
.ExecuteStoredProcedureAsync<ExampleEntity>("[ext].CONTOSO_INSERTEXAMPLE", parameters, request.QueryResultSettings)
.ConfigureAwait(continueOnCapturedContext: false);
insertedId = result.Item2.Single().UnusualEntityId;
}
return new CreateExampleEntityDataResponse(insertedId);
}
private async Task<Response> GetExampleEntities(ExampleEntityDataRequest request)
{
ThrowIf.Null(request, "request");
using (DatabaseContext databaseContext = new DatabaseContext(request.RequestContext))
{
var query = new SqlPagedQuery(request.QueryResultSettings)
{
DatabaseSchema = "ext",
Select = new ColumnSet("EXAMPLEINT", "EXAMPLESTRING", "EXAMPLEID"),
From = "CONTOSO_EXAMPLEVIEW",
OrderBy = "EXAMPLEID",
};
var queryResults =
await databaseContext
.ReadEntityAsync<Entities.DataModel.ExampleEntity>(query)
.ConfigureAwait(continueOnCapturedContext: false);
return new ExampleEntityDataResponse(queryResults);
}
}
private async Task<Response> UpdateExampleEntity(UpdateExampleEntityDataRequest request)
{
ThrowIf.Null(request, nameof(request));
ThrowIf.Null(request.UpdatedExampleEntity, nameof(request.UpdatedExampleEntity));
if (request.ExampleEntityKey == 0)
{
throw new DataValidationException(DataValidationErrors.Microsoft_Dynamics_Commerce_Runtime_ValueOutOfRange, $"{nameof(request.ExampleEntityKey)} cannot be 0");
}
bool updateSuccess = false;
using (var databaseContext = new DatabaseContext(request.RequestContext))
{
ParameterSet parameters = new ParameterSet();
parameters["@bi_Id"] = request.ExampleEntityKey;
parameters["@i_ExampleInt"] = request.UpdatedExampleEntity.IntData;
parameters["@s_ExampleString"] = request.UpdatedExampleEntity.StringData;
int sprocErrorCode =
await databaseContext
.ExecuteStoredProcedureNonQueryAsync("[ext].CONTOSO_UPDATEEXAMPLE", parameters, request.QueryResultSettings)
.ConfigureAwait(continueOnCapturedContext: false);
updateSuccess = (sprocErrorCode == 0);
}
return new UpdateExampleEntityDataResponse(updateSuccess);
}
private async Task<Response> DeleteExampleEntity(DeleteExampleEntityDataRequest request)
{
ThrowIf.Null(request, nameof(request));
if (request.ExampleEntityKey == 0)
{
throw new DataValidationException(DataValidationErrors.Microsoft_Dynamics_Commerce_Runtime_ValueOutOfRange, $"{nameof(request.ExampleEntityKey)} cannot be 0");
}
bool deleteSuccess = false;
using (var databaseContext = new DatabaseContext(request.RequestContext))
{
ParameterSet parameters = new ParameterSet();
parameters["@bi_Id"] = request.ExampleEntityKey;
int sprocErrorCode =
await databaseContext
.ExecuteStoredProcedureNonQueryAsync("[ext].CONTOSO_DELETEEXAMPLE", parameters, request.QueryResultSettings)
.ConfigureAwait(continueOnCapturedContext: false);
deleteSuccess = sprocErrorCode == 0;
}
return new DeleteExampleEntityDataResponse(deleteSuccess);
}
}
}

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

@ -0,0 +1,61 @@
/**
* SAMPLE CODE NOTICE
*
* THIS SAMPLE CODE IS MADE AVAILABLE AS IS. MICROSOFT MAKES NO WARRANTIES, WHETHER EXPRESS OR IMPLIED,
* OF FITNESS FOR A PARTICULAR PURPOSE, OF ACCURACY OR COMPLETENESS OF RESPONSES, OF RESULTS, OR CONDITIONS OF MERCHANTABILITY.
* THE ENTIRE RISK OF THE USE OR THE RESULTS FROM THE USE OF THIS SAMPLE CODE REMAINS WITH THE USER.
* NO TECHNICAL SUPPORT IS PROVIDED. YOU MAY NOT DISTRIBUTE THIS CODE UNLESS YOU HAVE A LICENSE AGREEMENT WITH MICROSOFT THAT ALLOWS YOU TO DO SO.
*/
namespace Contoso.CommerceRuntime.Triggers
{
using System;
using System.Collections.Generic;
using Microsoft.Dynamics.Commerce.Runtime;
using Microsoft.Dynamics.Commerce.Runtime.DataModel;
using Microsoft.Dynamics.Commerce.Runtime.Messages;
/// <summary>
/// Class that implements a post trigger for the GetCustomerDataRequest request type.
/// </summary>
public class DefinePosExtensionTrigger : IRequestTrigger
{
/// <summary>
/// Gets the supported requests for this trigger.
/// </summary>
public IEnumerable<Type> SupportedRequestTypes
{
get
{
return new[] { typeof(GetExtensionPackageDefinitionsRequest) };
}
}
/// <summary>
/// Post trigger code to retrieve extension properties.
/// </summary>
/// <param name="request">The request.</param>
/// <param name="response">The response.</param>
public void OnExecuted(Request request, Response response)
{
ThrowIf.Null(request, "request");
ThrowIf.Null(response, "response");
var getExtensionsResponse = (GetExtensionPackageDefinitionsResponse)response;
var extensionPackageDefinition = new ExtensionPackageDefinition();
extensionPackageDefinition.Name = "POS";
extensionPackageDefinition.Publisher = "Contoso";
extensionPackageDefinition.IsEnabled = true;
getExtensionsResponse.ExtensionPackageDefinitions.Add(extensionPackageDefinition);
}
/// <summary>
/// Pre trigger code.
/// </summary>
/// <param name="request">The request.</param>
public void OnExecuting(Request request)
{
}
}
}

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

@ -0,0 +1,12 @@
<Project>
<Import Project="..\..\repo.props" />
<PropertyGroup>
<PackagePublisher Condition="'$(PackagePublisher)' == ''">$(Publisher)</PackagePublisher>
<PackagePublisherDisplayName Condition="'$(PackagePublisherDisplayName)' == ''">$(PublisherDisplayName)</PackagePublisherDisplayName>
<PackageVersion Condition="'$(PackageVersion)' == ''">$(Version)</PackageVersion>
<PackageName Condition="'$(PackageName)' == ''">Contoso.Commerce.ScaleUnit</PackageName>
<PackageDisplayName Condition="'$(PackageDisplayName)' == ''">Contoso Scale Unit Example Commerce Customization</PackageDisplayName>
<PackageDescription Condition="'$(PackageDescription)' == ''">Contoso Scale Unit Example Commerce Customization</PackageDescription>
</PropertyGroup>
</Project>

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

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<commerceRuntimeExtensions>
<composition>
<add source="assembly" value="CommerceRuntime" />
</composition>
</commerceRuntimeExtensions>

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

@ -0,0 +1,28 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\CustomizationPackage.props" />
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net461</TargetFramework>
</PropertyGroup>
<ItemGroup>
<Content Include="Extension.config" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Dynamics.Commerce.Sdk.Installers.ScaleUnit" Version="$(CommerceSdkPackagesVersion)" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ChannelDatabase\ChannelDatabase.csproj">
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
</ProjectReference>
<ProjectReference Include="..\CommerceRuntime\CommerceRuntime.csproj">
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
</ProjectReference>
<ProjectReference Include="..\POS\POS.csproj">
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
</ProjectReference>
</ItemGroup>
</Project>

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

@ -0,0 +1,25 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Example Create Dialog</title>
</head>
<body>
<div class="ExampleCreateDialog col grow">
<div>
<div class="h4">Int data:</div>
<input type="number" id="intData"></select>
<br />
<br />
<div class="h4">String data:</div>
<input type="text" id="stringData"></input>
<br />
<br />
<div class="h4">Extension property string data:</div>
<input type="text" id="extensionPropertyStringData"></input>
</div>
<div class="grow"></div>
<div class="row"></div>
</div>
</body>
</html>

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

@ -0,0 +1,88 @@
/**
* SAMPLE CODE NOTICE
*
* THIS SAMPLE CODE IS MADE AVAILABLE AS IS. MICROSOFT MAKES NO WARRANTIES, WHETHER EXPRESS OR IMPLIED,
* OF FITNESS FOR A PARTICULAR PURPOSE, OF ACCURACY OR COMPLETENESS OF RESPONSES, OF RESULTS, OR CONDITIONS OF MERCHANTABILITY.
* THE ENTIRE RISK OF THE USE OR THE RESULTS FROM THE USE OF THIS SAMPLE CODE REMAINS WITH THE USER.
* NO TECHNICAL SUPPORT IS PROVIDED. YOU MAY NOT DISTRIBUTE THIS CODE UNLESS YOU HAVE A LICENSE AGREEMENT WITH MICROSOFT THAT ALLOWS YOU TO DO SO.
*/
import * as Dialogs from "PosApi/Create/Dialogs";
import { Entities } from "../../../DataService/DataServiceEntities.g";
import { ObjectExtensions } from "PosApi/TypeExtensions";
type DialogResolve = (updatedEntity: Entities.ExampleEntity) => void;
type DialogReject = (reason: any) => void;
export default class ExampleCreateDialog extends Dialogs.ExtensionTemplatedDialogBase {
private _resolve: DialogResolve;
private _data: Entities.ExampleEntity;
constructor() {
super();
this._data = {
UnusualEntityId: -1,
IntData: 0,
StringData: "",
ExtensionProperties: [{
Key: "customExtensionProp",
Value: {}
}]
};
}
public onReady(element: HTMLElement): void {
let intDataInput: HTMLInputElement = element.querySelector("#intData") as HTMLInputElement;
intDataInput.onchange = () => { this._data.IntData = intDataInput.valueAsNumber; };
let stringDataInput: HTMLInputElement = element.querySelector("#stringData") as HTMLInputElement;
stringDataInput.onchange = () => { this._data.StringData = stringDataInput.value; };
let extensionPropertyStringDataInput: HTMLInputElement = element.querySelector("#extensionPropertyStringData") as HTMLInputElement;
extensionPropertyStringDataInput.onchange = () => {
this._data.ExtensionProperties[0].Value.StringValue = extensionPropertyStringDataInput.value;
};
}
public open(): Promise<Entities.ExampleEntity> {
let promise: Promise<Entities.ExampleEntity> = new Promise((resolve: DialogResolve, reject: DialogReject) => {
this._resolve = resolve;
let option: Dialogs.ITemplatedDialogOptions = {
title: "Create Example Entity",
button1: {
id: "btnCreate",
label: this.context.resources.getString("string_2001"),
isPrimary: true,
onClick: this.btnUpdateClickHandler.bind(this)
},
button2: {
id: "btnCancel",
label: this.context.resources.getString("string_2004"),
onClick: this.btnCancelClickHandler.bind(this)
},
onCloseX: () => this.btnCancelClickHandler()
};
this.openDialog(option);
});
return promise;
}
private btnUpdateClickHandler(): boolean {
this.resolvePromise(this._data);
return true;
}
private btnCancelClickHandler(): boolean {
this.resolvePromise(null);
return true;
}
private resolvePromise(editResult: Entities.ExampleEntity): void {
if (ObjectExtensions.isFunction(this._resolve)) {
this._resolve(editResult);
this._resolve = null;
}
}
}

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

@ -0,0 +1,25 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Ping Result Dialog</title>
</head>
<body>
<div class="ExampleCreateDialog col grow">
<p>
<div class="h4">Unbound GET endpoint ping result:</div>
<br />
<br />
<b class="h5" id="UnboundGetResult"></b>
</p>
<p>
<div class="h4">Unbound POST endpoint ping result:</div>
<br />
<br />
<b class="h5" id="UnboundPostResult"></b>
</p>
<div class="grow"></div>
<div class="row"></div>
</div>
</body>
</html>

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

@ -0,0 +1,63 @@
/**
* SAMPLE CODE NOTICE
*
* THIS SAMPLE CODE IS MADE AVAILABLE AS IS. MICROSOFT MAKES NO WARRANTIES, WHETHER EXPRESS OR IMPLIED,
* OF FITNESS FOR A PARTICULAR PURPOSE, OF ACCURACY OR COMPLETENESS OF RESPONSES, OF RESULTS, OR CONDITIONS OF MERCHANTABILITY.
* THE ENTIRE RISK OF THE USE OR THE RESULTS FROM THE USE OF THIS SAMPLE CODE REMAINS WITH THE USER.
* NO TECHNICAL SUPPORT IS PROVIDED. YOU MAY NOT DISTRIBUTE THIS CODE UNLESS YOU HAVE A LICENSE AGREEMENT WITH MICROSOFT THAT ALLOWS YOU TO DO SO.
*/
import * as Dialogs from "PosApi/Create/Dialogs";
import { ObjectExtensions } from "PosApi/TypeExtensions";
type DialogResolve = (result: any) => void;
type DialogReject = (reason: any) => void;
export default class PingResultDialog extends Dialogs.ExtensionTemplatedDialogBase {
private _resolve: DialogResolve;
private _pingUnboundGetResult: boolean;
private _pingUnboundPostResult: boolean;
constructor() {
super();
}
public onReady(element: HTMLElement): void {
let getPingResult = element.querySelector("#UnboundGetResult") as HTMLSpanElement;
getPingResult.textContent = this._pingUnboundGetResult ? "Success!" : "Failed.";
let postPingResult = element.querySelector("#UnboundPostResult") as HTMLSpanElement;
postPingResult.textContent = this._pingUnboundPostResult ? "Success!" : "Failed.";
}
public open(pingUnboundGetResult: boolean, pingUnboundPostResult: boolean): Promise<void> {
let promise: Promise<void> = new Promise((resolve: DialogResolve, reject: DialogReject) => {
this._resolve = resolve;
this._pingUnboundGetResult = pingUnboundGetResult;
this._pingUnboundPostResult = pingUnboundPostResult;
this.openDialog({
title: "Ping Test Results",
button1: {
id: "btnOk",
label: this.context.resources.getString("string_2005"),
isPrimary: true,
onClick: this.closeDialogHandler.bind(this)
},
onCloseX: () => this.closeDialogHandler()
});
});
return promise;
}
private closeDialogHandler(): boolean {
this.resolvePromise();
return true;
}
private resolvePromise(): void {
if (ObjectExtensions.isFunction(this._resolve)) {
this._resolve(null);
this._resolve = null;
}
}
}

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

@ -0,0 +1,25 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Example Edit Dialog</title>
</head>
<body>
<div class="ExampleEditDialog col grow">
<div>
<div class="h4">Int data:</div>
<input type="number" id="intData"></select>
<br />
<br />
<div class="h4">String data:</div>
<input type="text" id="stringData"></input>
<br />
<br />
<div class="h4">Extension property string data:</div>
<input type="text" id="extensionPropertyStringData"></input>
</div>
<div class="grow"></div>
<div class="row"></div>
</div>
</body>
</html>

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

@ -0,0 +1,93 @@
/**
* SAMPLE CODE NOTICE
*
* THIS SAMPLE CODE IS MADE AVAILABLE AS IS. MICROSOFT MAKES NO WARRANTIES, WHETHER EXPRESS OR IMPLIED,
* OF FITNESS FOR A PARTICULAR PURPOSE, OF ACCURACY OR COMPLETENESS OF RESPONSES, OF RESULTS, OR CONDITIONS OF MERCHANTABILITY.
* THE ENTIRE RISK OF THE USE OR THE RESULTS FROM THE USE OF THIS SAMPLE CODE REMAINS WITH THE USER.
* NO TECHNICAL SUPPORT IS PROVIDED. YOU MAY NOT DISTRIBUTE THIS CODE UNLESS YOU HAVE A LICENSE AGREEMENT WITH MICROSOFT THAT ALLOWS YOU TO DO SO.
*/
import * as Dialogs from "PosApi/Create/Dialogs";
import { Entities } from "../../../DataService/DataServiceEntities.g";
import { ObjectExtensions } from "PosApi/TypeExtensions";
type DialogResolve = (updatedEntity: Entities.ExampleEntity) => void;
type DialogReject = (reason: any) => void;
export default class ExampleEditDialog extends Dialogs.ExtensionTemplatedDialogBase {
private _resolve: DialogResolve;
private _data: Entities.ExampleEntity;
constructor() {
super();
}
public onReady(element: HTMLElement): void {
let intDataInput: HTMLInputElement = element.querySelector("#intData") as HTMLInputElement;
intDataInput.value = this._data.IntData.toString();
intDataInput.onchange = () => { this._data.IntData = intDataInput.valueAsNumber; };
let stringDataInput: HTMLInputElement = element.querySelector("#stringData") as HTMLInputElement;
stringDataInput.value = this._data.StringData;
stringDataInput.onchange = () => { this._data.StringData = stringDataInput.value; };
let extensionPropertyStringDataInput: HTMLInputElement = element.querySelector("#extensionPropertyStringData") as HTMLInputElement;
extensionPropertyStringDataInput.value = this._data.ExtensionProperties.filter(prop => prop.Key == "customExtensionProp").map(prop => prop.Value.StringValue)[0];
extensionPropertyStringDataInput.onchange = () => {
if (this._data.ExtensionProperties.length > 0) {
this._data.ExtensionProperties.filter(prop => prop.Key == "customExtensionProp")[0].Value.StringValue = extensionPropertyStringDataInput.value;
} else {
this._data.ExtensionProperties = [{
Key: "customExtensionProp",
Value: {
StringValue: extensionPropertyStringDataInput.value
}
}];
}
};
}
public open(dataToEdit: Entities.ExampleEntity): Promise<Entities.ExampleEntity> {
this._data = dataToEdit;
let promise: Promise<Entities.ExampleEntity> = new Promise((resolve: DialogResolve, reject: DialogReject) => {
this._resolve = resolve;
let option: Dialogs.ITemplatedDialogOptions = {
title: "Update Example Entity",
button1: {
id: "btnUpdate",
label: this.context.resources.getString("string_2002"),
isPrimary: true,
onClick: this.btnUpdateClickHandler.bind(this)
},
button2: {
id: "btnCancel",
label: this.context.resources.getString("string_2004"),
onClick: this.btnCancelClickHandler.bind(this)
},
onCloseX: () => this.btnCancelClickHandler()
};
this.openDialog(option);
});
return promise;
}
private btnUpdateClickHandler(): boolean {
this.resolvePromise(this._data);
return true;
}
private btnCancelClickHandler(): boolean {
this.resolvePromise(null);
return true;
}
private resolvePromise(editResult: Entities.ExampleEntity): void {
if (ObjectExtensions.isFunction(this._resolve)) {
this._resolve(editResult);
this._resolve = null;
}
}
}

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

@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\CustomizationPackage.props" />
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Dynamics.Commerce.Sdk.Pos" Version="$(CommerceSdkPackagesVersion)" />
<PackageReference Include="Microsoft.TypeScript.MSBuild" Version="4.0.*" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\CommerceRuntime\CommerceRuntime.csproj" />
</ItemGroup>
</Project>

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

@ -0,0 +1,38 @@
//======================================================================================================
//======================================= Store Hour Sample comment. ===================================
//======================================================================================================
{
//======================== View extension titles. ========================
"string_0001" : "EXAMPLE VIEW",
"_string_0001.comment" : "The Example View's title.",
//======================== Column names. ========================
"string_1001" : "Int data",
"_string_1001.comment" : "A column title for the int data on the Example Entity.",
"string_1002" : "String data",
"_string_2.comment" : "A column title for the string data on the Example Entity.",
"string_1003" : "Extension property string data",
"_string_3.comment" : "A column title for the extension property data on the Example Entity.",
//======================== Dialog button labels. ========================
"string_2001" : "Create",
"_string_4.comment" : "Create button used on a dialog for making a new entity.",
"string_2002" : "Update",
"_string_5.comment" : "Update button used to commit changes made to an entity in an update dialog.",
"string_1006" : "Delete",
"_string_6.comment" : "Delete button used to delete an entity instance in the list view.",
"string_2004" : "Cancel",
"_string_7.comment" : "Cancel button shared across dialogs.",
"string_2005" : "OK",
"_string_8.comment" : "OK button used to dismiss a dialog.",
//======================== Command labels. ========================
"string_3001" : "Ping Test",
"_string_3001.comment" : "A button label used in the app bar, when pressed two unbound endpoints are pinged."
}

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

@ -0,0 +1,42 @@
/**
* SAMPLE CODE NOTICE
*
* THIS SAMPLE CODE IS MADE AVAILABLE AS IS. MICROSOFT MAKES NO WARRANTIES, WHETHER EXPRESS OR IMPLIED,
* OF FITNESS FOR A PARTICULAR PURPOSE, OF ACCURACY OR COMPLETENESS OF RESPONSES, OF RESULTS, OR CONDITIONS OF MERCHANTABILITY.
* THE ENTIRE RISK OF THE USE OR THE RESULTS FROM THE USE OF THIS SAMPLE CODE REMAINS WITH THE USER.
* NO TECHNICAL SUPPORT IS PROVIDED. YOU MAY NOT DISTRIBUTE THIS CODE UNLESS YOU HAVE A LICENSE AGREEMENT WITH MICROSOFT THAT ALLOWS YOU TO DO SO.
*/
import { IExtensionCommandContext } from "PosApi/Extend/Views/AppBarCommands";
import * as SearchView from "PosApi/Extend/Views/SearchView";
export default class NavigateToExampleViewCommand extends SearchView.ProductSearchExtensionCommandBase {
/**
* Creates a new instance of the NavigateToExampleViewCommand class.
* @param {IExtensionCommandContext<ProductDetailsView.IProductSearchToExtensionCommandMessageTypeMap>} context The command context.
* @remarks The command context contains APIs through which a command can communicate with POS.
*/
constructor(context: IExtensionCommandContext<SearchView.IProductSearchToExtensionCommandMessageTypeMap>) {
super(context);
this.id = "navigateToExampleViewCommand";
this.label = "Navigate to Full System Example View";
this.extraClass = "iconGo";
}
/**
* Initializes the command.
* @param {ProductDetailsView.IProductDetailsExtensionCommandState} state The state used to initialize the command.
*/
protected init(state: SearchView.IProductSearchExtensionCommandState): void {
this.canExecute = true;
this.isVisible = true;
}
/**
* Executes the command.
*/
protected execute(): void {
this.context.navigator.navigate("ExampleView");
}
}

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

@ -0,0 +1,13 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Example View</title>
</head>
<body>
<div class="exampleView height100Percent">
<div id="exampleListView" class="pad20 height100Percent">
</div>
</div>
</body>
</html>

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

@ -0,0 +1,152 @@
/**
* SAMPLE CODE NOTICE
*
* THIS SAMPLE CODE IS MADE AVAILABLE AS IS. MICROSOFT MAKES NO WARRANTIES, WHETHER EXPRESS OR IMPLIED,
* OF FITNESS FOR A PARTICULAR PURPOSE, OF ACCURACY OR COMPLETENESS OF RESPONSES, OF RESULTS, OR CONDITIONS OF MERCHANTABILITY.
* THE ENTIRE RISK OF THE USE OR THE RESULTS FROM THE USE OF THIS SAMPLE CODE REMAINS WITH THE USER.
* NO TECHNICAL SUPPORT IS PROVIDED. YOU MAY NOT DISTRIBUTE THIS CODE UNLESS YOU HAVE A LICENSE AGREEMENT WITH MICROSOFT THAT ALLOWS YOU TO DO SO.
*/
import * as Views from "PosApi/Create/Views";
import { Entities } from "../DataService/DataServiceEntities.g";
import ExampleViewModel from "./ExampleViewModel";
import { IDataList, IDataListOptions, DataListInteractionMode } from "PosApi/Consume/Controls";
import { ObjectExtensions, ArrayExtensions } from "PosApi/TypeExtensions";
/**
* The controller for ExampleView.
*/
export default class StoreHoursView extends Views.CustomViewControllerBase {
public readonly viewModel: ExampleViewModel;
public dataList: IDataList<Entities.ExampleEntity>;
constructor(context: Views.ICustomViewControllerContext) {
let config: Views.ICustomViewControllerConfiguration = {
title: context.resources.getString("string_0001"),
commandBar: {
commands: [
{
name: "Create",
label: context.resources.getString("string_2001"),
icon: Views.Icons.Add,
isVisible: true,
canExecute: true,
execute: (args: Views.CustomViewControllerExecuteCommandArgs): void => {
this.viewModel.createExampleEntity().then((entityCreated) => {
if (entityCreated) {
// Re-load the list, since the underlying data was amended
this.dataList.data = this.viewModel.loadedData;
}
});
}
},
{
name: "Edit",
label: context.resources.getString("string_2002"),
icon: Views.Icons.Edit,
isVisible: true,
canExecute: false,
execute: (args: Views.CustomViewControllerExecuteCommandArgs): void => {
this.state.isProcessing = true;
this.viewModel.editExampleEntity().then((editsMade) => {
if (editsMade) {
// Re-load the list since the underlying data changed
this.dataList.data = this.viewModel.loadedData;
}
this.state.isProcessing = false;
});
}
},
{
name: "Delete",
label: context.resources.getString("string_1006"),
icon: Views.Icons.Delete,
isVisible: true,
canExecute: false,
execute: (args: Views.CustomViewControllerExecuteCommandArgs): void => {
this.state.isProcessing = true;
this.viewModel.deleteExampleEntity().then(() => {
// Re-load the list, since the data has changed
this.dataList.data = this.viewModel.loadedData;
this.state.isProcessing = false;
});
}
},
{
name: "PingTest",
label: context.resources.getString("string_3001"),
icon: Views.Icons.LightningBolt,
isVisible: true,
canExecute: true,
execute: (args: Views.CustomViewControllerExecuteCommandArgs): void => {
this.state.isProcessing = true;
this.viewModel.runPingTest().then(() => {
this.state.isProcessing = false;
});
}
}
]
}
};
super(context, config);
// Initialize the view model.
this.viewModel = new ExampleViewModel(context);
}
public dispose(): void {
ObjectExtensions.disposeAllProperties(this);
}
public onReady(element: HTMLElement): void {
// DataList
let dataListOptions: IDataListOptions<Entities.ExampleEntity> = {
interactionMode: DataListInteractionMode.SingleSelect,
data: this.viewModel.loadedData,
columns: [
{
title: this.context.resources.getString("string_1001"), // Int data
ratio: 40, collapseOrder: 1, minWidth: 100,
computeValue: (data: Entities.ExampleEntity): string => data.IntData.toString()
},
{
title: this.context.resources.getString("string_1002"), // String data
ratio: 30, collapseOrder: 2, minWidth: 100,
computeValue: (data: Entities.ExampleEntity): string => data.StringData
},
{
title: this.context.resources.getString("string_1003"), // Extension property string data
ratio: 30, collapseOrder: 3, minWidth: 100,
computeValue: (data: Entities.ExampleEntity): string => {
return ArrayExtensions.firstOrUndefined(
data.ExtensionProperties.filter(prop => prop.Key == "customExtensionProp").map(prop => prop.Value.StringValue)
);
}
}
]
};
let dataListRootElem: HTMLDivElement = element.querySelector("#exampleListView") as HTMLDivElement;
this.dataList = this.context.controlFactory.create(this.context.logger.getNewCorrelationId(), "DataList", dataListOptions, dataListRootElem);
this.dataList.addEventListener("SelectionChanged", (eventData: { items: Entities.ExampleEntity[] }) => {
this.viewModel.seletionChanged(eventData.items);
// Update the command states to reflect the current selection state.
this.state.commandBar.commands.forEach(
command => command.canExecute = (
["Create", "PingTest"].some(name => name == command.name) ||
this.viewModel.isItemSelected()
)
);
});
this.state.isProcessing = true;
this.viewModel.load().then((): void => {
// Initialize the data list with what the view model loaded
this.dataList.data = this.viewModel.loadedData;
this.state.isProcessing = false;
});
}
}

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

@ -0,0 +1,139 @@
/**
* SAMPLE CODE NOTICE
*
* THIS SAMPLE CODE IS MADE AVAILABLE AS IS. MICROSOFT MAKES NO WARRANTIES, WHETHER EXPRESS OR IMPLIED,
* OF FITNESS FOR A PARTICULAR PURPOSE, OF ACCURACY OR COMPLETENESS OF RESPONSES, OF RESULTS, OR CONDITIONS OF MERCHANTABILITY.
* THE ENTIRE RISK OF THE USE OR THE RESULTS FROM THE USE OF THIS SAMPLE CODE REMAINS WITH THE USER.
* NO TECHNICAL SUPPORT IS PROVIDED. YOU MAY NOT DISTRIBUTE THIS CODE UNLESS YOU HAVE A LICENSE AGREEMENT WITH MICROSOFT THAT ALLOWS YOU TO DO SO.
*/
import { IExtensionViewControllerContext } from "PosApi/Create/Views";
import { Entities } from "../DataService/DataServiceEntities.g";
import * as Messages from "../DataService/DataServiceRequests.g";
import ExampleCreateDialog from "../Controls/Dialogs/Create/ExampleCreateDialogModule";
import ExampleEditDialog from "../Controls/Dialogs/Edit/ExampleEditDialogModule";
import PingResultDialog from "../Controls/Dialogs/Display/PingResultDialogModule";
import { ObjectExtensions, ArrayExtensions } from "PosApi/TypeExtensions";
/**
* The ViewModel for ExampleView.
*/
export default class ExampleViewModel {
public title: string;
public loadedData: Entities.ExampleEntity[];
public isItemSelected: () => boolean;
private _selectedItem: Entities.ExampleEntity;
private _context: IExtensionViewControllerContext;
constructor(context: IExtensionViewControllerContext) {
this._context = context;
this.title = context.resources.getString("string_0001");
this.loadedData = [];
this.isItemSelected = () => !ObjectExtensions.isNullOrUndefined(this._selectedItem);
}
public load(): Promise<void> {
return this._context.runtime
.executeAsync(new Messages.BoundController.GetAllExampleEntitiesRequest())
.then(response => {
if (!response.canceled) {
this.loadedData = response.data.result;
}
});
}
/**
* Handler for list item selection.
* @param {Entities.ExampleEntity[]} items
*/
public seletionChanged(items: Entities.ExampleEntity[]): Promise<void> {
this._context.logger.logInformational("Item selected:" + JSON.stringify(items));
this._selectedItem = ArrayExtensions.firstOrUndefined(items);
return Promise.resolve();
}
public createExampleEntity(): Promise<boolean> {
let dialog: ExampleCreateDialog = new ExampleCreateDialog();
return dialog
.open()
.then(newItem => {
// No action if the dialog was canceled
if (ObjectExtensions.isNullOrUndefined(newItem)) {
this._context.logger.logInformational("Create canceled.");
return Promise.resolve(false);;
}
this._context.logger.logInformational("Item created with data: " + JSON.stringify(newItem));
// Create the entity and reload the loaded data to reflect the change:
return this._context.runtime
.executeAsync(new Messages.BoundController.CreateExampleEntityRequest(newItem))
.then(response => {
if (!response.canceled && response.data.result != 0) {
this._context.logger.logInformational("Create success for id: " + response.data.result);
return this.load().then((): boolean => true); // Load the updated data
}
this._context.logger.logInformational("Create failed for entity: " + JSON.stringify(newItem));
return Promise.resolve(false);
});
}).catch(reason => {
this._context.logger.logError("Error occurred in the create dialog: " + JSON.stringify(reason));
return Promise.resolve(false);;
});
}
public editExampleEntity(): Promise<boolean> {
let dialog: ExampleEditDialog = new ExampleEditDialog();
return dialog
.open(this._selectedItem)
.then(updatedItem => {
// No action if the dialog was canceled
if (ObjectExtensions.isNullOrUndefined(updatedItem)) {
this._context.logger.logInformational("Update canceled for data: " + JSON.stringify(updatedItem));
return Promise.resolve(false);
}
this._context.logger.logInformational("Updated data is: " + JSON.stringify(updatedItem));
// Perform the update and reload the loaded data to reflect the change:
return this._context.runtime
.executeAsync(new Messages.BoundController.UpdateExampleEntityRequest(updatedItem.UnusualEntityId, updatedItem))
.then(response => {
if (!response.canceled && response.data.result) {
this._context.logger.logInformational("Update success for id: " + updatedItem.UnusualEntityId);
return this.load().then((): boolean => true); // Load the updated data
}
this._context.logger.logInformational("Update failed for id: " + updatedItem.UnusualEntityId);
return Promise.resolve(false);
});
}).catch(reason => {
this._context.logger.logError("Error occurred in the edit dialog: " + JSON.stringify(reason));
return Promise.resolve(false);
});
}
public deleteExampleEntity(): Promise<void> {
// Delete the selected entity and reload the loaded data to reflect the change:
return this._context.runtime
.executeAsync(new Messages.BoundController.DeleteExampleEntityRequest(this._selectedItem.UnusualEntityId))
.then(response => {
if (!response.canceled && response.data.result) {
this._context.logger.logInformational("Delete success for id: " + this._selectedItem.UnusualEntityId);
return this.load(); // Load the updated data
}
this._context.logger.logInformational("Delete failed for id " + this._selectedItem.UnusualEntityId);
return Promise.resolve();
});
}
public runPingTest(): Promise<void> {
return this._context.runtime
.executeAsync(new Messages.StoreOperations.SimplePingGetRequest())
.then(pingGetResponse => {
return this._context.runtime
.executeAsync(new Messages.StoreOperations.SimplePingPostRequest())
.then(pingPostResponse => {
let pingResultDialog: PingResultDialog = new PingResultDialog();
return pingResultDialog.open(pingGetResponse.data.result, pingPostResponse.data.result);
});
});
}
}

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

@ -0,0 +1,50 @@
{
"$schema": "./devDependencies/schemas/manifestSchema.json",
"name": "Contoso.Pos.FullSystemExample.Sample",
"publisher": "Contoso",
"version": "1.0.0",
"minimumPosVersion": "9.29.0.0",
"description": "An extension package that makes use of a Retail Server extension. Also works off-line.",
"components": {
"resources": {
"supportedUICultures": [ "en-US" ],
"fallbackUICulture": "en-US",
"culturesDirectoryPath": "Resources/Strings",
"stringResourcesFileName": "resources.resjson"
},
"extend": {
"views": {
"SearchView": {
"productAppBarCommands": [
{ "modulePath": "ViewExtensions/Search/NavigateToExampleViewCommand" },
]
}
}
},
"create": {
"templatedDialogs": [
{
"htmlPath": "Controls/Dialogs/Create/ExampleCreateDialog.html",
"modulePath": "Controls/Dialogs/Create/ExampleCreateDialogModule"
},
{
"htmlPath": "Controls/Dialogs/Edit/ExampleEditDialog.html",
"modulePath": "Controls/Dialogs/Edit/ExampleEditDialogModule"
},
{
"htmlPath": "Controls/Dialogs/Display/PingResultDialog.html",
"modulePath": "Controls/Dialogs/Display/PingResultDialogModule"
}
],
"views": [
{
"title": "Sample Extension View",
"pageName": "ExampleView",
"phonePageName": "ExampleView",
"viewDirectory": "Views/",
"viewControllerPath": "Views/ExampleView"
}
]
}
}
}

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

@ -0,0 +1,3 @@
{
"extends": "./devDependencies/pos-tsconfig-base.json"
}

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

@ -0,0 +1,49 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.28307.1267
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ChannelDatabase", "ChannelDatabase\ChannelDatabase.csproj", "{A8166D6A-9868-43C8-8732-0D2DD6C9826C}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CommerceRuntime", "CommerceRuntime\CommerceRuntime.csproj", "{59AA9A4E-084B-4DF4-83D2-151759F6944F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ScaleUnit", "ScaleUnit\ScaleUnit.csproj", "{2888FAB4-68EF-4670-ABFF-20E1DBAA32F4}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "POS", "POS\POS.csproj", "{F69DE011-47C5-46FC-A9E0-88A62650B082}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ScaleUnit.Installer", "Installer\ScaleUnit.Installer.csproj", "{E937C87D-E159-44F0-AD36-DEAA6D72E678}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{A8166D6A-9868-43C8-8732-0D2DD6C9826C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A8166D6A-9868-43C8-8732-0D2DD6C9826C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A8166D6A-9868-43C8-8732-0D2DD6C9826C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A8166D6A-9868-43C8-8732-0D2DD6C9826C}.Release|Any CPU.Build.0 = Release|Any CPU
{59AA9A4E-084B-4DF4-83D2-151759F6944F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{59AA9A4E-084B-4DF4-83D2-151759F6944F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{59AA9A4E-084B-4DF4-83D2-151759F6944F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{59AA9A4E-084B-4DF4-83D2-151759F6944F}.Release|Any CPU.Build.0 = Release|Any CPU
{2888FAB4-68EF-4670-ABFF-20E1DBAA32F4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2888FAB4-68EF-4670-ABFF-20E1DBAA32F4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2888FAB4-68EF-4670-ABFF-20E1DBAA32F4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2888FAB4-68EF-4670-ABFF-20E1DBAA32F4}.Release|Any CPU.Build.0 = Release|Any CPU
{F69DE011-47C5-46FC-A9E0-88A62650B082}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F69DE011-47C5-46FC-A9E0-88A62650B082}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F69DE011-47C5-46FC-A9E0-88A62650B082}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F69DE011-47C5-46FC-A9E0-88A62650B082}.Release|Any CPU.Build.0 = Release|Any CPU
{E937C87D-E159-44F0-AD36-DEAA6D72E678}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E937C87D-E159-44F0-AD36-DEAA6D72E678}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E937C87D-E159-44F0-AD36-DEAA6D72E678}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E937C87D-E159-44F0-AD36-DEAA6D72E678}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {D8D07A3D-D311-441B-A70E-A959154EE41B}
EndGlobalSection
EndGlobal

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

@ -0,0 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk" ToolsVersion="15.0">
<Import Project="..\CustomizationPackage.props" />
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\ChannelDatabase\ChannelDatabase.csproj">
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
</ProjectReference>
<ProjectReference Include="..\CommerceRuntime\CommerceRuntime.csproj">
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
</ProjectReference>
<ProjectReference Include="..\POS\POS.csproj">
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Dynamics.Commerce.Sdk.ScaleUnit" Version="$(CommerceSdkPackagesVersion)" />
</ItemGroup>
</Project>