Browse Source

Implement basic FlashSales

pull/184/head
Jadyn 4 years ago
parent
commit
9ae75cd0b7
  1. 223
      plugins/FlashSales/.editorconfig
  2. 95
      plugins/FlashSales/src/EasyAbp.EShop.Orders.Plugins.FlashSales.Application/EasyAbp/EShop/Orders/Orders/CreateFlashSalesOrderEventHandler.cs
  3. 40
      plugins/FlashSales/src/EasyAbp.EShop.Orders.Plugins.FlashSales.Application/EasyAbp/EShop/Orders/Orders/FlashSalesOrderCreationAuthorizationHandler.cs
  4. 35
      plugins/FlashSales/src/EasyAbp.EShop.Orders.Plugins.FlashSales.Application/EasyAbp/EShop/Plugins/FlashSales/EShopOrdersPluginsFlashSalesApplicationAutoMapperProfile.cs
  5. 25
      plugins/FlashSales/src/EasyAbp.EShop.Orders.Plugins.FlashSales.Application/EasyAbp/EShop/Plugins/FlashSales/EShopOrdersPluginsFlashSalesApplicationModule.cs
  6. 2
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Application.Contracts/EasyAbp/EShop/Plugins/FlashSales/EShopPluginsFlashSalesRemoteServiceConsts.cs
  7. 9
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Application.Contracts/EasyAbp/EShop/Plugins/FlashSales/FlashSalesPlans/Dtos/CreateOrderInput.cs
  8. 21
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Application.Contracts/EasyAbp/EShop/Plugins/FlashSales/FlashSalesPlans/Dtos/FlashSalesPlanCreateDto.cs
  9. 23
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Application.Contracts/EasyAbp/EShop/Plugins/FlashSales/FlashSalesPlans/Dtos/FlashSalesPlanDto.cs
  10. 20
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Application.Contracts/EasyAbp/EShop/Plugins/FlashSales/FlashSalesPlans/Dtos/FlashSalesPlanGetListInput.cs
  11. 21
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Application.Contracts/EasyAbp/EShop/Plugins/FlashSales/FlashSalesPlans/Dtos/FlashSalesPlanUpdateDto.cs
  12. 21
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Application.Contracts/EasyAbp/EShop/Plugins/FlashSales/FlashSalesPlans/IFlashSalesPlanAppService.cs
  13. 19
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Application.Contracts/EasyAbp/EShop/Plugins/FlashSales/FlashSalesResults/Dtos/FlashSalesResultDto.cs
  14. 17
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Application.Contracts/EasyAbp/EShop/Plugins/FlashSales/FlashSalesResults/Dtos/FlashSalesResultGetListInput.cs
  15. 14
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Application.Contracts/EasyAbp/EShop/Plugins/FlashSales/FlashSalesResults/IFlashSalesResultAppService.cs
  16. 11
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Application.Contracts/EasyAbp/EShop/Plugins/FlashSales/Permissions/FlashSalesPermissionDefinitionProvider.cs
  17. 19
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Application.Contracts/EasyAbp/EShop/Plugins/FlashSales/Permissions/FlashSalesPermissions.cs
  18. 3
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Application/EasyAbp.EShop.Plugins.FlashSales.Application.csproj
  19. 22
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Application/EasyAbp/EShop/Plugins/FlashSales/EShopPluginsFlashSalesApplicationModule.cs
  20. 41
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Application/EasyAbp/EShop/Plugins/FlashSales/FlashSalesApplicationAutoMapperProfile.cs
  21. 362
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Application/EasyAbp/EShop/Plugins/FlashSales/FlashSalesPlans/FlashSalesPlanAppService.cs
  22. 18
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Application/EasyAbp/EShop/Plugins/FlashSales/FlashSalesPlans/FlashSalesPlanCacheInvalidator.cs
  23. 9
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Application/EasyAbp/EShop/Plugins/FlashSales/FlashSalesPlans/FlashSalesPlanCacheItem.cs
  24. 51
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Application/EasyAbp/EShop/Plugins/FlashSales/FlashSalesResults/FlashSalesResultAppService.cs
  25. 4
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Domain.Shared/EasyAbp.EShop.Plugins.FlashSales.Domain.Shared.csproj
  26. 13
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Domain.Shared/EasyAbp/EShop/Plugins/FlashSales/FlashSalesErrorCodes.cs
  27. 25
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Domain.Shared/EasyAbp/EShop/Plugins/FlashSales/FlashSalesPlans/CreateFlashSalesOrderCompleteEto.cs
  28. 32
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Domain.Shared/EasyAbp/EShop/Plugins/FlashSales/FlashSalesPlans/CreateFlashSalesOrderEto.cs
  29. 22
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Domain.Shared/EasyAbp/EShop/Plugins/FlashSales/FlashSalesPlans/FlashSalesPlanEto.cs
  30. 16
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Domain.Shared/EasyAbp/EShop/Plugins/FlashSales/FlashSalesPlans/FlashSalesProductAttributeEto.cs
  31. 13
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Domain.Shared/EasyAbp/EShop/Plugins/FlashSales/FlashSalesPlans/FlashSalesProductAttributeOptionEto.cs
  32. 39
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Domain.Shared/EasyAbp/EShop/Plugins/FlashSales/FlashSalesPlans/FlashSalesProductEto.cs
  33. 25
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Domain.Shared/EasyAbp/EShop/Plugins/FlashSales/FlashSalesPlans/FlashSalesProductSkuEto.cs
  34. 10
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Domain.Shared/EasyAbp/EShop/Plugins/FlashSales/FlashSalesPlans/ProductDetailEto.cs
  35. 12
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Domain.Shared/EasyAbp/EShop/Plugins/FlashSales/FlashSalesResults/FlashSalesResultStatus.cs
  36. 23
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Domain.Shared/EasyAbp/EShop/Plugins/FlashSales/FullAuditedEntityEto.cs
  37. 2
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Domain.Shared/EasyAbp/EShop/Plugins/FlashSales/Localization/FlashSalesResource.cs
  38. 29
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Domain.Shared/EasyAbp/EShop/Plugins/FlashSales/Localization/en.json
  39. 29
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Domain.Shared/EasyAbp/EShop/Plugins/FlashSales/Localization/zh-Hans.json
  40. 29
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Domain.Shared/EasyAbp/EShop/Plugins/FlashSales/Localization/zh-Hant.json
  41. 1
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Domain/EasyAbp.EShop.Plugins.FlashSales.Domain.csproj
  42. 16
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Domain/EasyAbp/EShop/Plugins/FlashSales/EShopPluginsFlashSalesDomainAutoMapperProfile.cs
  43. 22
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Domain/EasyAbp/EShop/Plugins/FlashSales/EShopPluginsFlashSalesDomainModule.cs
  44. 4
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Domain/EasyAbp/EShop/Plugins/FlashSales/FlashSalesDbProperties.cs
  45. 12
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Domain/EasyAbp/EShop/Plugins/FlashSales/FlashSalesPlans/EndTimeMustBeLaterThanBeginTimeException.cs
  46. 58
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Domain/EasyAbp/EShop/Plugins/FlashSales/FlashSalesPlans/FlashSalesPlan.cs
  47. 44
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Domain/EasyAbp/EShop/Plugins/FlashSales/FlashSalesPlans/FlashSalesPlanManager.cs
  48. 8
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Domain/EasyAbp/EShop/Plugins/FlashSales/FlashSalesPlans/IFlashSalesPlanRepository.cs
  49. 37
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Domain/EasyAbp/EShop/Plugins/FlashSales/FlashSalesResults/CreateFlashSalesOrderCompleteEventHandler.cs
  50. 49
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Domain/EasyAbp/EShop/Plugins/FlashSales/FlashSalesResults/FlashSalesResult.cs
  51. 9
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Domain/EasyAbp/EShop/Plugins/FlashSales/FlashSalesResults/IFlashSalesResultRepository.cs
  52. 9
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.EntityFrameworkCore/EasyAbp/EShop/Plugins/FlashSales/EntityFrameworkCore/EShopPluginsFlashSalesEntityFrameworkCoreModule.cs
  53. 12
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.EntityFrameworkCore/EasyAbp/EShop/Plugins/FlashSales/EntityFrameworkCore/FlashSalesDbContext.cs
  54. 29
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.EntityFrameworkCore/EasyAbp/EShop/Plugins/FlashSales/EntityFrameworkCore/FlashSalesDbContextModelCreatingExtensions.cs
  55. 11
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.EntityFrameworkCore/EasyAbp/EShop/Plugins/FlashSales/EntityFrameworkCore/IFlashSalesDbContext.cs
  56. 21
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.EntityFrameworkCore/EasyAbp/EShop/Plugins/FlashSales/FlashSalesPlans/EfCoreFlashSalesPlanRepository.cs
  57. 18
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.EntityFrameworkCore/EasyAbp/EShop/Plugins/FlashSales/FlashSalesPlans/FlashSalesPlanEfCoreQuerableExtensions.cs
  58. 20
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.EntityFrameworkCore/EasyAbp/EShop/Plugins/FlashSales/FlashSalesResults/EfCoreFlashSalesResultRepository.cs
  59. 16
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.EntityFrameworkCore/EasyAbp/EShop/Plugins/FlashSales/FlashSalesResults/FlashSalesResultEfCoreQuerableExtensions.cs
  60. 71
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.HttpApi/EasyAbp/EShop/Plugins/FlashSales/FlashSalesPlans/FlashSalesPlanController.cs
  61. 33
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.HttpApi/EasyAbp/EShop/Plugins/FlashSales/FlashSalesResults/FlashSalesResultController.cs
  62. 13
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.MongoDB/EasyAbp/EShop/Plugins/FlashSales/FlashSalesPlans/MongoFlashSalesPlanRepository.cs
  63. 13
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.MongoDB/EasyAbp/EShop/Plugins/FlashSales/FlashSalesResults/MongoFlashSalesResultRepository.cs
  64. 9
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.MongoDB/EasyAbp/EShop/Plugins/FlashSales/MongoDB/EShopPluginsFlashSalesMongoDbModule.cs
  65. 11
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.MongoDB/EasyAbp/EShop/Plugins/FlashSales/MongoDB/FlashSalesMongoDbContext.cs
  66. 8
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.MongoDB/EasyAbp/EShop/Plugins/FlashSales/MongoDB/FlashSalesMongoDbContextExtensions.cs
  67. 11
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.MongoDB/EasyAbp/EShop/Plugins/FlashSales/MongoDB/IFlashSalesMongoDbContext.cs
  68. 12
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Web/EShopPluginsFlashSalesWebAutoMapperProfile.cs
  69. 2
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Web/EShopPluginsFlashSalesWebModule.cs
  70. 5
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Web/EasyAbp.EShop.Plugins.FlashSales.Web.csproj
  71. 40
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Web/Menus/FlashSalesMenuContributor.cs
  72. 12
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Web/Menus/FlashSalesMenus.cs
  73. 21
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Web/Pages/EShop/Plugins/FlashSales/FlashSalesPlans/FlashSalesPlan/CreateModal.cshtml
  74. 27
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Web/Pages/EShop/Plugins/FlashSales/FlashSalesPlans/FlashSalesPlan/CreateModal.cshtml.cs
  75. 22
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Web/Pages/EShop/Plugins/FlashSales/FlashSalesPlans/FlashSalesPlan/EditModal.cshtml
  76. 38
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Web/Pages/EShop/Plugins/FlashSales/FlashSalesPlans/FlashSalesPlan/EditModal.cshtml.cs
  77. 50
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Web/Pages/EShop/Plugins/FlashSales/FlashSalesPlans/FlashSalesPlan/Index.cshtml
  78. 11
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Web/Pages/EShop/Plugins/FlashSales/FlashSalesPlans/FlashSalesPlan/Index.cshtml.cs
  79. 25
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Web/Pages/EShop/Plugins/FlashSales/FlashSalesPlans/FlashSalesPlan/ViewModels/CreateFlashSalesPlanViewModel.cs
  80. 33
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Web/Pages/EShop/Plugins/FlashSales/FlashSalesPlans/FlashSalesPlan/ViewModels/EditFlashSalesPlanViewModel.cs
  81. 0
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Web/Pages/EShop/Plugins/FlashSales/FlashSalesPlans/FlashSalesPlan/index.css
  82. 87
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Web/Pages/EShop/Plugins/FlashSales/FlashSalesPlans/FlashSalesPlan/index.js
  83. 41
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Web/Pages/EShop/Plugins/FlashSales/FlashSalesResults/FlashSalesResult/Index.cshtml
  84. 11
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Web/Pages/EShop/Plugins/FlashSales/FlashSalesResults/FlashSalesResult/Index.cshtml.cs
  85. 22
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Web/Pages/EShop/Plugins/FlashSales/FlashSalesResults/FlashSalesResult/ViewModal.cshtml
  86. 31
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Web/Pages/EShop/Plugins/FlashSales/FlashSalesResults/FlashSalesResult/ViewModal.cshtml.cs
  87. 23
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Web/Pages/EShop/Plugins/FlashSales/FlashSalesResults/FlashSalesResult/ViewModels/ViewFlashSalesResultViewModel.cs
  88. 0
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Web/Pages/EShop/Plugins/FlashSales/FlashSalesResults/FlashSalesResult/index.css
  89. 62
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Web/Pages/EShop/Plugins/FlashSales/FlashSalesResults/FlashSalesResult/index.js
  90. 5
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Web/Pages/EShop/Plugins/FlashSales/Index.cshtml
  91. 2
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Web/Pages/EShop/Plugins/FlashSales/Index.cshtml.cs
  92. 0
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Web/Pages/EShop/Plugins/FlashSales/_ViewImports.cshtml

223
plugins/FlashSales/.editorconfig

@ -0,0 +1,223 @@
# Remove the line below if you want to inherit .editorconfig settings from higher directories
root = true
# C# files
[*.cs]
#### Core EditorConfig Options ####
# Indentation and spacing
indent_size = 4
indent_style = space
tab_width = 4
# New line preferences
end_of_line = crlf
insert_final_newline = false
#### .NET Coding Conventions ####
# Organize usings
dotnet_separate_import_directive_groups = false
dotnet_sort_system_directives_first = true
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 = omit_if_default
# Expression-level preferences
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_compound_assignment = true
dotnet_style_prefer_conditional_expression_over_assignment = true
dotnet_style_prefer_conditional_expression_over_return = true
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 = 0
# New line preferences
dotnet_style_allow_multiple_blank_lines_experimental = false
dotnet_style_allow_statement_immediately_after_block_experimental = false
#### C# Coding Conventions ####
# var preferences
csharp_style_var_elsewhere = false
csharp_style_var_for_built_in_types = false
csharp_style_var_when_type_is_apparent = false
# Expression-bodied members
csharp_style_expression_bodied_accessors = true
csharp_style_expression_bodied_constructors = false
csharp_style_expression_bodied_indexers = true
csharp_style_expression_bodied_lambdas = true
csharp_style_expression_bodied_local_functions = false
csharp_style_expression_bodied_methods = false
csharp_style_expression_bodied_operators = false
csharp_style_expression_bodied_properties = true
# 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
csharp_style_prefer_parameter_null_checking = true
# Modifier preferences
csharp_prefer_static_local_function = true
csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async
# Code-block preferences
csharp_prefer_braces = true
csharp_prefer_simple_using_statement = true
csharp_style_namespace_declarations = file_scoped
csharp_style_prefer_method_group_conversion = true
# Expression-level preferences
csharp_prefer_simple_default_expression = true
csharp_style_deconstructed_variable_declaration = true
csharp_style_implicit_object_creation_when_type_is_apparent = true
csharp_style_inlined_variable_declaration = true
csharp_style_prefer_index_operator = true
csharp_style_prefer_local_over_anonymous_function = true
csharp_style_prefer_null_check_over_type_check = true
csharp_style_prefer_range_operator = true
csharp_style_prefer_tuple_swap = true
csharp_style_throw_expression = true
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:suggestion
# New line preferences
csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = true
csharp_style_allow_blank_lines_between_consecutive_braces_experimental = false
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 = true
csharp_indent_labels = one_less_than_current
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
#### 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_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.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.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_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

95
plugins/FlashSales/src/EasyAbp.EShop.Orders.Plugins.FlashSales.Application/EasyAbp/EShop/Orders/Orders/CreateFlashSalesOrderEventHandler.cs

@ -0,0 +1,95 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using EasyAbp.EShop.Orders.Orders.Dtos;
using EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans;
using EasyAbp.EShop.Products.ProductDetails.Dtos;
using EasyAbp.EShop.Products.Products.Dtos;
using Volo.Abp.DependencyInjection;
using Volo.Abp.EventBus.Distributed;
using Volo.Abp.ObjectMapping;
using Volo.Abp.Uow;
namespace EasyAbp.EShop.Orders.Orders;
public class CreateFlashSalesOrderEventHandler : IDistributedEventHandler<CreateFlashSalesOrderEto>, ITransientDependency
{
protected INewOrderGenerator NewOrderGenerator { get; }
protected IObjectMapper ObjectMapper { get; }
protected IEnumerable<IOrderDiscountProvider> OrderDiscountProviders { get; }
protected IOrderRepository OrderRepository { get; }
protected IDistributedEventBus DistributedEventBus { get; }
public CreateFlashSalesOrderEventHandler(
INewOrderGenerator newOrderGenerator,
IObjectMapper objectMapper,
IEnumerable<IOrderDiscountProvider> orderDiscountProviders,
IOrderRepository orderRepository,
IDistributedEventBus distributedEventBus)
{
NewOrderGenerator = newOrderGenerator;
ObjectMapper = objectMapper;
OrderDiscountProviders = orderDiscountProviders;
OrderRepository = orderRepository;
DistributedEventBus = distributedEventBus;
}
[UnitOfWork(true)]
public virtual async Task HandleEventAsync(CreateFlashSalesOrderEto eventData)
{
//How to check product is available?
//How to reduce product stock?
var input = new CreateOrderDto()
{
StoreId = eventData.StoreId,
CustomerRemark = eventData.CustomerRemark,
OrderLines = new List<CreateOrderLineDto>()
{
new CreateOrderLineDto()
{
ProductId = eventData.Plan.ProductId,
ProductSkuId = eventData.Plan.ProductSkuId,
Quantity = eventData.Quantity
}
}
};
var productDict = new Dictionary<Guid, ProductDto>()
{
{eventData.Product.Id, ObjectMapper.Map<FlashSalesProductEto,ProductDto>(eventData.Product)}
};
var productDetailDict = new Dictionary<Guid, ProductDetailDto>()
{
{eventData.ProductDetail.Id, ObjectMapper.Map<FlashSalesProductDetailEto,ProductDetailDto>(eventData.ProductDetail)}
};
var order = await NewOrderGenerator.GenerateAsync(eventData.UserId, input, productDict, productDetailDict);
await DiscountOrderAsync(order, productDict);
await OrderRepository.InsertAsync(order, autoSave: true);
await DistributedEventBus.PublishAsync(new CreateFlashSalesOrderCompleteEto()
{
TenantId = eventData.TenantId,
PlanId = eventData.PlanId,
OrderId = order.Id,
UserId = eventData.UserId,
StoreId = eventData.StoreId,
PendingResultId = eventData.PendingResultId,
Success = true
});
}
protected virtual async Task DiscountOrderAsync(Order order, Dictionary<Guid, ProductDto> productDict)
{
foreach (var provider in OrderDiscountProviders)
{
await provider.DiscountAsync(order, productDict);
}
}
}

40
plugins/FlashSales/src/EasyAbp.EShop.Orders.Plugins.FlashSales.Application/EasyAbp/EShop/Orders/Orders/FlashSalesOrderCreationAuthorizationHandler.cs

@ -0,0 +1,40 @@
using System.Threading.Tasks;
using EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans;
using EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans.Dtos;
using Microsoft.AspNetCore.Authorization;
using Volo.Abp.DependencyInjection;
namespace EasyAbp.EShop.Orders.Orders;
public class FlashSalesOrderCreationAuthorizationHandler : OrderCreationAuthorizationHandler
{
protected IAbpLazyServiceProvider LazyServiceProvider { get; }
public FlashSalesOrderCreationAuthorizationHandler(IAbpLazyServiceProvider lazyServiceProvider)
{
LazyServiceProvider = lazyServiceProvider;
}
protected override async Task HandleOrderCreationAsync(AuthorizationHandlerContext context,
OrderOperationAuthorizationRequirement requirement, OrderCreationResource resource)
{
var flashSalesPlanAppService = LazyServiceProvider.LazyGetRequiredService<IFlashSalesPlanAppService>();
foreach (var orderLine in resource.Input.OrderLines)
{
var plans = await flashSalesPlanAppService.GetListAsync(new FlashSalesPlanGetListInput()
{
StoreId = resource.Input.StoreId,
ProductId = orderLine.ProductId,
ProductSkuId = orderLine.ProductSkuId,
OnlyShowPublished = true
});
if (plans.Items.Count > 0)
{
context.Fail();
return;
}
}
context.Succeed(requirement);
}
}

35
plugins/FlashSales/src/EasyAbp.EShop.Orders.Plugins.FlashSales.Application/EasyAbp/EShop/Plugins/FlashSales/EShopOrdersPluginsFlashSalesApplicationAutoMapperProfile.cs

@ -0,0 +1,35 @@
using System.Collections.Generic;
using System;
using AutoMapper;
using EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans;
using EasyAbp.EShop.Products.ProductDetails.Dtos;
using EasyAbp.EShop.Products.Products;
using EasyAbp.EShop.Products.Products.Dtos;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Json;
namespace EasyAbp.EShop.Orders
{
public class EShopOrdersPluginsFlashSalesApplicationAutoMapperProfile : Profile, ISingletonDependency
{
public EShopOrdersPluginsFlashSalesApplicationAutoMapperProfile(IJsonSerializer jsonSerializer)
{
/* You can configure your AutoMapper mapping configuration here.
* Alternatively, you can split your mapping configurations
* into multiple profile classes for a better organization. */
CreateMap<FlashSalesProductEto, ProductDto>(MemberList.Source)
.ForSourceMember(x => x.TenantId, opt => opt.DoNotValidate())
.MapExtraProperties();
CreateMap<FlashSalesProductSkuEto, ProductSkuDto>(MemberList.Source)
.ForMember(x => x.AttributeOptionIds, opt => opt.Ignore())
.AfterMap((src, dest) => dest.AttributeOptionIds = jsonSerializer.Deserialize<List<Guid>>(src.SerializedAttributeOptionIds))
.MapExtraProperties();
CreateMap<FlashSalesProductAttributeEto, ProductAttributeDto>(MemberList.Source)
.MapExtraProperties();
CreateMap<FlashSalesProductAttributeOptionEto, ProductAttributeOptionDto>(MemberList.Source)
.MapExtraProperties();
CreateMap<FlashSalesProductDetailEto, ProductDetailDto>(MemberList.Source)
.MapExtraProperties();
}
}
}

25
plugins/FlashSales/src/EasyAbp.EShop.Orders.Plugins.FlashSales.Application/EasyAbp/EShop/Plugins/FlashSales/EShopOrdersPluginsFlashSalesApplicationModule.cs

@ -1,12 +1,37 @@
using EasyAbp.EShop.Orders;
using EasyAbp.EShop.Orders.Orders;
using EasyAbp.EShop.Products;
using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.AutoMapper;
using Volo.Abp.Modularity;
namespace EasyAbp.EShop.Plugins.FlashSales;
[DependsOn(
typeof(EShopOrdersApplicationModule),
typeof(EShopProductsApplicationContractsModule),
typeof(EShopPluginsFlashSalesApplicationContractsModule)
)]
public class EShopOrdersPluginsFlashSalesApplicationModule : AbpModule
{
public override void PreConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddSingleton<IAuthorizationHandler, FlashSalesOrderCreationAuthorizationHandler>();
}
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddAutoMapperObjectMapper<EShopOrdersPluginsFlashSalesApplicationAutoMapperProfile>();
Configure<AbpAutoMapperOptions>(options =>
{
options.Configurators.Add(abpAutoMapperConfigurationContext =>
{
var profile = abpAutoMapperConfigurationContext.ServiceProvider
.GetRequiredService<EShopOrdersPluginsFlashSalesApplicationAutoMapperProfile>();
abpAutoMapperConfigurationContext.MapperConfiguration.AddProfile(profile);
});
});
}
}

2
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Application.Contracts/EasyAbp/EShop/Plugins/FlashSales/EShopPluginsFlashSalesRemoteServiceConsts.cs

@ -4,5 +4,5 @@ public class EShopPluginsFlashSalesRemoteServiceConsts
{
public const string RemoteServiceName = "FlashSales";
public const string ModuleName = "flashSales";
public const string ModuleName = "flash-sales";
}

9
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Application.Contracts/EasyAbp/EShop/Plugins/FlashSales/FlashSalesPlans/Dtos/CreateOrderInput.cs

@ -0,0 +1,9 @@
using System.ComponentModel.DataAnnotations;
using Volo.Abp.Application.Dtos;
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans.Dtos;
public class CreateOrderInput : ExtensibleEntityDto
{
public string CustomerRemark { get; set; }
}

21
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Application.Contracts/EasyAbp/EShop/Plugins/FlashSales/FlashSalesPlans/Dtos/FlashSalesPlanCreateDto.cs

@ -0,0 +1,21 @@
using System;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Domain.Entities;
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans.Dtos;
[Serializable]
public class FlashSalesPlanCreateDto : ExtensibleEntityDto
{
public Guid StoreId { get; set; }
public DateTime BeginTime { get; set; }
public DateTime EndTime { get; set; }
public Guid ProductId { get; set; }
public Guid ProductSkuId { get; set; }
public bool IsPublished { get; set; }
}

23
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Application.Contracts/EasyAbp/EShop/Plugins/FlashSales/FlashSalesPlans/Dtos/FlashSalesPlanDto.cs

@ -0,0 +1,23 @@
using System;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Domain.Entities;
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans.Dtos;
[Serializable]
public class FlashSalesPlanDto : ExtensibleFullAuditedEntityDto<Guid>, IHasConcurrencyStamp
{
public Guid StoreId { get; set; }
public DateTime BeginTime { get; set; }
public DateTime EndTime { get; set; }
public Guid ProductId { get; set; }
public Guid ProductSkuId { get; set; }
public bool IsPublished { get; set; }
public string ConcurrencyStamp { get; set; }
}

20
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Application.Contracts/EasyAbp/EShop/Plugins/FlashSales/FlashSalesPlans/Dtos/FlashSalesPlanGetListInput.cs

@ -0,0 +1,20 @@
using System;
using Volo.Abp.Application.Dtos;
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans.Dtos;
[Serializable]
public class FlashSalesPlanGetListInput : ExtensiblePagedAndSortedResultRequestDto
{
public Guid? StoreId { get; set; }
public Guid? ProductId { get; set; }
public Guid? ProductSkuId { get; set; }
public bool OnlyShowPublished { get; set; }
public DateTime? Start { get; set; }
public DateTime? End { get; set; }
}

21
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Application.Contracts/EasyAbp/EShop/Plugins/FlashSales/FlashSalesPlans/Dtos/FlashSalesPlanUpdateDto.cs

@ -0,0 +1,21 @@
using System;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Domain.Entities;
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans.Dtos;
[Serializable]
public class FlashSalesPlanUpdateDto : ExtensibleEntityDto, IHasConcurrencyStamp
{
public DateTime BeginTime { get; set; }
public DateTime EndTime { get; set; }
public Guid ProductId { get; set; }
public Guid ProductSkuId { get; set; }
public bool IsPublished { get; set; }
public string ConcurrencyStamp { get; set; }
}

21
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Application.Contracts/EasyAbp/EShop/Plugins/FlashSales/FlashSalesPlans/IFlashSalesPlanAppService.cs

@ -0,0 +1,21 @@
using System;
using System.Threading.Tasks;
using EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans.Dtos;
using Volo.Abp.Application.Services;
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans;
public interface IFlashSalesPlanAppService :
ICrudAppService<
FlashSalesPlanDto,
Guid,
FlashSalesPlanGetListInput,
FlashSalesPlanCreateDto,
FlashSalesPlanUpdateDto>
{
Task PreOrderAsync(Guid id);
Task CheckPreOrderAsync(Guid id);
Task CreateOrderAsync(Guid id, CreateOrderInput input);
}

19
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Application.Contracts/EasyAbp/EShop/Plugins/FlashSales/FlashSalesResults/Dtos/FlashSalesResultDto.cs

@ -0,0 +1,19 @@
using System;
using Volo.Abp.Application.Dtos;
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalesResults.Dtos;
public class FlashSalesResultDto : ExtensibleFullAuditedEntityDto<Guid>
{
public virtual Guid StoreId { get; set; }
public virtual Guid PlanId { get; set; }
public virtual FlashSalesResultStatus Status { get; set; }
public virtual string Reason { get; set; }
public virtual Guid UserId { get; set; }
public virtual Guid? OrderId { get; set; }
}

17
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Application.Contracts/EasyAbp/EShop/Plugins/FlashSales/FlashSalesResults/Dtos/FlashSalesResultGetListInput.cs

@ -0,0 +1,17 @@
using System;
using Volo.Abp.Application.Dtos;
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalesResults.Dtos;
public class FlashSalesResultGetListInput : ExtensiblePagedAndSortedResultRequestDto
{
public virtual Guid? StoreId { get; set; }
public virtual Guid? PlanId { get; set; }
public virtual FlashSalesResultStatus? Status { get; set; }
public virtual Guid? UserId { get; set; }
public virtual Guid? OrderId { get; set; }
}

14
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Application.Contracts/EasyAbp/EShop/Plugins/FlashSales/FlashSalesResults/IFlashSalesResultAppService.cs

@ -0,0 +1,14 @@
using System;
using EasyAbp.EShop.Plugins.FlashSales.FlashSalesResults.Dtos;
using Volo.Abp.Application.Services;
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalesResults;
public interface IFlashSalesResultAppService :
IReadOnlyAppService<
FlashSalesResultDto,
Guid,
FlashSalesResultGetListInput>
{
}

11
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Application.Contracts/EasyAbp/EShop/Plugins/FlashSales/Permissions/FlashSalesPermissionDefinitionProvider.cs

@ -1,4 +1,4 @@
using EasyAbp.EShop.Plugins.FlashSales.Localization;
using EasyAbp.EShop.Plugins.FlashSales.Localization;
using Volo.Abp.Authorization.Permissions;
using Volo.Abp.Localization;
@ -9,6 +9,15 @@ public class FlashSalesPermissionDefinitionProvider : PermissionDefinitionProvid
public override void Define(IPermissionDefinitionContext context)
{
var myGroup = context.AddGroup(FlashSalesPermissions.GroupName, L("Permission:FlashSales"));
var flashSalesPlanPermission = myGroup.AddPermission(FlashSalesPermissions.FlashSalesPlan.Default, L("Permission:FlashSalesPlan"));
flashSalesPlanPermission.AddChild(FlashSalesPermissions.FlashSalesPlan.Manage, L("Permission:Manage"));
flashSalesPlanPermission.AddChild(FlashSalesPermissions.FlashSalesPlan.Create, L("Permission:Create"));
flashSalesPlanPermission.AddChild(FlashSalesPermissions.FlashSalesPlan.Update, L("Permission:Update"));
flashSalesPlanPermission.AddChild(FlashSalesPermissions.FlashSalesPlan.Delete, L("Permission:Delete"));
var flashSalesResultPermission = myGroup.AddPermission(FlashSalesPermissions.FlashSalesResult.Default, L("Permission:FlashSalesResult"));
flashSalesResultPermission.AddChild(FlashSalesPermissions.FlashSalesResult.Manage, L("Permission:Manage"));
}
private static LocalizableString L(string name)

19
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Application.Contracts/EasyAbp/EShop/Plugins/FlashSales/Permissions/FlashSalesPermissions.cs

@ -1,13 +1,28 @@
using Volo.Abp.Reflection;
using Volo.Abp.Reflection;
namespace EasyAbp.EShop.Plugins.FlashSales.Permissions;
public class FlashSalesPermissions
{
public const string GroupName = "FlashSales";
public const string GroupName = "EasyAbp.EShop.Plugins.FlashSales";
public static string[] GetAll()
{
return ReflectionHelper.GetPublicConstantsRecursively(typeof(FlashSalesPermissions));
}
public class FlashSalesPlan
{
public const string Default = GroupName + ".FlashSalesPlan";
public const string Manage = Default + ".Manage";
public const string Update = Default + ".Update";
public const string Create = Default + ".Create";
public const string Delete = Default + ".Delete";
}
public class FlashSalesResult
{
public const string Default = GroupName + ".FlashSalesResult";
public const string Manage = Default + ".Manage";
}
}

3
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Application/EasyAbp.EShop.Plugins.FlashSales.Application.csproj

@ -9,7 +9,10 @@
<ItemGroup>
<PackageReference Include="Volo.Abp.AutoMapper" Version="$(AbpVersion)" />
<PackageReference Include="Volo.Abp.Caching" Version="$(AbpVersion)" />
<PackageReference Include="Volo.Abp.Ddd.Application" Version="$(AbpVersion)" />
<ProjectReference Include="..\..\..\..\modules\EasyAbp.EShop.Products\src\EasyAbp.EShop.Products.Application.Contracts\EasyAbp.EShop.Products.Application.Contracts.csproj" />
<ProjectReference Include="..\..\..\..\modules\EasyAbp.EShop.Stores\src\EasyAbp.EShop.Stores.Application.Shared\EasyAbp.EShop.Stores.Application.Shared.csproj" />
<ProjectReference Include="..\EasyAbp.EShop.Plugins.FlashSales.Application.Contracts\EasyAbp.EShop.Plugins.FlashSales.Application.Contracts.csproj" />
<ProjectReference Include="..\EasyAbp.EShop.Plugins.FlashSales.Domain\EasyAbp.EShop.Plugins.FlashSales.Domain.csproj" />
</ItemGroup>

22
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Application/EasyAbp/EShop/Plugins/FlashSales/EShopPluginsFlashSalesApplicationModule.cs

@ -1,15 +1,20 @@
using Microsoft.Extensions.DependencyInjection;
using EasyAbp.EShop.Products;
using EasyAbp.EShop.Stores;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Application;
using Volo.Abp.AutoMapper;
using Volo.Abp.Caching;
using Volo.Abp.Modularity;
using Volo.Abp.Application;
namespace EasyAbp.EShop.Plugins.FlashSales;
[DependsOn(
typeof(EShopProductsApplicationContractsModule),
typeof(EShopPluginsFlashSalesDomainModule),
typeof(EShopPluginsFlashSalesApplicationContractsModule),
typeof(EShopStoresApplicationSharedModule),
typeof(AbpDddApplicationModule),
typeof(AbpAutoMapperModule)
typeof(AbpAutoMapperModule),
typeof(AbpCachingModule)
)]
public class EShopPluginsFlashSalesApplicationModule : AbpModule
{
@ -18,7 +23,14 @@ public class EShopPluginsFlashSalesApplicationModule : AbpModule
context.Services.AddAutoMapperObjectMapper<EShopPluginsFlashSalesApplicationModule>();
Configure<AbpAutoMapperOptions>(options =>
{
options.AddMaps<EShopPluginsFlashSalesApplicationModule>(validate: true);
options.Configurators.Add(abpAutoMapperConfigurationContext =>
{
var profile = abpAutoMapperConfigurationContext.ServiceProvider
.GetRequiredService<FlashSalesApplicationAutoMapperProfile>();
abpAutoMapperConfigurationContext.MapperConfiguration.AddProfile(profile);
});
});
}
}

41
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Application/EasyAbp/EShop/Plugins/FlashSales/FlashSalesApplicationAutoMapperProfile.cs

@ -1,13 +1,48 @@
using AutoMapper;
using System.Linq;
using AutoMapper;
using EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans;
using EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans.Dtos;
using EasyAbp.EShop.Plugins.FlashSales.FlashSalesResults;
using EasyAbp.EShop.Plugins.FlashSales.FlashSalesResults.Dtos;
using EasyAbp.EShop.Products.ProductDetails.Dtos;
using EasyAbp.EShop.Products.Products.Dtos;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Json;
namespace EasyAbp.EShop.Plugins.FlashSales;
public class FlashSalesApplicationAutoMapperProfile : Profile
public class FlashSalesApplicationAutoMapperProfile : Profile, ISingletonDependency
{
public FlashSalesApplicationAutoMapperProfile()
public FlashSalesApplicationAutoMapperProfile(IJsonSerializer jsonSerializer)
{
/* You can configure your AutoMapper mapping configuration here.
* Alternatively, you can split your mapping configurations
* into multiple profile classes for a better organization. */
CreateMap<FlashSalesPlan, FlashSalesPlanDto>()
.MapExtraProperties();
CreateMap<FlashSalesPlanDto, FlashSalesPlanEto>()
.ForMember(x => x.TenantId, opt => opt.Ignore())
.MapExtraProperties();
CreateMap<FlashSalesPlanCreateDto, FlashSalesPlan>(MemberList.Source);
CreateMap<FlashSalesPlanUpdateDto, FlashSalesPlan>(MemberList.Source);
CreateMap<FlashSalesPlan, FlashSalesPlanCacheItem>()
.MapExtraProperties();
CreateMap<FlashSalesResult, FlashSalesResultDto>()
.MapExtraProperties();
CreateMap<ProductDto, FlashSalesProductEto>()
.ForMember(x => x.TenantId, opt => opt.Ignore())
.MapExtraProperties();
CreateMap<ProductSkuDto, FlashSalesProductSkuEto>()
.ForMember(x => x.SerializedAttributeOptionIds, opt => opt.Ignore())
.AfterMap((src, dest) => dest.SerializedAttributeOptionIds = jsonSerializer.Serialize(src.AttributeOptionIds.OrderBy(x => x)))
.MapExtraProperties();
CreateMap<ProductAttributeDto, FlashSalesProductAttributeEto>()
.MapExtraProperties();
CreateMap<ProductAttributeOptionDto, FlashSalesProductAttributeOptionEto>()
.MapExtraProperties();
CreateMap<ProductDetailDto, FlashSalesProductDetailEto>()
.MapExtraProperties();
}
}

362
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Application/EasyAbp/EShop/Plugins/FlashSales/FlashSalesPlans/FlashSalesPlanAppService.cs

@ -0,0 +1,362 @@
using System;
using System.Linq;
using System.Numerics;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans.Dtos;
using EasyAbp.EShop.Plugins.FlashSales.FlashSalesResults;
using EasyAbp.EShop.Plugins.FlashSales.Permissions;
using EasyAbp.EShop.Products.ProductDetails;
using EasyAbp.EShop.Products.ProductDetails.Dtos;
using EasyAbp.EShop.Products.Products;
using EasyAbp.EShop.Products.Products.Dtos;
using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.Caching.Distributed;
using Volo.Abp;
using Volo.Abp.Application.Services;
using Volo.Abp.Caching;
using Volo.Abp.Data;
using Volo.Abp.DistributedLocking;
using Volo.Abp.Domain.Entities;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.EventBus.Distributed;
using Volo.Abp.Users;
using static EasyAbp.EShop.Products.Permissions.ProductsPermissions;
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans;
[Authorize]
public class FlashSalesPlanAppService :
CrudAppService<FlashSalesPlan, FlashSalesPlanDto, Guid, FlashSalesPlanGetListInput, FlashSalesPlanCreateDto, FlashSalesPlanUpdateDto>,
IFlashSalesPlanAppService
{
protected override string GetPolicyName { get; set; }
protected override string GetListPolicyName { get; set; }
protected override string CreatePolicyName { get; set; } = FlashSalesPermissions.FlashSalesPlan.Create;
protected override string UpdatePolicyName { get; set; } = FlashSalesPermissions.FlashSalesPlan.Update;
protected override string DeletePolicyName { get; set; } = FlashSalesPermissions.FlashSalesPlan.Delete;
protected IFlashSalesPlanRepository FlashSalesPlanRepository { get; }
protected IProductAppService ProductAppService { get; }
protected IProductDetailAppService ProductDetailAppService { get; }
protected IDistributedCache TokenDistributedCache { get; }
protected IDistributedCache<FlashSalesPlanCacheItem, Guid> DistributedCache { get; }
protected IDistributedEventBus DistributedEventBus { get; }
protected FlashSalesPlanManager FlashSalesPlanManager { get; }
protected IFlashSalesResultRepository FlashSalesResultRepository { get; }
protected IAbpDistributedLock DistributedLock { get; }
public FlashSalesPlanAppService(
IFlashSalesPlanRepository flashSalesPlanRepository,
IProductAppService productAppService,
IProductDetailAppService productDetailAppService,
IDistributedCache tokenDistributedCache,
IDistributedCache<FlashSalesPlanCacheItem, Guid> distributedCache,
IDistributedEventBus distributedEventBus,
FlashSalesPlanManager flashSalesPlanManager,
IFlashSalesResultRepository flashSalesResultRepository,
IAbpDistributedLock distributedLock)
: base(flashSalesPlanRepository)
{
FlashSalesPlanRepository = flashSalesPlanRepository;
ProductAppService = productAppService;
ProductDetailAppService = productDetailAppService;
TokenDistributedCache = tokenDistributedCache;
DistributedCache = distributedCache;
DistributedEventBus = distributedEventBus;
FlashSalesPlanManager = flashSalesPlanManager;
FlashSalesResultRepository = flashSalesResultRepository;
DistributedLock = distributedLock;
}
public override async Task<FlashSalesPlanDto> GetAsync(Guid id)
{
await CheckGetPolicyAsync();
var flashSalesPlan = await GetEntityByIdAsync(id);
if (!flashSalesPlan.IsPublished)
{
await CheckPolicyAsync(FlashSalesPermissions.FlashSalesPlan.Manage);
}
return await MapToGetOutputDtoAsync(flashSalesPlan);
}
public override async Task<FlashSalesPlanDto> CreateAsync(FlashSalesPlanCreateDto input)
{
await CheckCreatePolicyAsync();
var flashSalesPlan = await FlashSalesPlanManager.CreateAsync(
input.StoreId,
input.BeginTime,
input.EndTime,
input.ProductId,
input.ProductSkuId,
input.IsPublished
);
await FlashSalesPlanRepository.InsertAsync(flashSalesPlan, autoSave: true);
return await MapToGetOutputDtoAsync(flashSalesPlan);
}
public override async Task<FlashSalesPlanDto> UpdateAsync(Guid id, FlashSalesPlanUpdateDto input)
{
await CheckUpdatePolicyAsync();
var flashSalesPlan = await GetEntityByIdAsync(id);
await FlashSalesPlanManager.UpdateAsync(
flashSalesPlan,
input.BeginTime,
input.EndTime,
input.ProductId,
input.ProductSkuId,
input.IsPublished
);
flashSalesPlan.SetConcurrencyStampIfNotNull(input.ConcurrencyStamp);
await FlashSalesPlanRepository.UpdateAsync(flashSalesPlan, autoSave: true);
return await MapToGetOutputDtoAsync(flashSalesPlan);
}
protected override async Task<IQueryable<FlashSalesPlan>> CreateFilteredQueryAsync(FlashSalesPlanGetListInput input)
{
if (!input.OnlyShowPublished)
{
await CheckPolicyAsync(FlashSalesPermissions.FlashSalesPlan.Manage);
}
return (await base.CreateFilteredQueryAsync(input))
.WhereIf(input.StoreId.HasValue, x => x.StoreId == input.StoreId.Value)
.WhereIf(input.ProductId.HasValue, x => x.ProductId == input.ProductId.Value)
.WhereIf(input.ProductSkuId.HasValue, x => x.ProductSkuId == input.ProductSkuId.Value)
.WhereIf(input.OnlyShowPublished, x => x.IsPublished)
.WhereIf(input.Start.HasValue, x => x.BeginTime >= input.Start.Value)
.WhereIf(input.End.HasValue, x => x.BeginTime <= input.End.Value);
}
public virtual async Task PreOrderAsync(Guid id)
{
var plan = await GetFlashSalesPlanCacheAsync(id);
var product = await ProductAppService.GetAsync(plan.ProductId);
var productSku = product.GetSkuById(plan.ProductSkuId);
if (!product.IsPublished)
{
throw new BusinessException(FlashSalesErrorCodes.ProductIsNotPublished);
}
if (product.InventoryStrategy != InventoryStrategy.FlashSales)
{
throw new BusinessException(FlashSalesErrorCodes.IsNotFlashSalesProduct);
}
if (!plan.IsPublished)
{
throw new EntityNotFoundException(typeof(FlashSalesPlan), id);
}
if (Clock.Now > plan.EndTime)
{
throw new BusinessException(FlashSalesErrorCodes.FlashSalesPlanIsExpired);
}
await SetCacheHashTokenAsync(plan, product, productSku);
}
public virtual async Task CheckPreOrderAsync(Guid id)
{
var plan = await GetFlashSalesPlanCacheAsync(id);
if (Clock.Now > plan.EndTime)
{
throw new BusinessException(FlashSalesErrorCodes.FlashSalesPlanIsExpired);
}
var cacheHashToken = await GetCacheHashTokenAsync(plan);
if (cacheHashToken.IsNullOrWhiteSpace())
{
throw new BusinessException(FlashSalesErrorCodes.PreOrderExipred);
}
var product = await ProductAppService.GetAsync(plan.ProductId);
var productSku = product.GetSkuById(plan.ProductSkuId);
if (!await ComparekHashTokenAsync(cacheHashToken, plan, product, productSku))
{
throw new BusinessException(FlashSalesErrorCodes.PreOrderExipred);
}
}
public virtual async Task CreateOrderAsync(Guid id, CreateOrderInput input)
{
var plan = await GetFlashSalesPlanCacheAsync(id);
var now = Clock.Now;
if (plan.BeginTime > now)
{
throw new BusinessException(FlashSalesErrorCodes.ProductIsNotPublished);
}
if (now > plan.EndTime)
{
throw new BusinessException(FlashSalesErrorCodes.FlashSalesPlanIsExpired);
}
var cacheHashToken = await GetCacheHashTokenAsync(plan);
if (cacheHashToken.IsNullOrWhiteSpace())
{
throw new BusinessException(FlashSalesErrorCodes.PreOrderExipred);
}
var product = await ProductAppService.GetAsync(plan.ProductId);
var productSku = product.GetSkuById(plan.ProductSkuId);
if (!await ComparekHashTokenAsync(cacheHashToken, plan, product, productSku))
{
throw new BusinessException(FlashSalesErrorCodes.PreOrderExipred);
}
await RemoveCacheHashTokenAsync(plan);
var userId = CurrentUser.GetId();
var result = await CreatePendingFlashSalesResultAsync(plan, userId);
var CreateFlashSalesOrderEto = await PrepareCreateFlashSalesOrderEtoAsync(plan, product, productSku, result, input, userId, now);
await DistributedEventBus.PublishAsync(CreateFlashSalesOrderEto);
}
protected virtual async Task<CreateFlashSalesOrderEto> PrepareCreateFlashSalesOrderEtoAsync(
FlashSalesPlanDto plan,
ProductDto product,
ProductSkuDto productSku,
FlashSalesResult result,
CreateOrderInput input,
Guid userId,
DateTime now)
{
FlashSalesProductDetailEto productDetail = null;
var productDetailId = productSku.ProductDetailId ?? product.ProductDetailId;
if (productDetailId.HasValue)
{
productDetail = ObjectMapper.Map<ProductDetailDto, FlashSalesProductDetailEto>(await ProductDetailAppService.GetAsync(productDetailId.Value));
}
var productEto = ObjectMapper.Map<ProductDto, FlashSalesProductEto>(product);
productEto.TenantId = CurrentTenant.Id;
var planEto = ObjectMapper.Map<FlashSalesPlanDto, FlashSalesPlanEto>(plan);
planEto.TenantId = CurrentTenant.Id;
var eto = new CreateFlashSalesOrderEto()
{
TenantId = CurrentTenant.Id,
PlanId = plan.Id,
UserId = userId,
PendingResultId = result.Id,
StoreId = plan.StoreId,
CreateTime = now,
CustomerRemark = input.CustomerRemark,
Quantity = 1,//should configure
Product = productEto,
ProductDetail = productDetail,
Plan = planEto
};
foreach (var item in input.ExtraProperties)
{
eto.ExtraProperties.Add(item.Key, item.Value);
}
return eto;
}
protected virtual async Task<FlashSalesPlanCacheItem> GetFlashSalesPlanCacheAsync(Guid id)
{
return await DistributedCache.GetOrAddAsync(id, async () =>
{
var flashSalesPlan = await FlashSalesPlanRepository.GetAsync(id);
return ObjectMapper.Map<FlashSalesPlan, FlashSalesPlanCacheItem>(flashSalesPlan);
});
}
protected virtual Task<string> GetCacheKeyAsync(FlashSalesPlanDto plan)
{
return Task.FromResult($"eshopflashsales_{CurrentUser.Id}_{plan.ProductSkuId}");
}
protected virtual async Task<string> GetCacheHashTokenAsync(FlashSalesPlanDto plan)
{
return await TokenDistributedCache.GetStringAsync(await GetCacheKeyAsync(plan));
}
protected virtual async Task RemoveCacheHashTokenAsync(FlashSalesPlanDto plan)
{
await TokenDistributedCache.RemoveAsync(await GetCacheKeyAsync(plan));
}
protected virtual async Task SetCacheHashTokenAsync(FlashSalesPlanDto plan, ProductDto product, ProductSkuDto productSku)
{
await TokenDistributedCache.SetStringAsync(await GetCacheKeyAsync(plan), await GetHashTokenAsync(plan, product, productSku), new DistributedCacheEntryOptions()
{
AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(3)
});
}
protected virtual Task<string> GetHashTokenAsync(FlashSalesPlanDto plan, ProductDto product, ProductSkuDto productSku)
{
using var md5 = MD5.Create();
var inputBytes = Encoding.UTF8.GetBytes($"{plan.LastModificationTime}|{product.LastModificationTime}|{productSku.LastModificationTime}");
var sb = new StringBuilder();
foreach (var t in md5.ComputeHash(inputBytes))
{
sb.Append(t.ToString("X2"));
}
return Task.FromResult(sb.ToString());
}
protected virtual async Task<bool> ComparekHashTokenAsync(string cacheHashToken, FlashSalesPlanDto plan, ProductDto product, ProductSkuDto productSku)
{
if (cacheHashToken.IsNullOrWhiteSpace())
{
return false;
}
var hashToken = await GetHashTokenAsync(plan, product, productSku);
return cacheHashToken == hashToken;
}
protected virtual async Task<FlashSalesResult> CreatePendingFlashSalesResultAsync(FlashSalesPlanDto plan, Guid userId)
{
var lockKey = $"create-flash-sales-order-{plan.Id}-{userId}";
await using var handle = await DistributedLock.TryAcquireAsync(lockKey);
if (handle == null)
{
throw new BusinessException(FlashSalesErrorCodes.CreateFlashSalesOrderBusy);
}
// Prevent repeat submit
if (await FlashSalesResultRepository.AnyAsync(x => x.PlanId == plan.Id && x.UserId == userId))
{
throw new BusinessException(FlashSalesErrorCodes.AlreadySubmitCreateFlashSalesOrder);
}
var result = new FlashSalesResult(
id: GuidGenerator.Create(),
tenantId: CurrentTenant.Id,
storeId: plan.StoreId,
planId: plan.Id,
status: FlashSalesResultStatus.Pending,
reason: null,
userId: userId,
orderId: null
);
return await FlashSalesResultRepository.InsertAsync(result, autoSave: true);
}
}

18
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Application/EasyAbp/EShop/Plugins/FlashSales/FlashSalesPlans/FlashSalesPlanCacheInvalidator.cs

@ -0,0 +1,18 @@
using System;
using System.Threading.Tasks;
using EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans.Dtos;
using Volo.Abp.Caching;
using Volo.Abp.Domain.Entities.Events;
using Volo.Abp.EventBus;
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans;
public class FlashSalesPlanCacheInvalidator : ILocalEventHandler<EntityChangedEventData<FlashSalesPlan>>
{
protected IDistributedCache<FlashSalesPlanCacheItem, Guid> DistributedCache { get; }
public virtual async Task HandleEventAsync(EntityChangedEventData<FlashSalesPlan> eventData)
{
await DistributedCache.RemoveAsync(eventData.Entity.Id);
}
}

9
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Application/EasyAbp/EShop/Plugins/FlashSales/FlashSalesPlans/FlashSalesPlanCacheItem.cs

@ -0,0 +1,9 @@
using System;
using EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans.Dtos;
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans;
[Serializable]
public class FlashSalesPlanCacheItem : FlashSalesPlanDto
{
}

51
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Application/EasyAbp/EShop/Plugins/FlashSales/FlashSalesResults/FlashSalesResultAppService.cs

@ -0,0 +1,51 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using EasyAbp.EShop.Plugins.FlashSales.FlashSalesResults.Dtos;
using EasyAbp.EShop.Plugins.FlashSales.Permissions;
using Volo.Abp.Application.Services;
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalesResults;
public class FlashSalesResultAppService :
ReadOnlyAppService<FlashSalesResult, FlashSalesResultDto, Guid, FlashSalesResultGetListInput>,
IFlashSalesResultAppService
{
protected override string GetPolicyName { get; set; }
protected override string GetListPolicyName { get; set; }
protected IFlashSalesResultRepository FlashSalesResultRepository { get; }
public FlashSalesResultAppService(IFlashSalesResultRepository flashSalesResultRepository) : base(flashSalesResultRepository)
{
}
public override async Task<FlashSalesResultDto> GetAsync(Guid id)
{
await CheckGetPolicyAsync();
var flashSalesPlan = await GetEntityByIdAsync(id);
if (flashSalesPlan.UserId != CurrentUser.Id)
{
await CheckPolicyAsync(FlashSalesPermissions.FlashSalesResult.Manage);
}
return await MapToGetOutputDtoAsync(flashSalesPlan);
}
protected override async Task<IQueryable<FlashSalesResult>> CreateFilteredQueryAsync(FlashSalesResultGetListInput input)
{
if (input.UserId != CurrentUser.Id)
{
await CheckPolicyAsync(FlashSalesPermissions.FlashSalesResult.Manage);
}
return (await base.CreateFilteredQueryAsync(input))
.WhereIf(input.StoreId.HasValue, x => x.StoreId == input.StoreId.Value)
.WhereIf(input.PlanId.HasValue, x => x.PlanId == input.PlanId.Value)
.WhereIf(input.Status.HasValue, x => x.Status == input.Status.Value)
.WhereIf(input.UserId.HasValue, x => x.UserId == input.UserId.Value)
.WhereIf(input.OrderId.HasValue, x => x.OrderId == input.OrderId.Value);
}
}

4
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Domain.Shared/EasyAbp.EShop.Plugins.FlashSales.Domain.Shared.csproj

@ -21,4 +21,8 @@
<Content Remove="EasyAbp\EShop\Plugins\FlashSales\Localization\*.json" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\modules\EasyAbp.EShop.Products\src\EasyAbp.EShop.Products.Domain.Shared\EasyAbp.EShop.Products.Domain.Shared.csproj" />
</ItemGroup>
</Project>

13
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Domain.Shared/EasyAbp/EShop/Plugins/FlashSales/FlashSalesErrorCodes.cs

@ -6,4 +6,17 @@ public static class FlashSalesErrorCodes
public const string EndTimeMustBeLaterThanBeginTime = $"{Namespace}:{nameof(EndTimeMustBeLaterThanBeginTime)}";
public const string ProductIsNotPublished = $"{Namespace}:{nameof(ProductIsNotPublished)}";
public const string IsNotFlashSalesProduct = $"{Namespace}:{nameof(IsNotFlashSalesProduct)}";
public const string PreOrderExipred = $"{Namespace}:{nameof(PreOrderExipred)}";
public const string FlashSalesPlanIsNotStart = $"{Namespace}:{nameof(FlashSalesPlanIsNotStart)}";
public const string FlashSalesPlanIsExpired = $"{Namespace}:{nameof(FlashSalesPlanIsExpired)}";
public const string CreateFlashSalesOrderBusy = $"{Namespace}:{nameof(CreateFlashSalesOrderBusy)}";
public const string AlreadySubmitCreateFlashSalesOrder = $"{Namespace}:{nameof(AlreadySubmitCreateFlashSalesOrder)}";
}

25
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Domain.Shared/EasyAbp/EShop/Plugins/FlashSales/FlashSalesPlans/CreateFlashSalesOrderCompleteEto.cs

@ -0,0 +1,25 @@
using System;
using EasyAbp.EShop.Plugins.FlashSales.FlashSalesResults;
using Volo.Abp.MultiTenancy;
using Volo.Abp.ObjectExtending;
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans;
public class CreateFlashSalesOrderCompleteEto : ExtensibleObject, IMultiTenant
{
public Guid? TenantId { get; set; }
public Guid PendingResultId { get; set; }
public bool Success { get; set; }
public Guid StoreId { get; set; }
public Guid PlanId { get; set; }
public string Reason { get; set; }
public Guid UserId { get; set; }
public Guid? OrderId { get; set; }
}

32
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Domain.Shared/EasyAbp/EShop/Plugins/FlashSales/FlashSalesPlans/CreateFlashSalesOrderEto.cs

@ -0,0 +1,32 @@
using System;
using EasyAbp.EShop.Products.Products;
using Volo.Abp.MultiTenancy;
using Volo.Abp.ObjectExtending;
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans;
[Serializable]
public class CreateFlashSalesOrderEto : ExtensibleObject, IMultiTenant
{
public Guid? TenantId { get; set; }
public Guid StoreId { get; set; }
public Guid PlanId { get; set; }
public Guid UserId { get; set; }
public Guid PendingResultId { get; set; }
public DateTime CreateTime { get; set; }
public string CustomerRemark { get; set; }
public int Quantity { get; set; }
public FlashSalesProductEto Product { get; set; }
public FlashSalesProductDetailEto ProductDetail { get; set; }
public FlashSalesPlanEto Plan { get; set; }
}

22
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Domain.Shared/EasyAbp/EShop/Plugins/FlashSales/FlashSalesPlans/FlashSalesPlanEto.cs

@ -0,0 +1,22 @@
using System;
using Volo.Abp.MultiTenancy;
using Volo.Abp.ObjectExtending;
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans;
public class FlashSalesPlanEto : FullAuditedEntityEto<Guid>, IMultiTenant
{
public Guid? TenantId { get; set; }
public Guid StoreId { get; set; }
public DateTime BeginTime { get; set; }
public DateTime EndTime { get; set; }
public Guid ProductId { get; set; }
public Guid ProductSkuId { get; set; }
public bool IsPublished { get; set; }
}

16
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Domain.Shared/EasyAbp/EShop/Plugins/FlashSales/FlashSalesPlans/FlashSalesProductAttributeEto.cs

@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using EasyAbp.EShop.Products.Products;
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans;
public class FlashSalesProductAttributeEto : FullAuditedEntityEto<Guid>, IProductAttribute
{
public string DisplayName { get; set; }
public string Description { get; set; }
public int DisplayOrder { get; set; }
public List<FlashSalesProductAttributeOptionEto> ProductAttributeOptions { get; set; }
}

13
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Domain.Shared/EasyAbp/EShop/Plugins/FlashSales/FlashSalesPlans/FlashSalesProductAttributeOptionEto.cs

@ -0,0 +1,13 @@
using System;
using EasyAbp.EShop.Products.Products;
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans;
public class FlashSalesProductAttributeOptionEto : FullAuditedEntityEto<Guid>, IProductAttributeOption
{
public string DisplayName { get; set; }
public string Description { get; set; }
public int DisplayOrder { get; set; }
}

39
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Domain.Shared/EasyAbp/EShop/Plugins/FlashSales/FlashSalesPlans/FlashSalesProductEto.cs

@ -0,0 +1,39 @@
using System;
using System.Collections.Generic;
using EasyAbp.EShop.Products.Products;
using Volo.Abp.MultiTenancy;
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans;
public class FlashSalesProductEto : FullAuditedEntityEto<Guid>, IProduct, IMultiTenant
{
public Guid? TenantId { get; set; }
public Guid StoreId { get; set; }
public string ProductGroupName { get; set; }
public Guid? ProductDetailId { get; set; }
public string UniqueName { get; set; }
public string DisplayName { get; set; }
public InventoryStrategy InventoryStrategy { get; set; }
public string InventoryProviderName { get; set; }
public string MediaResources { get; set; }
public int DisplayOrder { get; set; }
public bool IsPublished { get; set; }
public bool IsStatic { get; set; }
public bool IsHidden { get; set; }
public List<FlashSalesProductAttributeEto> ProductAttributes { get; set; }
public List<FlashSalesProductSkuEto> ProductSkus { get; set; }
}

25
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Domain.Shared/EasyAbp/EShop/Plugins/FlashSales/FlashSalesPlans/FlashSalesProductSkuEto.cs

@ -0,0 +1,25 @@
using System;
using EasyAbp.EShop.Products.Products;
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans;
public class FlashSalesProductSkuEto : FullAuditedEntityEto<Guid>, IProductSku
{
public string SerializedAttributeOptionIds { get; set; }
public string Name { get; set; }
public string Currency { get; set; }
public decimal? OriginalPrice { get; set; }
public decimal Price { get; set; }
public int OrderMinQuantity { get; set; }
public int OrderMaxQuantity { get; set; }
public string MediaResources { get; set; }
public Guid? ProductDetailId { get; set; }
}

10
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Domain.Shared/EasyAbp/EShop/Plugins/FlashSales/FlashSalesPlans/ProductDetailEto.cs

@ -0,0 +1,10 @@
using System;
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans;
public class FlashSalesProductDetailEto : FullAuditedEntityEto<Guid>
{
public Guid? StoreId { get; set; }
public string Description { get; set; }
}

12
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Domain.Shared/EasyAbp/EShop/Plugins/FlashSales/FlashSalesResults/FlashSalesResultStatus.cs

@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalesResults;
public enum FlashSalesResultStatus
{
Pending,
Successful,
Failed
}

23
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Domain.Shared/EasyAbp/EShop/Plugins/FlashSales/FullAuditedEntityEto.cs

@ -0,0 +1,23 @@
using System;
using Volo.Abp.ObjectExtending;
namespace EasyAbp.EShop.Plugins.FlashSales;
public class FullAuditedEntityEto<TPrimaryKey> : ExtensibleObject
{
public TPrimaryKey Id { get; set; }
public DateTime CreationTime { get; set; }
public Guid? CreatorId { get; set; }
public DateTime? LastModificationTime { get; set; }
public Guid? LastModifierId { get; set; }
public bool IsDeleted { get; set; }
public Guid? DeleterId { get; set; }
public DateTime? DeletionTime { get; set; }
}

2
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Domain.Shared/EasyAbp/EShop/Plugins/FlashSales/Localization/FlashSalesResource.cs

@ -2,7 +2,7 @@
namespace EasyAbp.EShop.Plugins.FlashSales.Localization;
[LocalizationResourceName("FlashSales")]
[LocalizationResourceName("EasyAbpEShopPluginsFlashSales")]
public class FlashSalesResource
{

29
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Domain.Shared/EasyAbp/EShop/Plugins/FlashSales/Localization/en.json

@ -1,5 +1,34 @@
{
"culture": "en",
"texts": {
"EasyAbp.EShop.Plugins.FlashSales:EndTimeMustBeLaterThanBeginTime": "End time must be later than start time",
"Menu:FlashSalesManagement": "FlashSalesManagement",
"Permission:FlashSalesPlan": "FlashSalesPlan",
"Permission:Manage": "Manage",
"Permission:Create": "Create",
"Permission:Update": "Update",
"Permission:Delete": "Delete",
"Menu:FlashSalesPlan": "FlashSalesPlan",
"FlashSalesPlan": "FlashSalesPlan",
"FlashSalesPlanStoreId": "Store ID",
"FlashSalesPlanBeginTime": "Begin Time",
"FlashSalesPlanEndTime": "End Time",
"FlashSalesPlanProductId": "Product ID",
"FlashSalesPlanProductSkuId": "Product SKU ID",
"FlashSalesPlanIsPublished": "Is Published",
"CreateFlashSalesPlan": "Create",
"EditFlashSalesPlan": "Edit",
"FlashSalesPlanDeletionConfirmationMessage": "Are you sure to delete the flashSalesPlan {0}?",
"SuccessfullyDeleted": "Successfully deleted",
"Permission:FlashSalesResult": "FlashSalesResult",
"Menu:FlashSalesResult": "FlashSalesResult",
"FlashSalesResult": "FlashSalesResult",
"FlashSalesResultStoreId": "Store ID",
"FlashSalesResultPlanId": "Plan ID",
"FlashSalesResultStatus": "Status",
"FlashSalesResultUserId": "User ID",
"FlashSalesResultOrderId": "Order ID",
"FlashSalesResultCreationTime": "Creation Time",
"ViewFlashSalesPlan": "View"
}
}

29
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Domain.Shared/EasyAbp/EShop/Plugins/FlashSales/Localization/zh-Hans.json

@ -1,5 +1,34 @@
{
"culture": "zh-Hans",
"texts": {
"EasyAbp.EShop.Plugins.FlashSales:EndTimeMustBeLaterThanBeginTime": "结束时间必须晚于开始时间",
"Menu:FlashSalesManagement": "闪购",
"Permission:FlashSalesPlan": "闪购计划",
"Permission:Manage": "管理",
"Permission:Create": "新建",
"Permission:Update": "更新",
"Permission:Delete": "删除",
"Menu:FlashSalesPlan": "闪购计划",
"FlashSalesPlan": "闪购计划",
"FlashSalesPlanStoreId": "店铺 ID",
"FlashSalesPlanBeginTime": "开始时间",
"FlashSalesPlanEndTime": "结束时间",
"FlashSalesPlanProductId": "产品 ID",
"FlashSalesPlanProductSkuId": "产品SKU ID",
"FlashSalesPlanIsPublished": "发布",
"CreateFlashSalesPlan": "新建",
"EditFlashSalesPlan": "编辑",
"FlashSalesPlanDeletionConfirmationMessage": "确认删除闪购计划 {0}?",
"SuccessfullyDeleted": "删除成功",
"Permission:FlashSalesResult": "闪购结果",
"Menu:FlashSalesResult": "闪购结果",
"FlashSalesResult": "闪购结果",
"FlashSalesResultStoreId": "店铺 ID",
"FlashSalesResultPlanId": "计划 ID",
"FlashSalesResultStatus": "状态",
"FlashSalesResultUserId": "用户 ID",
"FlashSalesResultOrderId": "订单 ID",
"FlashSalesResultCreationTime": "创建时间",
"ViewFlashSalesPlan": "查看"
}
}

29
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Domain.Shared/EasyAbp/EShop/Plugins/FlashSales/Localization/zh-Hant.json

@ -1,5 +1,34 @@
{
"culture": "zh-Hant",
"texts": {
"EasyAbp.EShop.Plugins.FlashSales:EndTimeMustBeLaterThanBeginTime": "結束時間必須晚於開始時間",
"Menu:FlashSalesManagement": "FlashSalesManagement",
"Permission:FlashSalesPlan": "FlashSalesPlan",
"Permission:Manage": "Manage",
"Permission:Create": "Create",
"Permission:Update": "Update",
"Permission:Delete": "Delete",
"Menu:FlashSalesPlan": "FlashSalesPlan",
"FlashSalesPlan": "FlashSalesPlan",
"FlashSalesPlanStoreId": "FlashSalesPlanStoreId",
"FlashSalesPlanBeginTime": "FlashSalesPlanBeginTime",
"FlashSalesPlanEndTime": "FlashSalesPlanEndTime",
"FlashSalesPlanProductId": "FlashSalesPlanProductId",
"FlashSalesPlanProductSkuId": "FlashSalesPlanProductSkuId",
"FlashSalesPlanIsPublished": "FlashSalesPlanIsActive",
"CreateFlashSalesPlan": "CreateFlashSalesPlan",
"EditFlashSalesPlan": "EditFlashSalesPlan",
"FlashSalesPlanDeletionConfirmationMessage": "Are you sure to delete the flashSalesPlan {0}?",
"SuccessfullyDeleted": "Successfully deleted",
"Permission:FlashSalesResult": "闪购结果",
"Menu:FlashSalesResult": "闪购计划",
"FlashSalesResult": "闪购结果",
"FlashSalesResultStoreId": "店铺 ID",
"FlashSalesResultPlanId": "计划 ID",
"FlashSalesResultStatus": "状态",
"FlashSalesResultUserId": "用户 ID",
"FlashSalesResultOrderId": "订单 ID",
"FlashSalesResultCreationTime": "创建时间",
"ViewFlashSalesPlan": "查看"
}
}

1
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Domain/EasyAbp.EShop.Plugins.FlashSales.Domain.csproj

@ -8,6 +8,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Volo.Abp.AutoMapper" Version="$(AbpVersion)" />
<PackageReference Include="Volo.Abp.Ddd.Domain" Version="$(AbpVersion)" />
<ProjectReference Include="..\EasyAbp.EShop.Plugins.FlashSales.Domain.Shared\EasyAbp.EShop.Plugins.FlashSales.Domain.Shared.csproj" />
</ItemGroup>

16
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Domain/EasyAbp/EShop/Plugins/FlashSales/EShopPluginsFlashSalesDomainAutoMapperProfile.cs

@ -0,0 +1,16 @@
using AutoMapper;
using EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans;
namespace EasyAbp.EShop.Plugins.FlashSales;
public class EShopPluginsFlashSalesDomainAutoMapperProfile : Profile
{
public EShopPluginsFlashSalesDomainAutoMapperProfile()
{
/* You can configure your AutoMapper mapping configuration here.
* Alternatively, you can split your mapping configurations
* into multiple profile classes for a better organization. */
CreateMap<FlashSalesPlan, FlashSalesPlanEto>()
.MapExtraProperties();
}
}

22
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Domain/EasyAbp/EShop/Plugins/FlashSales/EShopPluginsFlashSalesDomainModule.cs

@ -1,13 +1,33 @@
using Volo.Abp.Domain;
using EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.AutoMapper;
using Volo.Abp.Domain;
using Volo.Abp.Domain.Entities.Events.Distributed;
using Volo.Abp.Modularity;
namespace EasyAbp.EShop.Plugins.FlashSales;
[DependsOn(
typeof(AbpDddDomainModule),
typeof(AbpAutoMapperModule),
typeof(EShopPluginsFlashSalesDomainSharedModule)
)]
public class EShopPluginsFlashSalesDomainModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddAutoMapperObjectMapper<EShopPluginsFlashSalesDomainModule>();
Configure<AbpAutoMapperOptions>(options =>
{
options.AddProfile<EShopPluginsFlashSalesDomainAutoMapperProfile>(validate: true);
});
Configure<AbpDistributedEntityEventOptions>(options =>
{
options.EtoMappings.Add<FlashSalesPlan, FlashSalesPlanEto>(typeof(EShopPluginsFlashSalesDomainModule));
options.AutoEventSelectors.Add<FlashSalesPlan>();
});
}
}

4
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Domain/EasyAbp/EShop/Plugins/FlashSales/FlashSalesDbProperties.cs

@ -2,9 +2,9 @@
public static class FlashSalesDbProperties
{
public static string DbTablePrefix { get; set; } = "FlashSales";
public static string DbTablePrefix { get; set; } = "EasyAbpEShopPluginsFlashSales";
public static string DbSchema { get; set; } = null;
public const string ConnectionStringName = "FlashSales";
public const string ConnectionStringName = "EasyAbpEShopPluginsFlashSales";
}

12
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Domain/EasyAbp/EShop/Plugins/FlashSales/FlashSalesPlans/EndTimeMustBeLaterThanBeginTimeException.cs

@ -0,0 +1,12 @@
using Volo.Abp;
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans;
internal class EndTimeMustBeLaterThanBeginTimeException : BusinessException
{
public EndTimeMustBeLaterThanBeginTimeException()
: base(FlashSalesErrorCodes.EndTimeMustBeLaterThanBeginTime)
{
}
}

58
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Domain/EasyAbp/EShop/Plugins/FlashSales/FlashSalesPlans/FlashSalesPlan.cs

@ -0,0 +1,58 @@
using System;
using Volo.Abp.Domain.Entities.Auditing;
using Volo.Abp.MultiTenancy;
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans;
public class FlashSalesPlan : FullAuditedAggregateRoot<Guid>, IMultiTenant
{
public virtual Guid? TenantId { get; protected set; }
public virtual Guid StoreId { get; protected set; }
public virtual DateTime BeginTime { get; set; }
public virtual DateTime EndTime { get; set; }
public virtual Guid ProductId { get; protected set; }
public virtual Guid ProductSkuId { get; protected set; }
public virtual bool IsPublished { get; protected set; }
protected FlashSalesPlan()
{
}
public FlashSalesPlan(Guid id, Guid? tenantId, Guid storeId, DateTime beginTime, DateTime endTime, Guid productId, Guid productSkuId, bool isPublished)
: base(id)
{
TenantId = tenantId;
StoreId = storeId;
SetTimeRange(beginTime, endTime);
SetProduct(productId, productSkuId);
SetPublished(isPublished);
}
public void SetTimeRange(DateTime beginTime, DateTime endTime)
{
if (beginTime > endTime)
{
throw new EndTimeMustBeLaterThanBeginTimeException();
}
BeginTime = beginTime;
EndTime = endTime;
}
public void SetProduct(Guid productId, Guid productSkuId)
{
ProductId = productId;
ProductSkuId = productSkuId;
}
public void SetPublished(bool isPublished)
{
IsPublished = isPublished;
}
}

44
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Domain/EasyAbp/EShop/Plugins/FlashSales/FlashSalesPlans/FlashSalesPlanManager.cs

@ -0,0 +1,44 @@
using System;
using System.Threading.Tasks;
using Volo.Abp.Domain.Services;
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans;
public class FlashSalesPlanManager : DomainService
{
public virtual Task<FlashSalesPlan> CreateAsync(
Guid storeId,
DateTime beginTime,
DateTime endTime,
Guid productId,
Guid productSkuId,
bool isActive)
{
var flashSalesPlan = new FlashSalesPlan(
GuidGenerator.Create(),
CurrentTenant.Id,
storeId,
beginTime,
endTime,
productId,
productSkuId,
isActive
);
return Task.FromResult(flashSalesPlan);
}
public virtual Task<FlashSalesPlan> UpdateAsync(
FlashSalesPlan flashSalesPlan,
DateTime beginTime,
DateTime endTime,
Guid productId,
Guid productSkuId,
bool isPublished)
{
flashSalesPlan.SetTimeRange(beginTime, endTime);
flashSalesPlan.SetProduct(productId, productSkuId);
flashSalesPlan.SetPublished(isPublished);
return Task.FromResult(flashSalesPlan);
}
}

8
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Domain/EasyAbp/EShop/Plugins/FlashSales/FlashSalesPlans/IFlashSalesPlanRepository.cs

@ -0,0 +1,8 @@
using System;
using Volo.Abp.Domain.Repositories;
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans;
public interface IFlashSalesPlanRepository : IRepository<FlashSalesPlan, Guid>
{
}

37
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Domain/EasyAbp/EShop/Plugins/FlashSales/FlashSalesResults/CreateFlashSalesOrderCompleteEventHandler.cs

@ -0,0 +1,37 @@
using System.Threading.Tasks;
using EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans;
using Volo.Abp.DependencyInjection;
using Volo.Abp.EventBus.Distributed;
using Volo.Abp.Guids;
using Volo.Abp.Uow;
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalesResults;
public class CreateFlashSalesOrderCompleteEventHandler : IDistributedEventHandler<CreateFlashSalesOrderCompleteEto>, ITransientDependency
{
protected IFlashSalesResultRepository FlashSalesResultRepository { get; }
protected IGuidGenerator GuidGenerator { get; }
public CreateFlashSalesOrderCompleteEventHandler(IFlashSalesResultRepository flashSalesResultRepository, IGuidGenerator guidGenerator)
{
FlashSalesResultRepository = flashSalesResultRepository;
GuidGenerator = guidGenerator;
}
[UnitOfWork]
public virtual async Task HandleEventAsync(CreateFlashSalesOrderCompleteEto eventData)
{
var flashSalesResult = await FlashSalesResultRepository.GetAsync(eventData.PendingResultId);
if (eventData.Success)
{
flashSalesResult.MarkAsSuccessful(eventData.OrderId.Value);
}
else
{
flashSalesResult.MarkAsFailed(eventData.Reason);
}
await FlashSalesResultRepository.UpdateAsync(flashSalesResult, autoSave: true);
}
}

49
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Domain/EasyAbp/EShop/Plugins/FlashSales/FlashSalesResults/FlashSalesResult.cs

@ -0,0 +1,49 @@
using System;
using Volo.Abp;
using Volo.Abp.Domain.Entities.Auditing;
using Volo.Abp.MultiTenancy;
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalesResults;
public class FlashSalesResult : FullAuditedAggregateRoot<Guid>, IMultiTenant
{
public virtual Guid? TenantId { get; protected set; }
public virtual Guid StoreId { get; protected set; }
public virtual Guid PlanId { get; protected set; }
public virtual FlashSalesResultStatus Status { get; protected set; }
public virtual string Reason { get; protected set; }
public virtual Guid UserId { get; protected set; }
public virtual Guid? OrderId { get; protected set; }
protected FlashSalesResult() { }
public FlashSalesResult(Guid id, Guid? tenantId, Guid storeId, Guid planId, FlashSalesResultStatus status, string reason, Guid userId, Guid? orderId)
: base(id)
{
TenantId = tenantId;
StoreId = storeId;
PlanId = planId;
Status = status;
Reason = reason;
UserId = userId;
OrderId = orderId;
}
public void MarkAsSuccessful(Guid orderId)
{
Status = FlashSalesResultStatus.Successful;
OrderId = orderId;
}
public void MarkAsFailed(string reason)
{
Status = FlashSalesResultStatus.Failed;
Reason = Check.NotNullOrEmpty(reason, nameof(reason));
}
}

9
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Domain/EasyAbp/EShop/Plugins/FlashSales/FlashSalesResults/IFlashSalesResultRepository.cs

@ -0,0 +1,9 @@
using System;
using Volo.Abp.Domain.Repositories;
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalesResults;
public interface IFlashSalesResultRepository : IRepository<FlashSalesResult, Guid>
{
}

9
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.EntityFrameworkCore/EasyAbp/EShop/Plugins/FlashSales/EntityFrameworkCore/EShopPluginsFlashSalesEntityFrameworkCoreModule.cs

@ -1,4 +1,6 @@
using Microsoft.Extensions.DependencyInjection;
using EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans;
using EasyAbp.EShop.Plugins.FlashSales.FlashSalesResults;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.EntityFrameworkCore;
using Volo.Abp.Modularity;
@ -14,9 +16,8 @@ public class EShopPluginsFlashSalesEntityFrameworkCoreModule : AbpModule
{
context.Services.AddAbpDbContext<FlashSalesDbContext>(options =>
{
/* Add custom repositories here. Example:
* options.AddRepository<Question, EfCoreQuestionRepository>();
*/
options.AddRepository<FlashSalesPlan, EfCoreFlashSalesPlanRepository>();
options.AddRepository<FlashSalesResult, EfCoreFlashSalesResultRepository>();
});
}
}

12
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.EntityFrameworkCore/EasyAbp/EShop/Plugins/FlashSales/EntityFrameworkCore/FlashSalesDbContext.cs

@ -1,4 +1,6 @@
using Microsoft.EntityFrameworkCore;
using EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans;
using EasyAbp.EShop.Plugins.FlashSales.FlashSalesResults;
using Microsoft.EntityFrameworkCore;
using Volo.Abp.Data;
using Volo.Abp.EntityFrameworkCore;
@ -7,9 +9,9 @@ namespace EasyAbp.EShop.Plugins.FlashSales.EntityFrameworkCore;
[ConnectionStringName(FlashSalesDbProperties.ConnectionStringName)]
public class FlashSalesDbContext : AbpDbContext<FlashSalesDbContext>, IFlashSalesDbContext
{
/* Add DbSet for each Aggregate Root here. Example:
* public DbSet<Question> Questions { get; set; }
*/
public DbSet<FlashSalesPlan> Plans { get; set; }
public DbSet<FlashSalesResult> Results { get; set; }
public FlashSalesDbContext(DbContextOptions<FlashSalesDbContext> options)
: base(options)
@ -21,6 +23,6 @@ public class FlashSalesDbContext : AbpDbContext<FlashSalesDbContext>, IFlashSale
{
base.OnModelCreating(builder);
builder.ConfigureFlashSales();
builder.ConfigureEShopPluginsFlashSales();
}
}

29
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.EntityFrameworkCore/EasyAbp/EShop/Plugins/FlashSales/EntityFrameworkCore/FlashSalesDbContextModelCreatingExtensions.cs

@ -1,33 +1,32 @@
using Microsoft.EntityFrameworkCore;
using EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans;
using EasyAbp.EShop.Plugins.FlashSales.FlashSalesResults;
using Microsoft.EntityFrameworkCore;
using Volo.Abp;
using Volo.Abp.EntityFrameworkCore.Modeling;
namespace EasyAbp.EShop.Plugins.FlashSales.EntityFrameworkCore;
public static class FlashSalesDbContextModelCreatingExtensions
{
public static void ConfigureFlashSales(
public static void ConfigureEShopPluginsFlashSales(
this ModelBuilder builder)
{
Check.NotNull(builder, nameof(builder));
/* Configure all entities here. Example:
builder.Entity<Question>(b =>
builder.Entity<FlashSalesPlan>(b =>
{
//Configure table & schema name
b.ToTable(FlashSalesDbProperties.DbTablePrefix + "Questions", FlashSalesDbProperties.DbSchema);
b.ToTable(FlashSalesDbProperties.DbTablePrefix + "Plans", FlashSalesDbProperties.DbSchema);
b.ConfigureByConvention();
//Properties
b.Property(q => q.Title).IsRequired().HasMaxLength(QuestionConsts.MaxTitleLength);
/* Configure more properties here */
});
//Relations
b.HasMany(question => question.Tags).WithOne().HasForeignKey(qt => qt.QuestionId);
builder.Entity<FlashSalesResult>(b =>
{
b.ToTable(FlashSalesDbProperties.DbTablePrefix + "Results", FlashSalesDbProperties.DbSchema);
b.ConfigureByConvention();
//Indexes
b.HasIndex(q => q.CreationTime);
/* Configure more properties here */
});
*/
}
}

11
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.EntityFrameworkCore/EasyAbp/EShop/Plugins/FlashSales/EntityFrameworkCore/IFlashSalesDbContext.cs

@ -1,4 +1,7 @@
using Volo.Abp.Data;
using EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans;
using EasyAbp.EShop.Plugins.FlashSales.FlashSalesResults;
using Microsoft.EntityFrameworkCore;
using Volo.Abp.Data;
using Volo.Abp.EntityFrameworkCore;
namespace EasyAbp.EShop.Plugins.FlashSales.EntityFrameworkCore;
@ -6,7 +9,7 @@ namespace EasyAbp.EShop.Plugins.FlashSales.EntityFrameworkCore;
[ConnectionStringName(FlashSalesDbProperties.ConnectionStringName)]
public interface IFlashSalesDbContext : IEfCoreDbContext
{
/* Add DbSet for each Aggregate Root here. Example:
* DbSet<Question> Questions { get; }
*/
DbSet<FlashSalesPlan> Plans { get; set; }
DbSet<FlashSalesResult> Results { get; set; }
}

21
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.EntityFrameworkCore/EasyAbp/EShop/Plugins/FlashSales/FlashSalesPlans/EfCoreFlashSalesPlanRepository.cs

@ -0,0 +1,21 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using EasyAbp.EShop.Plugins.FlashSales.EntityFrameworkCore;
using Volo.Abp.Domain.Repositories.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore;
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans
{
public class EfCoreFlashSalesPlanRepository : EfCoreRepository<IFlashSalesDbContext, FlashSalesPlan, Guid>, IFlashSalesPlanRepository
{
public EfCoreFlashSalesPlanRepository(IDbContextProvider<IFlashSalesDbContext> dbContextProvider) : base(dbContextProvider)
{
}
public override async Task<IQueryable<FlashSalesPlan>> WithDetailsAsync()
{
return (await GetQueryableAsync()).IncludeDetails();
}
}
}

18
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.EntityFrameworkCore/EasyAbp/EShop/Plugins/FlashSales/FlashSalesPlans/FlashSalesPlanEfCoreQuerableExtensions.cs

@ -0,0 +1,18 @@
using System.Linq;
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans;
public static class FlashSalesPlanEfCoreQueryableExtensions
{
public static IQueryable<FlashSalesPlan> IncludeDetails(this IQueryable<FlashSalesPlan> queryable, bool include = true)
{
if (!include)
{
return queryable;
}
return queryable
// .Include(x => x.xxx) // TODO: AbpHelper generated
;
}
}

20
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.EntityFrameworkCore/EasyAbp/EShop/Plugins/FlashSales/FlashSalesResults/EfCoreFlashSalesResultRepository.cs

@ -0,0 +1,20 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using EasyAbp.EShop.Plugins.FlashSales.EntityFrameworkCore;
using Volo.Abp.Domain.Repositories.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore;
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalesResults;
public class EfCoreFlashSalesResultRepository : EfCoreRepository<IFlashSalesDbContext, FlashSalesResult, Guid>, IFlashSalesResultRepository
{
public EfCoreFlashSalesResultRepository(IDbContextProvider<IFlashSalesDbContext> dbContextProvider) : base(dbContextProvider)
{
}
public override async Task<IQueryable<FlashSalesResult>> WithDetailsAsync()
{
return (await GetQueryableAsync()).IncludeDetails();
}
}

16
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.EntityFrameworkCore/EasyAbp/EShop/Plugins/FlashSales/FlashSalesResults/FlashSalesResultEfCoreQuerableExtensions.cs

@ -0,0 +1,16 @@
using System.Linq;
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalesResults;
public static class FlashSalesResultEfCoreQuerableExtensions
{
public static IQueryable<FlashSalesResult> IncludeDetails(this IQueryable<FlashSalesResult> queryable, bool include = true)
{
if (!include)
{
return queryable;
}
return queryable;
}
}

71
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.HttpApi/EasyAbp/EShop/Plugins/FlashSales/FlashSalesPlans/FlashSalesPlanController.cs

@ -0,0 +1,71 @@
using System;
using System.Threading.Tasks;
using EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans.Dtos;
using Microsoft.AspNetCore.Mvc;
using Volo.Abp;
using Volo.Abp.Application.Dtos;
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans;
[Area(EShopPluginsFlashSalesRemoteServiceConsts.ModuleName)]
[RemoteService(Name = EShopPluginsFlashSalesRemoteServiceConsts.RemoteServiceName)]
[Route("/api/e-shop/plugins/flash-sales/flash-sales-plan")]
public class FlashSalesPlanController :
FlashSalesController,
IFlashSalesPlanAppService
{
protected IFlashSalesPlanAppService Service { get; }
public FlashSalesPlanController(IFlashSalesPlanAppService flashSalesPlanAppService)
{
Service = flashSalesPlanAppService;
}
[HttpGet("{id}")]
public virtual Task<FlashSalesPlanDto> GetAsync(Guid id)
{
return Service.GetAsync(id);
}
[HttpGet]
public virtual Task<PagedResultDto<FlashSalesPlanDto>> GetListAsync(FlashSalesPlanGetListInput input)
{
return Service.GetListAsync(input);
}
[HttpPost("{id}")]
public virtual Task<FlashSalesPlanDto> CreateAsync(FlashSalesPlanCreateDto input)
{
return Service.CreateAsync(input);
}
[HttpPut("{id}")]
public virtual Task<FlashSalesPlanDto> UpdateAsync(Guid id, FlashSalesPlanUpdateDto input)
{
return Service.UpdateAsync(id, input);
}
[HttpDelete("{id}")]
public virtual Task DeleteAsync(Guid id)
{
return Service.DeleteAsync(id);
}
[HttpPost("{id}/pre-order")]
public virtual Task PreOrderAsync(Guid id)
{
return Service.PreOrderAsync(id);
}
[HttpGet("{id}/check-pre-order")]
public virtual Task CheckPreOrderAsync(Guid id)
{
return Service.CheckPreOrderAsync(id);
}
[HttpPost("{id}/order")]
public virtual Task CreateOrderAsync(Guid id, CreateOrderInput input)
{
return Service.CreateOrderAsync(id, input);
}
}

33
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.HttpApi/EasyAbp/EShop/Plugins/FlashSales/FlashSalesResults/FlashSalesResultController.cs

@ -0,0 +1,33 @@
using System;
using System.Threading.Tasks;
using EasyAbp.EShop.Plugins.FlashSales.FlashSalesResults.Dtos;
using Microsoft.AspNetCore.Mvc;
using Volo.Abp;
using Volo.Abp.Application.Dtos;
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalesResults;
[Area(EShopPluginsFlashSalesRemoteServiceConsts.ModuleName)]
[RemoteService(Name = EShopPluginsFlashSalesRemoteServiceConsts.RemoteServiceName)]
[Route("/api/e-shop/plugins/flash-sales/flash-sales-result")]
public class FlashSalesResultController : FlashSalesController, IFlashSalesResultAppService
{
protected IFlashSalesResultAppService Service { get; }
public FlashSalesResultController(IFlashSalesResultAppService service)
{
Service = service;
}
[HttpGet("{id}")]
public virtual Task<FlashSalesResultDto> GetAsync(Guid id)
{
return Service.GetAsync(id);
}
[HttpGet]
public virtual Task<PagedResultDto<FlashSalesResultDto>> GetListAsync(FlashSalesResultGetListInput input)
{
return Service.GetListAsync(input);
}
}

13
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.MongoDB/EasyAbp/EShop/Plugins/FlashSales/FlashSalesPlans/MongoFlashSalesPlanRepository.cs

@ -0,0 +1,13 @@
using System;
using EasyAbp.EShop.Plugins.FlashSales.MongoDB;
using Volo.Abp.Domain.Repositories.MongoDB;
using Volo.Abp.MongoDB;
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans;
public class MongoFlashSalesPlanRepository : MongoDbRepository<IFlashSalesMongoDbContext, FlashSalesPlan, Guid>, IFlashSalesPlanRepository
{
public MongoFlashSalesPlanRepository(IMongoDbContextProvider<IFlashSalesMongoDbContext> dbContextProvider) : base(dbContextProvider)
{
}
}

13
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.MongoDB/EasyAbp/EShop/Plugins/FlashSales/FlashSalesResults/MongoFlashSalesResultRepository.cs

@ -0,0 +1,13 @@
using System;
using EasyAbp.EShop.Plugins.FlashSales.MongoDB;
using Volo.Abp.Domain.Repositories.MongoDB;
using Volo.Abp.MongoDB;
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalesResults;
public class MongoFlashSalesResultRepository : MongoDbRepository<IFlashSalesMongoDbContext, FlashSalesResult, Guid>, IFlashSalesResultRepository
{
public MongoFlashSalesResultRepository(IMongoDbContextProvider<IFlashSalesMongoDbContext> dbContextProvider) : base(dbContextProvider)
{
}
}

9
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.MongoDB/EasyAbp/EShop/Plugins/FlashSales/MongoDB/EShopPluginsFlashSalesMongoDbModule.cs

@ -1,4 +1,6 @@
using Microsoft.Extensions.DependencyInjection;
using EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans;
using EasyAbp.EShop.Plugins.FlashSales.FlashSalesResults;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Modularity;
using Volo.Abp.MongoDB;
@ -14,9 +16,8 @@ public class EShopPluginsFlashSalesMongoDbModule : AbpModule
{
context.Services.AddMongoDbContext<FlashSalesMongoDbContext>(options =>
{
/* Add custom repositories here. Example:
* options.AddRepository<Question, MongoQuestionRepository>();
*/
options.AddRepository<FlashSalesPlan, MongoFlashSalesPlanRepository>();
options.AddRepository<FlashSalesResult, MongoFlashSalesResultRepository>();
});
}
}

11
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.MongoDB/EasyAbp/EShop/Plugins/FlashSales/MongoDB/FlashSalesMongoDbContext.cs

@ -1,4 +1,7 @@
using Volo.Abp.Data;
using EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans;
using EasyAbp.EShop.Plugins.FlashSales.FlashSalesResults;
using MongoDB.Driver;
using Volo.Abp.Data;
using Volo.Abp.MongoDB;
namespace EasyAbp.EShop.Plugins.FlashSales.MongoDB;
@ -6,9 +9,9 @@ namespace EasyAbp.EShop.Plugins.FlashSales.MongoDB;
[ConnectionStringName(FlashSalesDbProperties.ConnectionStringName)]
public class FlashSalesMongoDbContext : AbpMongoDbContext, IFlashSalesMongoDbContext
{
/* Add mongo collections here. Example:
* public IMongoCollection<Question> Questions => Collection<Question>();
*/
public IMongoCollection<FlashSalesPlan> Plans => Collection<FlashSalesPlan>();
public IMongoCollection<FlashSalesResult> Results => Collection<FlashSalesResult>();
protected override void CreateModel(IMongoModelBuilder modelBuilder)
{

8
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.MongoDB/EasyAbp/EShop/Plugins/FlashSales/MongoDB/FlashSalesMongoDbContextExtensions.cs

@ -1,4 +1,6 @@
using Volo.Abp;
using EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans;
using EasyAbp.EShop.Plugins.FlashSales.FlashSalesResults;
using Volo.Abp;
using Volo.Abp.MongoDB;
namespace EasyAbp.EShop.Plugins.FlashSales.MongoDB;
@ -9,5 +11,9 @@ public static class FlashSalesMongoDbContextExtensions
this IMongoModelBuilder builder)
{
Check.NotNull(builder, nameof(builder));
builder.Entity<FlashSalesPlan>(b => b.CollectionName = FlashSalesDbProperties.DbTablePrefix + "Plans");
builder.Entity<FlashSalesResult>(b => b.CollectionName = FlashSalesDbProperties.DbTablePrefix + "Results");
}
}

11
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.MongoDB/EasyAbp/EShop/Plugins/FlashSales/MongoDB/IFlashSalesMongoDbContext.cs

@ -1,4 +1,7 @@
using Volo.Abp.Data;
using EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans;
using EasyAbp.EShop.Plugins.FlashSales.FlashSalesResults;
using MongoDB.Driver;
using Volo.Abp.Data;
using Volo.Abp.MongoDB;
namespace EasyAbp.EShop.Plugins.FlashSales.MongoDB;
@ -6,7 +9,7 @@ namespace EasyAbp.EShop.Plugins.FlashSales.MongoDB;
[ConnectionStringName(FlashSalesDbProperties.ConnectionStringName)]
public interface IFlashSalesMongoDbContext : IAbpMongoDbContext
{
/* Define mongo collections here. Example:
* IMongoCollection<Question> Questions { get; }
*/
IMongoCollection<FlashSalesPlan> Plans { get; }
IMongoCollection<FlashSalesResult> Results { get; }
}

12
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Web/EShopPluginsFlashSalesWebAutoMapperProfile.cs

@ -1,4 +1,8 @@
using AutoMapper;
using EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans.Dtos;
using EasyAbp.EShop.Plugins.FlashSales.FlashSalesResults.Dtos;
using EasyAbp.EShop.Plugins.FlashSales.Web.Pages.EShop.Plugins.FlashSales.FlashSalesPlans.FlashSalesPlan.ViewModels;
using EasyAbp.EShop.Plugins.FlashSales.Web.Pages.EShop.Plugins.FlashSales.FlashSalesResults.FlashSalesResult.ViewModels;
namespace EasyAbp.EShop.Plugins.FlashSales.Web;
@ -9,5 +13,13 @@ public class EShopPluginsFlashSalesWebAutoMapperProfile : Profile
/* You can configure your AutoMapper mapping configuration here.
* Alternatively, you can split your mapping configurations
* into multiple profile classes for a better organization. */
CreateMap<CreateFlashSalesPlanViewModel, FlashSalesPlanCreateDto>()
.ForMember(dest => dest.ExtraProperties, opt => opt.Ignore());
CreateMap<EditFlashSalesPlanViewModel, FlashSalesPlanUpdateDto>()
.ForMember(dest => dest.ExtraProperties, opt => opt.Ignore());
CreateMap<FlashSalesPlanDto, EditFlashSalesPlanViewModel>()
.ForSourceMember(dest => dest.ExtraProperties, opt => opt.DoNotValidate());
CreateMap<FlashSalesResultDto, ViewFlashSalesResultViewModel>()
.ForSourceMember(dest => dest.ExtraProperties, opt => opt.DoNotValidate());
}
}

2
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Web/EShopPluginsFlashSalesWebModule.cs

@ -53,6 +53,6 @@ public class EShopPluginsFlashSalesWebModule : AbpModule
Configure<RazorPagesOptions>(options =>
{
//Configure authorization.
});
});
}
}

5
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Web/EasyAbp.EShop.Plugins.FlashSales.Web.csproj

@ -37,4 +37,9 @@
<Content Remove="wwwroot\**\*.*" />
</ItemGroup>
<ItemGroup>
<None Remove="Pages\EShop\Plugins\FlashSales\FlashSalesResults\FlashSalesResult\index.css" />
<None Remove="Pages\EShop\Plugins\FlashSales\FlashSalesResults\FlashSalesResult\index.js" />
</ItemGroup>
</Project>

40
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Web/Menus/FlashSalesMenuContributor.cs

@ -1,4 +1,7 @@
using System.Threading.Tasks;
using System.Collections.Generic;
using System.Threading.Tasks;
using EasyAbp.EShop.Plugins.FlashSales.Localization;
using EasyAbp.EShop.Plugins.FlashSales.Permissions;
using Volo.Abp.UI.Navigation;
namespace EasyAbp.EShop.Plugins.FlashSales.Web.Menus;
@ -13,11 +16,40 @@ public class FlashSalesMenuContributor : IMenuContributor
}
}
private Task ConfigureMainMenuAsync(MenuConfigurationContext context)
private async Task ConfigureMainMenuAsync(MenuConfigurationContext context)
{
var l = context.GetLocalizer<FlashSalesResource>();
//Add main menu items.
context.Menu.AddItem(new ApplicationMenuItem(FlashSalesMenus.Prefix, displayName: "FlashSales", "~/FlashSales", icon: "fa fa-globe"));
var flashSalesManagementMenuItem = new ApplicationMenuItem(FlashSalesMenus.Prefix, l["Menu:FlashSalesManagement"]);
return Task.CompletedTask;
if (await context.IsGrantedAsync(FlashSalesPermissions.FlashSalesPlan.Default))
{
flashSalesManagementMenuItem.AddItem(
new ApplicationMenuItem(
FlashSalesMenus.FlashSalesPlan,
l["Menu:FlashSalesPlan"],
"/EShop/Plugins/FlashSales/FlashSalesPlans/FlashSalesPlan"
)
);
}
if (await context.IsGrantedAsync(FlashSalesPermissions.FlashSalesResult.Default))
{
flashSalesManagementMenuItem.AddItem(
new ApplicationMenuItem(
FlashSalesMenus.FlashSalesResult,
l["Menu:FlashSalesResult"],
"/EShop/Plugins/FlashSales/FlashSalesResults/FlashSalesResult"
)
);
}
if (!flashSalesManagementMenuItem.Items.IsNullOrEmpty())
{
var eShopMenuItem = context.Menu.Items.GetOrAdd(i => i.Name == FlashSalesMenus.ModuleGroupPrefix,
() => new ApplicationMenuItem(FlashSalesMenus.ModuleGroupPrefix, l["Menu:EasyAbpEShop"], icon: "fa fa-shopping-bag"));
eShopMenuItem.Items.Add(flashSalesManagementMenuItem);
}
}
}

12
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Web/Menus/FlashSalesMenus.cs

@ -1,10 +1,12 @@
namespace EasyAbp.EShop.Plugins.FlashSales.Web.Menus;
namespace EasyAbp.EShop.Plugins.FlashSales.Web.Menus;
public class FlashSalesMenus
public static class FlashSalesMenus
{
public const string Prefix = "FlashSales";
public const string ModuleGroupPrefix = "EasyAbp.EShop";
//Add your menu items here...
//public const string Home = Prefix + ".MyNewMenuItem";
public const string Prefix = ModuleGroupPrefix + ".Plugins.FlashSales";
public const string FlashSalesPlan = Prefix + ".FlashSalesPlan";
public const string FlashSalesResult = Prefix + ".FlashSalesResult";
}

21
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Web/Pages/EShop/Plugins/FlashSales/FlashSalesPlans/FlashSalesPlan/CreateModal.cshtml

@ -0,0 +1,21 @@
@page
@using Microsoft.AspNetCore.Mvc.Localization
@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal
@using EasyAbp.EShop.Plugins.FlashSales.Localization
@using EasyAbp.EShop.Plugins.FlashSales.Web.Pages.EShop.Plugins.FlashSales.FlashSalesPlans.FlashSalesPlan
@inject IHtmlLocalizer<FlashSalesResource> L
@model CreateModalModel
@{
Layout = null;
}
<abp-dynamic-form abp-model="ViewModel" data-ajaxForm="true" asp-page="CreateModal">
<abp-modal>
<abp-modal-header title="@L["CreateFlashSalesPlan"].Value"></abp-modal-header>
<abp-modal-body>
<abp-form-content />
</abp-modal-body>
<abp-modal-footer buttons="@(AbpModalButtons.Cancel|AbpModalButtons.Save)"></abp-modal-footer>
</abp-modal>
</abp-dynamic-form>

27
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Web/Pages/EShop/Plugins/FlashSales/FlashSalesPlans/FlashSalesPlan/CreateModal.cshtml.cs

@ -0,0 +1,27 @@
using System.Threading.Tasks;
using EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans;
using EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans.Dtos;
using EasyAbp.EShop.Plugins.FlashSales.Web.Pages.EShop.Plugins.FlashSales.FlashSalesPlans.FlashSalesPlan.ViewModels;
using Microsoft.AspNetCore.Mvc;
namespace EasyAbp.EShop.Plugins.FlashSales.Web.Pages.EShop.Plugins.FlashSales.FlashSalesPlans.FlashSalesPlan;
public class CreateModalModel : FlashSalesPageModel
{
[BindProperty]
public CreateFlashSalesPlanViewModel ViewModel { get; set; }
protected IFlashSalesPlanAppService Service { get; }
public CreateModalModel(IFlashSalesPlanAppService service)
{
Service = service;
}
public virtual async Task<IActionResult> OnPostAsync()
{
var dto = ObjectMapper.Map<CreateFlashSalesPlanViewModel, FlashSalesPlanCreateDto>(ViewModel);
await Service.CreateAsync(dto);
return NoContent();
}
}

22
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Web/Pages/EShop/Plugins/FlashSales/FlashSalesPlans/FlashSalesPlan/EditModal.cshtml

@ -0,0 +1,22 @@
@page
@using EasyAbp.EShop.Plugins.FlashSales.Localization
@using Microsoft.AspNetCore.Mvc.Localization
@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal
@using EasyAbp.EShop.Plugins.FlashSales.Web.Pages.EShop.Plugins.FlashSales.FlashSalesPlans.FlashSalesPlan
@inject IHtmlLocalizer<FlashSalesResource> L
@model EditModalModel
@{
Layout = null;
}
<abp-dynamic-form abp-model="ViewModel" data-ajaxForm="true" asp-page="EditModal">
<abp-modal>
<abp-modal-header title="@L["EditFlashSalesPlan"].Value"></abp-modal-header>
<abp-modal-body>
<abp-input asp-for="Id" />
<abp-form-content />
</abp-modal-body>
<abp-modal-footer buttons="@(AbpModalButtons.Cancel|AbpModalButtons.Save)"></abp-modal-footer>
</abp-modal>
</abp-dynamic-form>

38
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Web/Pages/EShop/Plugins/FlashSales/FlashSalesPlans/FlashSalesPlan/EditModal.cshtml.cs

@ -0,0 +1,38 @@
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans;
using EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans.Dtos;
using EasyAbp.EShop.Plugins.FlashSales.Web.Pages.EShop.Plugins.FlashSales.FlashSalesPlans.FlashSalesPlan.ViewModels;
namespace EasyAbp.EShop.Plugins.FlashSales.Web.Pages.EShop.Plugins.FlashSales.FlashSalesPlans.FlashSalesPlan;
public class EditModalModel : FlashSalesPageModel
{
[HiddenInput]
[BindProperty(SupportsGet = true)]
public Guid Id { get; set; }
[BindProperty]
public EditFlashSalesPlanViewModel ViewModel { get; set; }
protected IFlashSalesPlanAppService Service { get; }
public EditModalModel(IFlashSalesPlanAppService service)
{
Service = service;
}
public virtual async Task OnGetAsync()
{
var dto = await Service.GetAsync(Id);
ViewModel = ObjectMapper.Map<FlashSalesPlanDto, EditFlashSalesPlanViewModel>(dto);
}
public virtual async Task<IActionResult> OnPostAsync()
{
var dto = ObjectMapper.Map<EditFlashSalesPlanViewModel, FlashSalesPlanUpdateDto>(ViewModel);
await Service.UpdateAsync(Id, dto);
return NoContent();
}
}

50
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Web/Pages/EShop/Plugins/FlashSales/FlashSalesPlans/FlashSalesPlan/Index.cshtml

@ -0,0 +1,50 @@
@page
@using EasyAbp.EShop.Plugins.FlashSales.Permissions
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Mvc.Localization
@using Volo.Abp.AspNetCore.Mvc.UI.Layout
@using EasyAbp.EShop.Plugins.FlashSales.Web.Pages.EShop.Plugins.FlashSales.FlashSalesPlans.FlashSalesPlan
@using EasyAbp.EShop.Plugins.FlashSales.Localization
@using EasyAbp.EShop.Plugins.FlashSales.Web.Menus
@model IndexModel
@inject IPageLayout PageLayout
@inject IHtmlLocalizer<FlashSalesResource> L
@inject IAuthorizationService Authorization
@{
PageLayout.Content.Title = L["FlashSalesPlan"].Value;
PageLayout.Content.BreadCrumb.Add(L["Menu:FlashSalesPlan"].Value);
PageLayout.Content.MenuItemName = FlashSalesMenus.FlashSalesPlan;
}
@section scripts
{
<abp-script src="/Pages/EShop/Plugins/FlashSales/FlashSalesPlans/FlashSalesPlan/index.js" />
}
@section styles
{
<abp-style src="/Pages/EShop/Plugins/FlashSales/FlashSalesPlans/FlashSalesPlan/index.css" />
}
<abp-card>
<abp-card-header>
<abp-row>
<abp-column size-md="_6">
<abp-card-title>@L["FlashSalesPlan"]</abp-card-title>
</abp-column>
<abp-column size-md="_6" class="text-end">
@if (await Authorization.IsGrantedAsync(FlashSalesPermissions.FlashSalesPlan.Create))
{
<abp-button id="NewFlashSalesPlanButton"
text="@L["CreateFlashSalesPlan"].Value"
icon="plus"
button-type="Primary" />
}
</abp-column>
</abp-row>
</abp-card-header>
<abp-card-body>
<abp-table striped-rows="true" id="FlashSalesPlanTable" class="nowrap" />
</abp-card-body>
</abp-card>

11
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Web/Pages/EShop/Plugins/FlashSales/FlashSalesPlans/FlashSalesPlan/Index.cshtml.cs

@ -0,0 +1,11 @@
using System.Threading.Tasks;
namespace EasyAbp.EShop.Plugins.FlashSales.Web.Pages.EShop.Plugins.FlashSales.FlashSalesPlans.FlashSalesPlan;
public class IndexModel : FlashSalesPageModel
{
public virtual async Task OnGetAsync()
{
await Task.CompletedTask;
}
}

25
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Web/Pages/EShop/Plugins/FlashSales/FlashSalesPlans/FlashSalesPlan/ViewModels/CreateFlashSalesPlanViewModel.cs

@ -0,0 +1,25 @@
using System;
using System.ComponentModel.DataAnnotations;
namespace EasyAbp.EShop.Plugins.FlashSales.Web.Pages.EShop.Plugins.FlashSales.FlashSalesPlans.FlashSalesPlan.ViewModels;
public class CreateFlashSalesPlanViewModel
{
[Display(Name = "FlashSalesPlanStoreId")]
public Guid StoreId { get; set; }
[Display(Name = "FlashSalesPlanBeginTime")]
public DateTime BeginTime { get; set; }
[Display(Name = "FlashSalesPlanEndTime")]
public DateTime EndTime { get; set; }
[Display(Name = "FlashSalesPlanProductId")]
public Guid ProductId { get; set; }
[Display(Name = "FlashSalesPlanProductSkuId")]
public Guid ProductSkuId { get; set; }
[Display(Name = "FlashSalesPlanIsPublished")]
public bool IsPublished { get; set; }
}

33
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Web/Pages/EShop/Plugins/FlashSales/FlashSalesPlans/FlashSalesPlan/ViewModels/EditFlashSalesPlanViewModel.cs

@ -0,0 +1,33 @@
using System;
using System.ComponentModel.DataAnnotations;
using Microsoft.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form;
using Volo.Abp.Domain.Entities;
namespace EasyAbp.EShop.Plugins.FlashSales.Web.Pages.EShop.Plugins.FlashSales.FlashSalesPlans.FlashSalesPlan.ViewModels;
public class EditFlashSalesPlanViewModel : IHasConcurrencyStamp
{
[DisabledInput]
[ReadOnlyInput]
[Display(Name = "FlashSalesPlanStoreId")]
public Guid StoreId { get; set; }
[Display(Name = "FlashSalesPlanBeginTime")]
public DateTime BeginTime { get; set; }
[Display(Name = "FlashSalesPlanEndTime")]
public DateTime EndTime { get; set; }
[Display(Name = "FlashSalesPlanProductId")]
public Guid ProductId { get; set; }
[Display(Name = "FlashSalesPlanProductSkuId")]
public Guid ProductSkuId { get; set; }
[Display(Name = "FlashSalesPlanIsPublished")]
public bool IsPublished { get; set; }
[HiddenInput]
public string ConcurrencyStamp { get; set; }
}

0
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Web/Pages/EShop/Plugins/FlashSales/FlashSalesPlans/FlashSalesPlan/index.css

87
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Web/Pages/EShop/Plugins/FlashSales/FlashSalesPlans/FlashSalesPlan/index.js

@ -0,0 +1,87 @@
$(function () {
var l = abp.localization.getResource('EasyAbpEShopPluginsFlashSales');
var service = easyAbp.eShop.plugins.flashSales.flashSalesPlans.flashSalesPlan;
var createModal = new abp.ModalManager(abp.appPath + 'EShop/Plugins/FlashSales/FlashSalesPlans/FlashSalesPlan/CreateModal');
var editModal = new abp.ModalManager(abp.appPath + 'EShop/Plugins/FlashSales/FlashSalesPlans/FlashSalesPlan/EditModal');
var dataTable = $('#FlashSalesPlanTable').DataTable(abp.libs.datatables.normalizeConfiguration({
processing: true,
serverSide: true,
paging: true,
searching: false,
autoWidth: false,
scrollCollapse: true,
order: [[2, "asc"]],
ajax: abp.libs.datatables.createAjax(service.getList),
columnDefs: [
{
rowAction: {
items:
[
{
text: l('Edit'),
visible: abp.auth.isGranted('EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlan.Update'),
action: function (data) {
editModal.open({ id: data.record.id });
}
},
{
text: l('Delete'),
visible: abp.auth.isGranted('EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlan.Delete'),
confirmMessage: function (data) {
return l('FlashSalesPlanDeletionConfirmationMessage', data.record.id);
},
action: function (data) {
service.delete(data.record.id)
.then(function () {
abp.notify.info(l('SuccessfullyDeleted'));
dataTable.ajax.reload();
});
}
}
]
}
},
{
title: l('FlashSalesPlanStoreId'),
data: "storeId"
},
{
title: l('FlashSalesPlanBeginTime'),
data: "beginTime"
},
{
title: l('FlashSalesPlanEndTime'),
data: "endTime"
},
{
title: l('FlashSalesPlanProductId'),
data: "productId"
},
{
title: l('FlashSalesPlanProductSkuId'),
data: "productSkuId"
},
{
title: l('FlashSalesPlanIsPublished'),
data: "isPublished",
dataFormat: 'boolean'
},
]
}));
createModal.onResult(function () {
dataTable.ajax.reload();
});
editModal.onResult(function () {
dataTable.ajax.reload();
});
$('#NewFlashSalesPlanButton').click(function (e) {
e.preventDefault();
createModal.open();
});
});

41
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Web/Pages/EShop/Plugins/FlashSales/FlashSalesResults/FlashSalesResult/Index.cshtml

@ -0,0 +1,41 @@
@page
@using EasyAbp.EShop.Plugins.FlashSales.Permissions
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Mvc.Localization
@using Volo.Abp.AspNetCore.Mvc.UI.Layout
@using EasyAbp.EShop.Plugins.FlashSales.Web.Pages.EShop.Plugins.FlashSales.FlashSalesResults.FlashSalesResult
@using EasyAbp.EShop.Plugins.FlashSales.Localization
@using EasyAbp.EShop.Plugins.FlashSales.Web.Menus
@model IndexModel
@inject IPageLayout PageLayout
@inject IHtmlLocalizer<FlashSalesResource> L
@inject IAuthorizationService Authorization
@{
PageLayout.Content.Title = L["FlashSalesResult"].Value;
PageLayout.Content.BreadCrumb.Add(L["Menu:FlashSalesResult"].Value);
PageLayout.Content.MenuItemName = FlashSalesMenus.FlashSalesResult;
}
@section scripts
{
<abp-script src="/Pages/EShop/Plugins/FlashSales/FlashSalesResults/FlashSalesResult/index.js" />
}
@section styles
{
<abp-style src="/Pages/EShop/Plugins/FlashSales/FlashSalesResults/FlashSalesResult/index.css" />
}
<abp-card>
<abp-card-header>
<abp-row>
<abp-column size-md="_6">
<abp-card-title>@L["FlashSalesResult"]</abp-card-title>
</abp-column>
</abp-row>
</abp-card-header>
<abp-card-body>
<abp-table striped-rows="true" id="FlashSalesResultTable" class="nowrap" />
</abp-card-body>
</abp-card>

11
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Web/Pages/EShop/Plugins/FlashSales/FlashSalesResults/FlashSalesResult/Index.cshtml.cs

@ -0,0 +1,11 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace EasyAbp.EShop.Plugins.FlashSales.Web.Pages.EShop.Plugins.FlashSales.FlashSalesResults.FlashSalesResult;
public class IndexModel : PageModel
{
public void OnGet()
{
}
}

22
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Web/Pages/EShop/Plugins/FlashSales/FlashSalesResults/FlashSalesResult/ViewModal.cshtml

@ -0,0 +1,22 @@
@page
@using EasyAbp.EShop.Plugins.FlashSales.Localization
@using Microsoft.AspNetCore.Mvc.Localization
@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal
@using EasyAbp.EShop.Plugins.FlashSales.Web.Pages.EShop.Plugins.FlashSales.FlashSalesResults.FlashSalesResult
@inject IHtmlLocalizer<FlashSalesResource> L
@model ViewModalModel
@{
Layout = null;
}
<abp-dynamic-form abp-model="ViewModel" data-ajaxForm="true" asp-page="ViewModal">
<abp-modal>
<abp-modal-header title="@L["ViewFlashSalesResult"].Value"></abp-modal-header>
<abp-modal-body>
<abp-input asp-for="Id" />
<abp-form-content />
</abp-modal-body>
<abp-modal-footer buttons="@(AbpModalButtons.Close)"></abp-modal-footer>
</abp-modal>
</abp-dynamic-form>

31
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Web/Pages/EShop/Plugins/FlashSales/FlashSalesResults/FlashSalesResult/ViewModal.cshtml.cs

@ -0,0 +1,31 @@
using System;
using System.Threading.Tasks;
using EasyAbp.EShop.Plugins.FlashSales.FlashSalesResults;
using EasyAbp.EShop.Plugins.FlashSales.FlashSalesResults.Dtos;
using EasyAbp.EShop.Plugins.FlashSales.Web.Pages.EShop.Plugins.FlashSales.FlashSalesResults.FlashSalesResult.ViewModels;
using Microsoft.AspNetCore.Mvc;
namespace EasyAbp.EShop.Plugins.FlashSales.Web.Pages.EShop.Plugins.FlashSales.FlashSalesResults.FlashSalesResult;
public class ViewModalModel : FlashSalesPageModel
{
[HiddenInput]
[BindProperty(SupportsGet = true)]
public Guid Id { get; set; }
[BindProperty]
public ViewFlashSalesResultViewModel ViewModel { get; set; }
protected IFlashSalesResultAppService Service { get; }
public ViewModalModel(IFlashSalesResultAppService service)
{
Service = service;
}
public virtual async Task OnGetAsync()
{
var dto = await Service.GetAsync(Id);
ViewModel = ObjectMapper.Map<FlashSalesResultDto, ViewFlashSalesResultViewModel>(dto);
}
}

23
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Web/Pages/EShop/Plugins/FlashSales/FlashSalesResults/FlashSalesResult/ViewModels/ViewFlashSalesResultViewModel.cs

@ -0,0 +1,23 @@
using System;
using System.ComponentModel.DataAnnotations;
using EasyAbp.EShop.Plugins.FlashSales.FlashSalesResults;
namespace EasyAbp.EShop.Plugins.FlashSales.Web.Pages.EShop.Plugins.FlashSales.FlashSalesResults.FlashSalesResult.ViewModels;
public class ViewFlashSalesResultViewModel
{
[Display(Name = "FlashSalesResultStoreId")]
public virtual Guid StoreId { get; protected set; }
[Display(Name = "FlashSalesResultPlanId")]
public virtual Guid PlanId { get; protected set; }
[Display(Name = "FlashSalesResultStatus")]
public virtual FlashSalesResultStatus Status { get; protected set; }
[Display(Name = "FlashSalesResultUserId")]
public virtual Guid UserId { get; protected set; }
[Display(Name = "FlashSalesResultOrderId")]
public virtual Guid? OrderId { get; protected set; }
}

0
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Web/Pages/EShop/Plugins/FlashSales/FlashSalesResults/FlashSalesResult/index.css

62
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Web/Pages/EShop/Plugins/FlashSales/FlashSalesResults/FlashSalesResult/index.js

@ -0,0 +1,62 @@
$(function () {
var l = abp.localization.getResource('EasyAbpEShopPluginsFlashSales');
var service = easyAbp.eShop.plugins.flashSales.flashSalesPlans.flashSalesPlan;
var viewModal = new abp.ModalManager(abp.appPath + 'EShop/Plugins/FlashSales/FlashSalesResults/FlashSalesResult/ViewModal');
var dataTable = $('#FlashSalesResultTable').DataTable(abp.libs.datatables.normalizeConfiguration({
processing: true,
serverSide: true,
paging: true,
searching: false,
autoWidth: false,
scrollCollapse: true,
order: [[6, "desc"]],
ajax: abp.libs.datatables.createAjax(service.getList),
columnDefs: [
{
rowAction: {
items:
[
{
text: l('ViewFlashSalesPlan'),
action: function (data) {
viewModal.open({ id: data.record.id });
}
}
]
}
},
{
title: l('FlashSalesResultStoreId'),
data: "storeId"
},
{
title: l('FlashSalesResultPlanId'),
data: "planId"
},
{
title: l('FlashSalesResultStatus'),
data: "status"
},
{
title: l('FlashSalesResultUserId'),
data: "userId"
},
{
title: l('FlashSalesResultOrderId'),
data: "orderId"
},
{
title: l('FlashSalesResultCreationTime'),
data: "creationTime",
dataFormat: 'datetime'
},
]
}));
viewModal.onResult(function () {
dataTable.ajax.reload();
});
});

5
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Web/Pages/EasyAbp/EShop/Plugins/FlashSales/Index.cshtml → plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Web/Pages/EShop/Plugins/FlashSales/Index.cshtml

@ -1,11 +1,12 @@
@page
@using Microsoft.Extensions.Localization
@using EasyAbp.EShop.Plugins.FlashSales.Localization
@using EasyAbp.EShop.Plugins.FlashSales.Web.Pages.EasyAbp.EShop.Plugins.FlashSales
@using EasyAbp.EShop.Plugins.FlashSales.Web.Pages.EShop.Plugins.FlashSales
@model IndexModel
@inject IStringLocalizer<FlashSalesResource> L
@{
}
<h1>FlashSales</h1>
<p>@L["SamplePageMessage"]</p>

2
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Web/Pages/EasyAbp/EShop/Plugins/FlashSales/Index.cshtml.cs → plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Web/Pages/EShop/Plugins/FlashSales/Index.cshtml.cs

@ -1,4 +1,4 @@
namespace EasyAbp.EShop.Plugins.FlashSales.Web.Pages.EasyAbp.EShop.Plugins.FlashSales;
namespace EasyAbp.EShop.Plugins.FlashSales.Web.Pages.EShop.Plugins.FlashSales;
public class IndexModel : FlashSalesPageModel
{

0
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Web/Pages/EasyAbp/EShop/Plugins/FlashSales/_ViewImports.cshtml → plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Web/Pages/EShop/Plugins/FlashSales/_ViewImports.cshtml

Loading…
Cancel
Save