mirror of https://github.com/EasyAbp/EShop.git
committed by
GitHub
282 changed files with 43373 additions and 62 deletions
@ -0,0 +1,12 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Threading.Tasks; |
||||
|
using EasyAbp.EShop.Products.Products.Dtos; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Orders.Orders |
||||
|
{ |
||||
|
public interface IOrderDiscountProvider |
||||
|
{ |
||||
|
Task<Order> DiscountAsync(Order order, Dictionary<Guid, ProductDto> productDict); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,12 @@ |
|||||
|
using Volo.Abp; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Orders.Orders |
||||
|
{ |
||||
|
public class DiscountAmountOverflowException : BusinessException |
||||
|
{ |
||||
|
public DiscountAmountOverflowException() |
||||
|
: base("DiscountAmountOverflow", $"The discount amount overflow.") |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,10 +0,0 @@ |
|||||
using System.Collections.Generic; |
|
||||
using System.Threading.Tasks; |
|
||||
|
|
||||
namespace EasyAbp.EShop.Orders.Orders |
|
||||
{ |
|
||||
public interface IOrderDiscountProvider |
|
||||
{ |
|
||||
Task<Order> DiscountAsync(Order order, Dictionary<string, object> inputExtraProperties); |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1 @@ |
|||||
|
**/wwwroot/libs/** linguist-vendored |
||||
@ -0,0 +1,258 @@ |
|||||
|
## Ignore Visual Studio temporary files, build results, and |
||||
|
## files generated by popular Visual Studio add-ons. |
||||
|
|
||||
|
# 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 |
||||
|
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 |
||||
|
*.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 |
||||
|
|
||||
|
# Coupons |
||||
|
host/EasyAbp.EShop.Plugins.Coupons.IdentityServer/Logs/logs.txt |
||||
|
host/EasyAbp.EShop.Plugins.Coupons.HttpApi.Host/Logs/logs.txt |
||||
|
host/EasyAbp.EShop.Plugins.Coupons.Web.Host/Logs/logs.txt |
||||
|
host/EasyAbp.EShop.Plugins.Coupons.Web.Unified/Logs/logs.txt |
||||
@ -0,0 +1,5 @@ |
|||||
|
{ |
||||
|
"singleQuote": true, |
||||
|
"useTabs": false, |
||||
|
"tabWidth": 4 |
||||
|
} |
||||
@ -0,0 +1,167 @@ |
|||||
|
|
||||
|
Microsoft Visual Studio Solution File, Format Version 12.00 |
||||
|
# Visual Studio Version 16 |
||||
|
VisualStudioVersion = 16.0.29001.49 |
||||
|
MinimumVisualStudioVersion = 10.0.40219.1 |
||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EasyAbp.EShop.Plugins.Coupons.Domain.Shared", "src\EasyAbp.EShop.Plugins.Coupons.Domain.Shared\EasyAbp.EShop.Plugins.Coupons.Domain.Shared.csproj", "{D64C1577-4929-4B60-939E-96DE1534891A}" |
||||
|
EndProject |
||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EasyAbp.EShop.Plugins.Coupons.Domain", "src\EasyAbp.EShop.Plugins.Coupons.Domain\EasyAbp.EShop.Plugins.Coupons.Domain.csproj", "{F2840BC7-0188-4606-9126-DADD0F5ABF7A}" |
||||
|
EndProject |
||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EasyAbp.EShop.Plugins.Coupons.Application.Contracts", "src\EasyAbp.EShop.Plugins.Coupons.Application.Contracts\EasyAbp.EShop.Plugins.Coupons.Application.Contracts.csproj", "{BD65D04F-08D5-40C1-8C24-77CA0BACB877}" |
||||
|
EndProject |
||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EasyAbp.EShop.Plugins.Coupons.Application", "src\EasyAbp.EShop.Plugins.Coupons.Application\EasyAbp.EShop.Plugins.Coupons.Application.csproj", "{78040F9E-3501-4A40-82DF-00A597710F35}" |
||||
|
EndProject |
||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{649A3FFA-182F-4E56-9717-E6A9A2BEC545}" |
||||
|
EndProject |
||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{CCD2960C-23CC-4AB4-B84D-60C7AAA52F4D}" |
||||
|
EndProject |
||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "host", "host", "{E400416D-2895-4512-9D17-90681EEC7E0A}" |
||||
|
EndProject |
||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EasyAbp.EShop.Plugins.Coupons.EntityFrameworkCore", "src\EasyAbp.EShop.Plugins.Coupons.EntityFrameworkCore\EasyAbp.EShop.Plugins.Coupons.EntityFrameworkCore.csproj", "{0CE86223-D31D-4315-A1F5-87BA3EE1B844}" |
||||
|
EndProject |
||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EasyAbp.EShop.Plugins.Coupons.MongoDB", "src\EasyAbp.EShop.Plugins.Coupons.MongoDB\EasyAbp.EShop.Plugins.Coupons.MongoDB.csproj", "{F1C58097-4C08-4D88-8976-6B3389391481}" |
||||
|
EndProject |
||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EasyAbp.EShop.Plugins.Coupons.HttpApi", "src\EasyAbp.EShop.Plugins.Coupons.HttpApi\EasyAbp.EShop.Plugins.Coupons.HttpApi.csproj", "{077AA5F8-8B61-420C-A6B5-0150A66FDB34}" |
||||
|
EndProject |
||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EasyAbp.EShop.Plugins.Coupons.HttpApi.Client", "src\EasyAbp.EShop.Plugins.Coupons.HttpApi.Client\EasyAbp.EShop.Plugins.Coupons.HttpApi.Client.csproj", "{36E2735F-CEAB-44C8-A6D1-2CDAFF399751}" |
||||
|
EndProject |
||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EasyAbp.EShop.Plugins.Coupons.TestBase", "test\EasyAbp.EShop.Plugins.Coupons.TestBase\EasyAbp.EShop.Plugins.Coupons.TestBase.csproj", "{C5BB573D-3030-4BCB-88B7-F6A85C32766C}" |
||||
|
EndProject |
||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EasyAbp.EShop.Plugins.Coupons.EntityFrameworkCore.Tests", "test\EasyAbp.EShop.Plugins.Coupons.EntityFrameworkCore.Tests\EasyAbp.EShop.Plugins.Coupons.EntityFrameworkCore.Tests.csproj", "{527F645C-C1FC-406E-8479-81386C8ECF13}" |
||||
|
EndProject |
||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EasyAbp.EShop.Plugins.Coupons.MongoDB.Tests", "test\EasyAbp.EShop.Plugins.Coupons.MongoDB.Tests\EasyAbp.EShop.Plugins.Coupons.MongoDB.Tests.csproj", "{D0AD9179-125C-40B2-A8EE-CD4C1EE24BB6}" |
||||
|
EndProject |
||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EasyAbp.EShop.Plugins.Coupons.Domain.Tests", "test\EasyAbp.EShop.Plugins.Coupons.Domain.Tests\EasyAbp.EShop.Plugins.Coupons.Domain.Tests.csproj", "{E60895E5-79C4-447D-88B7-85CB5BA336A4}" |
||||
|
EndProject |
||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EasyAbp.EShop.Plugins.Coupons.Application.Tests", "test\EasyAbp.EShop.Plugins.Coupons.Application.Tests\EasyAbp.EShop.Plugins.Coupons.Application.Tests.csproj", "{90CB5DC4-C040-45C7-8900-9688B26405BC}" |
||||
|
EndProject |
||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EasyAbp.EShop.Plugins.Coupons.HttpApi.Host", "host\EasyAbp.EShop.Plugins.Coupons.HttpApi.Host\EasyAbp.EShop.Plugins.Coupons.HttpApi.Host.csproj", "{37B135B0-DAFE-4616-B25C-1BDF32FC44A2}" |
||||
|
EndProject |
||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EasyAbp.EShop.Plugins.Coupons.Web", "src\EasyAbp.EShop.Plugins.Coupons.Web\EasyAbp.EShop.Plugins.Coupons.Web.csproj", "{3B7B6317-1B85-4164-8E11-75574F80AE17}" |
||||
|
EndProject |
||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EasyAbp.EShop.Plugins.Coupons.HttpApi.Client.ConsoleTestApp", "test\EasyAbp.EShop.Plugins.Coupons.HttpApi.Client.ConsoleTestApp\EasyAbp.EShop.Plugins.Coupons.HttpApi.Client.ConsoleTestApp.csproj", "{1EDCD6D4-DF3A-4E3B-ABB6-C0D0B373EAB8}" |
||||
|
EndProject |
||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EasyAbp.EShop.Plugins.Coupons.Web.Host", "host\EasyAbp.EShop.Plugins.Coupons.Web.Host\EasyAbp.EShop.Plugins.Coupons.Web.Host.csproj", "{73513786-B6C6-4A21-89C5-0FBDD0A46107}" |
||||
|
EndProject |
||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EasyAbp.EShop.Plugins.Coupons.IdentityServer", "host\EasyAbp.EShop.Plugins.Coupons.IdentityServer\EasyAbp.EShop.Plugins.Coupons.IdentityServer.csproj", "{690203F4-3CD5-4569-88D9-EE831EEA5F5F}" |
||||
|
EndProject |
||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EasyAbp.EShop.Plugins.Coupons.Host.Shared", "host\EasyAbp.EShop.Plugins.Coupons.Host.Shared\EasyAbp.EShop.Plugins.Coupons.Host.Shared.csproj", "{F6AC8D4A-EDD7-4514-8E8A-5BCB019864DB}" |
||||
|
EndProject |
||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EasyAbp.EShop.Plugins.Coupons.Web.Unified", "host\EasyAbp.EShop.Plugins.Coupons.Web.Unified\EasyAbp.EShop.Plugins.Coupons.Web.Unified.csproj", "{3D872C41-E226-45C8-89C1-9D3DBD7C73F2}" |
||||
|
EndProject |
||||
|
Global |
||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution |
||||
|
Debug|Any CPU = Debug|Any CPU |
||||
|
Release|Any CPU = Release|Any CPU |
||||
|
EndGlobalSection |
||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution |
||||
|
{D64C1577-4929-4B60-939E-96DE1534891A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU |
||||
|
{D64C1577-4929-4B60-939E-96DE1534891A}.Debug|Any CPU.Build.0 = Debug|Any CPU |
||||
|
{D64C1577-4929-4B60-939E-96DE1534891A}.Release|Any CPU.ActiveCfg = Release|Any CPU |
||||
|
{D64C1577-4929-4B60-939E-96DE1534891A}.Release|Any CPU.Build.0 = Release|Any CPU |
||||
|
{F2840BC7-0188-4606-9126-DADD0F5ABF7A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU |
||||
|
{F2840BC7-0188-4606-9126-DADD0F5ABF7A}.Debug|Any CPU.Build.0 = Debug|Any CPU |
||||
|
{F2840BC7-0188-4606-9126-DADD0F5ABF7A}.Release|Any CPU.ActiveCfg = Release|Any CPU |
||||
|
{F2840BC7-0188-4606-9126-DADD0F5ABF7A}.Release|Any CPU.Build.0 = Release|Any CPU |
||||
|
{BD65D04F-08D5-40C1-8C24-77CA0BACB877}.Debug|Any CPU.ActiveCfg = Debug|Any CPU |
||||
|
{BD65D04F-08D5-40C1-8C24-77CA0BACB877}.Debug|Any CPU.Build.0 = Debug|Any CPU |
||||
|
{BD65D04F-08D5-40C1-8C24-77CA0BACB877}.Release|Any CPU.ActiveCfg = Release|Any CPU |
||||
|
{BD65D04F-08D5-40C1-8C24-77CA0BACB877}.Release|Any CPU.Build.0 = Release|Any CPU |
||||
|
{78040F9E-3501-4A40-82DF-00A597710F35}.Debug|Any CPU.ActiveCfg = Debug|Any CPU |
||||
|
{78040F9E-3501-4A40-82DF-00A597710F35}.Debug|Any CPU.Build.0 = Debug|Any CPU |
||||
|
{78040F9E-3501-4A40-82DF-00A597710F35}.Release|Any CPU.ActiveCfg = Release|Any CPU |
||||
|
{78040F9E-3501-4A40-82DF-00A597710F35}.Release|Any CPU.Build.0 = Release|Any CPU |
||||
|
{0CE86223-D31D-4315-A1F5-87BA3EE1B844}.Debug|Any CPU.ActiveCfg = Debug|Any CPU |
||||
|
{0CE86223-D31D-4315-A1F5-87BA3EE1B844}.Debug|Any CPU.Build.0 = Debug|Any CPU |
||||
|
{0CE86223-D31D-4315-A1F5-87BA3EE1B844}.Release|Any CPU.ActiveCfg = Release|Any CPU |
||||
|
{0CE86223-D31D-4315-A1F5-87BA3EE1B844}.Release|Any CPU.Build.0 = Release|Any CPU |
||||
|
{F1C58097-4C08-4D88-8976-6B3389391481}.Debug|Any CPU.ActiveCfg = Debug|Any CPU |
||||
|
{F1C58097-4C08-4D88-8976-6B3389391481}.Debug|Any CPU.Build.0 = Debug|Any CPU |
||||
|
{F1C58097-4C08-4D88-8976-6B3389391481}.Release|Any CPU.ActiveCfg = Release|Any CPU |
||||
|
{F1C58097-4C08-4D88-8976-6B3389391481}.Release|Any CPU.Build.0 = Release|Any CPU |
||||
|
{077AA5F8-8B61-420C-A6B5-0150A66FDB34}.Debug|Any CPU.ActiveCfg = Debug|Any CPU |
||||
|
{077AA5F8-8B61-420C-A6B5-0150A66FDB34}.Debug|Any CPU.Build.0 = Debug|Any CPU |
||||
|
{077AA5F8-8B61-420C-A6B5-0150A66FDB34}.Release|Any CPU.ActiveCfg = Release|Any CPU |
||||
|
{077AA5F8-8B61-420C-A6B5-0150A66FDB34}.Release|Any CPU.Build.0 = Release|Any CPU |
||||
|
{36E2735F-CEAB-44C8-A6D1-2CDAFF399751}.Debug|Any CPU.ActiveCfg = Debug|Any CPU |
||||
|
{36E2735F-CEAB-44C8-A6D1-2CDAFF399751}.Debug|Any CPU.Build.0 = Debug|Any CPU |
||||
|
{36E2735F-CEAB-44C8-A6D1-2CDAFF399751}.Release|Any CPU.ActiveCfg = Release|Any CPU |
||||
|
{36E2735F-CEAB-44C8-A6D1-2CDAFF399751}.Release|Any CPU.Build.0 = Release|Any CPU |
||||
|
{C5BB573D-3030-4BCB-88B7-F6A85C32766C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU |
||||
|
{C5BB573D-3030-4BCB-88B7-F6A85C32766C}.Debug|Any CPU.Build.0 = Debug|Any CPU |
||||
|
{C5BB573D-3030-4BCB-88B7-F6A85C32766C}.Release|Any CPU.ActiveCfg = Release|Any CPU |
||||
|
{C5BB573D-3030-4BCB-88B7-F6A85C32766C}.Release|Any CPU.Build.0 = Release|Any CPU |
||||
|
{527F645C-C1FC-406E-8479-81386C8ECF13}.Debug|Any CPU.ActiveCfg = Debug|Any CPU |
||||
|
{527F645C-C1FC-406E-8479-81386C8ECF13}.Debug|Any CPU.Build.0 = Debug|Any CPU |
||||
|
{527F645C-C1FC-406E-8479-81386C8ECF13}.Release|Any CPU.ActiveCfg = Release|Any CPU |
||||
|
{527F645C-C1FC-406E-8479-81386C8ECF13}.Release|Any CPU.Build.0 = Release|Any CPU |
||||
|
{D0AD9179-125C-40B2-A8EE-CD4C1EE24BB6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU |
||||
|
{D0AD9179-125C-40B2-A8EE-CD4C1EE24BB6}.Debug|Any CPU.Build.0 = Debug|Any CPU |
||||
|
{D0AD9179-125C-40B2-A8EE-CD4C1EE24BB6}.Release|Any CPU.ActiveCfg = Release|Any CPU |
||||
|
{D0AD9179-125C-40B2-A8EE-CD4C1EE24BB6}.Release|Any CPU.Build.0 = Release|Any CPU |
||||
|
{E60895E5-79C4-447D-88B7-85CB5BA336A4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU |
||||
|
{E60895E5-79C4-447D-88B7-85CB5BA336A4}.Debug|Any CPU.Build.0 = Debug|Any CPU |
||||
|
{E60895E5-79C4-447D-88B7-85CB5BA336A4}.Release|Any CPU.ActiveCfg = Release|Any CPU |
||||
|
{E60895E5-79C4-447D-88B7-85CB5BA336A4}.Release|Any CPU.Build.0 = Release|Any CPU |
||||
|
{90CB5DC4-C040-45C7-8900-9688B26405BC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU |
||||
|
{90CB5DC4-C040-45C7-8900-9688B26405BC}.Debug|Any CPU.Build.0 = Debug|Any CPU |
||||
|
{90CB5DC4-C040-45C7-8900-9688B26405BC}.Release|Any CPU.ActiveCfg = Release|Any CPU |
||||
|
{90CB5DC4-C040-45C7-8900-9688B26405BC}.Release|Any CPU.Build.0 = Release|Any CPU |
||||
|
{37B135B0-DAFE-4616-B25C-1BDF32FC44A2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU |
||||
|
{37B135B0-DAFE-4616-B25C-1BDF32FC44A2}.Debug|Any CPU.Build.0 = Debug|Any CPU |
||||
|
{37B135B0-DAFE-4616-B25C-1BDF32FC44A2}.Release|Any CPU.ActiveCfg = Release|Any CPU |
||||
|
{37B135B0-DAFE-4616-B25C-1BDF32FC44A2}.Release|Any CPU.Build.0 = Release|Any CPU |
||||
|
{3B7B6317-1B85-4164-8E11-75574F80AE17}.Debug|Any CPU.ActiveCfg = Debug|Any CPU |
||||
|
{3B7B6317-1B85-4164-8E11-75574F80AE17}.Debug|Any CPU.Build.0 = Debug|Any CPU |
||||
|
{3B7B6317-1B85-4164-8E11-75574F80AE17}.Release|Any CPU.ActiveCfg = Release|Any CPU |
||||
|
{3B7B6317-1B85-4164-8E11-75574F80AE17}.Release|Any CPU.Build.0 = Release|Any CPU |
||||
|
{1EDCD6D4-DF3A-4E3B-ABB6-C0D0B373EAB8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU |
||||
|
{1EDCD6D4-DF3A-4E3B-ABB6-C0D0B373EAB8}.Debug|Any CPU.Build.0 = Debug|Any CPU |
||||
|
{1EDCD6D4-DF3A-4E3B-ABB6-C0D0B373EAB8}.Release|Any CPU.ActiveCfg = Release|Any CPU |
||||
|
{1EDCD6D4-DF3A-4E3B-ABB6-C0D0B373EAB8}.Release|Any CPU.Build.0 = Release|Any CPU |
||||
|
{73513786-B6C6-4A21-89C5-0FBDD0A46107}.Debug|Any CPU.ActiveCfg = Debug|Any CPU |
||||
|
{73513786-B6C6-4A21-89C5-0FBDD0A46107}.Debug|Any CPU.Build.0 = Debug|Any CPU |
||||
|
{73513786-B6C6-4A21-89C5-0FBDD0A46107}.Release|Any CPU.ActiveCfg = Release|Any CPU |
||||
|
{73513786-B6C6-4A21-89C5-0FBDD0A46107}.Release|Any CPU.Build.0 = Release|Any CPU |
||||
|
{690203F4-3CD5-4569-88D9-EE831EEA5F5F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU |
||||
|
{690203F4-3CD5-4569-88D9-EE831EEA5F5F}.Debug|Any CPU.Build.0 = Debug|Any CPU |
||||
|
{690203F4-3CD5-4569-88D9-EE831EEA5F5F}.Release|Any CPU.ActiveCfg = Release|Any CPU |
||||
|
{690203F4-3CD5-4569-88D9-EE831EEA5F5F}.Release|Any CPU.Build.0 = Release|Any CPU |
||||
|
{F6AC8D4A-EDD7-4514-8E8A-5BCB019864DB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU |
||||
|
{F6AC8D4A-EDD7-4514-8E8A-5BCB019864DB}.Debug|Any CPU.Build.0 = Debug|Any CPU |
||||
|
{F6AC8D4A-EDD7-4514-8E8A-5BCB019864DB}.Release|Any CPU.ActiveCfg = Release|Any CPU |
||||
|
{F6AC8D4A-EDD7-4514-8E8A-5BCB019864DB}.Release|Any CPU.Build.0 = Release|Any CPU |
||||
|
{3D872C41-E226-45C8-89C1-9D3DBD7C73F2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU |
||||
|
{3D872C41-E226-45C8-89C1-9D3DBD7C73F2}.Debug|Any CPU.Build.0 = Debug|Any CPU |
||||
|
{3D872C41-E226-45C8-89C1-9D3DBD7C73F2}.Release|Any CPU.ActiveCfg = Release|Any CPU |
||||
|
{3D872C41-E226-45C8-89C1-9D3DBD7C73F2}.Release|Any CPU.Build.0 = Release|Any CPU |
||||
|
EndGlobalSection |
||||
|
GlobalSection(SolutionProperties) = preSolution |
||||
|
HideSolutionNode = FALSE |
||||
|
EndGlobalSection |
||||
|
GlobalSection(NestedProjects) = preSolution |
||||
|
{D64C1577-4929-4B60-939E-96DE1534891A} = {649A3FFA-182F-4E56-9717-E6A9A2BEC545} |
||||
|
{F2840BC7-0188-4606-9126-DADD0F5ABF7A} = {649A3FFA-182F-4E56-9717-E6A9A2BEC545} |
||||
|
{BD65D04F-08D5-40C1-8C24-77CA0BACB877} = {649A3FFA-182F-4E56-9717-E6A9A2BEC545} |
||||
|
{78040F9E-3501-4A40-82DF-00A597710F35} = {649A3FFA-182F-4E56-9717-E6A9A2BEC545} |
||||
|
{0CE86223-D31D-4315-A1F5-87BA3EE1B844} = {649A3FFA-182F-4E56-9717-E6A9A2BEC545} |
||||
|
{F1C58097-4C08-4D88-8976-6B3389391481} = {649A3FFA-182F-4E56-9717-E6A9A2BEC545} |
||||
|
{077AA5F8-8B61-420C-A6B5-0150A66FDB34} = {649A3FFA-182F-4E56-9717-E6A9A2BEC545} |
||||
|
{36E2735F-CEAB-44C8-A6D1-2CDAFF399751} = {649A3FFA-182F-4E56-9717-E6A9A2BEC545} |
||||
|
{C5BB573D-3030-4BCB-88B7-F6A85C32766C} = {CCD2960C-23CC-4AB4-B84D-60C7AAA52F4D} |
||||
|
{527F645C-C1FC-406E-8479-81386C8ECF13} = {CCD2960C-23CC-4AB4-B84D-60C7AAA52F4D} |
||||
|
{D0AD9179-125C-40B2-A8EE-CD4C1EE24BB6} = {CCD2960C-23CC-4AB4-B84D-60C7AAA52F4D} |
||||
|
{E60895E5-79C4-447D-88B7-85CB5BA336A4} = {CCD2960C-23CC-4AB4-B84D-60C7AAA52F4D} |
||||
|
{90CB5DC4-C040-45C7-8900-9688B26405BC} = {CCD2960C-23CC-4AB4-B84D-60C7AAA52F4D} |
||||
|
{37B135B0-DAFE-4616-B25C-1BDF32FC44A2} = {E400416D-2895-4512-9D17-90681EEC7E0A} |
||||
|
{3B7B6317-1B85-4164-8E11-75574F80AE17} = {649A3FFA-182F-4E56-9717-E6A9A2BEC545} |
||||
|
{1EDCD6D4-DF3A-4E3B-ABB6-C0D0B373EAB8} = {CCD2960C-23CC-4AB4-B84D-60C7AAA52F4D} |
||||
|
{73513786-B6C6-4A21-89C5-0FBDD0A46107} = {E400416D-2895-4512-9D17-90681EEC7E0A} |
||||
|
{690203F4-3CD5-4569-88D9-EE831EEA5F5F} = {E400416D-2895-4512-9D17-90681EEC7E0A} |
||||
|
{F6AC8D4A-EDD7-4514-8E8A-5BCB019864DB} = {E400416D-2895-4512-9D17-90681EEC7E0A} |
||||
|
{3D872C41-E226-45C8-89C1-9D3DBD7C73F2} = {E400416D-2895-4512-9D17-90681EEC7E0A} |
||||
|
EndGlobalSection |
||||
|
GlobalSection(ExtensibilityGlobals) = postSolution |
||||
|
SolutionGuid = {4324B3B4-B60B-4E3C-91D8-59576B4E26DD} |
||||
|
EndGlobalSection |
||||
|
EndGlobal |
||||
@ -0,0 +1,23 @@ |
|||||
|
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation"> |
||||
|
<s:Boolean x:Key="/Default/CodeEditing/Intellisense/CodeCompletion/IntelliSenseCompletingCharacters/CSharpCompletingCharacters/UpgradedFromVSSettings/@EntryValue">True</s:Boolean> |
||||
|
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=EnforceDoWhileStatementBraces/@EntryIndexedValue">WARNING</s:String> |
||||
|
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=EnforceFixedStatementBraces/@EntryIndexedValue">WARNING</s:String> |
||||
|
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=EnforceForeachStatementBraces/@EntryIndexedValue">WARNING</s:String> |
||||
|
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=EnforceForStatementBraces/@EntryIndexedValue">WARNING</s:String> |
||||
|
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=EnforceIfStatementBraces/@EntryIndexedValue">WARNING</s:String> |
||||
|
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=EnforceLockStatementBraces/@EntryIndexedValue">WARNING</s:String> |
||||
|
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=EnforceUsingStatementBraces/@EntryIndexedValue">WARNING</s:String> |
||||
|
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=EnforceWhileStatementBraces/@EntryIndexedValue">WARNING</s:String> |
||||
|
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_FOR_FOR/@EntryValue">Required</s:String> |
||||
|
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_FOR_FOREACH/@EntryValue">Required</s:String> |
||||
|
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_FOR_IFELSE/@EntryValue">Required</s:String> |
||||
|
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_FOR_WHILE/@EntryValue">Required</s:String> |
||||
|
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_REDUNDANT/@EntryValue">False</s:Boolean> |
||||
|
<s:Boolean x:Key="/Default/CodeStyle/Generate/=Implementations/@KeyIndexDefined">True</s:Boolean> |
||||
|
<s:String x:Key="/Default/CodeStyle/Generate/=Implementations/Options/=Async/@EntryIndexedValue">False</s:String> |
||||
|
<s:String x:Key="/Default/CodeStyle/Generate/=Implementations/Options/=Mutable/@EntryIndexedValue">False</s:String> |
||||
|
<s:Boolean x:Key="/Default/CodeStyle/Generate/=Overrides/@KeyIndexDefined">True</s:Boolean> |
||||
|
<s:String x:Key="/Default/CodeStyle/Generate/=Overrides/Options/=Async/@EntryIndexedValue">False</s:String> |
||||
|
<s:String x:Key="/Default/CodeStyle/Generate/=Overrides/Options/=Mutable/@EntryIndexedValue">False</s:String> |
||||
|
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=SQL/@EntryIndexedValue">SQL</s:String> |
||||
|
</wpf:ResourceDictionary> |
||||
@ -0,0 +1,13 @@ |
|||||
|
version: '3.4' |
||||
|
|
||||
|
services: |
||||
|
migrations: |
||||
|
build: |
||||
|
context: ../../ |
||||
|
dockerfile: templates/service/database/Dockerfile |
||||
|
depends_on: |
||||
|
- sqlserver |
||||
|
environment: |
||||
|
- IdentityServer_DB=Coupons_Identity |
||||
|
- Coupons_DB=Coupons_ModuleDb |
||||
|
- SA_PASSWORD=yourStrong(!)Password |
||||
@ -0,0 +1,29 @@ |
|||||
|
version: '3.4' |
||||
|
|
||||
|
services: |
||||
|
sqlserver: |
||||
|
environment: |
||||
|
- SA_PASSWORD=yourStrong(!)Password |
||||
|
- ACCEPT_EULA=Y |
||||
|
ports: |
||||
|
- "51599:1433" |
||||
|
|
||||
|
identity-server: |
||||
|
environment: |
||||
|
- ASPNETCORE_URLS=http://0.0.0.0:80 |
||||
|
- ConnectionStrings__Default=Server=sqlserver;Database=Coupons_Identity;Trusted_Connection=True;MultipleActiveResultSets=true;User=sa;Password=yourStrong(!)Password;Integrated Security=false |
||||
|
- ConnectionStrings__SqlServerCache=Server=sqlserver;Database=Coupons_Cache;Trusted_Connection=True;MultipleActiveResultSets=true;User=sa;Password=yourStrong(!)Password;Integrated Security=false |
||||
|
ports: |
||||
|
- "51600:80" |
||||
|
|
||||
|
coupons: |
||||
|
environment: |
||||
|
- ASPNETCORE_URLS=http://0.0.0.0:80 |
||||
|
- ConnectionStrings__Default=Server=sqlserver;Database=Coupons_ModuleDb;Trusted_Connection=True;MultipleActiveResultSets=true;User=sa;Password=yourStrong(!)Password;Integrated Security=false |
||||
|
- ConnectionStrings__AbpSettingManagement=Server=sqlserver;Database=Coupons_Identity;Trusted_Connection=True;MultipleActiveResultSets=true;User=sa;Password=yourStrong(!)Password;Integrated Security=false |
||||
|
- ConnectionStrings__AbpPermissionManagement=Server=sqlserver;Database=Coupons_Identity;Trusted_Connection=True;MultipleActiveResultSets=true;User=sa;Password=yourStrong(!)Password;Integrated Security=false |
||||
|
- ConnectionStrings__AbpAuditLogging=Server=sqlserver;Database=Coupons_Identity;Trusted_Connection=True;MultipleActiveResultSets=true;User=sa;Password=yourStrong(!)Password;Integrated Security=false |
||||
|
- ConnectionStrings__SqlServerCache=Server=sqlserver;Database=Coupons_Cache;Trusted_Connection=True;MultipleActiveResultSets=true;User=sa;Password=yourStrong(!)Password;Integrated Security=false |
||||
|
- AuthServer__Authority=http://identity-server |
||||
|
ports: |
||||
|
- "51601:80" |
||||
@ -0,0 +1,25 @@ |
|||||
|
version: '3.4' |
||||
|
|
||||
|
services: |
||||
|
sqlserver: |
||||
|
image: mcr.microsoft.com/mssql/server |
||||
|
volumes: |
||||
|
- dbdata:/var/opt/mssql |
||||
|
|
||||
|
identity-server: |
||||
|
build: |
||||
|
context: ../../ |
||||
|
dockerfile: templates/service/host/IdentityServerHost/Dockerfile |
||||
|
depends_on: |
||||
|
- sqlserver |
||||
|
|
||||
|
coupons: |
||||
|
build: |
||||
|
context: ../../ |
||||
|
dockerfile: templates/service/host/EasyAbp.EShop.Plugins.Coupons.Host/Dockerfile |
||||
|
depends_on: |
||||
|
- sqlserver |
||||
|
- identity-server |
||||
|
|
||||
|
volumes: |
||||
|
dbdata: |
||||
@ -0,0 +1,10 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
|
||||
|
<Import Project="..\..\..\..\common.props" /> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>netstandard2.0</TargetFramework> |
||||
|
<RootNamespace>EasyAbp.EShop.Plugins.Coupons</RootNamespace> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -0,0 +1,10 @@ |
|||||
|
namespace EasyAbp.EShop.Plugins.Coupons.MultiTenancy |
||||
|
{ |
||||
|
public static class MultiTenancyConsts |
||||
|
{ |
||||
|
/* Enable/disable multi-tenancy in a single point |
||||
|
* to test your module with multi-tenancy. |
||||
|
*/ |
||||
|
public const bool IsEnabled = false; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,15 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
|
||||
|
<Import Project="..\..\..\..\common.props" /> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>netcoreapp3.1</TargetFramework> |
||||
|
<RootNamespace /> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<ProjectReference Include="..\..\..\..\modules\EasyAbp.EShop.Orders\src\EasyAbp.EShop.Orders.Application\EasyAbp.EShop.Orders.Application.csproj" /> |
||||
|
<ProjectReference Include="..\EasyAbp.EShop.Plugins.Coupons.Application.Contracts\EasyAbp.EShop.Plugins.Coupons.Application.Contracts.csproj" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -0,0 +1,18 @@ |
|||||
|
using EasyAbp.EShop.Orders.Plugins.Coupons.ObjectExtending; |
||||
|
using EasyAbp.EShop.Plugins.Coupons; |
||||
|
using Volo.Abp.Modularity; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Orders.Plugins.Coupons |
||||
|
{ |
||||
|
[DependsOn( |
||||
|
typeof(EShopOrdersDomainModule), |
||||
|
typeof(EShopPluginsCouponsApplicationContractsModule) |
||||
|
)] |
||||
|
public class EShopOrdersPluginsCouponsModule : AbpModule |
||||
|
{ |
||||
|
public override void PreConfigureServices(ServiceConfigurationContext context) |
||||
|
{ |
||||
|
EShopOrdersPluginsCouponsObjectExtensions.Configure(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,60 @@ |
|||||
|
using System; |
||||
|
using EasyAbp.EShop.Orders.Orders; |
||||
|
using EasyAbp.EShop.Orders.Orders.Dtos; |
||||
|
using EasyAbp.EShop.Plugins.Coupons; |
||||
|
using Volo.Abp.ObjectExtending; |
||||
|
using Volo.Abp.Threading; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Orders.Plugins.Coupons.ObjectExtending |
||||
|
{ |
||||
|
public static class EShopOrdersPluginsCouponsObjectExtensions |
||||
|
{ |
||||
|
private static readonly OneTimeRunner OneTimeRunner = new OneTimeRunner(); |
||||
|
|
||||
|
public static void Configure() |
||||
|
{ |
||||
|
OneTimeRunner.Run(() => |
||||
|
{ |
||||
|
/* You can configure extension properties to entities or other object types |
||||
|
* defined in the depended modules. |
||||
|
* |
||||
|
* If you are using EF Core and want to map the entity extension properties to new |
||||
|
* table fields in the database, then configure them in the EShopSampleEfCoreEntityExtensionMappings |
||||
|
* |
||||
|
* Example: |
||||
|
* |
||||
|
* ObjectExtensionManager.Instance |
||||
|
* .AddOrUpdateProperty<IdentityRole, string>("Title"); |
||||
|
* |
||||
|
* See the documentation for more: |
||||
|
* https://docs.abp.io/en/abp/latest/Object-Extensions
|
||||
|
*/ |
||||
|
|
||||
|
ObjectExtensionManager.Instance |
||||
|
.AddOrUpdate( |
||||
|
new[] |
||||
|
{ |
||||
|
typeof(Order), |
||||
|
typeof(CreateOrderDto) |
||||
|
}, |
||||
|
config => |
||||
|
{ |
||||
|
config.AddOrUpdateProperty<Guid?>(CouponsConsts.OrderCouponIdPropertyName); |
||||
|
} |
||||
|
); |
||||
|
|
||||
|
ObjectExtensionManager.Instance |
||||
|
.AddOrUpdate( |
||||
|
new[] |
||||
|
{ |
||||
|
typeof(Order) |
||||
|
}, |
||||
|
config => |
||||
|
{ |
||||
|
config.AddOrUpdateProperty<decimal>(CouponsConsts.OrderCouponDiscountAmountPropertyName); |
||||
|
} |
||||
|
); |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,12 @@ |
|||||
|
using Volo.Abp; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Orders.Plugins.Coupons.OrderDiscount |
||||
|
{ |
||||
|
public class CouponNotFoundOrHasExpiredException : BusinessException |
||||
|
{ |
||||
|
public CouponNotFoundOrHasExpiredException() : base("CouponNotFoundOrHasExpired", |
||||
|
"Coupon not found or has expired.") |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,183 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Threading.Tasks; |
||||
|
using EasyAbp.EShop.Orders.Orders; |
||||
|
using EasyAbp.EShop.Plugins.Coupons; |
||||
|
using EasyAbp.EShop.Plugins.Coupons.Coupons; |
||||
|
using EasyAbp.EShop.Plugins.Coupons.Coupons.Dtos; |
||||
|
using EasyAbp.EShop.Plugins.Coupons.CouponTemplates; |
||||
|
using EasyAbp.EShop.Products.Products.Dtos; |
||||
|
using Volo.Abp.Data; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
using Volo.Abp.Timing; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Orders.Plugins.Coupons.OrderDiscount |
||||
|
{ |
||||
|
public class CouponOrderDiscountProvider : IOrderDiscountProvider, ITransientDependency |
||||
|
{ |
||||
|
private readonly IClock _clock; |
||||
|
private readonly ICouponAppService _couponAppService; |
||||
|
private readonly ICouponLookupService _couponLookupService; |
||||
|
private readonly ICouponTemplateLookupService _couponTemplateLookupService; |
||||
|
|
||||
|
public CouponOrderDiscountProvider( |
||||
|
IClock clock, |
||||
|
ICouponAppService couponAppService, |
||||
|
ICouponLookupService couponLookupService, |
||||
|
ICouponTemplateLookupService couponTemplateLookupService) |
||||
|
{ |
||||
|
_clock = clock; |
||||
|
_couponAppService = couponAppService; |
||||
|
_couponLookupService = couponLookupService; |
||||
|
_couponTemplateLookupService = couponTemplateLookupService; |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<Order> DiscountAsync(Order order, Dictionary<Guid, ProductDto> productDict) |
||||
|
{ |
||||
|
if (!Guid.TryParse(order.GetProperty<string>(CouponsConsts.OrderCouponIdPropertyName), |
||||
|
out var couponId)) |
||||
|
{ |
||||
|
return order; |
||||
|
} |
||||
|
|
||||
|
var now = _clock.Now; |
||||
|
|
||||
|
var coupon = await _couponLookupService.FindByIdAsync(couponId); |
||||
|
|
||||
|
if (coupon == null || coupon.ExpirationTime < now) |
||||
|
{ |
||||
|
throw new CouponNotFoundOrHasExpiredException(); |
||||
|
} |
||||
|
|
||||
|
if (coupon.OrderId.HasValue) |
||||
|
{ |
||||
|
throw new CouponHasBeenOccupiedException(); |
||||
|
} |
||||
|
|
||||
|
var couponTemplate = await _couponTemplateLookupService.FindByIdAsync(coupon.CouponTemplateId); |
||||
|
|
||||
|
if (couponTemplate == null || |
||||
|
!IsInUsableTime(couponTemplate, now)) |
||||
|
{ |
||||
|
throw new CouponTemplateNotFoundOrUnavailableException(); |
||||
|
} |
||||
|
|
||||
|
var orderLinesInScope = GetOrderLinesInScope(couponTemplate, order, productDict); |
||||
|
|
||||
|
DiscountOrderLines(couponTemplate, order, orderLinesInScope); |
||||
|
|
||||
|
await _couponAppService.OccupyAsync(coupon.Id, new OccupyCouponInput {OrderId = order.Id}); |
||||
|
|
||||
|
return order; |
||||
|
} |
||||
|
|
||||
|
protected virtual void DiscountOrderLines(CouponTemplateData couponTemplate, Order order, |
||||
|
List<OrderLine> orderLinesInScope) |
||||
|
{ |
||||
|
// Todo: support Custom coupon.
|
||||
|
if (couponTemplate.CouponType == CouponType.Custom) |
||||
|
{ |
||||
|
throw new NotSupportedException(); |
||||
|
} |
||||
|
|
||||
|
var totalOrderLineActualTotalPrice = orderLinesInScope.Sum(x => x.ActualTotalPrice); |
||||
|
|
||||
|
var totalDiscountedAmount = couponTemplate.CouponType == CouponType.PerMeet |
||||
|
? couponTemplate.DiscountAmount * |
||||
|
Math.Floor(totalOrderLineActualTotalPrice / couponTemplate.ConditionAmount) |
||||
|
: couponTemplate.DiscountAmount; |
||||
|
|
||||
|
if (totalDiscountedAmount > totalOrderLineActualTotalPrice) |
||||
|
{ |
||||
|
totalDiscountedAmount = totalOrderLineActualTotalPrice; |
||||
|
} |
||||
|
|
||||
|
var remainingDiscountedAmount = totalDiscountedAmount; |
||||
|
|
||||
|
// Todo: https://github.com/EasyAbp/EShop/issues/104
|
||||
|
const int accuracy = 2; |
||||
|
|
||||
|
foreach (var orderLine in orderLinesInScope) |
||||
|
{ |
||||
|
var maxDiscountAmount = |
||||
|
Math.Round(orderLine.ActualTotalPrice / totalOrderLineActualTotalPrice * totalDiscountedAmount, |
||||
|
accuracy, MidpointRounding.ToZero); |
||||
|
|
||||
|
var discountAmount = maxDiscountAmount > orderLine.ActualTotalPrice |
||||
|
? orderLine.ActualTotalPrice |
||||
|
: maxDiscountAmount; |
||||
|
|
||||
|
order.AddDiscount(orderLine.Id, discountAmount); |
||||
|
|
||||
|
remainingDiscountedAmount -= discountAmount; |
||||
|
} |
||||
|
|
||||
|
foreach (var orderLine in orderLinesInScope.OrderByDescending(x => x.ActualTotalPrice)) |
||||
|
{ |
||||
|
if (remainingDiscountedAmount == decimal.Zero) |
||||
|
{ |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
var discountAmount = remainingDiscountedAmount > orderLine.ActualTotalPrice |
||||
|
? orderLine.ActualTotalPrice |
||||
|
: remainingDiscountedAmount; |
||||
|
|
||||
|
order.AddDiscount(orderLine.Id, discountAmount); |
||||
|
|
||||
|
remainingDiscountedAmount -= discountAmount; |
||||
|
} |
||||
|
|
||||
|
if (remainingDiscountedAmount != decimal.Zero) |
||||
|
{ |
||||
|
throw new ApplicationException(); |
||||
|
} |
||||
|
|
||||
|
order.SetProperty(CouponsConsts.OrderCouponDiscountAmountPropertyName, totalDiscountedAmount); |
||||
|
} |
||||
|
|
||||
|
protected virtual List<OrderLine> GetOrderLinesInScope(CouponTemplateData couponTemplate, Order order, |
||||
|
Dictionary<Guid, ProductDto> productDict) |
||||
|
{ |
||||
|
if (couponTemplate.IsUnscoped) |
||||
|
{ |
||||
|
return order.OrderLines; |
||||
|
} |
||||
|
|
||||
|
var expectedOrderLines = new List<OrderLine>(); |
||||
|
|
||||
|
foreach (var scope in couponTemplate.Scopes.Where(scope => scope.StoreId == order.StoreId)) |
||||
|
{ |
||||
|
expectedOrderLines.AddRange(order.OrderLines |
||||
|
.WhereIf(scope.ProductGroupName != null, |
||||
|
x => productDict[x.ProductId].ProductGroupName == scope.ProductGroupName) |
||||
|
.WhereIf(scope.ProductId.HasValue, x => x.ProductId == scope.ProductId) |
||||
|
.WhereIf(scope.ProductSkuId.HasValue, x => x.ProductSkuId == scope.ProductSkuId)); |
||||
|
} |
||||
|
|
||||
|
if (expectedOrderLines.IsNullOrEmpty()) |
||||
|
{ |
||||
|
throw new OrderDoesNotMeetCouponUsageConditionException(); |
||||
|
} |
||||
|
|
||||
|
if (expectedOrderLines.Sum(x => GetOrderLineProductPrice(x, productDict) * x.Quantity) < |
||||
|
couponTemplate.ConditionAmount) |
||||
|
{ |
||||
|
throw new OrderDoesNotMeetCouponUsageConditionException(); |
||||
|
} |
||||
|
|
||||
|
return expectedOrderLines; |
||||
|
} |
||||
|
|
||||
|
protected virtual decimal GetOrderLineProductPrice(OrderLine orderLine, Dictionary<Guid, ProductDto> productDict) |
||||
|
{ |
||||
|
return productDict[orderLine.ProductId].GetSkuById(orderLine.ProductSkuId).Price; |
||||
|
} |
||||
|
|
||||
|
protected virtual bool IsInUsableTime(ICouponTemplate couponTemplate, DateTime now) |
||||
|
{ |
||||
|
return couponTemplate.UsableBeginTime <= now && couponTemplate.UsableEndTime > now; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,12 @@ |
|||||
|
using Volo.Abp; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Orders.Plugins.Coupons.OrderDiscount |
||||
|
{ |
||||
|
public class CouponTemplateNotFoundOrUnavailableException : BusinessException |
||||
|
{ |
||||
|
public CouponTemplateNotFoundOrUnavailableException() : base("CouponTemplateNotFoundOrUnavailable", |
||||
|
"Coupon template not found or unavailable.") |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,12 @@ |
|||||
|
using Volo.Abp; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Orders.Plugins.Coupons.OrderDiscount |
||||
|
{ |
||||
|
public class OrderDoesNotMeetCouponUsageConditionException : BusinessException |
||||
|
{ |
||||
|
public OrderDoesNotMeetCouponUsageConditionException() : base("OrderDoesNotMeetCouponUsageCondition", |
||||
|
"Order does not meet the coupon usage condition.") |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,3 @@ |
|||||
|
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd"> |
||||
|
<ConfigureAwait /> |
||||
|
</Weavers> |
||||
@ -0,0 +1,30 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> |
||||
|
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. --> |
||||
|
<xs:element name="Weavers"> |
||||
|
<xs:complexType> |
||||
|
<xs:all> |
||||
|
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1"> |
||||
|
<xs:complexType> |
||||
|
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" /> |
||||
|
</xs:complexType> |
||||
|
</xs:element> |
||||
|
</xs:all> |
||||
|
<xs:attribute name="VerifyAssembly" type="xs:boolean"> |
||||
|
<xs:annotation> |
||||
|
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation> |
||||
|
</xs:annotation> |
||||
|
</xs:attribute> |
||||
|
<xs:attribute name="VerifyIgnoreCodes" type="xs:string"> |
||||
|
<xs:annotation> |
||||
|
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation> |
||||
|
</xs:annotation> |
||||
|
</xs:attribute> |
||||
|
<xs:attribute name="GenerateXsd" type="xs:boolean"> |
||||
|
<xs:annotation> |
||||
|
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation> |
||||
|
</xs:annotation> |
||||
|
</xs:attribute> |
||||
|
</xs:complexType> |
||||
|
</xs:element> |
||||
|
</xs:schema> |
||||
@ -0,0 +1,16 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
|
||||
|
<Import Project="..\..\..\..\common.props" /> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>netstandard2.0</TargetFramework> |
||||
|
<RootNamespace /> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<PackageReference Include="Volo.Abp.Ddd.Application.Contracts" Version="3.1.2" /> |
||||
|
<PackageReference Include="Volo.Abp.Authorization" Version="3.1.2" /> |
||||
|
<ProjectReference Include="..\EasyAbp.EShop.Plugins.Coupons.Domain.Shared\EasyAbp.EShop.Plugins.Coupons.Domain.Shared.csproj" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -0,0 +1,34 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using Volo.Abp.Application.Dtos; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.Coupons.CouponTemplates.Dtos |
||||
|
{ |
||||
|
[Serializable] |
||||
|
public class CouponTemplateDto : FullAuditedEntityDto<Guid>, ICouponTemplate, IHasCouponTemplateScopes<CouponTemplateScopeDto> |
||||
|
{ |
||||
|
public Guid? StoreId { get; set; } |
||||
|
|
||||
|
public CouponType CouponType { get; set; } |
||||
|
|
||||
|
public string UniqueName { get; set; } |
||||
|
|
||||
|
public string DisplayName { get; set; } |
||||
|
|
||||
|
public string Description { get; set; } |
||||
|
|
||||
|
public TimeSpan? UsableDuration { get; set; } |
||||
|
|
||||
|
public DateTime? UsableBeginTime { get; set; } |
||||
|
|
||||
|
public DateTime? UsableEndTime { get; set; } |
||||
|
|
||||
|
public decimal ConditionAmount { get; set; } |
||||
|
|
||||
|
public decimal DiscountAmount { get; set; } |
||||
|
|
||||
|
public bool IsUnscoped { get; set; } |
||||
|
|
||||
|
public List<CouponTemplateScopeDto> Scopes { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,17 @@ |
|||||
|
using System; |
||||
|
using Volo.Abp.Application.Dtos; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.Coupons.CouponTemplates.Dtos |
||||
|
{ |
||||
|
[Serializable] |
||||
|
public class CouponTemplateScopeDto : FullAuditedEntityDto<Guid>, ICouponTemplateScope |
||||
|
{ |
||||
|
public Guid StoreId { get; set; } |
||||
|
|
||||
|
public string ProductGroupName { get; set; } |
||||
|
|
||||
|
public Guid? ProductId { get; set; } |
||||
|
|
||||
|
public Guid? ProductSkuId { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,54 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.ComponentModel; |
||||
|
using System.ComponentModel.DataAnnotations; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.Coupons.CouponTemplates.Dtos |
||||
|
{ |
||||
|
[Serializable] |
||||
|
public class CreateUpdateCouponTemplateDto : IValidatableObject |
||||
|
{ |
||||
|
public Guid? StoreId { get; set; } |
||||
|
|
||||
|
public CouponType CouponType { get; set; } |
||||
|
|
||||
|
public string UniqueName { get; set; } |
||||
|
|
||||
|
public string DisplayName { get; set; } |
||||
|
|
||||
|
public string Description { get; set; } |
||||
|
|
||||
|
public TimeSpan? UsableDuration { get; set; } |
||||
|
|
||||
|
public DateTime? UsableBeginTime { get; set; } |
||||
|
|
||||
|
public DateTime? UsableEndTime { get; set; } |
||||
|
|
||||
|
public decimal ConditionAmount { get; set; } |
||||
|
|
||||
|
public decimal DiscountAmount { get; set; } |
||||
|
|
||||
|
public bool IsUnscoped { get; set; } |
||||
|
|
||||
|
public List<CreateUpdateCouponTemplateScopeDto> Scopes { get; set; } = new List<CreateUpdateCouponTemplateScopeDto>(); |
||||
|
|
||||
|
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext) |
||||
|
{ |
||||
|
if (DiscountAmount > ConditionAmount) |
||||
|
{ |
||||
|
yield return new ValidationResult( |
||||
|
"DiscountAmount should not be greater than ConditionAmount!", |
||||
|
new[] { nameof(DiscountAmount) } |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
if (CouponType == CouponType.PerMeet && ConditionAmount == decimal.Zero) |
||||
|
{ |
||||
|
yield return new ValidationResult( |
||||
|
"ConditionAmount should be greater than zero if the CouponType is PerMeet!", |
||||
|
new[] { nameof(ConditionAmount) } |
||||
|
); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,16 @@ |
|||||
|
using System; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.Coupons.CouponTemplates.Dtos |
||||
|
{ |
||||
|
[Serializable] |
||||
|
public class CreateUpdateCouponTemplateScopeDto |
||||
|
{ |
||||
|
public Guid StoreId { get; set; } |
||||
|
|
||||
|
public string ProductGroupName { get; set; } |
||||
|
|
||||
|
public Guid? ProductId { get; set; } |
||||
|
|
||||
|
public Guid? ProductSkuId { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,18 @@ |
|||||
|
using System; |
||||
|
using EasyAbp.EShop.Plugins.Coupons.CouponTemplates.Dtos; |
||||
|
using Volo.Abp.Application.Dtos; |
||||
|
using Volo.Abp.Application.Services; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.Coupons.CouponTemplates |
||||
|
{ |
||||
|
public interface ICouponTemplateAppService : |
||||
|
ICrudAppService< |
||||
|
CouponTemplateDto, |
||||
|
Guid, |
||||
|
PagedAndSortedResultRequestDto, |
||||
|
CreateUpdateCouponTemplateDto, |
||||
|
CreateUpdateCouponTemplateDto> |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,11 @@ |
|||||
|
using Volo.Abp; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.Coupons.Coupons |
||||
|
{ |
||||
|
public class CouponHasBeenOccupiedException : BusinessException |
||||
|
{ |
||||
|
public CouponHasBeenOccupiedException() : base("CouponHasBeenOccupied", "Coupon has been occupied.") |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,24 @@ |
|||||
|
using System; |
||||
|
using EasyAbp.EShop.Plugins.Coupons.CouponTemplates.Dtos; |
||||
|
using Volo.Abp.Application.Dtos; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.Coupons.Coupons.Dtos |
||||
|
{ |
||||
|
[Serializable] |
||||
|
public class CouponDto : FullAuditedEntityDto<Guid>, ICoupon |
||||
|
{ |
||||
|
public Guid CouponTemplateId { get; set; } |
||||
|
|
||||
|
public Guid UserId { get; set; } |
||||
|
|
||||
|
public Guid? OrderId { get; set; } |
||||
|
|
||||
|
public DateTime? ExpirationTime { get; set; } |
||||
|
|
||||
|
public DateTime? UsedTime { get; set; } |
||||
|
|
||||
|
public decimal? DiscountedAmount { get; set; } |
||||
|
|
||||
|
public CouponTemplateDto CouponTemplate { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,11 @@ |
|||||
|
using System; |
||||
|
namespace EasyAbp.EShop.Plugins.Coupons.Coupons.Dtos |
||||
|
{ |
||||
|
[Serializable] |
||||
|
public class CreateCouponDto |
||||
|
{ |
||||
|
public Guid CouponTemplateId { get; set; } |
||||
|
|
||||
|
public Guid UserId { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,22 @@ |
|||||
|
using System; |
||||
|
using Volo.Abp.Application.Dtos; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.Coupons.Coupons.Dtos |
||||
|
{ |
||||
|
[Serializable] |
||||
|
public class GetCouponListInput : PagedAndSortedResultRequestDto |
||||
|
{ |
||||
|
public bool AvailableOnly { get; set; } |
||||
|
|
||||
|
public Guid? StoreId { get; set; } |
||||
|
|
||||
|
public Guid? UserId { get; set; } |
||||
|
|
||||
|
public bool IncludesExpired { get; set; } |
||||
|
|
||||
|
public GetCouponListInput() |
||||
|
{ |
||||
|
MaxMaxResultCount = CouponsConsts.MaxNotExpiredCouponQuantityPerUser; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,10 @@ |
|||||
|
using System; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.Coupons.Coupons.Dtos |
||||
|
{ |
||||
|
[Serializable] |
||||
|
public class OccupyCouponInput |
||||
|
{ |
||||
|
public Guid OrderId { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,9 @@ |
|||||
|
using System; |
||||
|
namespace EasyAbp.EShop.Plugins.Coupons.Coupons.Dtos |
||||
|
{ |
||||
|
[Serializable] |
||||
|
public class UpdateCouponDto |
||||
|
{ |
||||
|
public DateTime? ExpirationTime { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,19 @@ |
|||||
|
using System; |
||||
|
using System.Threading.Tasks; |
||||
|
using EasyAbp.EShop.Plugins.Coupons.Coupons.Dtos; |
||||
|
using Volo.Abp.Application.Dtos; |
||||
|
using Volo.Abp.Application.Services; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.Coupons.Coupons |
||||
|
{ |
||||
|
public interface ICouponAppService : |
||||
|
ICrudAppService< |
||||
|
CouponDto, |
||||
|
Guid, |
||||
|
GetCouponListInput, |
||||
|
CreateCouponDto, |
||||
|
UpdateCouponDto> |
||||
|
{ |
||||
|
Task<CouponDto> OccupyAsync(Guid id, OccupyCouponInput input); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,16 @@ |
|||||
|
using Volo.Abp.Application; |
||||
|
using Volo.Abp.Modularity; |
||||
|
using Volo.Abp.Authorization; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.Coupons |
||||
|
{ |
||||
|
[DependsOn( |
||||
|
typeof(EShopPluginsCouponsDomainSharedModule), |
||||
|
typeof(AbpDddApplicationContractsModule), |
||||
|
typeof(AbpAuthorizationModule) |
||||
|
)] |
||||
|
public class EShopPluginsCouponsApplicationContractsModule : AbpModule |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,33 @@ |
|||||
|
using EasyAbp.EShop.Plugins.Coupons.Localization; |
||||
|
using Volo.Abp.Authorization.Permissions; |
||||
|
using Volo.Abp.Localization; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.Coupons.Permissions |
||||
|
{ |
||||
|
public class CouponsPermissionDefinitionProvider : PermissionDefinitionProvider |
||||
|
{ |
||||
|
public override void Define(IPermissionDefinitionContext context) |
||||
|
{ |
||||
|
var myGroup = context.AddGroup(CouponsPermissions.GroupName, L("Permission:Coupons")); |
||||
|
|
||||
|
var couponTemplatePermission = myGroup.AddPermission(CouponsPermissions.CouponTemplate.Default, L("Permission:CouponTemplate")); |
||||
|
couponTemplatePermission.AddChild(CouponsPermissions.CouponTemplate.CrossStore, L("Permission:CrossStore")); |
||||
|
couponTemplatePermission.AddChild(CouponsPermissions.CouponTemplate.Create, L("Permission:Create")); |
||||
|
couponTemplatePermission.AddChild(CouponsPermissions.CouponTemplate.Update, L("Permission:Update")); |
||||
|
couponTemplatePermission.AddChild(CouponsPermissions.CouponTemplate.Delete, L("Permission:Delete")); |
||||
|
|
||||
|
var couponPermission = myGroup.AddPermission(CouponsPermissions.Coupon.Default, L("Permission:Coupon")); |
||||
|
couponPermission.AddChild(CouponsPermissions.Coupon.Use, L("Permission:Use")); |
||||
|
couponPermission.AddChild(CouponsPermissions.Coupon.Manage, L("Permission:Manage")); |
||||
|
couponPermission.AddChild(CouponsPermissions.Coupon.CrossStore, L("Permission:CrossStore")); |
||||
|
couponPermission.AddChild(CouponsPermissions.Coupon.Create, L("Permission:Create")); |
||||
|
couponPermission.AddChild(CouponsPermissions.Coupon.Update, L("Permission:Update")); |
||||
|
couponPermission.AddChild(CouponsPermissions.Coupon.Delete, L("Permission:Delete")); |
||||
|
} |
||||
|
|
||||
|
private static LocalizableString L(string name) |
||||
|
{ |
||||
|
return LocalizableString.Create<CouponsResource>(name); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,34 @@ |
|||||
|
using Volo.Abp.Reflection; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.Coupons.Permissions |
||||
|
{ |
||||
|
public class CouponsPermissions |
||||
|
{ |
||||
|
public const string GroupName = "EasyAbp.EShop.Plugins.Coupons"; |
||||
|
|
||||
|
public static string[] GetAll() |
||||
|
{ |
||||
|
return ReflectionHelper.GetPublicConstantsRecursively(typeof(CouponsPermissions)); |
||||
|
} |
||||
|
|
||||
|
public class CouponTemplate |
||||
|
{ |
||||
|
public const string Default = GroupName + ".CouponTemplate"; |
||||
|
public const string CrossStore = Default + ".CrossStore"; |
||||
|
public const string Update = Default + ".Update"; |
||||
|
public const string Create = Default + ".Create"; |
||||
|
public const string Delete = Default + ".Delete"; |
||||
|
} |
||||
|
|
||||
|
public class Coupon |
||||
|
{ |
||||
|
public const string Default = GroupName + ".Coupon"; |
||||
|
public const string Use = Default + ".Use"; |
||||
|
public const string Manage = Default + ".Manage"; |
||||
|
public const string CrossStore = Default + ".CrossStore"; |
||||
|
public const string Update = Default + ".Update"; |
||||
|
public const string Create = Default + ".Create"; |
||||
|
public const string Delete = Default + ".Delete"; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,3 @@ |
|||||
|
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd"> |
||||
|
<ConfigureAwait ContinueOnCapturedContext="false" /> |
||||
|
</Weavers> |
||||
@ -0,0 +1,30 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> |
||||
|
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. --> |
||||
|
<xs:element name="Weavers"> |
||||
|
<xs:complexType> |
||||
|
<xs:all> |
||||
|
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1"> |
||||
|
<xs:complexType> |
||||
|
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" /> |
||||
|
</xs:complexType> |
||||
|
</xs:element> |
||||
|
</xs:all> |
||||
|
<xs:attribute name="VerifyAssembly" type="xs:boolean"> |
||||
|
<xs:annotation> |
||||
|
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation> |
||||
|
</xs:annotation> |
||||
|
</xs:attribute> |
||||
|
<xs:attribute name="VerifyIgnoreCodes" type="xs:string"> |
||||
|
<xs:annotation> |
||||
|
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation> |
||||
|
</xs:annotation> |
||||
|
</xs:attribute> |
||||
|
<xs:attribute name="GenerateXsd" type="xs:boolean"> |
||||
|
<xs:annotation> |
||||
|
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation> |
||||
|
</xs:annotation> |
||||
|
</xs:attribute> |
||||
|
</xs:complexType> |
||||
|
</xs:element> |
||||
|
</xs:schema> |
||||
@ -0,0 +1,18 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
|
||||
|
<Import Project="..\..\..\..\common.props" /> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>netstandard2.0</TargetFramework> |
||||
|
<RootNamespace /> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<PackageReference Include="Volo.Abp.AutoMapper" Version="3.1.2" /> |
||||
|
<PackageReference Include="Volo.Abp.Ddd.Application" Version="3.1.2" /> |
||||
|
<ProjectReference Include="..\..\..\..\modules\EasyAbp.EShop.Stores\src\EasyAbp.EShop.Stores.Application.Shared\EasyAbp.EShop.Stores.Application.Shared.csproj" /> |
||||
|
<ProjectReference Include="..\EasyAbp.EShop.Plugins.Coupons.Application.Contracts\EasyAbp.EShop.Plugins.Coupons.Application.Contracts.csproj" /> |
||||
|
<ProjectReference Include="..\EasyAbp.EShop.Plugins.Coupons.Domain\EasyAbp.EShop.Plugins.Coupons.Domain.csproj" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -0,0 +1,114 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Collections.ObjectModel; |
||||
|
using System.Linq; |
||||
|
using System.Threading.Tasks; |
||||
|
using EasyAbp.EShop.Plugins.Coupons.Permissions; |
||||
|
using EasyAbp.EShop.Plugins.Coupons.CouponTemplates.Dtos; |
||||
|
using EasyAbp.EShop.Stores.Authorization; |
||||
|
using Microsoft.AspNetCore.Authorization; |
||||
|
using Volo.Abp.Application.Dtos; |
||||
|
using Volo.Abp.Application.Services; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.Coupons.CouponTemplates |
||||
|
{ |
||||
|
public class CouponTemplateAppService : CrudAppService<CouponTemplate, CouponTemplateDto, Guid, PagedAndSortedResultRequestDto, CreateUpdateCouponTemplateDto, CreateUpdateCouponTemplateDto>, |
||||
|
ICouponTemplateAppService |
||||
|
{ |
||||
|
protected override string GetPolicyName { get; set; } = CouponsPermissions.CouponTemplate.Default; |
||||
|
protected override string GetListPolicyName { get; set; } = CouponsPermissions.CouponTemplate.Default; |
||||
|
protected override string CreatePolicyName { get; set; } = CouponsPermissions.CouponTemplate.Create; |
||||
|
protected override string UpdatePolicyName { get; set; } = CouponsPermissions.CouponTemplate.Update; |
||||
|
protected override string DeletePolicyName { get; set; } = CouponsPermissions.CouponTemplate.Delete; |
||||
|
|
||||
|
private readonly ICouponTemplateRepository _repository; |
||||
|
|
||||
|
public CouponTemplateAppService(ICouponTemplateRepository repository) : base(repository) |
||||
|
{ |
||||
|
_repository = repository; |
||||
|
} |
||||
|
|
||||
|
protected override IQueryable<CouponTemplate> CreateFilteredQuery(PagedAndSortedResultRequestDto input) |
||||
|
{ |
||||
|
return _repository.WithDetails(); |
||||
|
} |
||||
|
|
||||
|
public override async Task<CouponTemplateDto> CreateAsync(CreateUpdateCouponTemplateDto input) |
||||
|
{ |
||||
|
await AuthorizationService.CheckMultiStorePolicyAsync(input.StoreId, CreatePolicyName, |
||||
|
CouponsPermissions.CouponTemplate.CrossStore); |
||||
|
|
||||
|
if (input.Scopes.Any(x => x.StoreId != input.StoreId)) |
||||
|
{ |
||||
|
await AuthorizationService.CheckAsync(CouponsPermissions.CouponTemplate.CrossStore); |
||||
|
} |
||||
|
|
||||
|
var entity = await MapToEntityAsync(input); |
||||
|
|
||||
|
TryToSetTenantId(entity); |
||||
|
|
||||
|
foreach (var inputScoreDto in input.Scopes) |
||||
|
{ |
||||
|
entity.Scopes.Add(new CouponTemplateScope(GuidGenerator.Create(), inputScoreDto.StoreId, |
||||
|
inputScoreDto.ProductGroupName, inputScoreDto.ProductId, inputScoreDto.ProductSkuId)); |
||||
|
} |
||||
|
|
||||
|
await Repository.InsertAsync(entity, autoSave: true); |
||||
|
|
||||
|
return await MapToGetOutputDtoAsync(entity); |
||||
|
} |
||||
|
|
||||
|
public override async Task<CouponTemplateDto> UpdateAsync(Guid id, CreateUpdateCouponTemplateDto input) |
||||
|
{ |
||||
|
var entity = await GetEntityByIdAsync(id); |
||||
|
|
||||
|
await AuthorizationService.CheckMultiStorePolicyAsync(entity.StoreId, UpdatePolicyName, |
||||
|
CouponsPermissions.CouponTemplate.CrossStore); |
||||
|
|
||||
|
if (input.StoreId != entity.StoreId || input.Scopes.Any(x => x.StoreId != input.StoreId)) |
||||
|
{ |
||||
|
await AuthorizationService.CheckAsync(CouponsPermissions.CouponTemplate.CrossStore); |
||||
|
} |
||||
|
|
||||
|
await MapToEntityAsync(input, entity); |
||||
|
|
||||
|
foreach (var inputScoreDto in input.Scopes.Where(dto => !ExistScope(entity.Scopes, dto))) |
||||
|
{ |
||||
|
entity.Scopes.Add(new CouponTemplateScope(GuidGenerator.Create(), inputScoreDto.StoreId, |
||||
|
inputScoreDto.ProductGroupName, inputScoreDto.ProductId, inputScoreDto.ProductSkuId)); |
||||
|
} |
||||
|
|
||||
|
entity.Scopes.RemoveAll(scope => !ExistScope(input.Scopes, scope)); |
||||
|
|
||||
|
await Repository.UpdateAsync(entity, autoSave: true); |
||||
|
|
||||
|
return await MapToGetOutputDtoAsync(entity); |
||||
|
} |
||||
|
|
||||
|
public override async Task DeleteAsync(Guid id) |
||||
|
{ |
||||
|
var couponTemplate = await GetEntityByIdAsync(id); |
||||
|
|
||||
|
await AuthorizationService.CheckMultiStorePolicyAsync(couponTemplate.StoreId, DeletePolicyName, |
||||
|
CouponsPermissions.CouponTemplate.CrossStore); |
||||
|
|
||||
|
await _repository.DeleteAsync(couponTemplate); |
||||
|
} |
||||
|
|
||||
|
protected virtual bool ExistScope(IEnumerable<CreateUpdateCouponTemplateScopeDto> scopes, ICouponTemplateScope need) |
||||
|
{ |
||||
|
return scopes.Any(x => x.StoreId == need.StoreId && |
||||
|
x.ProductGroupName == need.ProductGroupName && |
||||
|
x.ProductId == need.ProductId && |
||||
|
x.ProductSkuId == need.ProductSkuId); |
||||
|
} |
||||
|
|
||||
|
protected virtual bool ExistScope(IEnumerable<ICouponTemplateScope> scopes, CreateUpdateCouponTemplateScopeDto dto) |
||||
|
{ |
||||
|
return scopes.Any(x => x.StoreId == dto.StoreId && |
||||
|
x.ProductGroupName == dto.ProductGroupName && |
||||
|
x.ProductId == dto.ProductId && |
||||
|
x.ProductSkuId == dto.ProductSkuId); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,172 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Threading.Tasks; |
||||
|
using EasyAbp.EShop.Plugins.Coupons.Permissions; |
||||
|
using EasyAbp.EShop.Plugins.Coupons.Coupons.Dtos; |
||||
|
using EasyAbp.EShop.Plugins.Coupons.CouponTemplates; |
||||
|
using EasyAbp.EShop.Plugins.Coupons.CouponTemplates.Dtos; |
||||
|
using EasyAbp.EShop.Stores.Authorization; |
||||
|
using Microsoft.AspNetCore.Authorization; |
||||
|
using Volo.Abp.Application.Dtos; |
||||
|
using Volo.Abp.Application.Services; |
||||
|
using Volo.Abp.Authorization; |
||||
|
using Volo.Abp.Users; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.Coupons.Coupons |
||||
|
{ |
||||
|
public class CouponAppService : CrudAppService<Coupon, CouponDto, Guid, GetCouponListInput, CreateCouponDto, UpdateCouponDto>, |
||||
|
ICouponAppService |
||||
|
{ |
||||
|
protected override string GetPolicyName { get; set; } = CouponsPermissions.Coupon.Default; |
||||
|
protected override string GetListPolicyName { get; set; } = CouponsPermissions.Coupon.Default; |
||||
|
protected override string CreatePolicyName { get; set; } = CouponsPermissions.Coupon.Create; |
||||
|
protected override string UpdatePolicyName { get; set; } = CouponsPermissions.Coupon.Update; |
||||
|
protected override string DeletePolicyName { get; set; } = CouponsPermissions.Coupon.Delete; |
||||
|
|
||||
|
private readonly ICouponTemplateRepository _couponTemplateRepository; |
||||
|
private readonly ICouponRepository _repository; |
||||
|
|
||||
|
public CouponAppService( |
||||
|
ICouponTemplateRepository couponTemplateRepository, |
||||
|
ICouponRepository repository) : base(repository) |
||||
|
{ |
||||
|
_couponTemplateRepository = couponTemplateRepository; |
||||
|
_repository = repository; |
||||
|
} |
||||
|
|
||||
|
protected override IQueryable<Coupon> CreateFilteredQuery(GetCouponListInput input) |
||||
|
{ |
||||
|
return (input.AvailableOnly ? _repository.GetAvailableCouponQueryable(Clock) : _repository.AsQueryable()) |
||||
|
.WhereIf(input.UserId.HasValue, x => x.UserId == input.UserId.Value) |
||||
|
.WhereIf(!input.AvailableOnly && !input.IncludesExpired, x => x.ExpirationTime > Clock.Now); |
||||
|
} |
||||
|
|
||||
|
protected virtual CouponDto FillCouponTemplateData(CouponDto couponDto, CouponTemplate couponTemplate) |
||||
|
{ |
||||
|
couponDto.CouponTemplate = ObjectMapper.Map<CouponTemplate, CouponTemplateDto>(couponTemplate); |
||||
|
|
||||
|
return couponDto; |
||||
|
} |
||||
|
|
||||
|
public override async Task<CouponDto> GetAsync(Guid id) |
||||
|
{ |
||||
|
await CheckGetPolicyAsync(); |
||||
|
|
||||
|
var coupon = await GetEntityByIdAsync(id); |
||||
|
|
||||
|
var couponTemplate = await _couponTemplateRepository.GetAsync(coupon.CouponTemplateId); |
||||
|
|
||||
|
if (coupon.UserId != CurrentUser.GetId()) |
||||
|
{ |
||||
|
await AuthorizationService.CheckMultiStorePolicyAsync(couponTemplate.StoreId, |
||||
|
CouponsPermissions.Coupon.Manage, CouponsPermissions.Coupon.CrossStore); |
||||
|
} |
||||
|
|
||||
|
return FillCouponTemplateData(await MapToGetOutputDtoAsync(coupon), couponTemplate); |
||||
|
} |
||||
|
|
||||
|
public override async Task<PagedResultDto<CouponDto>> GetListAsync(GetCouponListInput input) |
||||
|
{ |
||||
|
if (input.UserId != CurrentUser.GetId()) |
||||
|
{ |
||||
|
await AuthorizationService.CheckMultiStorePolicyAsync(input.StoreId, |
||||
|
CouponsPermissions.Coupon.Manage, CouponsPermissions.Coupon.CrossStore); |
||||
|
} |
||||
|
|
||||
|
var result = await base.GetListAsync(input); |
||||
|
|
||||
|
var couponTemplateDtoDictionary = new Dictionary<Guid, CouponTemplateDto>(); |
||||
|
|
||||
|
foreach (var couponDto in result.Items) |
||||
|
{ |
||||
|
if (!couponTemplateDtoDictionary.ContainsKey(couponDto.CouponTemplateId)) |
||||
|
{ |
||||
|
couponTemplateDtoDictionary.Add(couponDto.CouponTemplateId, |
||||
|
ObjectMapper.Map<CouponTemplate, CouponTemplateDto>( |
||||
|
await _couponTemplateRepository.GetAsync(couponDto.CouponTemplateId))); |
||||
|
} |
||||
|
|
||||
|
couponDto.CouponTemplate = couponTemplateDtoDictionary[couponDto.CouponTemplateId]; |
||||
|
} |
||||
|
|
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
public override async Task<CouponDto> CreateAsync(CreateCouponDto input) |
||||
|
{ |
||||
|
await CheckCreatePolicyAsync(); |
||||
|
|
||||
|
var couponTemplate = await _couponTemplateRepository.GetAsync(input.CouponTemplateId); |
||||
|
|
||||
|
await AuthorizationService.CheckMultiStorePolicyAsync(couponTemplate.StoreId, |
||||
|
CouponsPermissions.Coupon.Manage, CouponsPermissions.Coupon.CrossStore); |
||||
|
|
||||
|
var coupon = await MapToEntityAsync(input); |
||||
|
|
||||
|
TryToSetTenantId(coupon); |
||||
|
|
||||
|
coupon.SetExpirationTime(couponTemplate.GetCalculatedExpirationTime(Clock)); |
||||
|
|
||||
|
await _repository.InsertAsync(coupon, autoSave: true); |
||||
|
|
||||
|
return FillCouponTemplateData(await MapToGetOutputDtoAsync(coupon), couponTemplate); |
||||
|
} |
||||
|
|
||||
|
public override async Task<CouponDto> UpdateAsync(Guid id, UpdateCouponDto input) |
||||
|
{ |
||||
|
await CheckUpdatePolicyAsync(); |
||||
|
|
||||
|
var coupon = await GetEntityByIdAsync(id); |
||||
|
|
||||
|
var couponTemplate = await _couponTemplateRepository.GetAsync(coupon.CouponTemplateId); |
||||
|
|
||||
|
await AuthorizationService.CheckMultiStorePolicyAsync(couponTemplate.StoreId, |
||||
|
CouponsPermissions.Coupon.Manage, CouponsPermissions.Coupon.CrossStore); |
||||
|
|
||||
|
await MapToEntityAsync(input, coupon); |
||||
|
|
||||
|
await Repository.UpdateAsync(coupon, autoSave: true); |
||||
|
|
||||
|
return FillCouponTemplateData(await MapToGetOutputDtoAsync(coupon), couponTemplate); |
||||
|
} |
||||
|
|
||||
|
public override async Task DeleteAsync(Guid id) |
||||
|
{ |
||||
|
await CheckDeletePolicyAsync(); |
||||
|
|
||||
|
var coupon = await GetEntityByIdAsync(id); |
||||
|
|
||||
|
var couponTemplate = await _couponTemplateRepository.GetAsync(coupon.CouponTemplateId); |
||||
|
|
||||
|
await AuthorizationService.CheckMultiStorePolicyAsync(couponTemplate.StoreId, |
||||
|
CouponsPermissions.Coupon.Manage, CouponsPermissions.Coupon.CrossStore); |
||||
|
|
||||
|
await _repository.DeleteAsync(coupon, true); |
||||
|
} |
||||
|
|
||||
|
[Authorize(CouponsPermissions.Coupon.Use)] |
||||
|
public virtual async Task<CouponDto> OccupyAsync(Guid id, OccupyCouponInput input) |
||||
|
{ |
||||
|
var coupon = await GetEntityByIdAsync(id); |
||||
|
|
||||
|
if (coupon.UserId != CurrentUser.GetId()) |
||||
|
{ |
||||
|
throw new AbpAuthorizationException(); |
||||
|
} |
||||
|
|
||||
|
if (coupon.OrderId.HasValue) |
||||
|
{ |
||||
|
throw new CouponHasBeenOccupiedException(); |
||||
|
} |
||||
|
|
||||
|
var couponTemplate = await _couponTemplateRepository.GetAsync(coupon.CouponTemplateId); |
||||
|
|
||||
|
coupon.SetOrderId(input.OrderId); |
||||
|
|
||||
|
await _repository.UpdateAsync(coupon, true); |
||||
|
|
||||
|
return FillCouponTemplateData(await MapToGetOutputDtoAsync(coupon), couponTemplate); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,14 @@ |
|||||
|
using EasyAbp.EShop.Plugins.Coupons.Localization; |
||||
|
using Volo.Abp.Application.Services; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.Coupons |
||||
|
{ |
||||
|
public abstract class CouponsAppService : ApplicationService |
||||
|
{ |
||||
|
protected CouponsAppService() |
||||
|
{ |
||||
|
LocalizationResource = typeof(CouponsResource); |
||||
|
ObjectMapperContext = typeof(EShopPluginsCouponsApplicationModule); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,30 @@ |
|||||
|
using EasyAbp.EShop.Plugins.Coupons.CouponTemplates; |
||||
|
using EasyAbp.EShop.Plugins.Coupons.CouponTemplates.Dtos; |
||||
|
using EasyAbp.EShop.Plugins.Coupons.Coupons; |
||||
|
using EasyAbp.EShop.Plugins.Coupons.Coupons.Dtos; |
||||
|
using AutoMapper; |
||||
|
using Volo.Abp.AutoMapper; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.Coupons |
||||
|
{ |
||||
|
public class CouponsApplicationAutoMapperProfile : Profile |
||||
|
{ |
||||
|
public CouponsApplicationAutoMapperProfile() |
||||
|
{ |
||||
|
/* You can configure your AutoMapper mapping configuration here. |
||||
|
* Alternatively, you can split your mapping configurations |
||||
|
* into multiple profile classes for a better organization. */ |
||||
|
CreateMap<CouponTemplate, CouponTemplateDto>(); |
||||
|
CreateMap<CreateUpdateCouponTemplateDto, CouponTemplate>(MemberList.Source) |
||||
|
.Ignore(x => x.Scopes); |
||||
|
|
||||
|
CreateMap<CouponTemplateScope, CouponTemplateScopeDto>(); |
||||
|
CreateMap<CreateUpdateCouponTemplateScopeDto, CouponTemplateScope>(MemberList.Source); |
||||
|
|
||||
|
CreateMap<Coupon, CouponDto>() |
||||
|
.Ignore(x => x.CouponTemplate); |
||||
|
CreateMap<CreateCouponDto, Coupon>(MemberList.Source); |
||||
|
CreateMap<UpdateCouponDto, Coupon>(MemberList.Source); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,27 @@ |
|||||
|
using EasyAbp.EShop.Stores; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Volo.Abp.AutoMapper; |
||||
|
using Volo.Abp.Modularity; |
||||
|
using Volo.Abp.Application; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.Coupons |
||||
|
{ |
||||
|
[DependsOn( |
||||
|
typeof(EShopPluginsCouponsDomainModule), |
||||
|
typeof(EShopPluginsCouponsApplicationContractsModule), |
||||
|
typeof(EShopStoresApplicationSharedModule), |
||||
|
typeof(AbpDddApplicationModule), |
||||
|
typeof(AbpAutoMapperModule) |
||||
|
)] |
||||
|
public class EShopPluginsCouponsApplicationModule : AbpModule |
||||
|
{ |
||||
|
public override void ConfigureServices(ServiceConfigurationContext context) |
||||
|
{ |
||||
|
context.Services.AddAutoMapperObjectMapper<EShopPluginsCouponsApplicationModule>(); |
||||
|
Configure<AbpAutoMapperOptions>(options => |
||||
|
{ |
||||
|
options.AddMaps<EShopPluginsCouponsApplicationModule>(validate: true); |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,3 @@ |
|||||
|
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd"> |
||||
|
<ConfigureAwait ContinueOnCapturedContext="false" /> |
||||
|
</Weavers> |
||||
@ -0,0 +1,30 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> |
||||
|
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. --> |
||||
|
<xs:element name="Weavers"> |
||||
|
<xs:complexType> |
||||
|
<xs:all> |
||||
|
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1"> |
||||
|
<xs:complexType> |
||||
|
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" /> |
||||
|
</xs:complexType> |
||||
|
</xs:element> |
||||
|
</xs:all> |
||||
|
<xs:attribute name="VerifyAssembly" type="xs:boolean"> |
||||
|
<xs:annotation> |
||||
|
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation> |
||||
|
</xs:annotation> |
||||
|
</xs:attribute> |
||||
|
<xs:attribute name="VerifyIgnoreCodes" type="xs:string"> |
||||
|
<xs:annotation> |
||||
|
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation> |
||||
|
</xs:annotation> |
||||
|
</xs:attribute> |
||||
|
<xs:attribute name="GenerateXsd" type="xs:boolean"> |
||||
|
<xs:annotation> |
||||
|
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation> |
||||
|
</xs:annotation> |
||||
|
</xs:attribute> |
||||
|
</xs:complexType> |
||||
|
</xs:element> |
||||
|
</xs:schema> |
||||
@ -0,0 +1,25 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
|
||||
|
<Import Project="..\..\..\..\common.props" /> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>netstandard2.0</TargetFramework> |
||||
|
<RootNamespace /> |
||||
|
<GenerateEmbeddedFilesManifest>true</GenerateEmbeddedFilesManifest> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<PackageReference Include="Volo.Abp.Validation" Version="3.1.2" /> |
||||
|
<ProjectReference Include="..\..\..\..\modules\EasyAbp.EShop.Stores\src\EasyAbp.EShop.Stores.Domain.Shared\EasyAbp.EShop.Stores.Domain.Shared.csproj" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" Version="3.1.6" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<EmbeddedResource Include="EasyAbp\EShop\Plugins\Coupons\Localization\*.json" /> |
||||
|
<Content Remove="EasyAbp\EShop\Plugins\Coupons\Localization\*.json" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -0,0 +1,36 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.Coupons.CouponTemplates |
||||
|
{ |
||||
|
public class CouponTemplateData : ICouponTemplate, IHasCouponTemplateScopes<CouponTemplateScopeData> |
||||
|
{ |
||||
|
public Guid Id { get; set; } |
||||
|
|
||||
|
public Guid? TenantId { get; set; } |
||||
|
|
||||
|
public Guid? StoreId { get; set; } |
||||
|
|
||||
|
public CouponType CouponType { get; set; } |
||||
|
|
||||
|
public string UniqueName { get; set; } |
||||
|
|
||||
|
public string DisplayName { get; set; } |
||||
|
|
||||
|
public string Description { get; set; } |
||||
|
|
||||
|
public TimeSpan? UsableDuration { get; set; } |
||||
|
|
||||
|
public DateTime? UsableBeginTime { get; set; } |
||||
|
|
||||
|
public DateTime? UsableEndTime { get; set; } |
||||
|
|
||||
|
public decimal ConditionAmount { get; set; } |
||||
|
|
||||
|
public decimal DiscountAmount { get; set; } |
||||
|
|
||||
|
public bool IsUnscoped { get; set; } |
||||
|
|
||||
|
public List<CouponTemplateScopeData> Scopes { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,15 @@ |
|||||
|
using System; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.Coupons.CouponTemplates |
||||
|
{ |
||||
|
public class CouponTemplateScopeData : ICouponTemplateScope |
||||
|
{ |
||||
|
public Guid StoreId { get; set; } |
||||
|
|
||||
|
public string ProductGroupName { get; set; } |
||||
|
|
||||
|
public Guid? ProductId { get; set; } |
||||
|
|
||||
|
public Guid? ProductSkuId { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,27 @@ |
|||||
|
using System; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.Coupons.CouponTemplates |
||||
|
{ |
||||
|
[Flags] |
||||
|
public enum CouponType |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Discount once if the condition is met.
|
||||
|
/// e.g. arrange ConditionAmount = 300 and DiscountAmount = 20.
|
||||
|
/// If the price of a product is 300, the actual order price will be discounted by 20.
|
||||
|
/// </summary>
|
||||
|
Normal = 1, |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Discount every time the condition is met.
|
||||
|
/// e.g. arrange ConditionAmount = 300 and DiscountAmount = 20.
|
||||
|
/// If the price of a product is 300, the actual order price will be discounted by 60.
|
||||
|
/// </summary>
|
||||
|
PerMeet = 2, |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// A type of coupon with custom usage rules.
|
||||
|
/// </summary>
|
||||
|
Custom = 4 |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,34 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using JetBrains.Annotations; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.Coupons.CouponTemplates |
||||
|
{ |
||||
|
public interface ICouponTemplate |
||||
|
{ |
||||
|
Guid? StoreId { get; } |
||||
|
|
||||
|
CouponType CouponType { get; } |
||||
|
|
||||
|
[CanBeNull] |
||||
|
string UniqueName { get; } |
||||
|
|
||||
|
[NotNull] |
||||
|
string DisplayName { get; } |
||||
|
|
||||
|
[CanBeNull] |
||||
|
string Description { get; } |
||||
|
|
||||
|
TimeSpan? UsableDuration { get; } |
||||
|
|
||||
|
DateTime? UsableBeginTime { get; } |
||||
|
|
||||
|
DateTime? UsableEndTime { get; } |
||||
|
|
||||
|
decimal ConditionAmount { get; } |
||||
|
|
||||
|
decimal DiscountAmount { get; } |
||||
|
|
||||
|
bool IsUnscoped { get; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,11 @@ |
|||||
|
using System; |
||||
|
using System.Threading; |
||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.Coupons.CouponTemplates |
||||
|
{ |
||||
|
public interface ICouponTemplateLookupService |
||||
|
{ |
||||
|
Task<CouponTemplateData> FindByIdAsync(Guid id, CancellationToken cancellationToken = default); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,16 @@ |
|||||
|
using System; |
||||
|
using EasyAbp.EShop.Stores.Stores; |
||||
|
using JetBrains.Annotations; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.Coupons.CouponTemplates |
||||
|
{ |
||||
|
public interface ICouponTemplateScope : IMultiStore |
||||
|
{ |
||||
|
[CanBeNull] |
||||
|
string ProductGroupName { get; } |
||||
|
|
||||
|
Guid? ProductId { get; } |
||||
|
|
||||
|
Guid? ProductSkuId { get; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,11 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using JetBrains.Annotations; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.Coupons.CouponTemplates |
||||
|
{ |
||||
|
public interface IHasCouponTemplateScopes<T> where T : ICouponTemplateScope |
||||
|
{ |
||||
|
List<T> Scopes { get; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,25 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using EasyAbp.EShop.Plugins.Coupons.CouponTemplates; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.Coupons.Coupons |
||||
|
{ |
||||
|
public class CouponData : ICoupon |
||||
|
{ |
||||
|
public Guid Id { get; set; } |
||||
|
|
||||
|
public Guid? TenantId { get; set; } |
||||
|
|
||||
|
public Guid CouponTemplateId { get; set; } |
||||
|
|
||||
|
public Guid UserId { get; set; } |
||||
|
|
||||
|
public Guid? OrderId { get; set; } |
||||
|
|
||||
|
public DateTime? ExpirationTime { get; set; } |
||||
|
|
||||
|
public DateTime? UsedTime { get; set; } |
||||
|
|
||||
|
public decimal? DiscountedAmount { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,19 @@ |
|||||
|
using System; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.Coupons.Coupons |
||||
|
{ |
||||
|
public interface ICoupon |
||||
|
{ |
||||
|
Guid CouponTemplateId { get; } |
||||
|
|
||||
|
Guid UserId { get; } |
||||
|
|
||||
|
Guid? OrderId { get; } |
||||
|
|
||||
|
DateTime? ExpirationTime { get; } |
||||
|
|
||||
|
DateTime? UsedTime { get; } |
||||
|
|
||||
|
decimal? DiscountedAmount { get; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,11 @@ |
|||||
|
using System; |
||||
|
using System.Threading; |
||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.Coupons.Coupons |
||||
|
{ |
||||
|
public interface ICouponLookupService |
||||
|
{ |
||||
|
Task<CouponData> FindByIdAsync(Guid id, CancellationToken cancellationToken = default); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,11 @@ |
|||||
|
namespace EasyAbp.EShop.Plugins.Coupons |
||||
|
{ |
||||
|
public static class CouponsConsts |
||||
|
{ |
||||
|
public const string OrderCouponIdPropertyName = "CouponId"; |
||||
|
|
||||
|
public const string OrderCouponDiscountAmountPropertyName = "CouponDiscountAmount"; |
||||
|
|
||||
|
public const int MaxNotExpiredCouponQuantityPerUser = 100; |
||||
|
} |
||||
|
} |
||||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue