新增续费接口,移除旧续费API

OEM结算 增加续费返现
This commit is contained in:
chfei committed 2026-09-16 12:05:45 +08:00
1 parent b86134357c
commit 1df94a1d28
29 files changed
+1784 -103

No files matched your search

+321
View File
@@ -0,0 +1,321 @@
# Remove the line below if you want to inherit .editorconfig settings from higher directories
root = true
# C# files
[*.cs]
# Default severity for analyzer diagnostics with category 'Interoperability'
dotnet_analyzer_diagnostic.category-Interoperability.severity = none
#### Core EditorConfig Options ####
# Indentation and spacing
indent_size = 4
indent_style = tab
tab_width = 4
# New line preferences
end_of_line = crlf
insert_final_newline = false
#### .NET Code Actions ####
# Type members
dotnet_hide_advanced_members = false
dotnet_member_insertion_location = with_other_members_of_the_same_kind
dotnet_property_generation_behavior = prefer_throwing_properties
# Symbol search
dotnet_search_reference_assemblies = true
#### .NET Coding Conventions ####
# Organize usings
dotnet_separate_import_directive_groups = false
dotnet_sort_system_directives_first = false
file_header_template = unset
# this. and Me. preferences
dotnet_style_qualification_for_event = false
dotnet_style_qualification_for_field = false
dotnet_style_qualification_for_method = false
dotnet_style_qualification_for_property = false
# Language keywords vs BCL types preferences
dotnet_style_predefined_type_for_locals_parameters_members = true
dotnet_style_predefined_type_for_member_access = true
# Parentheses preferences
dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity
dotnet_style_parentheses_in_other_binary_operators = always_for_clarity
dotnet_style_parentheses_in_other_operators = never_if_unnecessary
dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity
# Modifier preferences
dotnet_style_require_accessibility_modifiers = for_non_interface_members
# Expression-level preferences
dotnet_prefer_system_hash_code = true
dotnet_style_coalesce_expression = true
dotnet_style_collection_initializer = true
dotnet_style_explicit_tuple_names = true
dotnet_style_namespace_match_folder = true
dotnet_style_null_propagation = true
dotnet_style_object_initializer = true
dotnet_style_operator_placement_when_wrapping = beginning_of_line
dotnet_style_prefer_auto_properties = true
dotnet_style_prefer_collection_expression = when_types_loosely_match
dotnet_style_prefer_compound_assignment = true
dotnet_style_prefer_conditional_expression_over_assignment = true
dotnet_style_prefer_conditional_expression_over_return = true
dotnet_style_prefer_foreach_explicit_cast_in_source = when_strongly_typed
dotnet_style_prefer_inferred_anonymous_type_member_names = true
dotnet_style_prefer_inferred_tuple_names = true
dotnet_style_prefer_is_null_check_over_reference_equality_method = true
dotnet_style_prefer_simplified_boolean_expressions = true
dotnet_style_prefer_simplified_interpolation = true
# Field preferences
dotnet_style_readonly_field = true
# Parameter preferences
dotnet_code_quality_unused_parameters = all
# Suppression preferences
dotnet_remove_unnecessary_suppression_exclusions = none
# New line preferences
dotnet_style_allow_multiple_blank_lines_experimental = true
dotnet_style_allow_statement_immediately_after_block_experimental = true
#### C# Coding Conventions ####
# var preferences
csharp_style_var_elsewhere = false:silent
csharp_style_var_for_built_in_types = false:silent
csharp_style_var_when_type_is_apparent = false:silent
# Expression-bodied members
csharp_style_expression_bodied_accessors = true:silent
csharp_style_expression_bodied_constructors = false:silent
csharp_style_expression_bodied_indexers = true:silent
csharp_style_expression_bodied_lambdas = true:silent
csharp_style_expression_bodied_local_functions = false:silent
csharp_style_expression_bodied_methods = false:silent
csharp_style_expression_bodied_operators = false:silent
csharp_style_expression_bodied_properties = true:silent
# Pattern matching preferences
csharp_style_pattern_matching_over_as_with_null_check = true
csharp_style_pattern_matching_over_is_with_cast_check = true
csharp_style_prefer_extended_property_pattern = true
csharp_style_prefer_not_pattern = true
csharp_style_prefer_pattern_matching = true
csharp_style_prefer_switch_expression = true
# Null-checking preferences
csharp_style_conditional_delegate_call = true:suggestion
csharp_using_directive_placement = outside_namespace:silent
csharp_prefer_simple_using_statement = true:suggestion
# Modifier preferences
csharp_prefer_static_anonymous_function = true
csharp_prefer_static_local_function = true
csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,required,volatile,async
csharp_style_prefer_readonly_struct = true
csharp_style_prefer_readonly_struct_member = true
# Code-block preferences
csharp_prefer_braces = true:silent
csharp_prefer_simple_using_statement = true:suggestion
csharp_prefer_system_threading_lock = true:suggestion
csharp_style_namespace_declarations = file_scoped:silent
csharp_style_prefer_method_group_conversion = true:silent
csharp_style_prefer_primary_constructors = true:suggestion
csharp_style_prefer_top_level_statements = true:silent
csharp_style_prefer_primary_constructors = true:suggestion
csharp_prefer_system_threading_lock = true:suggestion
csharp_style_expression_bodied_methods = false:silent
csharp_style_expression_bodied_constructors = false:silent
csharp_style_expression_bodied_operators = false:silent
csharp_style_expression_bodied_properties = true:silent
csharp_style_expression_bodied_indexers = true:silent
csharp_style_expression_bodied_accessors = true:silent
csharp_style_expression_bodied_lambdas = true:silent
csharp_style_expression_bodied_local_functions = false:silent
# Expression-level preferences
csharp_prefer_simple_default_expression = true:suggestion
csharp_style_deconstructed_variable_declaration = true
csharp_style_implicit_object_creation_when_type_is_apparent = true:suggestion
csharp_style_inlined_variable_declaration = true
csharp_style_prefer_index_operator = true:suggestion
csharp_style_prefer_local_over_anonymous_function = true:suggestion
csharp_style_prefer_null_check_over_type_check = true:suggestion
csharp_style_prefer_range_operator = true:suggestion
csharp_style_prefer_tuple_swap = true
csharp_style_prefer_unbound_generic_type_in_nameof = true
csharp_style_prefer_utf8_string_literals = true
csharp_style_throw_expression = true:suggestion
csharp_style_unused_value_assignment_preference = discard_variable
csharp_style_unused_value_expression_statement_preference = discard_variable
# 'using' directive preferences
csharp_using_directive_placement = outside_namespace:silent
# New line preferences
csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = true
csharp_style_allow_blank_line_after_token_in_arrow_expression_clause_experimental = true
csharp_style_allow_blank_line_after_token_in_conditional_expression_experimental = true
csharp_style_allow_blank_lines_between_consecutive_braces_experimental = true
csharp_style_allow_embedded_statements_on_same_line_experimental = true
#### C# Formatting Rules ####
# New line preferences
csharp_new_line_before_catch = true
csharp_new_line_before_else = true
csharp_new_line_before_finally = true
csharp_new_line_before_members_in_anonymous_types = true
csharp_new_line_before_members_in_object_initializers = true
csharp_new_line_before_open_brace = all
csharp_new_line_between_query_expression_clauses = true
# Indentation preferences
csharp_indent_block_contents = true
csharp_indent_braces = false
csharp_indent_case_contents = true
csharp_indent_case_contents_when_block = false
csharp_indent_labels = no_change
csharp_indent_switch_labels = true
# Space preferences
csharp_space_after_cast = false
csharp_space_after_colon_in_inheritance_clause = true
csharp_space_after_comma = true
csharp_space_after_dot = false
csharp_space_after_keywords_in_control_flow_statements = true
csharp_space_after_semicolon_in_for_statement = true
csharp_space_around_binary_operators = before_and_after
csharp_space_around_declaration_statements = false
csharp_space_before_colon_in_inheritance_clause = true
csharp_space_before_comma = false
csharp_space_before_dot = false
csharp_space_before_open_square_brackets = false
csharp_space_before_semicolon_in_for_statement = false
csharp_space_between_empty_square_brackets = false
csharp_space_between_method_call_empty_parameter_list_parentheses = false
csharp_space_between_method_call_name_and_opening_parenthesis = false
csharp_space_between_method_call_parameter_list_parentheses = false
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
csharp_space_between_method_declaration_name_and_open_parenthesis = false
csharp_space_between_method_declaration_parameter_list_parentheses = false
csharp_space_between_parentheses = false
csharp_space_between_square_brackets = false
# Wrapping preferences
csharp_preserve_single_line_blocks = true
csharp_preserve_single_line_statements = true
[*.{cs,vb}]
#### Naming styles ####
# Naming rules
dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion
dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface
dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i
dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion
dotnet_naming_rule.types_should_be_pascal_case.symbols = types
dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case
dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion
dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members
dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case
# Symbol specifications
dotnet_naming_rule.private_or_internal_field_should_be__开头.severity = suggestion
dotnet_naming_rule.private_or_internal_field_should_be__开头.symbols = private_or_internal_field
dotnet_naming_rule.private_or_internal_field_should_be__开头.style = _开头
dotnet_naming_rule.private_or_internal_field_should_be__开头.severity = none
dotnet_naming_rule.private_or_internal_field_should_be__开头.symbols = private_or_internal_field
dotnet_naming_rule.private_or_internal_field_should_be__开头.style = _开头
dotnet_naming_symbols.interface.applicable_kinds = interface
dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
dotnet_naming_symbols.interface.required_modifiers =
dotnet_naming_symbols.private_or_internal_field.applicable_kinds = field
dotnet_naming_symbols.private_or_internal_field.applicable_accessibilities = internal, private, private_protected
dotnet_naming_symbols.private_or_internal_field.required_modifiers =
dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum
dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
dotnet_naming_symbols.types.required_modifiers =
dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method
dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
dotnet_naming_symbols.non_field_members.required_modifiers =
# Naming styles
dotnet_naming_style._开头.required_prefix = _
dotnet_naming_style._开头.required_suffix =
dotnet_naming_style._开头.word_separator =
dotnet_naming_style._开头.capitalization = camel_case
dotnet_naming_style.begins_with_i.required_prefix = I
dotnet_naming_style.begins_with_i.required_suffix =
dotnet_naming_style.begins_with_i.word_separator =
dotnet_naming_style.begins_with_i.capitalization = pascal_case
dotnet_naming_style.pascal_case.required_prefix =
dotnet_naming_style.pascal_case.required_suffix =
dotnet_naming_style.pascal_case.word_separator =
dotnet_naming_style.pascal_case.capitalization = pascal_case
dotnet_style_coalesce_expression = true:suggestion
dotnet_style_null_propagation = true:suggestion
dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion
dotnet_style_prefer_auto_properties = true:silent
dotnet_style_object_initializer = true:suggestion
dotnet_style_collection_initializer = true:suggestion
dotnet_style_prefer_simplified_boolean_expressions = true:suggestion
dotnet_style_prefer_conditional_expression_over_assignment = true:silent
dotnet_style_prefer_conditional_expression_over_return = true:silent
dotnet_style_explicit_tuple_names = true:suggestion
dotnet_style_prefer_inferred_tuple_names = true:silent
dotnet_style_prefer_inferred_anonymous_type_member_names = true:silent
dotnet_style_prefer_compound_assignment = true:suggestion
dotnet_style_prefer_simplified_interpolation = true:suggestion
dotnet_style_operator_placement_when_wrapping = beginning_of_line
tab_width = 4
indent_size = 4
end_of_line = crlf
# IDE0305: Simplify collection initialization
# dotnet_style_prefer_collection_expression = when_types_exactly_match
# dotnet_style_prefer_collection_expression = when_types_loosely_match
dotnet_diagnostic.IDE0305.severity = silent
dotnet_style_qualification_for_field = false:silent
dotnet_style_qualification_for_property = false:silent
dotnet_style_qualification_for_method = false:silent
dotnet_style_qualification_for_event = false:silent
dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent
# IDE1006: Naming Styles
dotnet_diagnostic.IDE1006.severity = none
# IDE0059: Unnecessary assignment of a value
dotnet_diagnostic.IDE0059.severity = silent
# CS0168: Variable is declared but never used
dotnet_diagnostic.CS0168.severity = silent
dotnet_style_prefer_collection_expression = when_types_loosely_match:suggestion
dotnet_style_namespace_match_folder = true:suggestion
+364 -15
View File
@@ -1,16 +1,365 @@
.vs
.svn
Bin
Bin.Oem
NotUse
obj
*.psd
packages
.user
bin
*.rar
*.zip
/Update/Update/*.user
## 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
*.user
IISProfile.pubxml
*/**/logs
*.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/
[Ww][Ii][Nn]32/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Oo]ut/
[Ll]og/
[Ll]ogs/
# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# Visual Studio 2017 auto generated files
Generated\ Files/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUnit
*.VisualState.xml
TestResult.xml
nunit-*.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# Benchmark Results
BenchmarkDotNet.Artifacts/
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
# ASP.NET Scaffolding
ScaffoldingReadMe.txt
# StyleCop
StyleCopReport.xml
# Files built by Visual Studio
*_i.c
*_p.c
*_h.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*_wpftmp.csproj
*.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
# 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
# Coverlet is a free, cross platform Code Coverage Tool
coverage*.json
coverage*.xml
coverage*.info
# 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
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
*.appxbundle
*.appxupload
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!?*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs
# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk
# 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
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/
# Fody - auto-generated XML schema
FodyWeavers.xsd
!Store.User
+23
View File
@@ -0,0 +1,23 @@
<Project>
<!-- See https://aka.ms/dotnet/msbuild/customize for more details on customizing your build -->
<PropertyGroup>
<DefaultTargetFramework>net472</DefaultTargetFramework>
<TargetFramework>$(DefaultTargetFramework)</TargetFramework>
<LangVersion>12.0</LangVersion>
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
<CheckEolTargetFramework>false</CheckEolTargetFramework>
<SuppressNETCoreSdkPreviewMessage>true</SuppressNETCoreSdkPreviewMessage>
<Nullable>annotations</Nullable>
<NoWarn>CS1591</NoWarn>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="PolySharp" Version="1.16.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
</Project>
+20 -1
View File
@@ -1,7 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 18
VisualStudioVersion = 18.9.12105.275 stable
VisualStudioVersion = 18.9.12105.275
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KJD_WebService", "KJD_WebService\KJD_WebService.csproj", "{A6C03FE1-142A-4C97-99A9-67FD915836B6}"
EndProject
@@ -9,6 +9,17 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".test", ".test", "{AA240C1D
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebServiceTest", "test\WebServiceTest\WebServiceTest.csproj", "{348EB476-1813-419E-910F-0D27E58B3D19}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{15CB4E89-94B5-4851-A58F-0A56FBCD9527}"
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
.gitignore = .gitignore
Directory.Build.props = Directory.Build.props
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Store.User", "Store.User\Store.User.csproj", "{20BA615B-6EAC-47EA-87FE-DD740D6F3AD7}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Store.Framework", "Store.Framework\Store.Framework.csproj", "{CD6FB773-0431-4FAE-9E30-65953118FEBF}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -23,6 +34,14 @@ Global
{348EB476-1813-419E-910F-0D27E58B3D19}.Debug|Any CPU.Build.0 = Debug|Any CPU
{348EB476-1813-419E-910F-0D27E58B3D19}.Release|Any CPU.ActiveCfg = Release|Any CPU
{348EB476-1813-419E-910F-0D27E58B3D19}.Release|Any CPU.Build.0 = Release|Any CPU
{20BA615B-6EAC-47EA-87FE-DD740D6F3AD7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{20BA615B-6EAC-47EA-87FE-DD740D6F3AD7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{20BA615B-6EAC-47EA-87FE-DD740D6F3AD7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{20BA615B-6EAC-47EA-87FE-DD740D6F3AD7}.Release|Any CPU.Build.0 = Release|Any CPU
{CD6FB773-0431-4FAE-9E30-65953118FEBF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CD6FB773-0431-4FAE-9E30-65953118FEBF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CD6FB773-0431-4FAE-9E30-65953118FEBF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CD6FB773-0431-4FAE-9E30-65953118FEBF}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
+113 -59
View File
@@ -17,6 +17,10 @@ namespace KJD_Web.BLL.WXXD
{
public class WXOemManage
{
/// <summary>
/// 店铺续费手续费 15
/// </summary>
const int ShopRenewFee = 15;
/// <summary>
/// 手续费
/// </summary>
@@ -603,7 +607,7 @@ namespace KJD_Web.BLL.WXXD
WHERE A.oem_id = '{MysqlUtils.ReplaceSqlSpecial(oem_id)}'";
var userDt = mySql.ExecuteDataTable(sql);
if (!string.IsNullOrEmpty(mySql.Message) || userDt == null || userDt.Rows.Count == 0)
return 0;
return 0;//找不到用户或数据库错误返回
List<string> userLst = userDt.Rows.Cast<DataRow>()
.Select(r => r["user_name"].ParseToString())
@@ -611,80 +615,130 @@ namespace KJD_Web.BLL.WXXD
.Distinct()
.ToList();
if (userLst.Count == 0)
return 0;
return 0;//用户列表空 返回
decimal total_amount = 0m; // 总金额(元)
decimal rebate_amount = 0m; // 正数部分(累计返利)
string now = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
// 2. 该oem所有账户的未结算流水,按id升序
sql = "SELECT * FROM `wxxd`.`user_payment_record` WHERE user_name IN ('" + string.Join("','", userLst) + "') AND type IN (20,23,26,16,31,34) AND settlement=0 AND is_deleted=0 ORDER BY id ASC";
var flowDt = mySql.ExecuteDataTable(sql);
if (!string.IsNullOrEmpty(mySql.Message) || flowDt == null || flowDt.Rows.Count == 0)
if (!string.IsNullOrEmpty(mySql.Message))
return 0;
decimal total_amount = 0m; // 总金额(元)
decimal rebate_amount = 0m; // 正数部分(累计返利)
HashSet<string> deductedOrderSet = new HashSet<string>(); // type=23 已扣减的订单
HashSet<string> giftsOrderSet = new HashSet<string>(); // type=34 礼物已扣减的订单
List<long> settleIdLst = new List<long>(); // 参与结算的流水id
foreach (DataRow row in flowDt.Rows)
if (flowDt != null && flowDt.Rows.Count > 0)
{
int type = row["type"].ParseToInt();
decimal amount = row["amount"].ParseToDecimal();
decimal oem_amount = row["oem_amount"].ParseToDecimal();
long flowId = row["id"].ParseToLong();
HashSet<string> deductedOrderSet = new HashSet<string>(); // type=23 已扣减的订单
HashSet<string> giftsOrderSet = new HashSet<string>(); // type=34 礼物已扣减的订单
List<long> settleIdLst = new List<long>(); // 参与结算的流水id
decimal itemAmount = 0m;
if (type == 20)
itemAmount = amount - 2.2m;
else if (type == 26)
itemAmount = amount - 2.5m;
else if (type == 16)
itemAmount = oem_amount;
else if (type == 31)
itemAmount = oem_amount;
else if (type == 23)
foreach (DataRow row in flowDt.Rows)
{
// 同一个订单只能减少一次
string orderId = row["order_id"].ParseToString();
if (orderId.IsNullOrEmpty() || deductedOrderSet.Contains(orderId))
continue;
deductedOrderSet.Add(orderId);
itemAmount = -(amount - 2.2m);
}
else if (type == 34)
{
// 同一个订单只能减少一次
string orderId = row["order_id"].ParseToString();
if (orderId.IsNullOrEmpty() || giftsOrderSet.Contains(orderId))
continue;
giftsOrderSet.Add(orderId);
itemAmount = -oem_amount;
}
else
{
continue; // 其他类型不计入
int type = row["type"].ParseToInt();
decimal amount = row["amount"].ParseToDecimal();
decimal oem_amount = row["oem_amount"].ParseToDecimal();
long flowId = row["id"].ParseToLong();
decimal itemAmount = 0m;
if (type == 20)
itemAmount = amount - 2.2m;
else if (type == 26)
itemAmount = amount - 2.5m;
else if (type == 16)
itemAmount = oem_amount;
else if (type == 31)
itemAmount = oem_amount;
else if (type == 23)
{
// 同一个订单只能减少一次
string orderId = row["order_id"].ParseToString();
if (orderId.IsNullOrEmpty() || deductedOrderSet.Contains(orderId))
continue;
deductedOrderSet.Add(orderId);
itemAmount = -(amount - 2.2m);
}
else if (type == 34)
{
// 同一个订单只能减少一次
string orderId = row["order_id"].ParseToString();
if (orderId.IsNullOrEmpty() || giftsOrderSet.Contains(orderId))
continue;
giftsOrderSet.Add(orderId);
itemAmount = -oem_amount;
}
else
{
continue; // 其他类型不计入
}
total_amount += itemAmount;
rebate_amount += itemAmount;
settleIdLst.Add(flowId);
}
total_amount += itemAmount;
rebate_amount += itemAmount;
if (settleIdLst.Count == 0)
return 0;
settleIdLst.Add(flowId);
//更新用户流水记录表结算
sql = "UPDATE wxxd.user_payment_record SET settlement=1,settlement_time='" + now + "' WHERE id IN (" + string.Join(",", settleIdLst) + ")";
var flowRst = mySql.ExecuteAffectedRows(sql);
if (!string.IsNullOrEmpty(mySql.Message) || flowRst <= 0)
throw new Exception("标记流水结算失败");
}
if (settleIdLst.Count == 0)
//读取用户店铺续费
sql = "SELECT id,delta_points FROM `wxxd`.`user_points_record` WHERE user_name IN ('" + string.Join("','", userLst) + "') AND option_type ='续费' AND settlement=0 ORDER BY id ASC";
var userPointsDt = mySql.ExecuteDataTable(sql);
if (!string.IsNullOrEmpty(mySql.Message))
return 0;
if (userPointsDt != null && userPointsDt.Rows.Count > 0) //更新用户流水记录表结算
{
int count = userPointsDt.Rows.Count;
//结算商铺续费
List<long> settleIdLst = new List<long>(); // 参与结算的流水id
foreach (DataRow row in userPointsDt.Rows)
{
long flowId = row["id"].ParseToLong();
decimal points = row["delta_points"].ParseToDecimal();
decimal itemAmount = points * 1;//比例1:1
itemAmount = itemAmount - ShopRenewFee;
total_amount += itemAmount;
rebate_amount += itemAmount;
settleIdLst.Add(flowId);
}
sql = "UPDATE wxxd.user_points_record SET settlement=1,settlement_time='" + now + "' WHERE id IN (" + string.Join(",", settleIdLst) + ")";
var flowRst = mySql.ExecuteAffectedRows(sql);
if (!string.IsNullOrEmpty(mySql.Message) || flowRst <= 0)
throw new Exception("商铺流水结算失败");
}
long total_fen = (long)Math.Round(total_amount * 100m);
long rebate_fen = (long)Math.Round(rebate_amount * 100m);
string now = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
// 3. 写oem金额 + 更新流水状态(同一事务)
sql = "UPDATE wxxd.oem SET available_balance=available_balance+" + total_fen +
", total_rebate_amount=total_rebate_amount+" + rebate_fen +
" WHERE oem_id='" + oem_id + "'";
var oemRst = mySql.ExecuteAffectedRows(sql);
if (!string.IsNullOrEmpty(mySql.Message) || oemRst <= 0)
throw new Exception("结算流水到账户失败");
sql = "UPDATE wxxd.user_payment_record SET settlement=1,settlement_time='" + now + "' WHERE id IN (" + string.Join(",", settleIdLst) + ")";
var flowRst = mySql.ExecuteAffectedRows(sql);
if (!string.IsNullOrEmpty(mySql.Message) || flowRst <= 0)
throw new Exception("标记流水结算失败");
if (total_fen > 0 || rebate_fen > 0)
{
//写oem金额 + 更新流水状态
sql = "UPDATE wxxd.oem SET available_balance=available_balance+" + total_fen +
", total_rebate_amount=total_rebate_amount+" + rebate_fen +
" WHERE oem_id='" + oem_id + "'";
var oemRst = mySql.ExecuteAffectedRows(sql);
if (!string.IsNullOrEmpty(mySql.Message) || oemRst <= 0)
throw new Exception("结算流水到账户失败");
}
return total_fen;
}
+2 -2
View File
@@ -902,9 +902,9 @@ namespace KJD_Web.BLL.WXXD
{
return "{\"code\":500,\"msg\":\"操作对象不能为空\"}";
}
if (delta_points <= 0 && option_type == "续费")
if (option_type == "续费")
{
return "{\"code\":500,\"msg\":\"续费金额错误,需大于0\"}";
return "{\"code\":500,\"msg\":\"续费金额错误\"}";
}
if (delta_points == 0)
{
@@ -1,4 +1,6 @@
using KJD_Web.BLL.WXXD;
using KJD_Web.BLL.WXXD.Requests;
using KJD_Web.Utils;
using System;
using System.Collections.Generic;
using System.IO;
@@ -26,6 +28,30 @@ namespace KJD_Web.Controllers
// return base.ExecuteAsync(controllerContext, cancellationToken);
//}
protected bool ValidateSign(SignRequestBase request, bool isUserLogin = false)
{
if (request == null || string.IsNullOrEmpty(request.time) || string.IsNullOrEmpty(request.code))
{
return false;
}
int time;
if (!int.TryParse(request.time, out time))
{
return false;
}
if (request.code != EncrypUtil.Encryption(time))
{
return false;
}
if (!isUserLogin && string.IsNullOrWhiteSpace(request.user_name))
{
return false;
}
return true;
}
protected string GetRequestJsonString()
{
//Context.Response.ContentType = "text/html;charset=utf-8";
@@ -17,7 +17,7 @@ namespace KJD_Web.Controllers
{
[RoutePrefix("wxxd_user")]
[Route("{action}")]
public class WXUserController : AsmxApiController
public partial class WXUserController : AsmxApiController
{
//GetE57Authorization
@@ -0,0 +1,51 @@
using KJD_Web.Model;
using KJD_Web.Requests.Users;
using KJD_Web.Services.Users;
using MAX.Core.Logger;
using System;
using System.Web.Http;
namespace KJD_Web.Controllers
{
public partial class WXUserController : AsmxApiController
{
private readonly UserService _userService;
private readonly ILoggerFacade _logger;
public WXUserController(UserService userService, ILoggerFacade logger)
{
_userService = userService ?? throw new ArgumentNullException(nameof(userService));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
/// <summary>
/// 用户续费商铺。
/// </summary>
[HttpPost]
public IHttpActionResult shop_renew([FromBody] ShopRenewRequest request)
{
if (!ValidateSign(request))
{
return Ok(ApiResult.Fail("校验失败", 999));
}
try
{
var response = _userService.ShopRenew(request);
return Ok(ApiResult.Success(response, "续费成功"));
}
catch (ArgumentException ex)
{
return Ok(ApiResult.Fail(ex.Message, ResultCode.ValidationError));
}
catch (InvalidOperationException ex)
{
return Ok(ApiResult.Fail(ex.Message, ResultCode.BusinessError));
}
catch (Exception ex)
{
_logger.Error(ex, "商铺续费失败, UserName=" + (request == null ? null : request.UserName) + ", ShopId=" + (request == null ? null : request.ShopId));
return Ok(ApiResult.Fail("续费失败,请稍后重试", ResultCode.ServerError));
}
}
}
}
+144
View File
@@ -0,0 +1,144 @@
using FreeSql.DataAnnotations;
using System;
namespace YourNamespace
{
/// <summary>
///shop 表
/// </summary>
[Table(Name = "wxxd.shop")]
public class ShopEntity
{
/// <summary>
/// 表id
/// </summary>
[Column(Name = "id", IsPrimary = true, IsIdentity = true)]
public int Id { get; set; }
/// <summary>
/// login_name
/// </summary>
[Column(Name = "login_name")]
public string LoginName { get; set; }
/// <summary>
/// login_pass
/// </summary>
[Column(Name = "login_pass")]
public string LoginPass { get; set; }
/// <summary>
/// cookie
/// </summary>
[Column(Name = "cookie")]
public string Cookie { get; set; }
/// <summary>
/// cookie2
/// </summary>
[Column(Name = "cookie2")]
public string Cookie2 { get; set; }
/// <summary>
/// anti_contents
/// </summary>
[Column(Name = "anti_contents")]
public string AntiContents { get; set; }
/// <summary>
/// openid
/// </summary>
[Column(Name = "openid")]
public string Openid { get; set; }
/// <summary>
/// shop_id
/// </summary>
[Column(Name = "shop_id")]
public string ShopId { get; set; }
/// <summary>
/// shop_account
/// </summary>
[Column(Name = "shop_account")]
public string ShopAccount { get; set; }
/// <summary>
/// sub_user_name
/// </summary>
[Column(Name = "sub_user_name")]
public string SubUserName { get; set; }
/// <summary>
/// user_name
/// </summary>
[Column(Name = "user_name")]
public string UserName { get; set; }
/// <summary>
/// 店铺分组名称(非子账号分组)
/// </summary>
[Column(Name = "group_name")]
public string GroupName { get; set; }
/// <summary>
/// add_time
/// </summary>
[Column(Name = "add_time")]
public DateTime? AddTime { get; set; }
/// <summary>
/// mdy_time
/// </summary>
[Column(Name = "mdy_time")]
public DateTime? MdyTime { get; set; }
/// <summary>
/// 店铺所属公司
/// </summary>
[Column(Name = "company_name")]
public string CompanyName { get; set; }
/// <summary>
/// 备注
/// </summary>
[Column(Name = "notes")]
public string Notes { get; set; }
/// <summary>
/// login_status
/// </summary>
[Column(Name = "login_status")]
public string LoginStatus { get; set; }
/// <summary>
/// 店铺每月商品上传限额剩余
/// </summary>
[Column(Name = "add_product_remaining")]
public int AddProductRemaining { get; set; }
/// <summary>
/// 上传限额所处月份
/// </summary>
[Column(Name = "add_product_month")]
public byte AddProductMonth { get; set; }
/// <summary>
/// 分配的二级超管的user_name
/// </summary>
[Column(Name = "operate_sub_sa_name")]
public string OperateSubSaName { get; set; }
/// <summary>
/// 分配二级超管的时间
/// </summary>
[Column(Name = "add_sub_sa_time")]
public DateTime? AddSubSaTime { get; set; }
/// <summary>
/// login_status2
/// </summary>
[Column(Name = "login_status2")]
public string LoginStatus2 { get; set; }
}
}
+156
View File
@@ -0,0 +1,156 @@
using FreeSql.DataAnnotations;
using System;
namespace KJD_Web.Entitys
{
/// <summary>
/// 用户表
/// </summary>
[Table(Name = "wxxd.user")]
public class UserEntity
{
/// <summary>
/// ID
/// </summary>
[Column(Name = "id", IsPrimary = true, IsIdentity = true)]
public int Id { get; set; }
/// <summary>
/// 用户昵称
/// </summary>
[Column(Name = "nick_name")]
public string NickName { get; set; }
/// <summary>
/// 用户名称(登录账户)
/// </summary>
[Column(Name = "user_name")]
public string UserName { get; set; }
/// <summary>
/// 登录密码
/// </summary>
[Column(Name = "password")]
public string Password { get; set; }
/// <summary>
/// card_id
/// </summary>
[Column(Name = "card_id")]
public string CardId { get; set; }
/// <summary>
/// 用户分组 3主号 4客服 5加盟 8登录 9采购 10加盟 11上货
/// </summary>
[Column(Name = "group_id")]
public byte GroupId { get; set; }
/// <summary>
/// 父账户用户名
/// </summary>
[Column(Name = "parent_user_name")]
public string ParentUserName { get; set; }
/// <summary>
/// oem编号,仅oem用户有值
/// </summary>
[Column(Name = "oem_id")]
public string OemId { get; set; }
/// <summary>
/// 手机号
/// </summary>
[Column(Name = "mobile")]
public string Mobile { get; set; }
/// <summary>
/// 添加时间
/// </summary>
[Column(Name = "add_time")]
public DateTime? AddTime { get; set; }
/// <summary>
/// 修改时间
/// </summary>
[Column(Name = "mdy_time")]
public DateTime? MdyTime { get; set; }
/// <summary>
/// 公司名称
/// </summary>
[Column(Name = "company_name")]
public string CompanyName { get; set; }
/// <summary>
/// 备注
/// </summary>
[Column(Name = "notes")]
public string Notes { get; set; }
/// <summary>
/// 超管等级 0 普通用户 1 超级管理员
/// </summary>
[Column(Name = "sa_level")]
public short? SaLevel { get; set; }
/// <summary>
/// 账户权限
/// </summary>
[Column(Name = "authority")]
public string Authority { get; set; }
/// <summary>
/// 子账号被禁止展示的功能页面
/// </summary>
[Column(Name = "forbidden_page")]
public string ForbiddenPage { get; set; }
/// <summary>
/// 账户积分,1积分=1元
/// </summary>
[Column(Name = "points")]
public decimal Points { get; set; }
/// <summary>
/// 积分历史累计充值金额
/// </summary>
[Column(Name = "recharge_points_total")]
public decimal? RechargePointsTotal { get; set; }
/// <summary>
/// 店铺每续费一个月需要的积分,单位元
/// </summary>
[Column(Name = "shop_points_per_month")]
public int ShopPointsPerMonth { get; set; }
/// <summary>
/// 可用余额
/// </summary>
[Column(Name = "balance")]
public decimal? Balance { get; set; }
/// <summary>
/// 累计充值金额
/// </summary>
[Column(Name = "recharge_amount_total")]
public decimal? RechargeAmountTotal { get; set; }
/// <summary>
/// 每单中转仓快递费用,单位元,两位小数
/// </summary>
[Column(Name = "postage_per_order")]
public decimal? PostagePerOrder { get; set; }
/// <summary>
/// 每单中转仓退货快递费用,单位元,两位小数
/// </summary>
[Column(Name = "refund_postage_per_order")]
public decimal? RefundPostagePerOrder { get; set; }
/// <summary>
/// 礼物每单额外收取费用,单位元,两位小数
/// </summary>
[Column(Name = "gift_oem_amount_per_order")]
public decimal? GiftOemAmountPerOrder { get; set; }
}
}
@@ -0,0 +1,109 @@
using FreeSql.DataAnnotations;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace KJD_Web.Entitys
{
[Table(Name = "wxxd.user_points_record")]
public class UserPointsRecordEntity
{
/// <summary>
/// 主键(自增)
/// </summary>
[Column(Name = "id", IsPrimary = true, IsIdentity = true)]
public int Id { get; set; }
/// <summary>
/// 用户名(NOT NULL)
/// </summary>
[Column(Name = "user_name")]
public string UserName { get; set; }
/// <summary>
/// 用户昵称(NOT NULL)
/// </summary>
[Column(Name = "user_nick")]
public string UserNick { get; set; }
/// <summary>
/// 操作记录金额,单位元,最小1元(NOT NULL)
/// </summary>
[Column(Name = "delta_points")]
public decimal DeltaPoints { get; set; }
/// <summary>
/// 充值或消费后的当前金额(允许 NULL)
/// </summary>
[Column(Name = "new_points")]
public decimal? NewPoints { get; set; }
/// <summary>
/// 操作类型 消费 充值 转入 转出(NOT NULL)
/// </summary>
[Column(Name = "option_type")]
public string OptionType { get; set; }
/// <summary>
/// 操作者类型 管理员 用户(NOT NULL)
/// </summary>
[Column(Name = "operator_type")]
public string OperatorType { get; set; }
/// <summary>
/// 实际操作者用户名(NOT NULL)
/// </summary>
[Column(Name = "operator_name")]
public string OperatorName { get; set; }
/// <summary>
/// 消费店铺编号(消费才有值,充值为空,允许 NULL)
/// </summary>
[Column(Name = "shop_id")]
public string? ShopId { get; set; }
/// <summary>
/// 消费店铺名称(消费才有值,充值为空,允许 NULL)
/// </summary>
[Column(Name = "shop_account")]
public string? ShopAccount { get; set; }
/// <summary>
/// 备注(允许 NULL)
/// </summary>
[Column(Name = "remark")]
public string? Remark { get; set; }
/// <summary>
/// (点数转出时的)对方账户(允许 NULL)
/// </summary>
[Column(Name = "counterparty_account_name")]
public string? CounterpartyAccountName { get; set; }
/// <summary>
/// 支付宝订单的外部订单号(允许 NULL)
/// </summary>
[Column(Name = "out_trade_no")]
public string? OutTradeNo { get; set; }
/// <summary>
/// 添加时间(NOT NULL,默认 CURRENT_TIMESTAMP)
/// </summary>
[Column(Name = "add_time")]
public DateTime AddTime { get; set; }
/// <summary>
/// OEM是否结算 0未结算 1已结算
/// </summary>
[Column(Name = "settlement")]
public bool Settlement { get; set; }
/// <summary>
/// 结算时间
/// </summary>
[Column(Name = "settlement_time")]
public DateTime? SettlementTime { get; set; }
}
}
@@ -0,0 +1,43 @@
using FreeSql.DataAnnotations;
using System;
namespace KJD_Web.Entitys
{
/// <summary>
/// 用户积分商店过期
/// </summary>
[Table(Name = "wxxd.user_points_shop_expire")]
public class UserPointsShopExpireEntity
{
/// <summary>
/// ID
/// </summary>
[Column(Name = "id", IsPrimary = true, IsIdentity = true)]
public int Id { get; set; }
/// <summary>
/// 商店ID
/// </summary>
[Column(Name = "shop_id")]
public string ShopId { get; set; }
/// <summary>
/// 过期时间
/// </summary>
// 数据库列名末尾包含 U+200C,不能改成普通 expire_time。
[Column(Name = "expire_time\u200c")]
public int ExpireTime { get; set; }
/// <summary>
/// 添加时间
/// </summary>
[Column(Name = "add_time")]
public DateTime AddTime { get; set; }
/// <summary>
/// 修改时间
/// </summary>
[Column(Name = "mdy_time")]
public DateTime MdyTime { get; set; }
}
}
+32 -9
View File
@@ -1,6 +1,7 @@
using Autofac;
using Autofac.Integration.WebApi;
using FreeSql;
using KJD_Web.Repository;
using KJD_Web.Utils;
using MAX.Core.DependencyInjection;
using MAX.Core.Logger;
@@ -37,14 +38,37 @@ namespace KJD_Web
var builder = new ContainerBuilder();
var appAssembly = Assembly.GetExecutingAssembly();
var connection = ConfigurationManager.ConnectionStrings["ConnKJD"];
if (connection == null || string.IsNullOrWhiteSpace(connection.ConnectionString))
{
throw new ConfigurationErrorsException("未配置连接字符串:ConnKJD");
}
// ImageCacheService 使用独立的 imagecache 数据库。
builder.Register(_ => CreateImageCacheFreeSql())
.As<IFreeSql>()
.SingleInstance();
builder.Register(_ =>
{
return new FreeSqlBuilder()
.UseConnectionString(
DataType.MySql,
connection.ConnectionString)
.Build();
})
.As<IFreeSql>()
.SingleInstance();
builder.RegisterGeneric(typeof(AutofacRepository<>))
.As(typeof(IBaseRepository<>))
.UsingConstructor(typeof(IFreeSql))
.InstancePerRequest();
// 注册 Web API 所有 Controller
builder.RegisterApiControllers(appAssembly);
builder.RegisterInstance(NLogger.Instance).As<ILoggerFacade>().SingleInstance();
#region 注册所有IOC接口
Type typeSingleton = typeof(ISingletonDependency);
@@ -87,14 +111,13 @@ namespace KJD_Web
{
throw new ConfigurationErrorsException("未配置连接字符串:ConnKJD");
}
var connectionBuilder = new MySqlConnectionStringBuilder(connection.ConnectionString)
{
Database = "imagecache"
};
//var connectionBuilder = new MySqlConnectionStringBuilder(connection.ConnectionString)
//{
// Database = "imagecache"
//};
return new FreeSqlBuilder()
.UseConnectionString(DataType.MySql, connectionBuilder.ConnectionString)
.UseConnectionString(DataType.MySql, connection.ConnectionString)
.UseAutoSyncStructure(false)
.Build();
}
+26 -10
View File
@@ -26,18 +26,18 @@
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<LangVersion>12</LangVersion>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
<LangVersion>12</LangVersion>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<LangVersion>12</LangVersion>
<LangVersion>12</LangVersion>
<DebugSymbols>true</DebugSymbols>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
@@ -60,9 +60,15 @@
<Reference Include="FreeSql, Version=3.5.311.0, Culture=neutral, PublicKeyToken=a33928e5d4a4b39c, processorArchitecture=MSIL">
<HintPath>..\packages\FreeSql.3.5.311\lib\net451\FreeSql.dll</HintPath>
</Reference>
<Reference Include="FreeSql.DbContext, Version=3.5.311.0, Culture=neutral, PublicKeyToken=d6971b25f8f033dc, processorArchitecture=MSIL">
<HintPath>..\packages\FreeSql.DbContext.3.5.311\lib\net45\FreeSql.DbContext.dll</HintPath>
</Reference>
<Reference Include="FreeSql.Provider.MySql, Version=3.5.311.0, Culture=neutral, PublicKeyToken=09c4767ab6141ff5, processorArchitecture=MSIL">
<HintPath>..\packages\FreeSql.Provider.MySql.3.5.311\lib\net452\FreeSql.Provider.MySql.dll</HintPath>
</Reference>
<Reference Include="FreeSql.Repository, Version=3.5.311.0, Culture=neutral, PublicKeyToken=e2c05379863de526, processorArchitecture=MSIL">
<HintPath>..\packages\FreeSql.Repository.3.5.311\lib\net45\FreeSql.Repository.dll</HintPath>
</Reference>
<Reference Include="Google.Protobuf, Version=3.19.4.0, Culture=neutral, PublicKeyToken=a7d26565bac4d604, processorArchitecture=MSIL">
<HintPath>..\packages\Google.Protobuf.3.19.4\lib\net45\Google.Protobuf.dll</HintPath>
</Reference>
@@ -186,6 +192,7 @@
<Compile Include="BLL\WXXD\WXUserManage.cs" />
<Compile Include="Controllers\AsmxApiController.cs" />
<Compile Include="Controllers\ImageCacheController.cs" />
<Compile Include="Controllers\WX\WXUser_N_Controller.cs" />
<Compile Include="Controllers\WX\WXShopController.cs" />
<Compile Include="Controllers\WX\WXUserController.cs" />
<Compile Include="Controllers\WX\WXShopRevenueStatisticsController.cs" />
@@ -211,6 +218,11 @@
<Compile Include="DependencyInjection\IScopedDependency.cs" />
<Compile Include="DependencyInjection\ISingletonDependency.cs" />
<Compile Include="DependencyInjection\ITransientDependency.cs" />
<Compile Include="Responses\Users\ShopRenewResponse.cs" />
<Compile Include="Entitys\ShopEntity.cs" />
<Compile Include="Entitys\UserEntity.cs" />
<Compile Include="Entitys\UserPointsRecordEntity.cs" />
<Compile Include="Entitys\UserPointsShopExpire.cs" />
<Compile Include="LogHelper.cs" />
<Compile Include="Model\ApiResult.cs" />
<Compile Include="Model\ErpModel\ErpMerchantInfo.cs" />
@@ -249,7 +261,11 @@
<Compile Include="Model\WxProdSecretSpuIdShopIdMapParam.cs" />
<Compile Include="Model\WXShopDefaultAddressInfo.cs" />
<Compile Include="NotFoundMessageFilter.cs" />
<Compile Include="Repository\AutofacRepository.cs" />
<Compile Include="Repository\UserPointsRecordRepository.cs" />
<Compile Include="Requests\Users\ShopRenewRequest.cs" />
<Compile Include="Services\ImageCacheService.cs" />
<Compile Include="Services\Users\UserService.cs" />
<Compile Include="Utils\ApiRequestLogger.cs" />
<Compile Include="GetPostActionSelector.cs" />
<Compile Include="WebApiConfig.cs" />
+3 -1
View File
@@ -1,10 +1,12 @@
using System;
using FreeSql.DataAnnotations;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace KJD_Web.Model.ShopModel
{
[Table(Name = "wxxd.shop")]
public class ShopParam
{
public int id { get; set; }
+4 -2
View File
@@ -1,10 +1,12 @@
using System;
using FreeSql.DataAnnotations;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace KJD_Web.Model
{
[Table(Name = "wxxd.user")]
public class UserLoginResultParam
{
public int id { get; set; }
@@ -80,7 +82,7 @@ namespace KJD_Web.Model
/// <summary>
/// 用户积分点数
/// </summary>
public int points { get; set; }
public decimal points { get; set; }
/// <summary>
/// 单店铺续费1个月消耗的点数
/// </summary>
+4 -1
View File
@@ -35,7 +35,10 @@ namespace KJD_Web
HttpRequestMessage request, CancellationToken cancellationToken)
{
var response = await base.SendAsync(request, cancellationToken);
var originalBody = await response.Content.ReadAsStringAsync();
Console.WriteLine($"[HTTP] {request.Method} {request.RequestUri}");
Console.WriteLine($"[HTTP] Status: {(int)response.StatusCode} {response.StatusCode}");
Console.WriteLine($"[HTTP] Body: {originalBody}");
if (response.StatusCode != HttpStatusCode.OK)
{
response.Content = new StringContent(
@@ -0,0 +1,17 @@
using FreeSql;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace KJD_Web.Repository
{
public class AutofacRepository<TEntity> : BaseRepository<TEntity>
where TEntity : class
{
public AutofacRepository(IFreeSql fsql)
: base(fsql)
{
}
}
}
@@ -0,0 +1,19 @@
//using FreeSql;
//using KJD_Web.Entitys;
//using MAX.Core.DependencyInjection;
//using System;
//using System.Collections.Generic;
//using System.Linq;
//using System.Web;
//namespace KJD_Web.Repository
//{
// public class UserPointsRecordRepository : BaseRepository<UserPointsRecordEntity>, IScopedDependency
// {
// public UserPointsRecordRepository(IFreeSql fsql) : base(fsql)
// {
// }
// }
//}
@@ -0,0 +1,34 @@
using KJD_Web.BLL.WXXD.Requests;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace KJD_Web.Requests.Users
{
/// <summary>
/// 用户续费商铺
/// </summary>
public class ShopRenewRequest : SignRequestBase
{
public string UserName
{
get { return user_name; }
set { user_name = value; }
}
/// <summary>
/// 店铺ID
/// </summary>
public string ShopId { get; set; }
/// <summary>
/// 续费时长数值,例如 3;范围 1-120 个月
/// </summary>
public int RenewDuration { get; set; }
/// <summary>
/// 备注
/// </summary>
public string Remark { get; set; }
}
}
@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace KJD_Web.Dtos.Users
{
public class ShopRenewResponse
{
public string ShopId { get; set; }
public int ExpireTime‌ { get; set; }
public int UserPoints { get; set; }
}
}
@@ -0,0 +1,220 @@
using FreeSql;
using KJD_Web.Dtos.Users;
using KJD_Web.Entitys;
using KJD_Web.Model;
using KJD_Web.Model.ShopModel;
using KJD_Web.Requests.Users;
using KJD_Web.Utils;
using MAX.Core.DependencyInjection;
using System;
using YourNamespace;
namespace KJD_Web.Services.Users
{
public class UserService : ITransientDependency
{
private const int MinShopPointsPerMonth = 30;
private const int UserNameMaxLength = 20;
private const int ShopIdMaxLength = 50;
private const int RemarkMaxLength = 255;
private const int MaxRenewDuration = 120;
private readonly IFreeSql _freeSql;
public UserService(IFreeSql freeSql)
{
_freeSql = freeSql ?? throw new ArgumentNullException(nameof(freeSql));
}
/// <summary>
/// 商铺续费
/// </summary>
/// <param name="request">续费请求</param>
public ShopRenewResponse ShopRenew(ShopRenewRequest request)
{
ShopRenewResponse response = new ShopRenewResponse();
ValidateRequest(request);
string userName = request.UserName.Trim();
string shopId = request.ShopId.Trim();
string remark = string.IsNullOrWhiteSpace(request.Remark) ? null : request.Remark.Trim();
_freeSql.Transaction(() =>
{
UserEntity user = _freeSql.Select<UserEntity>()
.Where(a => a.UserName == userName)
.ForUpdate()
.First();
if (user == null)
{
throw new InvalidOperationException("不存在的用户");
}
ShopEntity shop = _freeSql.Select<ShopEntity>()
.Where(a => a.ShopId == shopId && a.UserName == user.UserName)
.ForUpdate()
.First();
if (shop == null)
{
throw new InvalidOperationException("不存在的商铺");
}
if (!string.Equals(shop.UserName, userName, StringComparison.OrdinalIgnoreCase))
{
throw new InvalidOperationException("该商铺不属于当前用户");
}
int shopPointsPerMonth = Math.Max(MinShopPointsPerMonth, user.ShopPointsPerMonth);
int deltaPoints = shopPointsPerMonth * request.RenewDuration;
if (user.Points < deltaPoints)
{
throw new InvalidOperationException("余额不足");
}
int newPoints = (int)user.Points - deltaPoints;
DateTime now = DateTime.Now;
UserPointsShopExpireEntity currentExpire = _freeSql.Select<UserPointsShopExpireEntity>()
.Where(a => a.ShopId == shopId)
.ForUpdate()
.First();
DateTime expireBaseTime = now;
if (currentExpire != null && currentExpire.ExpireTime > 0)
{
DateTime currentExpireTime = TimeUtils.StampToDateTime(currentExpire.ExpireTime);
if (currentExpireTime > expireBaseTime)
{
expireBaseTime = currentExpireTime;
}
}
int newExpireTime = CalculateNewExpireTime(expireBaseTime, request.RenewDuration);
int affectedUser = _freeSql.Update<UserEntity>()
.Set(a => a.Points, newPoints)
.Where(a => a.UserName == userName && a.Points == user.Points)
.ExecuteAffrows();
if (affectedUser != 1)
{
throw new InvalidOperationException("账户已发生改变,请刷新账户后重新操作");
}
for (int i = 0; i < request.RenewDuration; i++)
{
decimal recordNewPoints = user.Points - (decimal)shopPointsPerMonth * (i + 1);
UserPointsRecordEntity item = new UserPointsRecordEntity
{
OptionType = "续费",
OperatorType = "用户",
OperatorName = userName,
UserName = userName,
UserNick = user.NickName,
DeltaPoints = shopPointsPerMonth,
NewPoints = recordNewPoints,
ShopId = shop.ShopId,
ShopAccount = shop.ShopAccount,
Remark = remark,
AddTime = now
};
int affectedRecord = _freeSql.Insert(item).ExecuteAffrows();
if (affectedRecord != 1)
{
throw new InvalidOperationException("新增操作记录失败,请稍候重试");
}
}
if (currentExpire == null)
{
UserPointsShopExpireEntity expire = new UserPointsShopExpireEntity
{
ShopId = shopId,
ExpireTime = newExpireTime,
AddTime = now,
MdyTime = now
};
int affectedExpire = _freeSql.Insert(expire).ExecuteAffrows();
if (affectedExpire != 1)
{
throw new InvalidOperationException("新增商铺过期时间失败,请稍候重试");
}
}
else
{
int affectedExpire = _freeSql.Update<UserPointsShopExpireEntity>()
.Set(a => a.ExpireTime, newExpireTime)
.Set(a => a.MdyTime, now)
.Where(a => a.Id == currentExpire.Id && a.ExpireTime == currentExpire.ExpireTime)
.ExecuteAffrows();
if (affectedExpire != 1)
{
throw new InvalidOperationException("店铺已发生改变,请刷新店铺后重新操作");
}
}
response.ShopId = request.ShopId;
response.UserPoints = newPoints;
response.ExpireTime‌ = newExpireTime;
});
return response;
}
private static void ValidateRequest(ShopRenewRequest request)
{
if (request == null)
{
throw new ArgumentException("请求参数不能为空", nameof(request));
}
if (string.IsNullOrWhiteSpace(request.UserName))
{
throw new ArgumentException("用户名不能为空", nameof(request.UserName));
}
if (request.UserName.Trim().Length > UserNameMaxLength)
{
throw new ArgumentException("用户名长度不能超过20个字符", nameof(request.UserName));
}
if (string.IsNullOrWhiteSpace(request.ShopId))
{
throw new ArgumentException("店铺ID不能为空", nameof(request.ShopId));
}
if (request.ShopId.Trim().Length > ShopIdMaxLength)
{
throw new ArgumentException("店铺ID长度不能超过50个字符", nameof(request.ShopId));
}
if (request.RenewDuration <= 0)
{
throw new ArgumentException("续费时长必须大于0", nameof(request.RenewDuration));
}
if (request.RenewDuration > MaxRenewDuration)
{
throw new ArgumentException("续费时长不能超过120个月", nameof(request.RenewDuration));
}
if (!string.IsNullOrEmpty(request.Remark) && request.Remark.Trim().Length > RemarkMaxLength)
{
throw new ArgumentException("备注长度不能超过255个字符", nameof(request.Remark));
}
}
private static int CalculateNewExpireTime(DateTime expireBaseTime, int renewDuration)
{
DateTime newExpireDateTime;
try
{
newExpireDateTime = expireBaseTime.AddMonths(renewDuration);
}
catch (ArgumentOutOfRangeException)
{
throw new InvalidOperationException("续费时长超出允许范围");
}
if (newExpireDateTime > TimeUtils.StampToDateTime(int.MaxValue))
{
throw new InvalidOperationException("续费时间超出系统支持范围");
}
return TimeUtils.DateTimeToTimestampSeconds(newExpireDateTime);
}
}
}
+2 -2
View File
@@ -5,8 +5,8 @@
-->
<configuration>
<connectionStrings>
<add name="ConnKJD" connectionString="Max Pool Size=512;Database='kjd';Data Source='nj-cynosdbmysql-grp-hl51pkfr.sql.tencentcdb.com';Port=27660;User Id='kjd';Password='Temukjd0625';Charset=utf8mb4;" />
<!--<add name="ConnKJD" connectionString="Server=192.168.0.200;Port=3306;Database=mysql;Uid=root;Pwd=123456;"/>-->
<!--<add name="ConnKJD" connectionString="Max Pool Size=512;Database='kjd';Data Source='nj-cynosdbmysql-grp-hl51pkfr.sql.tencentcdb.com';Port=27660;User Id='kjd';Password='Temukjd0625';Charset=utf8mb4;" />-->
<add name="ConnKJD" connectionString="Server=192.168.0.200;Port=3306;Database=mysql;Uid=root;Pwd=123456;"/>
<add name="ConnKJDBAK" connectionString="Max Pool Size=512;Database='kjd';Data Source='nj-cynosdbmysql-grp-9s7x16mt.sql.tencentcdb.com';Port=24049;User Id='kjdbak';Password='Temukjd0126';Charset=utf8mb4;" />
<add name="UpdateVersion" connectionString="99999" />
<add name="UpdateFileDir" connectionString="C:\inetpub\wwwroot\kjd_update" />
+2
View File
@@ -3,7 +3,9 @@
<package id="Autofac" version="9.3.2" targetFramework="net472" />
<package id="Autofac.WebApi2" version="6.2.0" targetFramework="net472" />
<package id="FreeSql" version="3.5.311" targetFramework="net472" />
<package id="FreeSql.DbContext" version="3.5.311" targetFramework="net472" />
<package id="FreeSql.Provider.MySql" version="3.5.311" targetFramework="net472" />
<package id="FreeSql.Repository" version="3.5.311" targetFramework="net472" />
<package id="Google.Protobuf" version="3.19.4" targetFramework="net472" />
<package id="K4os.Compression.LZ4" version="1.2.6" targetFramework="net472" />
<package id="K4os.Compression.LZ4.Streams" version="1.2.6" targetFramework="net472" />
+6
View File
@@ -0,0 +1,6 @@
namespace Store.Framework;
public class Class1
{
}
+17
View File
@@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Autofac" Version="9.3.2" />
<PackageReference Include="Autofac.WebApi2" Version="6.2.0" />
<PackageReference Include="FreeSql.Provider.MySql" Version="3.5.311" />
<PackageReference Include="FreeSql.Repository" Version="3.5.311" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
</ItemGroup>
</Project>
+6
View File
@@ -0,0 +1,6 @@
namespace Store.User;
public class Class1
{
}
+5
View File
@@ -0,0 +1,5 @@
<Project Sdk="Microsoft.NET.Sdk">
<ItemGroup>
<ProjectReference Include="..\Store.Framework\Store.Framework.csproj" />
</ItemGroup>
</Project>