From 6f690322832567b9cd29604b3b36c8abde99ba51 Mon Sep 17 00:00:00 2001 From: Basil Kotov Date: Fri, 10 Oct 2025 10:43:43 +0100 Subject: [PATCH 01/29] init --- .editorconfig | 169 ++ .gitattributes | 62 - .gitignore | 257 ++- CommonAssemblyInfo.cs | 28 - .../Datatrans.Checkout.Core.csproj | 85 - .../Datatrans.Checkout.Core.nuspec | 18 - .../Model/DatatransAirlineData.cs | 59 - .../Model/DatatransCheckoutSettings.cs | 51 - .../Model/DatatransErrorCodes.cs | 7 - .../Model/DatatransRefundRequest.cs | 22 - .../Model/DatatransRefundResponse.cs | 19 - .../Model/DatatransRequest.cs | 13 - .../Model/DatatransResponse.cs | 17 - .../Model/DatatransSettlementRequest.cs | 18 - .../Model/DatatransSettlementResponse.cs | 9 - .../Model/DatatransTransactionRequest.cs | 13 - .../Model/DatatransTransactionResponse.cs | 37 - .../Model/GetAirlineDataContext.cs | 25 - .../Properties/AssemblyInfo.cs | 4 - .../IDatatransCapturePaymentService.cs | 9 - .../Services/IDatatransCheckoutService.cs | 9 - .../Services/IDatatransClient.cs | 15 - Datatrans.Checkout.Core/app.config | 11 - Datatrans.Checkout.Core/packages.config | 6 - .../Datatrans.Checkout.Tests.csproj | 140 -- Datatrans.Checkout.Tests/DatatransTests.cs | 108 - .../DatatranscheckoutPaymentMethodTests.cs | 218 -- .../Properties/AssemblyInfo.cs | 4 - .../ServiceResponseCovertionTests.cs | 117 - Datatrans.Checkout.Tests/SignProviderTests.cs | 81 - Datatrans.Checkout.Tests/app.config | 11 - .../data/refundResponseError.xml | 19 - .../data/refundResponseSuccess.xml | 21 - .../data/settleResponseError.xml | 18 - .../data/settleResponseSuccess.xml | 17 - .../data/statusResponseError.xml | 15 - .../data/statusResponseSuccess.xml | 28 - Datatrans.Checkout.Tests/packages.config | 17 - Datatrans.Checkout.sln | 34 - Datatrans.Checkout/Content/logo.png | Bin 9389 -> 0 bytes Datatrans.Checkout/Content/paymentForm.liquid | 33 - Datatrans.Checkout/Datatrans.Checkout.csproj | 191 -- .../Converters/RefundConverter.cs | 69 - .../SettlementServiceRequestConverter.cs | 68 - .../SettlementServiceResponseConverter.cs | 38 - .../StatusServiceRequestConverter.cs | 25 - .../StatusServiceResponseConverter.cs | 54 - .../DatatransClient/DatatransClient.cs | 137 -- .../DatatransClient/Models/RefundResponse.cs | 477 ---- .../DatatransClient/Models/ServiceResponse.cs | 9 - .../Models/SettlementServiceReference.cs | 303 --- .../Models/StatusServiceReference.cs | 606 ----- .../Extensions/DecimalExtensions.cs | 12 - Datatrans.Checkout/Helpers/RoundingHelper.cs | 17 - .../DatatransCheckoutPaymentMethod.cs | 480 ---- Datatrans.Checkout/Module.cs | 53 - Datatrans.Checkout/Properties/AssemblyInfo.cs | 4 - .../DatatransCapturePaymentServiceEmptyImp.cs | 20 - .../Services/DatatransCheckoutService.cs | 70 - Datatrans.Checkout/Services/ISignProvider.cs | 9 - Datatrans.Checkout/Services/SignProvider.cs | 83 - Datatrans.Checkout/Web.Debug.config | 30 - Datatrans.Checkout/Web.Release.config | 31 - Datatrans.Checkout/Web.config | 11 - Datatrans.Checkout/app.config | 11 - Datatrans.Checkout/module.ignore | 3 - Datatrans.Checkout/module.manifest | 135 -- Datatrans.Checkout/packages.config | 14 - Directory.Build.props | 12 + Jenkinsfile | 2 - LICENSE | 12 + NuGet/build.bat | 14 - NuGet/icon.png | Bin 12302 -> 0 bytes NuGet/publish.bat | 17 - README.md | 5 + VirtoCommerce.Datatrans.sln | 64 + VirtoCommerce.Datatrans.sln.DotSettings | 7 + docs/media/diagram-db-model.drawio | 1 + docs/media/diagram-db-model.png | Bin 0 -> 19704 bytes module.ignore | 0 src/VirtoCommerce.Datatrans.Core/Events/.keep | 0 .../DatatransAuthorizeAuthenticatedRequest.cs | 9 + .../Models/DatatransAuthorizeResponse.cs | 9 + .../Models/DatatransCaptureRequest.cs | 8 + .../Models/DatatransCaptureResponse.cs | 9 + .../Models/DatatransError.cs | 8 + .../Models/DatatransInitRequest.cs | 12 + .../Models/DatatransInitResponse.cs | 7 + .../Models/DatatransOptions.cs | 43 + .../Models/DatatransPaymentMethodOptions.cs | 7 + .../Models/DatatransPushPayload.cs | 14 + .../Models/DatatransRefundRequest.cs | 8 + .../Models/DatatransRefundResponse.cs | 9 + .../Models/DatatransRequest.cs | 9 + .../Models/DatatransResponse.cs | 7 + .../Models/DatatransSignatureInput.cs | 7 + .../Models/DatatransTransaction.cs | 12 + .../Models/DatatransVoidResponse.cs | 9 + .../ModuleConstants.cs | 38 + .../Notifications/.keep | 0 .../Services/IDatatransClient.cs | 26 + .../VirtoCommerce.Datatrans.Core.csproj | 16 + .../Providers/DatatransPaymentMethod.cs | 212 ++ .../Services/DatatransClient.cs | 62 + .../VirtoCommerce.Datatrans.Data.csproj | 19 + .../Content/logo.png | Bin 0 -> 14153 bytes .../Controllers/TestController.cs | 30 + .../en.VirtoCommerce.Datatrans.json | 18 + src/VirtoCommerce.Datatrans.Web/Module.cs | 45 + .../VirtoCommerce.Datatrans.Web.csproj | 23 + .../module.manifest | 33 + .../package-lock.json | 1985 +++++++++++++++++ src/VirtoCommerce.Datatrans.Web/package.json | 20 + .../webpack.config.js | 51 + tests/VirtoCommerce.Datatrans.Tests/Test.cs | 13 + .../VirtoCommerce.Datatrans.Tests.csproj | 24 + 116 files changed, 3291 insertions(+), 4449 deletions(-) create mode 100644 .editorconfig delete mode 100644 CommonAssemblyInfo.cs delete mode 100644 Datatrans.Checkout.Core/Datatrans.Checkout.Core.csproj delete mode 100644 Datatrans.Checkout.Core/Datatrans.Checkout.Core.nuspec delete mode 100644 Datatrans.Checkout.Core/Model/DatatransAirlineData.cs delete mode 100644 Datatrans.Checkout.Core/Model/DatatransCheckoutSettings.cs delete mode 100644 Datatrans.Checkout.Core/Model/DatatransErrorCodes.cs delete mode 100644 Datatrans.Checkout.Core/Model/DatatransRefundRequest.cs delete mode 100644 Datatrans.Checkout.Core/Model/DatatransRefundResponse.cs delete mode 100644 Datatrans.Checkout.Core/Model/DatatransRequest.cs delete mode 100644 Datatrans.Checkout.Core/Model/DatatransResponse.cs delete mode 100644 Datatrans.Checkout.Core/Model/DatatransSettlementRequest.cs delete mode 100644 Datatrans.Checkout.Core/Model/DatatransSettlementResponse.cs delete mode 100644 Datatrans.Checkout.Core/Model/DatatransTransactionRequest.cs delete mode 100644 Datatrans.Checkout.Core/Model/DatatransTransactionResponse.cs delete mode 100644 Datatrans.Checkout.Core/Model/GetAirlineDataContext.cs delete mode 100644 Datatrans.Checkout.Core/Properties/AssemblyInfo.cs delete mode 100644 Datatrans.Checkout.Core/Services/IDatatransCapturePaymentService.cs delete mode 100644 Datatrans.Checkout.Core/Services/IDatatransCheckoutService.cs delete mode 100644 Datatrans.Checkout.Core/Services/IDatatransClient.cs delete mode 100644 Datatrans.Checkout.Core/app.config delete mode 100644 Datatrans.Checkout.Core/packages.config delete mode 100644 Datatrans.Checkout.Tests/Datatrans.Checkout.Tests.csproj delete mode 100644 Datatrans.Checkout.Tests/DatatransTests.cs delete mode 100644 Datatrans.Checkout.Tests/DatatranscheckoutPaymentMethodTests.cs delete mode 100644 Datatrans.Checkout.Tests/Properties/AssemblyInfo.cs delete mode 100644 Datatrans.Checkout.Tests/ServiceResponseCovertionTests.cs delete mode 100644 Datatrans.Checkout.Tests/SignProviderTests.cs delete mode 100644 Datatrans.Checkout.Tests/app.config delete mode 100644 Datatrans.Checkout.Tests/data/refundResponseError.xml delete mode 100644 Datatrans.Checkout.Tests/data/refundResponseSuccess.xml delete mode 100644 Datatrans.Checkout.Tests/data/settleResponseError.xml delete mode 100644 Datatrans.Checkout.Tests/data/settleResponseSuccess.xml delete mode 100644 Datatrans.Checkout.Tests/data/statusResponseError.xml delete mode 100644 Datatrans.Checkout.Tests/data/statusResponseSuccess.xml delete mode 100644 Datatrans.Checkout.Tests/packages.config delete mode 100644 Datatrans.Checkout.sln delete mode 100644 Datatrans.Checkout/Content/logo.png delete mode 100644 Datatrans.Checkout/Content/paymentForm.liquid delete mode 100644 Datatrans.Checkout/Datatrans.Checkout.csproj delete mode 100644 Datatrans.Checkout/DatatransClient/Converters/RefundConverter.cs delete mode 100644 Datatrans.Checkout/DatatransClient/Converters/SettlementServiceRequestConverter.cs delete mode 100644 Datatrans.Checkout/DatatransClient/Converters/SettlementServiceResponseConverter.cs delete mode 100644 Datatrans.Checkout/DatatransClient/Converters/StatusServiceRequestConverter.cs delete mode 100644 Datatrans.Checkout/DatatransClient/Converters/StatusServiceResponseConverter.cs delete mode 100644 Datatrans.Checkout/DatatransClient/DatatransClient.cs delete mode 100644 Datatrans.Checkout/DatatransClient/Models/RefundResponse.cs delete mode 100644 Datatrans.Checkout/DatatransClient/Models/ServiceResponse.cs delete mode 100644 Datatrans.Checkout/DatatransClient/Models/SettlementServiceReference.cs delete mode 100644 Datatrans.Checkout/DatatransClient/Models/StatusServiceReference.cs delete mode 100644 Datatrans.Checkout/Extensions/DecimalExtensions.cs delete mode 100644 Datatrans.Checkout/Helpers/RoundingHelper.cs delete mode 100644 Datatrans.Checkout/Managers/DatatransCheckoutPaymentMethod.cs delete mode 100644 Datatrans.Checkout/Module.cs delete mode 100644 Datatrans.Checkout/Properties/AssemblyInfo.cs delete mode 100644 Datatrans.Checkout/Services/DatatransCapturePaymentServiceEmptyImp.cs delete mode 100644 Datatrans.Checkout/Services/DatatransCheckoutService.cs delete mode 100644 Datatrans.Checkout/Services/ISignProvider.cs delete mode 100644 Datatrans.Checkout/Services/SignProvider.cs delete mode 100644 Datatrans.Checkout/Web.Debug.config delete mode 100644 Datatrans.Checkout/Web.Release.config delete mode 100644 Datatrans.Checkout/Web.config delete mode 100644 Datatrans.Checkout/app.config delete mode 100644 Datatrans.Checkout/module.ignore delete mode 100644 Datatrans.Checkout/module.manifest delete mode 100644 Datatrans.Checkout/packages.config create mode 100644 Directory.Build.props delete mode 100644 Jenkinsfile create mode 100644 LICENSE delete mode 100644 NuGet/build.bat delete mode 100644 NuGet/icon.png delete mode 100644 NuGet/publish.bat create mode 100644 VirtoCommerce.Datatrans.sln create mode 100644 VirtoCommerce.Datatrans.sln.DotSettings create mode 100644 docs/media/diagram-db-model.drawio create mode 100644 docs/media/diagram-db-model.png create mode 100644 module.ignore create mode 100644 src/VirtoCommerce.Datatrans.Core/Events/.keep create mode 100644 src/VirtoCommerce.Datatrans.Core/Models/DatatransAuthorizeAuthenticatedRequest.cs create mode 100644 src/VirtoCommerce.Datatrans.Core/Models/DatatransAuthorizeResponse.cs create mode 100644 src/VirtoCommerce.Datatrans.Core/Models/DatatransCaptureRequest.cs create mode 100644 src/VirtoCommerce.Datatrans.Core/Models/DatatransCaptureResponse.cs create mode 100644 src/VirtoCommerce.Datatrans.Core/Models/DatatransError.cs create mode 100644 src/VirtoCommerce.Datatrans.Core/Models/DatatransInitRequest.cs create mode 100644 src/VirtoCommerce.Datatrans.Core/Models/DatatransInitResponse.cs create mode 100644 src/VirtoCommerce.Datatrans.Core/Models/DatatransOptions.cs create mode 100644 src/VirtoCommerce.Datatrans.Core/Models/DatatransPaymentMethodOptions.cs create mode 100644 src/VirtoCommerce.Datatrans.Core/Models/DatatransPushPayload.cs create mode 100644 src/VirtoCommerce.Datatrans.Core/Models/DatatransRefundRequest.cs create mode 100644 src/VirtoCommerce.Datatrans.Core/Models/DatatransRefundResponse.cs create mode 100644 src/VirtoCommerce.Datatrans.Core/Models/DatatransRequest.cs create mode 100644 src/VirtoCommerce.Datatrans.Core/Models/DatatransResponse.cs create mode 100644 src/VirtoCommerce.Datatrans.Core/Models/DatatransSignatureInput.cs create mode 100644 src/VirtoCommerce.Datatrans.Core/Models/DatatransTransaction.cs create mode 100644 src/VirtoCommerce.Datatrans.Core/Models/DatatransVoidResponse.cs create mode 100644 src/VirtoCommerce.Datatrans.Core/ModuleConstants.cs create mode 100644 src/VirtoCommerce.Datatrans.Core/Notifications/.keep create mode 100644 src/VirtoCommerce.Datatrans.Core/Services/IDatatransClient.cs create mode 100644 src/VirtoCommerce.Datatrans.Core/VirtoCommerce.Datatrans.Core.csproj create mode 100644 src/VirtoCommerce.Datatrans.Data/Providers/DatatransPaymentMethod.cs create mode 100644 src/VirtoCommerce.Datatrans.Data/Services/DatatransClient.cs create mode 100644 src/VirtoCommerce.Datatrans.Data/VirtoCommerce.Datatrans.Data.csproj create mode 100644 src/VirtoCommerce.Datatrans.Web/Content/logo.png create mode 100644 src/VirtoCommerce.Datatrans.Web/Controllers/TestController.cs create mode 100644 src/VirtoCommerce.Datatrans.Web/Localizations/en.VirtoCommerce.Datatrans.json create mode 100644 src/VirtoCommerce.Datatrans.Web/Module.cs create mode 100644 src/VirtoCommerce.Datatrans.Web/VirtoCommerce.Datatrans.Web.csproj create mode 100644 src/VirtoCommerce.Datatrans.Web/module.manifest create mode 100644 src/VirtoCommerce.Datatrans.Web/package-lock.json create mode 100644 src/VirtoCommerce.Datatrans.Web/package.json create mode 100644 src/VirtoCommerce.Datatrans.Web/webpack.config.js create mode 100644 tests/VirtoCommerce.Datatrans.Tests/Test.cs create mode 100644 tests/VirtoCommerce.Datatrans.Tests/VirtoCommerce.Datatrans.Tests.csproj diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..d467f1b --- /dev/null +++ b/.editorconfig @@ -0,0 +1,169 @@ +root = true + +[*] +charset = utf-8 +indent_style = space +indent_size = 2 +end_of_line = crlf +trim_trailing_whitespace = true +insert_final_newline = true + +# Project files +[*.{csproj,props}] +insert_final_newline = false + +# HTML files +[*.{html,htm}] +insert_final_newline = false + +# Code +[*.{cs,js,ts,ps1,sh,bat,cmd}] +indent_size = 4 + +# Dotnet code style settings +[*.{cs,vb}] + +# Sort using and Import directives with System.* appearing first +dotnet_sort_system_directives_first = true + +# Avoid "this." and "Me." if not necessary +dotnet_style_qualification_for_field = false:suggestion +dotnet_style_qualification_for_property = false:suggestion +dotnet_style_qualification_for_method = false:suggestion +dotnet_style_qualification_for_event = false:suggestion + +# Use language keywords instead of framework type names for type references +dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion +dotnet_style_predefined_type_for_member_access = true:suggestion + +# Use explicit accessibility modifiers +dotnet_style_require_accessibility_modifiers = true:suggestion + +# Suggest more modern language features when available +dotnet_style_object_initializer = true:suggestion +dotnet_style_collection_initializer = true:suggestion +dotnet_style_coalesce_expression = true:suggestion +dotnet_style_null_propagation = true:suggestion +dotnet_style_explicit_tuple_names = true:suggestion +dotnet_prefer_inferred_tuple_names = true:suggestion +dotnet_prefer_inferred_anonymous_type_member_names = true:suggestion + +# CSharp code style settings +[*.cs] + +# Prefer curly braces even for one line of code +csharp_prefer_braces = true:suggestion + +# Prefer "var" everywhere +csharp_style_var_for_built_in_types = true:suggestion +csharp_style_var_when_type_is_apparent = true:suggestion +csharp_style_var_elsewhere = true:suggestion + +# Prefer method-like constructs to have a block body +csharp_style_expression_bodied_methods = false:none +csharp_style_expression_bodied_constructors = false:none +csharp_style_expression_bodied_operators = false:none + +# Prefer property-like constructs to have an expression-body +csharp_style_expression_bodied_properties = true:none +csharp_style_expression_bodied_indexers = true:none +csharp_style_expression_bodied_accessors = true:none + +# Suggest more modern language features when available +csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion +csharp_style_pattern_matching_over_as_with_null_check = true:suggestion +csharp_style_inlined_variable_declaration = true:suggestion +csharp_style_throw_expression = true:suggestion +csharp_style_conditional_delegate_call = true:suggestion +csharp_prefer_simple_default_expression = true:suggestion +csharp_style_deconstructed_variable_declaration = true:suggestion +csharp_style_pattern_local_over_anonymous_function = true:suggestion + +# Newline settings +csharp_new_line_before_open_brace = all +csharp_new_line_before_else = true +csharp_new_line_before_catch = true +csharp_new_line_before_finally = true +csharp_new_line_before_members_in_object_initializers = true +csharp_new_line_before_members_in_anonymous_types = true +csharp_new_line_between_query_expression_clauses = true + +csharp_indent_case_contents = true +csharp_indent_switch_labels = true +csharp_indent_labels = flush_left + +csharp_space_after_cast = false +csharp_space_after_keywords_in_control_flow_statements = true +csharp_space_between_method_declaration_parameter_list_parentheses = false +csharp_space_between_method_call_parameter_list_parentheses = false +csharp_space_between_parentheses = false + +csharp_preserve_single_line_statements = false +csharp_preserve_single_line_blocks = true +csharp_using_directive_placement = outside_namespace:silent +csharp_prefer_simple_using_statement = true:suggestion +csharp_style_namespace_declarations = file_scoped:silent +csharp_style_prefer_method_group_conversion = true:silent +csharp_style_prefer_top_level_statements = true:silent +csharp_style_expression_bodied_lambdas = true:silent +csharp_style_expression_bodied_local_functions = false:silent + +[*.{cs,vb}] +#### Naming styles #### + +# Naming rules + +dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion +dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface +dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i + +dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.types_should_be_pascal_case.symbols = types +dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case + +dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members +dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case + +# Symbol specifications + +dotnet_naming_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.begins_with_i.required_prefix = I +dotnet_naming_style.begins_with_i.required_suffix = +dotnet_naming_style.begins_with_i.word_separator = +dotnet_naming_style.begins_with_i.capitalization = pascal_case + +dotnet_naming_style.pascal_case.required_prefix = +dotnet_naming_style.pascal_case.required_suffix = +dotnet_naming_style.pascal_case.word_separator = +dotnet_naming_style.pascal_case.capitalization = pascal_case + +dotnet_naming_style.pascal_case.required_prefix = +dotnet_naming_style.pascal_case.required_suffix = +dotnet_naming_style.pascal_case.word_separator = +dotnet_naming_style.pascal_case.capitalization = pascal_case +dotnet_style_operator_placement_when_wrapping = beginning_of_line +tab_width = 4 +dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion +dotnet_style_prefer_auto_properties = true:silent +dotnet_style_prefer_simplified_boolean_expressions = true:suggestion +dotnet_style_prefer_conditional_expression_over_assignment = true:silent +dotnet_style_prefer_conditional_expression_over_return = true:silent +dotnet_style_prefer_inferred_tuple_names = true:suggestion +dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion +dotnet_style_prefer_compound_assignment = true:suggestion +dotnet_style_prefer_simplified_interpolation = true:suggestion +dotnet_style_namespace_match_folder = true:suggestion diff --git a/.gitattributes b/.gitattributes index 1ff0c42..176a458 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,63 +1 @@ -############################################################################### -# Set default behavior to automatically normalize line endings. -############################################################################### * text=auto - -############################################################################### -# Set default behavior for command prompt diff. -# -# This is need for earlier builds of msysgit that does not have it on by -# default for csharp files. -# Note: This is only used by command line -############################################################################### -#*.cs diff=csharp - -############################################################################### -# Set the merge driver for project and solution files -# -# Merging from the command prompt will add diff markers to the files if there -# are conflicts (Merging from VS is not affected by the settings below, in VS -# the diff markers are never inserted). Diff markers may cause the following -# file extensions to fail to load in VS. An alternative would be to treat -# these files as binary and thus will always conflict and require user -# intervention with every merge. To do so, just uncomment the entries below -############################################################################### -#*.sln merge=binary -#*.csproj merge=binary -#*.vbproj merge=binary -#*.vcxproj merge=binary -#*.vcproj merge=binary -#*.dbproj merge=binary -#*.fsproj merge=binary -#*.lsproj merge=binary -#*.wixproj merge=binary -#*.modelproj merge=binary -#*.sqlproj merge=binary -#*.wwaproj merge=binary - -############################################################################### -# behavior for image files -# -# image files are treated as binary by default. -############################################################################### -#*.jpg binary -#*.png binary -#*.gif binary - -############################################################################### -# diff behavior for common document formats -# -# Convert binary document formats to text before diffing them. This feature -# is only available from the command line. Turn it on by uncommenting the -# entries below. -############################################################################### -#*.doc diff=astextplain -#*.DOC diff=astextplain -#*.docx diff=astextplain -#*.DOCX diff=astextplain -#*.dot diff=astextplain -#*.DOT diff=astextplain -#*.pdf diff=astextplain -#*.PDF diff=astextplain -#*.rtf diff=astextplain -#*.RTF diff=astextplain diff --git a/.gitignore b/.gitignore index 184789a..ea99cfe 100644 --- a/.gitignore +++ b/.gitignore @@ -1,36 +1,72 @@ ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore # User-specific files *.suo *.user +*.userosscache *.sln.docstates -# Build results +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs +# Build results [Dd]ebug/ +[Dd]ebugPublic/ [Rr]elease/ -bin/x64/ -bin/x86/ -build/ +[Rr]eleases/ +x64/ +x86/ +bld/ [Bb]in/ -[Bb]in/**/* [Oo]bj/ +[Ll]og/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ -# Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets -!packages/*/build/ +# Visual Studio 2017 auto generated files +Generated\ Files/ # MSTest test Results [Tt]est[Rr]esult*/ [Bb]uild[Ll]og.* +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio *_i.c *_p.c +*_h.h *.ilk *.meta *.obj +*.iobj *.pch *.pdb +*.ipdb *.pgc *.pgd *.rsp @@ -45,21 +81,34 @@ build/ *.vssscc .builds *.pidb -*.log +*.svclog *.scc +# Chutzpah Test files +_Chutzpah* + # Visual C++ cache files ipch/ *.aps *.ncb +*.opendb *.opensdf *.sdf *.cachefile +*.VC.db +*.VC.VC.opendb # Visual Studio profiler *.psess *.vsp *.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ # Guidance Automation Toolkit *.gpState @@ -67,6 +116,10 @@ ipch/ # ReSharper is a .NET coding add-in _ReSharper*/ *.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode # TeamCity is a build add-in _TeamCity* @@ -74,9 +127,25 @@ _TeamCity* # DotCover is a Code Coverage Tool *.dotCover +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Visual Studio code coverage results +*.coverage +*.coveragexml + # NCrunch -*.ncrunch* +_NCrunch_* .*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ # Installshield output folder [Ee]xpress/ @@ -95,64 +164,176 @@ DocProject/Help/html publish/ # Publish Web Output -*.Publish.xml +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted *.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ -# NuGet Packages Directory -## TODO: If you have NuGet Package Restore enabled, uncomment the next line -packages/ +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets -# Windows Azure Build Output -csx +# Microsoft Azure Build Output +csx/ *.build.csdef -# Windows Store app package directory +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ # Others -sql/ -*.Cache ClientBin/ -[Ss]tyle[Cc]op.* ~$* *~ *.dbmdl -*.[Pp]ublish.xml +*.dbproj.schemaview +*.jfm *.pfx *.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ # RIA/Silverlight projects Generated_Code/ -# Backup & report files from converting an old project file to a newer -# Visual Studio version. Backup files are not needed, because we have git ;-) +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) _UpgradeReport_Files/ Backup*/ UpgradeLog*.XML UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak # SQL Server files -App_Data/*.mdf -App_Data/*.ldf +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ -# ========================= -# Windows detritus -# ========================= +# FAKE - F# Make +.fake/ -# Windows image file caches -Thumbs.db -ehthumbs.db +# JetBrains Rider +.idea/ +*.sln.iml -# Folder config file -Desktop.ini +# CodeRush +.cr/ -# Recycle Bin used on file shares -$RECYCLE.BIN/ +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc -# Mac crap -.DS_Store +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# Virto *.nupkg *.zip - -.vs/ +.nuke +dist/ +**/Properties/launchSettings.json diff --git a/CommonAssemblyInfo.cs b/CommonAssemblyInfo.cs deleted file mode 100644 index 4168720..0000000 --- a/CommonAssemblyInfo.cs +++ /dev/null @@ -1,28 +0,0 @@ -// ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -// -// Copyright © VirtoCommerce. All rights reserved. -// -// -// Virto Commerce -// -// ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- - -using System; -using System.Reflection; -using System.Runtime.InteropServices; - -[assembly: AssemblyCompany("VirtoCommerce")] -[assembly: AssemblyProduct("Virto Commerce Datatrans Module")] -[assembly: AssemblyCopyright("Copyright © VirtoCommerce 2020")] - -[assembly: AssemblyFileVersion("1.1.2.0")] -[assembly: AssemblyVersion("1.1.2.0")] - -#if DEBUG -[assembly: AssemblyConfiguration("Debug")] -#else -[assembly: AssemblyConfiguration("Release")] -#endif - -[assembly: ComVisible(false)] -[assembly: CLSCompliant(true)] diff --git a/Datatrans.Checkout.Core/Datatrans.Checkout.Core.csproj b/Datatrans.Checkout.Core/Datatrans.Checkout.Core.csproj deleted file mode 100644 index 6aae8a6..0000000 --- a/Datatrans.Checkout.Core/Datatrans.Checkout.Core.csproj +++ /dev/null @@ -1,85 +0,0 @@ - - - - - Debug - AnyCPU - {62A342C4-FEE9-474F-9433-43C81D9CEAC9} - Library - Properties - Datatrans.Checkout.Core - Datatrans.Checkout.Core - v4.6.1 - 512 - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - ..\packages\Newtonsoft.Json.11.0.2\lib\net45\Newtonsoft.Json.dll - - - - - - - - - - - ..\packages\VirtoCommerce.Domain.2.24.19\lib\net461\VirtoCommerce.Domain.dll - True - - - ..\packages\VirtoCommerce.Platform.Core.2.13.24\lib\net461\VirtoCommerce.Platform.Core.dll - - - - - Properties\CommonAssemblyInfo.cs - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Datatrans.Checkout.Core/Datatrans.Checkout.Core.nuspec b/Datatrans.Checkout.Core/Datatrans.Checkout.Core.nuspec deleted file mode 100644 index fd3b3a5..0000000 --- a/Datatrans.Checkout.Core/Datatrans.Checkout.Core.nuspec +++ /dev/null @@ -1,18 +0,0 @@ - - - - VirtoCommerce.DatatransModule.Core - 1.0.4 - VirtoCommerce.DatatransModule.Core - - - - VirtoCommerce - VirtoCommerce - https://github.com/VirtoCommerce/vc-module-datatrans - https://github.com/VirtoCommerce/vc-module-datatrans/raw/master/NuGet/icon.png - false - VirtoCommerce Datatrans payment gateway implementation - Copyright © VirtoCommerce 2011-2017 - - \ No newline at end of file diff --git a/Datatrans.Checkout.Core/Model/DatatransAirlineData.cs b/Datatrans.Checkout.Core/Model/DatatransAirlineData.cs deleted file mode 100644 index f6f0c6e..0000000 --- a/Datatrans.Checkout.Core/Model/DatatransAirlineData.cs +++ /dev/null @@ -1,59 +0,0 @@ -using System.Collections.Generic; - -namespace Datatrans.Checkout.Core.Model -{ - public class DatatransAirlineData - { - public DatatransAirlineData() - { - Tickets = new List(); - } - - public string CountryCode { get; set; } - - public string AgentCode { get; set; } - - public string PNR { get; set; } - - public string IssueDate { get; set; } - - public IList Tickets { get; set; } - } - - public class DatatransTicket - { - public DatatransTicket() - { - Flights = new List(); - } - - public string Index { get; set; } - - public string TicketNumber { get; set; } - - public string PassengerName { get; set; } - - public string DescrCode { get; set; } - - public IList Flights { get; set; } - } - - public class DatatransFlight - { - public string Index { get; set; } - - public string Origin { get; set; } - - public string Destination { get; set; } - - public string Carrier { get; set; } - - public string Class { get; set; } - - public string FareBasis { get; set; } - - public string FlightNumber { get; set; } - - public string FlightDate { get; set; } - } -} diff --git a/Datatrans.Checkout.Core/Model/DatatransCheckoutSettings.cs b/Datatrans.Checkout.Core/Model/DatatransCheckoutSettings.cs deleted file mode 100644 index e424c46..0000000 --- a/Datatrans.Checkout.Core/Model/DatatransCheckoutSettings.cs +++ /dev/null @@ -1,51 +0,0 @@ -using VirtoCommerce.Domain.Order.Model; -using VirtoCommerce.Domain.Store.Model; - -namespace Datatrans.Checkout.Core.Model -{ - public class DatatransCheckoutSettings - { - public Store Store { get; set; } - - public CustomerOrder Order { get; set; } - - public int Amount { get; set; } - - public string MerchantId { get; set; } - - public string ReferenceNumber { get; set; } - - public string Sign { get; set; } - - /// - /// Settlement or Sale - /// - public string PaymentAction { get; set; } - - /// - /// VIS,ECA etc - /// - public string PaymentMethod { get; set; } - - public string PurchaseCurrency { get; set; } - - public string Language { get; set; } - - /// - /// cart/externalpaymentcallback - /// - public string FormActionUrl { get; set; } - - /// - /// Live or test - /// - public string FrontendApi { get; set; } - - /// - /// Code of this payment method - /// - public string InternalPaymentMethodCode { get; set; } - - public string PaymentMethodCodeParamName { get; set; } - } -} \ No newline at end of file diff --git a/Datatrans.Checkout.Core/Model/DatatransErrorCodes.cs b/Datatrans.Checkout.Core/Model/DatatransErrorCodes.cs deleted file mode 100644 index 62d44ad..0000000 --- a/Datatrans.Checkout.Core/Model/DatatransErrorCodes.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Datatrans.Checkout.Core.Model -{ - public static class DatatransErrorCodes - { - public const int DefaultErrorCode = -1000; - } -} diff --git a/Datatrans.Checkout.Core/Model/DatatransRefundRequest.cs b/Datatrans.Checkout.Core/Model/DatatransRefundRequest.cs deleted file mode 100644 index 65e6590..0000000 --- a/Datatrans.Checkout.Core/Model/DatatransRefundRequest.cs +++ /dev/null @@ -1,22 +0,0 @@ -namespace Datatrans.Checkout.Core.Model -{ - /// - /// https://docs.datatrans.ch/docs/payment-process-refund - /// - public class DatatransRefundRequest : DatatransRequest - { - public DatatransRefundRequest() - { - TransType = "06"; // 06 Indicate a refund request - ServiceVersion = "1"; - } - - public string ReferenceNumber { get; set; } - - public int Amount { get; set; } - - public string Currency { get; set; } - - public string TransType { get; set; } - } -} diff --git a/Datatrans.Checkout.Core/Model/DatatransRefundResponse.cs b/Datatrans.Checkout.Core/Model/DatatransRefundResponse.cs deleted file mode 100644 index 09e76e8..0000000 --- a/Datatrans.Checkout.Core/Model/DatatransRefundResponse.cs +++ /dev/null @@ -1,19 +0,0 @@ -namespace Datatrans.Checkout.Core.Model -{ - public class DatatransRefundResponse - { - public string TransactionId { get; set; } - - public string ErrorCode { get; set; } - - public string ErrorMessage { get; set; } - - public string ErrorDetail { get; set; } - - public string ResponseData { get; set; } - - public string ResponseCode { get; set; } - - public string ResponseMessage { get; set; } - } -} diff --git a/Datatrans.Checkout.Core/Model/DatatransRequest.cs b/Datatrans.Checkout.Core/Model/DatatransRequest.cs deleted file mode 100644 index 6992204..0000000 --- a/Datatrans.Checkout.Core/Model/DatatransRequest.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace Datatrans.Checkout.Core.Model -{ - public abstract class DatatransRequest - { - public string MerchantId { get; set; } - - public string TransactionId { get; set; } - - public string ServiceVersion { get; set; } - - public string Sign { get; set; } - } -} diff --git a/Datatrans.Checkout.Core/Model/DatatransResponse.cs b/Datatrans.Checkout.Core/Model/DatatransResponse.cs deleted file mode 100644 index 5e95efe..0000000 --- a/Datatrans.Checkout.Core/Model/DatatransResponse.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace Datatrans.Checkout.Core.Model -{ - public class DatatransResponse - { - public string TransactionId { get; set; } - - public string ResponseContent { get; set; } - - public string Status { get; set; } - - public string ErrorMessage { get; set; } - - public string ErrorCode { get; set; } - - public string ErrorDetail { get; set; } - } -} diff --git a/Datatrans.Checkout.Core/Model/DatatransSettlementRequest.cs b/Datatrans.Checkout.Core/Model/DatatransSettlementRequest.cs deleted file mode 100644 index ca9361d..0000000 --- a/Datatrans.Checkout.Core/Model/DatatransSettlementRequest.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace Datatrans.Checkout.Core.Model -{ - public class DatatransSettlementRequest : DatatransRequest - { - public DatatransSettlementRequest() - { - ServiceVersion = "1"; - } - - public string ReferenceNumber { get; set; } - - public int Amount { get; set; } - - public string Currency { get; set; } - - public DatatransAirlineData AirlineData { get; set; } - } -} diff --git a/Datatrans.Checkout.Core/Model/DatatransSettlementResponse.cs b/Datatrans.Checkout.Core/Model/DatatransSettlementResponse.cs deleted file mode 100644 index 53f085a..0000000 --- a/Datatrans.Checkout.Core/Model/DatatransSettlementResponse.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Datatrans.Checkout.Core.Model -{ - public class DatatransSettlementResponse : DatatransResponse - { - public string ResponseCode { get; set; } - - public string ResponseMessage { get; set; } - } -} diff --git a/Datatrans.Checkout.Core/Model/DatatransTransactionRequest.cs b/Datatrans.Checkout.Core/Model/DatatransTransactionRequest.cs deleted file mode 100644 index 6b9c1e1..0000000 --- a/Datatrans.Checkout.Core/Model/DatatransTransactionRequest.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace Datatrans.Checkout.Core.Model -{ - public class DatatransTransactionRequest : DatatransRequest - { - public DatatransTransactionRequest() - { - ReqestType = "STX"; - ServiceVersion = "3"; - } - - public string ReqestType { get; set; } - } -} diff --git a/Datatrans.Checkout.Core/Model/DatatransTransactionResponse.cs b/Datatrans.Checkout.Core/Model/DatatransTransactionResponse.cs deleted file mode 100644 index 7ccaccc..0000000 --- a/Datatrans.Checkout.Core/Model/DatatransTransactionResponse.cs +++ /dev/null @@ -1,37 +0,0 @@ -namespace Datatrans.Checkout.Core.Model -{ - public class DatatransTransactionResponse : DatatransResponse - { - public string ResponseCode { get; set; } - - public string ResponseMessage { get; set; } - - public string ReferenceNumber { get; set; } - - public string Amount { get; set; } - - public string Currency { get; set; } - - public string AuthorizationCode { get; set; } - - public string PaymentMethod { get; set; } - - public string MaskedCC { get; set; } - - public string AliasCC { get; set; } - - public string ExpirationMonth { get; set; } - - public string ExpirationYear { get; set; } - - public string TransactionDate { get; set; } - - public string TransactionTime { get; set; } - - public string TransactionType { get; set; } - - public string SettledAmount { get; set; } - - public string ItemNumber { get; set; } - } -} diff --git a/Datatrans.Checkout.Core/Model/GetAirlineDataContext.cs b/Datatrans.Checkout.Core/Model/GetAirlineDataContext.cs deleted file mode 100644 index b6411cc..0000000 --- a/Datatrans.Checkout.Core/Model/GetAirlineDataContext.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System.Collections.Specialized; -using VirtoCommerce.Domain.Order.Model; - -namespace Datatrans.Checkout.Core.Model -{ - public class GetAirlineDataContext - { - public CustomerOrder Order { get; set; } - - public PaymentIn Payment { get; set; } - - public NameValueCollection Parameters { get; set; } - - public GetAirlineDataContext() - { - } - - public GetAirlineDataContext(CustomerOrder order, PaymentIn payment, NameValueCollection parameters) - { - Order = order; - Payment = payment; - Parameters = parameters; - } - } -} diff --git a/Datatrans.Checkout.Core/Properties/AssemblyInfo.cs b/Datatrans.Checkout.Core/Properties/AssemblyInfo.cs deleted file mode 100644 index 1ec9ef1..0000000 --- a/Datatrans.Checkout.Core/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,4 +0,0 @@ -using System.Reflection; - -[assembly: AssemblyTitle("Datatrans.Checkout.Core")] -[assembly: AssemblyDescription("")] \ No newline at end of file diff --git a/Datatrans.Checkout.Core/Services/IDatatransCapturePaymentService.cs b/Datatrans.Checkout.Core/Services/IDatatransCapturePaymentService.cs deleted file mode 100644 index f281cd0..0000000 --- a/Datatrans.Checkout.Core/Services/IDatatransCapturePaymentService.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Datatrans.Checkout.Core.Model; - -namespace Datatrans.Checkout.Core.Services -{ - public interface IDatatransCapturePaymentService - { - DatatransAirlineData GetAirlineData(GetAirlineDataContext context); - } -} \ No newline at end of file diff --git a/Datatrans.Checkout.Core/Services/IDatatransCheckoutService.cs b/Datatrans.Checkout.Core/Services/IDatatransCheckoutService.cs deleted file mode 100644 index ae5578a..0000000 --- a/Datatrans.Checkout.Core/Services/IDatatransCheckoutService.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Datatrans.Checkout.Core.Model; - -namespace Datatrans.Checkout.Core.Services -{ - public interface IDatatransCheckoutService - { - string GetCheckoutFormContent(DatatransCheckoutSettings context); - } -} \ No newline at end of file diff --git a/Datatrans.Checkout.Core/Services/IDatatransClient.cs b/Datatrans.Checkout.Core/Services/IDatatransClient.cs deleted file mode 100644 index 2e7729e..0000000 --- a/Datatrans.Checkout.Core/Services/IDatatransClient.cs +++ /dev/null @@ -1,15 +0,0 @@ -using Datatrans.Checkout.Core.Model; - -namespace Datatrans.Checkout.Core.Services -{ - public interface IDatatransClient - { - string ServiceEndpoint { get; set; } - - DatatransSettlementResponse SettleTransaction(DatatransSettlementRequest request); - - DatatransTransactionResponse GetTransactionStatus(DatatransTransactionRequest request); - - DatatransRefundResponse Refund(DatatransRefundRequest request); - } -} diff --git a/Datatrans.Checkout.Core/app.config b/Datatrans.Checkout.Core/app.config deleted file mode 100644 index 2bbe771..0000000 --- a/Datatrans.Checkout.Core/app.config +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/Datatrans.Checkout.Core/packages.config b/Datatrans.Checkout.Core/packages.config deleted file mode 100644 index 0321c3e..0000000 --- a/Datatrans.Checkout.Core/packages.config +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/Datatrans.Checkout.Tests/Datatrans.Checkout.Tests.csproj b/Datatrans.Checkout.Tests/Datatrans.Checkout.Tests.csproj deleted file mode 100644 index 97e4c4b..0000000 --- a/Datatrans.Checkout.Tests/Datatrans.Checkout.Tests.csproj +++ /dev/null @@ -1,140 +0,0 @@ - - - - - - - Debug - AnyCPU - {9D8B50C5-9DF1-461C-8BBD-FFE82FB1E400} - Library - Properties - Datatrans.Checkout.Tests - Datatrans.Checkout.Tests - v4.6.1 - 512 - - - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - ..\packages\Castle.Core.4.2.1\lib\net45\Castle.Core.dll - True - - - ..\packages\FluentValidation.7.3.1\lib\net45\FluentValidation.dll - True - - - ..\packages\Moq.4.7.145\lib\net45\Moq.dll - True - - - ..\packages\Newtonsoft.Json.11.0.2\lib\net45\Newtonsoft.Json.dll - - - - - - - - - - - - ..\packages\VirtoCommerce.Domain.2.24.19\lib\net461\VirtoCommerce.Domain.dll - True - - - ..\packages\VirtoCommerce.Platform.Core.2.13.24\lib\net461\VirtoCommerce.Platform.Core.dll - - - ..\packages\xunit.abstractions.2.0.1\lib\net35\xunit.abstractions.dll - True - - - ..\packages\xunit.assert.2.3.1\lib\netstandard1.1\xunit.assert.dll - True - - - ..\packages\xunit.extensibility.core.2.3.1\lib\netstandard1.1\xunit.core.dll - True - - - ..\packages\xunit.extensibility.execution.2.3.1\lib\net452\xunit.execution.desktop.dll - True - - - - - Properties\CommonAssemblyInfo.cs - - - - - - - - - - {62a342c4-fee9-474f-9433-43c81d9ceac9} - Datatrans.Checkout.Core - - - {c602c6c1-f419-466f-904d-d73d06b50af3} - Datatrans.Checkout - - - - - - - - - - - - - - - - - - - - - - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - - - - - \ No newline at end of file diff --git a/Datatrans.Checkout.Tests/DatatransTests.cs b/Datatrans.Checkout.Tests/DatatransTests.cs deleted file mode 100644 index 7f74af5..0000000 --- a/Datatrans.Checkout.Tests/DatatransTests.cs +++ /dev/null @@ -1,108 +0,0 @@ -using Datatrans.Checkout.Core.Services; -using Datatrans.Checkout.Managers; -using Datatrans.Checkout.Services; -using Moq; -using System; -using System.Collections.Generic; -using System.Collections.Specialized; -using System.Globalization; -using VirtoCommerce.Domain.Order.Model; -using VirtoCommerce.Domain.Payment.Model; -using VirtoCommerce.Platform.Core.Settings; -using Xunit; - -namespace Datatrans.Checkout.Tests -{ - public class DatatransTests - { - [Fact] - public void TestRefund() - { - var context = new RefundProcessPaymentEvaluationContext - { - Order = new CustomerOrder - { - Number = "", - Currency = "USD" - }, - Payment = new PaymentIn - { - OuterId = "", - Sum = 0M, - Transactions = new List() - }, - Parameters = new NameValueCollection - { - {"RefundAmount", (-5.33M).ToString(CultureInfo.InvariantCulture)} - } - }; - - var endpoint = "https://api.sandbox.datatrans.com"; - var username = ""; - var password = ""; - var hmacKey = ""; - - var datatransClient = CreateDatatransClient(endpoint, username, password); - - var datatransClientFactory = CreateDatatransClientFactory(datatransClient); - - var datatransCheckoutService = CreateDatatransCheckoutService(); - var datatransCapturePaymentService = CreateDatatransCapturePaymentService(); - - var datatransCheckoutPaymentMethod = CreateDatatransCheckoutPaymentMethod( - datatransCheckoutService.Object, - datatransClientFactory, - datatransCapturePaymentService.Object, - CreateSignProvider(hmacKey)); - - datatransCheckoutPaymentMethod.Settings = new List - { - new SettingEntry - { - Name = "Datatrans.Checkout.MerchantId", - Value = "" - } - }; - - var result = datatransCheckoutPaymentMethod.RefundProcessPayment(context); - } - - private Mock CreateDatatransCheckoutService() - { - return new Mock(); - } - - private IDatatransClient CreateDatatransClient(string serviceEndpoint, string username, string password) - { - return new DatatransClient.DatatransClient(serviceEndpoint, username, password); - } - - private Mock CreateDatatransCapturePaymentService() - { - return new Mock(); - } - - private Func CreateDatatransClientFactory(IDatatransClient datatransClient) - { - return (s, s1, s2) => datatransClient; - } - - private Func CreateSignProvider(string hmacKey) - { - return s => new SignProvider(hmacKey); - } - - private DatatransCheckoutPaymentMethod CreateDatatransCheckoutPaymentMethod( - IDatatransCheckoutService datatransCheckoutService, - Func datatransClientFactory, - IDatatransCapturePaymentService datatransCapturePaymentService, - Func signProviderFactory) - { - return new DatatransCheckoutPaymentMethod( - datatransCheckoutService, - datatransClientFactory, - datatransCapturePaymentService, - signProviderFactory); - } - } -} diff --git a/Datatrans.Checkout.Tests/DatatranscheckoutPaymentMethodTests.cs b/Datatrans.Checkout.Tests/DatatranscheckoutPaymentMethodTests.cs deleted file mode 100644 index e2443c4..0000000 --- a/Datatrans.Checkout.Tests/DatatranscheckoutPaymentMethodTests.cs +++ /dev/null @@ -1,218 +0,0 @@ -using Datatrans.Checkout.Core.Services; -using Datatrans.Checkout.Managers; -using Datatrans.Checkout.Services; -using Moq; -using System; -using System.Collections.Generic; -using System.Collections.Specialized; -using VirtoCommerce.Platform.Core.Settings; -using Xunit; - -namespace Datatrans.Checkout.Tests -{ - public class DatatransCheckoutPaymentMethodTests - { - [Fact] - public void ValidatePostProcessRequestWithHmacAndSign2Test() - { - var signProviderFactory = CreateMockSignProviderFactory(CreateSignProvider()); - - var paymentMethod = CreateDatatransCheckoutPaymentMethod( - CreateMockDatatransCheckoutService().Object, - CreateMockDatatransFactory().Object, - CreateMockDatatransCapturePaymentService().Object, - signProviderFactory.Object); - - paymentMethod.Settings = new List - { - new SettingEntry - { - Name = "Datatrans.Checkout.HMACHex", - Value = "testHMACHex" - }, - }; - - var queryParams = new NameValueCollection - { - {"paymentMethodCode", "DatatransCheckout"}, - {"sign2", "testSign2"}, - {"uppTransactionId", "testUppTransactionId"}, - {"amount", "123"}, - {"currency", "RU-ru"}, - {"merchantId", "testMerchantId"}, - {"status", "success"}, - }; - - var result = paymentMethod.ValidatePostProcessRequest(queryParams); - - signProviderFactory.Verify(x => x("testHMACHex"), Times.Once); - Assert.True(result.IsSuccess); - } - - [Fact] - public void ValidatePostProcessRequestWithHmacWithoutSign2Test() - { - var signProviderFactory = CreateMockSignProviderFactory(CreateSignProvider()); - - var paymentMethod = CreateDatatransCheckoutPaymentMethod( - CreateMockDatatransCheckoutService().Object, - CreateMockDatatransFactory().Object, - CreateMockDatatransCapturePaymentService().Object, - signProviderFactory.Object); - - paymentMethod.Settings = new List - { - new SettingEntry - { - Name = "Datatrans.Checkout.HMACHex", - Value = "test" - }, - }; - - var queryParams = new NameValueCollection - { - {"paymentMethodCode", "DatatransCheckout"}, - {"uppTransactionId", "testUppTransactionId"}, - {"amount", "123"}, - {"currency", "RU-ru"}, - {"merchantId", "testMerchantId"}, - }; - - var result = paymentMethod.ValidatePostProcessRequest(queryParams); - - signProviderFactory.Verify(x => x("test"), Times.Never); - Assert.False(result.IsSuccess); - } - - [Fact] - public void ValidatePorstProcessRequestWitHmac2WithSign2Test() - { - var signProviderFactory = CreateMockSignProviderFactory(CreateSignProvider()); - - var paymentMethod = CreateDatatransCheckoutPaymentMethod( - CreateMockDatatransCheckoutService().Object, - CreateMockDatatransFactory().Object, - CreateMockDatatransCapturePaymentService().Object, - signProviderFactory.Object); - - paymentMethod.Settings = new List - { - new SettingEntry - { - Name = "Datatrans.Checkout.HMACHEXSign2", - Value = "testHMACHEXSign2" - }, - new SettingEntry - { - Name = "Datatrans.Checkout.HMACHex", - Value = "testHMACHEX" - }, - }; - - var queryParams = new NameValueCollection - { - {"paymentMethodCode", "DatatransCheckout"}, - {"sign2", "testSign2"}, - {"uppTransactionId", "testUppTransactionId"}, - {"amount", "123"}, - {"currency", "RU-ru"}, - {"merchantId", "testMerchantId"}, - {"status", "success"}, - }; - - var result = paymentMethod.ValidatePostProcessRequest(queryParams); - - signProviderFactory.Verify(x => x("testHMACHEXSign2"), Times.Once); - Assert.True(result.IsSuccess); - } - - [Fact] - public void No_Validation_Test() - { - var signProviderFactory = CreateMockSignProviderFactory(CreateSignProvider()); - - var paymentMethod = CreateDatatransCheckoutPaymentMethod( - CreateMockDatatransCheckoutService().Object, - CreateMockDatatransFactory().Object, - CreateMockDatatransCapturePaymentService().Object, - signProviderFactory.Object); - - paymentMethod.Settings = new List - { - new SettingEntry - { - Name = "Datatrans.Checkout.HMACHex", - Value = null - }, - }; - - var queryParams = new NameValueCollection - { - {"paymentMethodCode", "DatatransCheckout"}, - {"uppTransactionId", "testUppTransactionId"}, - {"amount", "123"}, - {"currency", "RU-ru"}, - {"merchantId", "testMerchantId"}, - {"status", "success"}, - }; - - var result = paymentMethod.ValidatePostProcessRequest(queryParams); - - signProviderFactory.Verify(x => x(It.IsAny()), Times.Never); - Assert.True(result.IsSuccess); - } - - - private ISignProvider CreateSignProvider() - { - var signProvider = new Mock(); - - signProvider - .Setup(x => - x.ValidateSignature( - It.IsAny(), - It.IsAny(), - It.IsAny(), - It.IsAny(), - It.IsAny() - ) - ) - .Returns(true); - - return signProvider.Object; - } - - private Mock> CreateMockSignProviderFactory(ISignProvider signProvider) - { - var providerFactory = new Mock>(); - - providerFactory.Setup(x => x(It.IsAny())).Returns(signProvider); - - return providerFactory; - } - - private Mock CreateMockDatatransCapturePaymentService() - { - return new Mock(); - } - - private Mock> CreateMockDatatransFactory() - { - return new Mock>(); - } - - private Mock CreateMockDatatransCheckoutService() - { - return new Mock(); - } - - private DatatransCheckoutPaymentMethod CreateDatatransCheckoutPaymentMethod( - IDatatransCheckoutService datatransCheckoutService, - Func datatransClientFactory, - IDatatransCapturePaymentService datatransCapturePaymentService, - Func signProviderFactory) - { - return new DatatransCheckoutPaymentMethod(datatransCheckoutService, datatransClientFactory, datatransCapturePaymentService, signProviderFactory); - } - } -} diff --git a/Datatrans.Checkout.Tests/Properties/AssemblyInfo.cs b/Datatrans.Checkout.Tests/Properties/AssemblyInfo.cs deleted file mode 100644 index f90919c..0000000 --- a/Datatrans.Checkout.Tests/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,4 +0,0 @@ -using System.Reflection; - -[assembly: AssemblyTitle("Datatrans.Checkout.Tests")] -[assembly: AssemblyDescription("")] \ No newline at end of file diff --git a/Datatrans.Checkout.Tests/ServiceResponseCovertionTests.cs b/Datatrans.Checkout.Tests/ServiceResponseCovertionTests.cs deleted file mode 100644 index e080cfc..0000000 --- a/Datatrans.Checkout.Tests/ServiceResponseCovertionTests.cs +++ /dev/null @@ -1,117 +0,0 @@ -using Datatrans.Checkout.DatatransClient.Converters; -using Datatrans.Checkout.DatatransClient.Models; -using System.IO; -using VirtoCommerce.Platform.Core.Common; -using Xunit; - -namespace Datatrans.Checkout.Tests -{ - public class ServiceResponseTests - { - [Fact] - public void ReadSettleResponse_SuccessfulReponse_ResponseRead() - { - //arrange - var response = File.ReadAllText(@"../../data/settleResponseSuccess.xml"); - - //act - var deserializeXml = response.DeserializeXml(); - var target = deserializeXml.ToCoreModel(); - - //assert - Assert.Equal("01", target.ResponseCode); - Assert.Equal("settlement succeeded", target.ResponseMessage); - } - - [Fact] - public void ReadSettleResponse_FailedReponse_ResponseRead() - { - var response = File.ReadAllText(@"../../data/settleResponseError.xml"); - - var deserializeXml = response.DeserializeXml(); - var target = deserializeXml.ToCoreModel(); - - //assert - Assert.Equal("-80", target.ErrorCode); - Assert.Equal("UPP record not found", target.ErrorMessage); - } - - [Fact] - public void StatuesResponse_SuccessfulReponse_ResponseRead() - { - var response = File.ReadAllText(@"../../data/statusResponseSuccess.xml"); - - var deserializeXml = response.DeserializeXml(); - var target = deserializeXml.ToCoreModel(); - - //assert - Assert.Equal("2", target.ResponseCode); - Assert.Equal("Trx debit waiting for daily settlement process", target.ResponseMessage); - Assert.Equal("00400", target.ReferenceNumber); - Assert.Equal("24720", target.Amount); - Assert.Equal("USD", target.Currency); - Assert.Equal("9213", target.AuthorizationCode); - Assert.Equal("VIS", target.PaymentMethod); - Assert.Equal("111111111111111", target.TransactionId); - Assert.Equal("424242xxxxxx4242", target.MaskedCC); - Assert.Equal("12", target.ExpirationMonth); - Assert.Equal("18", target.ExpirationYear); - Assert.Equal("20171212", target.TransactionDate); - Assert.Equal("222638", target.TransactionTime); - Assert.Equal("05", target.TransactionType); - Assert.Equal("24720", target.SettledAmount); - } - - [Fact] - public void StatusSettleResponse_FailedReponse_ResponseRead() - { - var response = File.ReadAllText(@"../../data/statusResponseError.xml"); - - var deserializeXml = response.DeserializeXml(); - var target = deserializeXml.ToCoreModel(); - - //assert - Assert.Equal("2022", target.ErrorCode); - Assert.Equal("invalid value", target.ErrorMessage); - Assert.Equal("merchantId", target.ErrorDetail); - } - - [Fact] - public void TestRefundResponseSuccessDeserializing() - { - var response = File.ReadAllText(@"../../data/refundResponseSuccess.xml"); - - var deserializedXml = response.DeserializeXml(); - - var refundResponse = deserializedXml.ToCoreModel(); - - Assert.NotEmpty(refundResponse.ResponseCode); - Assert.NotEmpty(refundResponse.ResponseMessage); - Assert.NotEmpty(refundResponse.TransactionId); - - Assert.Null(refundResponse.ResponseData); - Assert.Null(refundResponse.ErrorMessage); - Assert.Null(refundResponse.ErrorCode); - Assert.Null(refundResponse.ErrorDetail); - } - - [Fact] - public void TestRefundResponseErrorDeserializing() - { - var response = File.ReadAllText(@"../../data/refundResponseError.xml"); - - var deserializedXml = response.DeserializeXml(); - - var refundResponse = deserializedXml.ToCoreModel(); - - Assert.NotEmpty(refundResponse.ErrorMessage); - Assert.NotEmpty(refundResponse.ErrorCode); - Assert.NotEmpty(refundResponse.ErrorDetail); - - Assert.Null(refundResponse.ResponseData); - Assert.Null(refundResponse.ResponseCode); - Assert.Null(refundResponse.ResponseMessage); - Assert.Null(refundResponse.TransactionId); - } - } -} diff --git a/Datatrans.Checkout.Tests/SignProviderTests.cs b/Datatrans.Checkout.Tests/SignProviderTests.cs deleted file mode 100644 index 800a980..0000000 --- a/Datatrans.Checkout.Tests/SignProviderTests.cs +++ /dev/null @@ -1,81 +0,0 @@ -using Datatrans.Checkout.Services; -using System; -using System.Security.Cryptography; -using System.Text; -using Xunit; - -namespace Datatrans.Checkout.Tests -{ - public class SignProviderTests - { - [Fact] - public void TestSignature() - { - var testSignatureKey = "testSignature"; - - var signProvider = CreateSignProvider(GetHexadecimalString(testSignatureKey)); - - var merchantId = "testMerchant"; - var amount = 123; - var currency = "USD"; - var refno = "testRefno"; - - var sign = signProvider.Sign(merchantId, amount, currency, refno); - var expectedSign = CreateSignature(GetStringBytesArray(testSignatureKey), $"{merchantId}{amount.ToString()}{currency}{refno}"); - - Assert.Equal(expectedSign, sign); - } - - [Fact] - public void TestValidation() - { - var testSignatureKey = "testSignatureKey"; - - var signProvider = CreateSignProvider(GetHexadecimalString(testSignatureKey)); - - var merchantId = "testMerchant"; - var amount = 123; - var currency = "USD"; - var transactionId = "testTransactionId"; - - var sourceSign = CreateSignature(GetStringBytesArray(testSignatureKey),$"{merchantId}{amount.ToString()}{currency}{transactionId}"); - - var result = signProvider.ValidateSignature(sourceSign, merchantId, amount, currency, transactionId); - - Assert.True(result); - } - - private SignProvider CreateSignProvider(string hex) - { - return new SignProvider(hex); - } - - private string GetHexadecimalString(string key) - { - var bytes = GetStringBytesArray(key); - - return ConvertBytesArrayToHexadecimalString(bytes); - } - - private byte[] GetStringBytesArray(string source) - { - return Encoding.ASCII.GetBytes(source); - } - - private string CreateSignature(byte[] bytes, string strToSign) - { - var toSign = GetStringBytesArray(strToSign); - - using (var hmac = new HMACSHA256(bytes)) - { - var hash = hmac.ComputeHash(toSign); - return ConvertBytesArrayToHexadecimalString(hash); - } - } - - private static string ConvertBytesArrayToHexadecimalString(byte[] source) - { - return BitConverter.ToString(source).Replace("-", string.Empty).ToLower(); - } - } -} diff --git a/Datatrans.Checkout.Tests/app.config b/Datatrans.Checkout.Tests/app.config deleted file mode 100644 index 2bbe771..0000000 --- a/Datatrans.Checkout.Tests/app.config +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/Datatrans.Checkout.Tests/data/refundResponseError.xml b/Datatrans.Checkout.Tests/data/refundResponseError.xml deleted file mode 100644 index ddb7514..0000000 --- a/Datatrans.Checkout.Tests/data/refundResponseError.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - 11999 - USD - 3333333333333333333333 - 06 - COA - - - -72 - cannot be credited - amount not valid - - - - \ No newline at end of file diff --git a/Datatrans.Checkout.Tests/data/refundResponseSuccess.xml b/Datatrans.Checkout.Tests/data/refundResponseSuccess.xml deleted file mode 100644 index d7eca5e..0000000 --- a/Datatrans.Checkout.Tests/data/refundResponseSuccess.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - 11999 - USD - 3333333333 - 06 - COA - - - 01 - credit succeeded - 444444444444444444 - 555555555555 - 6666666666 - - - - \ No newline at end of file diff --git a/Datatrans.Checkout.Tests/data/settleResponseError.xml b/Datatrans.Checkout.Tests/data/settleResponseError.xml deleted file mode 100644 index 01d9745..0000000 --- a/Datatrans.Checkout.Tests/data/settleResponseError.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - 101 - USD - 111111111111111 - COA - 05 - - - -80 - UPP record not found - - - - - \ No newline at end of file diff --git a/Datatrans.Checkout.Tests/data/settleResponseSuccess.xml b/Datatrans.Checkout.Tests/data/settleResponseSuccess.xml deleted file mode 100644 index c2edf07..0000000 --- a/Datatrans.Checkout.Tests/data/settleResponseSuccess.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - 101 - USD - 111111111111111 - COA - 05 - - - 01 - settlement succeeded - - - - \ No newline at end of file diff --git a/Datatrans.Checkout.Tests/data/statusResponseError.xml b/Datatrans.Checkout.Tests/data/statusResponseError.xml deleted file mode 100644 index 979d44b..0000000 --- a/Datatrans.Checkout.Tests/data/statusResponseError.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - 111111111111111 - STX - - - - 2022 - invalid value - merchantId - - - \ No newline at end of file diff --git a/Datatrans.Checkout.Tests/data/statusResponseSuccess.xml b/Datatrans.Checkout.Tests/data/statusResponseSuccess.xml deleted file mode 100644 index 0001508..0000000 --- a/Datatrans.Checkout.Tests/data/statusResponseSuccess.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - - 111111111111111 - STX - - - 2 - Trx debit waiting for daily settlement process - 00400 - 24720 - USD - 9213 - VIS - 111111111111111 - 424242xxxxxx4242 - - 12 - 18 - 20171212 - 222638 - 05 - 24720 - - - - \ No newline at end of file diff --git a/Datatrans.Checkout.Tests/packages.config b/Datatrans.Checkout.Tests/packages.config deleted file mode 100644 index 319bbb5..0000000 --- a/Datatrans.Checkout.Tests/packages.config +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Datatrans.Checkout.sln b/Datatrans.Checkout.sln deleted file mode 100644 index 6f8f7a6..0000000 --- a/Datatrans.Checkout.sln +++ /dev/null @@ -1,34 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.25420.1 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Datatrans.Checkout", "Datatrans.Checkout\Datatrans.Checkout.csproj", "{C602C6C1-F419-466F-904D-D73D06B50AF3}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Datatrans.Checkout.Core", "Datatrans.Checkout.Core\Datatrans.Checkout.Core.csproj", "{62A342C4-FEE9-474F-9433-43C81D9CEAC9}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Datatrans.Checkout.Tests", "Datatrans.Checkout.Tests\Datatrans.Checkout.Tests.csproj", "{9D8B50C5-9DF1-461C-8BBD-FFE82FB1E400}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {C602C6C1-F419-466F-904D-D73D06B50AF3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C602C6C1-F419-466F-904D-D73D06B50AF3}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C602C6C1-F419-466F-904D-D73D06B50AF3}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C602C6C1-F419-466F-904D-D73D06B50AF3}.Release|Any CPU.Build.0 = Release|Any CPU - {62A342C4-FEE9-474F-9433-43C81D9CEAC9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {62A342C4-FEE9-474F-9433-43C81D9CEAC9}.Debug|Any CPU.Build.0 = Debug|Any CPU - {62A342C4-FEE9-474F-9433-43C81D9CEAC9}.Release|Any CPU.ActiveCfg = Release|Any CPU - {62A342C4-FEE9-474F-9433-43C81D9CEAC9}.Release|Any CPU.Build.0 = Release|Any CPU - {9D8B50C5-9DF1-461C-8BBD-FFE82FB1E400}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {9D8B50C5-9DF1-461C-8BBD-FFE82FB1E400}.Debug|Any CPU.Build.0 = Debug|Any CPU - {9D8B50C5-9DF1-461C-8BBD-FFE82FB1E400}.Release|Any CPU.ActiveCfg = Release|Any CPU - {9D8B50C5-9DF1-461C-8BBD-FFE82FB1E400}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/Datatrans.Checkout/Content/logo.png b/Datatrans.Checkout/Content/logo.png deleted file mode 100644 index 78794dd01bd2c98a1d0d8dacce16ac7d00cd81cb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9389 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 - - - -
-
- - - - diff --git a/Datatrans.Checkout/Datatrans.Checkout.csproj b/Datatrans.Checkout/Datatrans.Checkout.csproj deleted file mode 100644 index 4caafea..0000000 --- a/Datatrans.Checkout/Datatrans.Checkout.csproj +++ /dev/null @@ -1,191 +0,0 @@ - - - - - Debug - AnyCPU - - - 2.0 - {C602C6C1-F419-466F-904D-D73D06B50AF3} - {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} - Library - Properties - Datatrans.Checkout - Datatrans.Checkout - v4.6.1 - true - - - - - - - - - - - true - full - false - bin\ - DEBUG;TRACE - prompt - 4 - true - - - pdbonly - true - bin\ - TRACE - prompt - 4 - true - - - - ..\packages\DotLiquid.1.8.0\lib\NET45\DotLiquid.dll - True - - - - ..\packages\CommonServiceLocator.1.3\lib\portable-net4+sl5+netcore45+wpa81+wp8\Microsoft.Practices.ServiceLocation.dll - True - - - ..\packages\Unity.4.0.1\lib\net45\Microsoft.Practices.Unity.dll - True - - - ..\packages\Unity.4.0.1\lib\net45\Microsoft.Practices.Unity.Configuration.dll - True - - - ..\packages\Unity.4.0.1\lib\net45\Microsoft.Practices.Unity.RegistrationByConvention.dll - True - - - ..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll - True - - - ..\packages\Newtonsoft.Json.11.0.2\lib\net45\Newtonsoft.Json.dll - - - - ..\packages\Microsoft.AspNet.WebApi.Client.5.2.4\lib\net45\System.Net.Http.Formatting.dll - - - - - - - - - - - ..\packages\Microsoft.AspNet.WebApi.Core.5.2.4\lib\net45\System.Web.Http.dll - - - - - - - - ..\packages\VirtoCommerce.Domain.2.24.19\lib\net461\VirtoCommerce.Domain.dll - True - - - ..\packages\VirtoCommerce.Platform.Core.2.13.24\lib\net461\VirtoCommerce.Platform.Core.dll - - - - - - - - - - Web.config - - - Web.config - - - - - - - - - Properties\CommonAssemblyInfo.cs - - - - - - - - - - - - - - - - - - - - - - - - {62a342c4-fee9-474f-9433-43c81d9ceac9} - Datatrans.Checkout.Core - - - - 10.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - - - - - - True - True - 26902 - / - http://localhost:26902/ - False - False - - - False - - - - - - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - - - - \ No newline at end of file diff --git a/Datatrans.Checkout/DatatransClient/Converters/RefundConverter.cs b/Datatrans.Checkout/DatatransClient/Converters/RefundConverter.cs deleted file mode 100644 index 03e9de4..0000000 --- a/Datatrans.Checkout/DatatransClient/Converters/RefundConverter.cs +++ /dev/null @@ -1,69 +0,0 @@ -using Datatrans.Checkout.Core.Model; -using Datatrans.Checkout.DatatransClient.Models; -using System.Linq; -using System.Xml.Linq; - -namespace Datatrans.Checkout.DatatransClient.Converters -{ - public static class RefundConverter - { - public static string ToDatatransRequest(this DatatransRefundRequest request) - { - var requestXml = - new XElement("paymentService", new XAttribute("version", request.ServiceVersion), - new XElement("body", new XAttribute("merchantId", request.MerchantId), - new XElement("transaction", new XAttribute("refno", request.ReferenceNumber), - new XElement("request", - new XElement("amount", request.Amount), - new XElement("currency", request.Currency), - new XElement("uppTransactionId", request.TransactionId), - new XElement("transtype", request.TransType), - new XElement("sign", request.Sign) - ) - ) - ) - ); - - return requestXml.ToString(); - } - - public static DatatransRefundResponse ToCoreModel(this RefundResponse.paymentService response) - { - var coreModel = new DatatransRefundResponse(); - - var refundResponseBody = response.body.FirstOrDefault(); - if (refundResponseBody == null) - { - return coreModel; - } - - var transaction = refundResponseBody.transaction?.FirstOrDefault(); - var actualResponse = transaction?.response?.FirstOrDefault(); - var transactionError = transaction?.error?.FirstOrDefault(); - var generalError = refundResponseBody.error?.FirstOrDefault(); - - if (transactionError != null) - { - coreModel.ErrorMessage = transactionError.errorMessage; - coreModel.ErrorCode = transactionError.errorCode; - coreModel.ErrorDetail = transactionError.errorDetail; - } - - if (generalError != null) - { - coreModel.ErrorMessage = generalError.errorMessage; - coreModel.ErrorCode = generalError.errorCode; - coreModel.ErrorDetail = generalError.errorDetail; - } - - if (actualResponse != null) - { - coreModel.ResponseCode = actualResponse.responseCode; - coreModel.ResponseMessage = actualResponse.responseMessage; - coreModel.TransactionId = actualResponse.uppTransactionId; - } - - return coreModel; - } - } -} \ No newline at end of file diff --git a/Datatrans.Checkout/DatatransClient/Converters/SettlementServiceRequestConverter.cs b/Datatrans.Checkout/DatatransClient/Converters/SettlementServiceRequestConverter.cs deleted file mode 100644 index 8972512..0000000 --- a/Datatrans.Checkout/DatatransClient/Converters/SettlementServiceRequestConverter.cs +++ /dev/null @@ -1,68 +0,0 @@ -using System.Linq; -using System.Xml.Linq; -using coreModel = Datatrans.Checkout.Core.Model; - -namespace Datatrans.Checkout.DatatransClient.Converters -{ - public static class SettlementServiceRequestConverter - { - public static string ToDatatransRequest(this coreModel.DatatransSettlementRequest coreModel) - { - var requestXml = - new XElement("paymentService", new XAttribute("version", coreModel.ServiceVersion), - new XElement("body", new XAttribute("merchantId", coreModel.MerchantId), - new XElement("transaction", new XAttribute("refno", coreModel.ReferenceNumber), - new XElement("request", - new XElement("amount", coreModel.Amount), - new XElement("currency", coreModel.Currency), - new XElement("uppTransactionId", coreModel.TransactionId), - new XElement("sign", coreModel.Sign) - ) - ) - ) - ); - - if (coreModel.AirlineData != null) - { - var ticketIndex = 1; - foreach (var datatransTicket in coreModel.AirlineData.Tickets) - { - var flighIndex = 1; - datatransTicket.Index = (ticketIndex++).ToString(); - foreach (var datatransFlight in datatransTicket.Flights) - { - datatransFlight.Index = (flighIndex++).ToString(); - } - } - - var airlineDataXml = new XElement("AIRLINEDATA", - new XElement("CountryCode", coreModel.AirlineData.CountryCode), - new XElement("AgentCode", coreModel.AirlineData.AgentCode), - new XElement("PNR", coreModel.AirlineData.PNR), - new XElement("IssueDate", coreModel.AirlineData.IssueDate), - - from ticket in coreModel.AirlineData.Tickets - select new XElement("Ticket", new XAttribute("nr", ticket.Index), - new XElement("TicketNumber", ticket.TicketNumber), - new XElement("PassengerName", ticket.PassengerName), - new XElement("DescrCode", ticket.DescrCode), - - from flight in ticket.Flights - select new XElement("Flight", new XAttribute("nr", flight.Index), - new XElement("Origin", flight.Origin), - new XElement("Destination", flight.Destination), - new XElement("Carrier", flight.Carrier), - new XElement("Class", flight.Class), - new XElement("FareBasis", flight.FareBasis), - new XElement("FlightNumber", flight.FlightNumber), - new XElement("FlightDate", flight.FlightDate))) - ); - - var requestElement = requestXml.Descendants().FirstOrDefault(x => x.Name == "request"); - requestElement?.Add(airlineDataXml); - } - - return requestXml.ToString(); - } - } -} \ No newline at end of file diff --git a/Datatrans.Checkout/DatatransClient/Converters/SettlementServiceResponseConverter.cs b/Datatrans.Checkout/DatatransClient/Converters/SettlementServiceResponseConverter.cs deleted file mode 100644 index b1ae62a..0000000 --- a/Datatrans.Checkout/DatatransClient/Converters/SettlementServiceResponseConverter.cs +++ /dev/null @@ -1,38 +0,0 @@ -using System.Linq; -using Datatrans.Checkout.DatatransClient.Models; -using VirtoCommerce.Platform.Core.Common; -using coreModel = Datatrans.Checkout.Core.Model; - -namespace Datatrans.Checkout.DatatransClient.Converters -{ - public static class SettlementServiceResponseConverter - { - public static coreModel.DatatransSettlementResponse ToCoreModel(this paymentService dataModel) - { - var coreModel = new coreModel.DatatransSettlementResponse(); - - var statusServiceBody = dataModel.body.FirstOrDefault(); - if (statusServiceBody == null) return coreModel; - - var transaction = statusServiceBody.transaction.FirstOrDefault(); - if (transaction == null) return coreModel; - - if (!transaction.response.IsNullOrEmpty()) - { - var response = transaction.response.FirstOrDefault(); - coreModel.ResponseCode = response.responseCode; - coreModel.ResponseMessage = response.responseMessage; - } - - if (!transaction.error.IsNullOrEmpty()) - { - var error = transaction.error.FirstOrDefault(); - coreModel.ErrorCode = error.errorCode; - coreModel.ErrorDetail = error.errorDetail; - coreModel.ErrorMessage = error.errorMessage; - } - - return coreModel; - } - } -} \ No newline at end of file diff --git a/Datatrans.Checkout/DatatransClient/Converters/StatusServiceRequestConverter.cs b/Datatrans.Checkout/DatatransClient/Converters/StatusServiceRequestConverter.cs deleted file mode 100644 index 41dacce..0000000 --- a/Datatrans.Checkout/DatatransClient/Converters/StatusServiceRequestConverter.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System.Xml.Linq; -using coreModel = Datatrans.Checkout.Core.Model; - -namespace Datatrans.Checkout.DatatransClient.Converters -{ - public static class StatusServiceRequestConverter - { - public static string ToDatatransRequest(this coreModel.DatatransTransactionRequest coreModel) - { - XElement requestXml = - new XElement("statusService", new XAttribute("version", coreModel.ServiceVersion), - new XElement("body", new XAttribute("merchantId", coreModel.MerchantId), - new XElement("transaction", - new XElement("request", - new XElement("uppTransactionId", coreModel.TransactionId), - new XElement("reqtype", coreModel.ReqestType) - ) - ) - ) - ); - - return requestXml.ToString(); - } - } -} \ No newline at end of file diff --git a/Datatrans.Checkout/DatatransClient/Converters/StatusServiceResponseConverter.cs b/Datatrans.Checkout/DatatransClient/Converters/StatusServiceResponseConverter.cs deleted file mode 100644 index 46c6c20..0000000 --- a/Datatrans.Checkout/DatatransClient/Converters/StatusServiceResponseConverter.cs +++ /dev/null @@ -1,54 +0,0 @@ -using System.Linq; -using Datatrans.Checkout.DatatransClient.Models; -using VirtoCommerce.Platform.Core.Common; -using coreModel = Datatrans.Checkout.Core.Model; - -namespace Datatrans.Checkout.DatatransClient.Converters -{ - public static class StatusServiceResponseConverter - { - public static coreModel.DatatransTransactionResponse ToCoreModel(this statusService dataModel) - { - var coreModel = new coreModel.DatatransTransactionResponse(); - - var statusServiceBody = dataModel.body.FirstOrDefault(); - if (statusServiceBody == null) return coreModel; - - if (!statusServiceBody.transaction.IsNullOrEmpty()) - { - var transaction = statusServiceBody.transaction.FirstOrDefault(); - if (transaction?.response != null) - { - var actualResponse = transaction.response.FirstOrDefault(); - coreModel.ResponseCode = actualResponse.responseCode; - coreModel.ResponseMessage = actualResponse.responseMessage; - coreModel.ReferenceNumber = actualResponse.refno; - coreModel.Amount = actualResponse.amount; - coreModel.Currency = actualResponse.currency; - coreModel.AuthorizationCode = actualResponse.authorizationCode; - coreModel.PaymentMethod = actualResponse.pmethod; - coreModel.TransactionId = actualResponse.uppTransactionId; - coreModel.MaskedCC = actualResponse.maskedCC; - coreModel.AliasCC = actualResponse.aliasCC; - coreModel.ExpirationMonth = actualResponse.expm; - coreModel.ExpirationYear = actualResponse.expy; - coreModel.TransactionDate = actualResponse.trxDate; - coreModel.TransactionTime = actualResponse.trxTime; - coreModel.TransactionType = actualResponse.trtype; - coreModel.SettledAmount = actualResponse.settledAmount; - coreModel.ItemNumber = actualResponse.itemNr; - } - } - - if (!statusServiceBody.error.IsNullOrEmpty()) - { - var error = statusServiceBody.error.FirstOrDefault(); - coreModel.ErrorCode = error.errorCode; - coreModel.ErrorDetail = error.errorDetail; - coreModel.ErrorMessage = error.errorMessage; - } - - return coreModel; - } - } -} diff --git a/Datatrans.Checkout/DatatransClient/DatatransClient.cs b/Datatrans.Checkout/DatatransClient/DatatransClient.cs deleted file mode 100644 index cbe30af..0000000 --- a/Datatrans.Checkout/DatatransClient/DatatransClient.cs +++ /dev/null @@ -1,137 +0,0 @@ -using Datatrans.Checkout.Core.Model; -using Datatrans.Checkout.Core.Services; -using Datatrans.Checkout.DatatransClient.Converters; -using Datatrans.Checkout.DatatransClient.Models; -using System; -using System.IO; -using System.Net; -using System.Text; -using System.Xml; -using VirtoCommerce.Platform.Core.Common; -using coreModel = Datatrans.Checkout.Core.Model; - -namespace Datatrans.Checkout.DatatransClient -{ - public class DatatransClient : IDatatransClient - { - public string ServiceEndpoint { get; set; } - - protected string AuthorizationEndpoint => ServiceEndpoint + "/upp/jsp/XML_authorize.jsp"; - - protected string StatusEndpoint => ServiceEndpoint + "/upp/jsp/XML_status.jsp"; - - protected string ProcessEndpoint => ServiceEndpoint + "/upp/jsp/XML_processor.jsp"; - - private readonly string _username; - private readonly string _password; - - #region Implementation of IDatatransClient - - public DatatransClient(string serviceEndpoint, string username, string password) - { - ServiceEndpoint = serviceEndpoint; - _username = username; - _password = password; - } - - public coreModel.DatatransSettlementResponse SettleTransaction(DatatransSettlementRequest request) - { - var requestXml = request.ToDatatransRequest(); - var response = MakeDatatransCall(ProcessEndpoint, requestXml); - - if (!response.ErrorMessage.IsNullOrEmpty()) - { - return new coreModel.DatatransSettlementResponse - { - ErrorMessage = response.ErrorMessage - }; - } - - var paymentServiceResponse = response.ResponseContent.DeserializeXml(); - var result = paymentServiceResponse.ToCoreModel(); - result.ResponseContent = response.ResponseContent; - return result; - } - - public coreModel.DatatransTransactionResponse GetTransactionStatus(DatatransTransactionRequest request) - { - var requestXml = request.ToDatatransRequest(); - var response = MakeDatatransCall(StatusEndpoint, requestXml); - - if (!response.ErrorMessage.IsNullOrEmpty()) - { - return new coreModel.DatatransTransactionResponse - { - ErrorMessage = response.ErrorMessage - }; - } - - var statusServiceResponse = response.ResponseContent.DeserializeXml(); - var result = statusServiceResponse.ToCoreModel(); - result.ResponseContent = response.ResponseContent; - return result; - } - - public coreModel.DatatransRefundResponse Refund(DatatransRefundRequest request) - { - var requestXml = request.ToDatatransRequest(); - var response = MakeDatatransCall(ProcessEndpoint, requestXml); - - if (!response.ErrorMessage.IsNullOrEmpty()) - { - return new DatatransRefundResponse - { - ErrorMessage = response.ErrorMessage - }; - } - - var datatransRefundResponse = response.ResponseContent.DeserializeXml(); - - var result = datatransRefundResponse.ToCoreModel(); - - result.ResponseData = response.ResponseContent; - - return result; - } - - private ServiceResponse MakeDatatransCall(string endpoint, string sXml) - { - var result = new ServiceResponse(); - var endpointUri = new Uri(endpoint); - try - { - var req = (HttpWebRequest) WebRequest.Create(endpointUri); - req.Method = "POST"; - req.ContentType = "text/xml; charset=utf-8"; - - var credentials = Convert.ToBase64String(Encoding.ASCII.GetBytes($"{_username}:{_password}")); - - req.Headers.Add("Authorization", $"Basic {credentials}"); - - req.ContentLength = sXml.Length; - using (var sw = new StreamWriter(req.GetRequestStream())) - { - sw.Write(sXml); - sw.Close(); - } - - var res = (HttpWebResponse)req.GetResponse(); - - var responseStream = res.GetResponseStream(); - using (var streamReader = new StreamReader(responseStream)) - { - var xml = new XmlDocument(); - xml.LoadXml(streamReader.ReadToEnd()); - result.ResponseContent = xml.InnerXml; - } - } - catch (Exception ex) - { - result.ErrorMessage = ex.Message; - } - return result; - } - - #endregion - } -} \ No newline at end of file diff --git a/Datatrans.Checkout/DatatransClient/Models/RefundResponse.cs b/Datatrans.Checkout/DatatransClient/Models/RefundResponse.cs deleted file mode 100644 index 0286460..0000000 --- a/Datatrans.Checkout/DatatransClient/Models/RefundResponse.cs +++ /dev/null @@ -1,477 +0,0 @@ -namespace Datatrans.Checkout.DatatransClient.Models -{ - public class RefundResponse - { - /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.6.1055.0")] - [System.SerializableAttribute()] - [System.Diagnostics.DebuggerStepThroughAttribute()] - [System.ComponentModel.DesignerCategoryAttribute("code")] - [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)] - [System.Xml.Serialization.XmlRootAttribute(Namespace = "", IsNullable = false)] - public partial class paymentService - { - - private paymentServiceBody[] bodyField; - - private string versionField; - - /// - [System.Xml.Serialization.XmlElementAttribute("body", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] - public paymentServiceBody[] body - { - get - { - return this.bodyField; - } - set - { - this.bodyField = value; - } - } - - /// - [System.Xml.Serialization.XmlAttributeAttribute()] - public string version - { - get - { - return this.versionField; - } - set - { - this.versionField = value; - } - } - } - - /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.6.1055.0")] - [System.SerializableAttribute()] - [System.Diagnostics.DebuggerStepThroughAttribute()] - [System.ComponentModel.DesignerCategoryAttribute("code")] - [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)] - public partial class paymentServiceBody - { - - private paymentServiceBodyTransaction[] transactionField; - - private paymentServiceBodyTransactionError[] errorField; - - private string merchantIdField; - - private string statusField; - - /// - [System.Xml.Serialization.XmlElementAttribute("transaction", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] - public paymentServiceBodyTransaction[] transaction - { - get - { - return this.transactionField; - } - set - { - this.transactionField = value; - } - } - - /// - [System.Xml.Serialization.XmlElementAttribute("error", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] - public paymentServiceBodyTransactionError[] error - { - get - { - return this.errorField; - } - set - { - this.errorField = value; - } - } - - /// - [System.Xml.Serialization.XmlAttributeAttribute()] - public string merchantId - { - get - { - return this.merchantIdField; - } - set - { - this.merchantIdField = value; - } - } - - /// - [System.Xml.Serialization.XmlAttributeAttribute()] - public string status - { - get - { - return this.statusField; - } - set - { - this.statusField = value; - } - } - } - - /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.6.1055.0")] - [System.SerializableAttribute()] - [System.Diagnostics.DebuggerStepThroughAttribute()] - [System.ComponentModel.DesignerCategoryAttribute("code")] - [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)] - public partial class paymentServiceBodyTransaction - { - - private paymentServiceBodyTransactionRequest[] requestField; - - private paymentServiceBodyTransactionResponse[] responseField; - - private paymentServiceBodyTransactionError[] errorField; - - private string refnoField; - - private string trxStatusField; - - /// - [System.Xml.Serialization.XmlElementAttribute("request", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] - public paymentServiceBodyTransactionRequest[] request - { - get - { - return this.requestField; - } - set - { - this.requestField = value; - } - } - - /// - [System.Xml.Serialization.XmlElementAttribute("response", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] - public paymentServiceBodyTransactionResponse[] response - { - get - { - return this.responseField; - } - set - { - this.responseField = value; - } - } - - /// - [System.Xml.Serialization.XmlElementAttribute("error", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] - public paymentServiceBodyTransactionError[] error - { - get - { - return this.errorField; - } - set - { - this.errorField = value; - } - } - - /// - [System.Xml.Serialization.XmlAttributeAttribute()] - public string refno - { - get - { - return this.refnoField; - } - set - { - this.refnoField = value; - } - } - - /// - [System.Xml.Serialization.XmlAttributeAttribute()] - public string trxStatus - { - get - { - return this.trxStatusField; - } - set - { - this.trxStatusField = value; - } - } - } - - /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.6.1055.0")] - [System.SerializableAttribute()] - [System.Diagnostics.DebuggerStepThroughAttribute()] - [System.ComponentModel.DesignerCategoryAttribute("code")] - [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)] - public partial class paymentServiceBodyTransactionRequest - { - - private string amountField; - - private string currencyField; - - private string uppTransactionIdField; - - private string transtypeField; - - private string reqtypeField; - - /// - [System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] - public string amount - { - get - { - return this.amountField; - } - set - { - this.amountField = value; - } - } - - /// - [System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] - public string currency - { - get - { - return this.currencyField; - } - set - { - this.currencyField = value; - } - } - - /// - [System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] - public string uppTransactionId - { - get - { - return this.uppTransactionIdField; - } - set - { - this.uppTransactionIdField = value; - } - } - - /// - [System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] - public string transtype - { - get - { - return this.transtypeField; - } - set - { - this.transtypeField = value; - } - } - - /// - [System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] - public string reqtype - { - get - { - return this.reqtypeField; - } - set - { - this.reqtypeField = value; - } - } - } - - /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.6.1055.0")] - [System.SerializableAttribute()] - [System.Diagnostics.DebuggerStepThroughAttribute()] - [System.ComponentModel.DesignerCategoryAttribute("code")] - [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)] - public partial class paymentServiceBodyTransactionResponse - { - - private string responseCodeField; - - private string responseMessageField; - - private string uppTransactionIdField; - - private string authorizationCodeField; - - private string acqAuthorizationCodeField; - - /// - [System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] - public string responseCode - { - get - { - return this.responseCodeField; - } - set - { - this.responseCodeField = value; - } - } - - /// - [System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] - public string responseMessage - { - get - { - return this.responseMessageField; - } - set - { - this.responseMessageField = value; - } - } - - /// - [System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] - public string uppTransactionId - { - get - { - return this.uppTransactionIdField; - } - set - { - this.uppTransactionIdField = value; - } - } - - /// - [System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] - public string authorizationCode - { - get - { - return this.authorizationCodeField; - } - set - { - this.authorizationCodeField = value; - } - } - - /// - [System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] - public string acqAuthorizationCode - { - get - { - return this.acqAuthorizationCodeField; - } - set - { - this.acqAuthorizationCodeField = value; - } - } - } - - /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.6.1055.0")] - [System.SerializableAttribute()] - [System.Diagnostics.DebuggerStepThroughAttribute()] - [System.ComponentModel.DesignerCategoryAttribute("code")] - [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)] - public partial class paymentServiceBodyTransactionError - { - - private string errorCodeField; - - private string errorMessageField; - - private string errorDetailField; - - /// - [System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] - public string errorCode - { - get - { - return this.errorCodeField; - } - set - { - this.errorCodeField = value; - } - } - - /// - [System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] - public string errorMessage - { - get - { - return this.errorMessageField; - } - set - { - this.errorMessageField = value; - } - } - - /// - [System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] - public string errorDetail - { - get - { - return this.errorDetailField; - } - set - { - this.errorDetailField = value; - } - } - } - - /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.6.1055.0")] - [System.SerializableAttribute()] - [System.Diagnostics.DebuggerStepThroughAttribute()] - [System.ComponentModel.DesignerCategoryAttribute("code")] - [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)] - [System.Xml.Serialization.XmlRootAttribute(Namespace = "", IsNullable = false)] - public partial class NewDataSet - { - - private paymentService[] itemsField; - - /// - [System.Xml.Serialization.XmlElementAttribute("paymentService")] - public paymentService[] Items - { - get - { - return this.itemsField; - } - set - { - this.itemsField = value; - } - } - } - } -} \ No newline at end of file diff --git a/Datatrans.Checkout/DatatransClient/Models/ServiceResponse.cs b/Datatrans.Checkout/DatatransClient/Models/ServiceResponse.cs deleted file mode 100644 index ca4378f..0000000 --- a/Datatrans.Checkout/DatatransClient/Models/ServiceResponse.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Datatrans.Checkout.DatatransClient.Models -{ - public class ServiceResponse - { - public string ResponseContent { get; set; } - - public string ErrorMessage { get; set; } - } -} \ No newline at end of file diff --git a/Datatrans.Checkout/DatatransClient/Models/SettlementServiceReference.cs b/Datatrans.Checkout/DatatransClient/Models/SettlementServiceReference.cs deleted file mode 100644 index b12b811..0000000 --- a/Datatrans.Checkout/DatatransClient/Models/SettlementServiceReference.cs +++ /dev/null @@ -1,303 +0,0 @@ - -namespace Datatrans.Checkout.DatatransClient.Models -{ - //------------------------------------------------------------------------------ - // - // This code was generated by a tool. - // Runtime Version:2.0.50727.8825 - // - // Changes to this file may cause incorrect behavior and will be lost if - // the code is regenerated. - // - //------------------------------------------------------------------------------ - - using System.Xml.Serialization; - -// -// This source code was auto-generated by xsd, Version=2.0.50727.3038. -// - - - /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.3038")] - [System.SerializableAttribute()] - [System.Diagnostics.DebuggerStepThroughAttribute()] - [System.ComponentModel.DesignerCategoryAttribute("code")] - [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)] - [System.Xml.Serialization.XmlRootAttribute(Namespace = "", IsNullable = false)] - public partial class paymentService - { - - private paymentServiceBody[] bodyField; - - private string versionField; - - /// - [System.Xml.Serialization.XmlElementAttribute("body", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] - public paymentServiceBody[] body - { - get { return this.bodyField; } - set { this.bodyField = value; } - } - - /// - [System.Xml.Serialization.XmlAttributeAttribute()] - public string version - { - get { return this.versionField; } - set { this.versionField = value; } - } - } - - /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.3038")] - [System.SerializableAttribute()] - [System.Diagnostics.DebuggerStepThroughAttribute()] - [System.ComponentModel.DesignerCategoryAttribute("code")] - [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)] - public partial class paymentServiceBody - { - - private paymentServiceBodyTransaction[] transactionField; - - private string merchantIdField; - - private string statusField; - - /// - [System.Xml.Serialization.XmlElementAttribute("transaction", Form = - System.Xml.Schema.XmlSchemaForm.Unqualified)] - public paymentServiceBodyTransaction[] transaction - { - get { return this.transactionField; } - set { this.transactionField = value; } - } - - /// - [System.Xml.Serialization.XmlAttributeAttribute()] - public string merchantId - { - get { return this.merchantIdField; } - set { this.merchantIdField = value; } - } - - /// - [System.Xml.Serialization.XmlAttributeAttribute()] - public string status - { - get { return this.statusField; } - set { this.statusField = value; } - } - } - - /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.3038")] - [System.SerializableAttribute()] - [System.Diagnostics.DebuggerStepThroughAttribute()] - [System.ComponentModel.DesignerCategoryAttribute("code")] - [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)] - public partial class paymentServiceBodyTransaction - { - - private paymentServiceBodyTransactionRequest[] requestField; - - private paymentServiceBodyTransactionResponse[] responseField; - - private paymentServiceBodyTransactionError[] errorField; - - private string refnoField; - - private string trxStatusField; - - /// - [System.Xml.Serialization.XmlElementAttribute("request", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] - public paymentServiceBodyTransactionRequest[] request - { - get { return this.requestField; } - set { this.requestField = value; } - } - - /// - [System.Xml.Serialization.XmlElementAttribute("response", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] - public paymentServiceBodyTransactionResponse[] response - { - get { return this.responseField; } - set { this.responseField = value; } - } - - /// - [System.Xml.Serialization.XmlAttributeAttribute()] - public string refno - { - get { return this.refnoField; } - set { this.refnoField = value; } - } - - /// - [System.Xml.Serialization.XmlAttributeAttribute()] - public string trxStatus - { - get { return this.trxStatusField; } - set { this.trxStatusField = value; } - } - - /// - [System.Xml.Serialization.XmlElementAttribute("error", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] - public paymentServiceBodyTransactionError[] error - { - get { return this.errorField; } - set { this.errorField = value; } - } - } - - /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.3038")] - [System.SerializableAttribute()] - [System.Diagnostics.DebuggerStepThroughAttribute()] - [System.ComponentModel.DesignerCategoryAttribute("code")] - [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)] - public partial class paymentServiceBodyTransactionRequest - { - - private string amountField; - - private string currencyField; - - private string uppTransactionIdField; - - private string reqtypeField; - - private string transtypeField; - - /// - [System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] - public string amount - { - get { return this.amountField; } - set { this.amountField = value; } - } - - /// - [System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] - public string currency - { - get { return this.currencyField; } - set { this.currencyField = value; } - } - - /// - [System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] - public string uppTransactionId - { - get { return this.uppTransactionIdField; } - set { this.uppTransactionIdField = value; } - } - - /// - [System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] - public string reqtype - { - get { return this.reqtypeField; } - set { this.reqtypeField = value; } - } - - /// - [System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] - public string transtype - { - get { return this.transtypeField; } - set { this.transtypeField = value; } - } - } - - /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.3038")] - [System.SerializableAttribute()] - [System.Diagnostics.DebuggerStepThroughAttribute()] - [System.ComponentModel.DesignerCategoryAttribute("code")] - [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)] - public partial class paymentServiceBodyTransactionResponse - { - - private string responseCodeField; - - private string responseMessageField; - - /// - [System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] - public string responseCode - { - get { return this.responseCodeField; } - set { this.responseCodeField = value; } - } - - /// - [System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] - public string responseMessage - { - get { return this.responseMessageField; } - set { this.responseMessageField = value; } - } - } - - ///// - //[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.3038")] - //[System.SerializableAttribute()] - //[System.Diagnostics.DebuggerStepThroughAttribute()] - //[System.ComponentModel.DesignerCategoryAttribute("code")] - //[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)] - //[System.Xml.Serialization.XmlRootAttribute(Namespace = "", IsNullable = false)] - //public partial class NewDataSet - //{ - - // private paymentService[] itemsField; - - // /// - // [System.Xml.Serialization.XmlElementAttribute("paymentService")] - // public paymentService[] Items - // { - // get { return this.itemsField; } - // set { this.itemsField = value; } - // } - //} - - - [System.Diagnostics.DebuggerStepThroughAttribute()] - [System.ComponentModel.DesignerCategoryAttribute("code")] - [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)] - public partial class paymentServiceBodyTransactionError - { - - private string errorCodeField; - - private string errorMessageField; - - private string errorDetailField; - - /// - [System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] - public string errorCode - { - get { return this.errorCodeField; } - set { this.errorCodeField = value; } - } - - /// - [System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] - public string errorMessage - { - get { return this.errorMessageField; } - set { this.errorMessageField = value; } - } - - /// - [System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] - public string errorDetail - { - get { return this.errorDetailField; } - set { this.errorDetailField = value; } - } - } - - -} \ No newline at end of file diff --git a/Datatrans.Checkout/DatatransClient/Models/StatusServiceReference.cs b/Datatrans.Checkout/DatatransClient/Models/StatusServiceReference.cs deleted file mode 100644 index 8f894c7..0000000 --- a/Datatrans.Checkout/DatatransClient/Models/StatusServiceReference.cs +++ /dev/null @@ -1,606 +0,0 @@ -using System; -using System.Xml.Serialization; - -namespace Datatrans.Checkout.DatatransClient.Models -{ - //------------------------------------------------------------------------------ - // - // This code was generated by a tool. - // Runtime Version:2.0.50727.8825 - // - // Changes to this file may cause incorrect behavior and will be lost if - // the code is regenerated. - // - //------------------------------------------------------------------------------ - // - // This source code was auto-generated by xsd, Version=2.0.50727.3038. - // - - /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.3038")] - [Serializable()] - [System.Diagnostics.DebuggerStepThroughAttribute()] - [System.ComponentModel.DesignerCategoryAttribute("code")] - [XmlType(AnonymousType = true)] - [XmlRoot(Namespace = "", IsNullable = false)] - public partial class statusService - { - - private statusServiceBody[] bodyField; - - private string versionField; - - /// - [XmlElement("body", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] - public statusServiceBody[] body - { - get - { - return this.bodyField; - } - set - { - this.bodyField = value; - } - } - - /// - [XmlAttribute()] - public string version - { - get - { - return this.versionField; - } - set - { - this.versionField = value; - } - } - } - - /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.3038")] - [Serializable()] - [System.Diagnostics.DebuggerStepThroughAttribute()] - [System.ComponentModel.DesignerCategoryAttribute("code")] - [XmlType(AnonymousType = true)] - public partial class statusServiceBody - { - - private statusServiceBodyTransaction[] transactionField; - - private statusServiceBodyError[] errorField; - - private string merchantIdField; - - private string statusField; - - /// - [XmlElement("transaction", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] - public statusServiceBodyTransaction[] transaction - { - get - { - return this.transactionField; - } - set - { - this.transactionField = value; - } - } - - /// - [System.Xml.Serialization.XmlElementAttribute("error", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] - public statusServiceBodyError[] error - { - get - { - return this.errorField; - } - set - { - this.errorField = value; - } - } - - /// - [XmlAttribute()] - public string merchantId - { - get - { - return this.merchantIdField; - } - set - { - this.merchantIdField = value; - } - } - - /// - [XmlAttribute()] - public string status - { - get - { - return this.statusField; - } - set - { - this.statusField = value; - } - } - } - - - - /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.3038")] - [Serializable()] - [System.Diagnostics.DebuggerStepThroughAttribute()] - [System.ComponentModel.DesignerCategoryAttribute("code")] - [XmlType(AnonymousType = true)] - public partial class statusServiceBodyTransaction - { - - private statusServiceBodyTransactionRequest[] requestField; - - private statusServiceBodyTransactionResponse[] responseField; - - private string trxStatusField; - - /// - [XmlElement("request", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] - public statusServiceBodyTransactionRequest[] request - { - get - { - return this.requestField; - } - set - { - this.requestField = value; - } - } - - /// - [XmlElement("response", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] - public statusServiceBodyTransactionResponse[] response - { - get - { - return this.responseField; - } - set - { - this.responseField = value; - } - } - - /// - [XmlAttribute()] - public string trxStatus - { - get - { - return this.trxStatusField; - } - set - { - this.trxStatusField = value; - } - } - } - - /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.3038")] - [Serializable()] - [System.Diagnostics.DebuggerStepThroughAttribute()] - [System.ComponentModel.DesignerCategoryAttribute("code")] - [XmlType(AnonymousType = true)] - public partial class statusServiceBodyTransactionRequest - { - - private string uppTransactionIdField; - - private string reqtypeField; - - /// - [XmlElement(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] - public string uppTransactionId - { - get - { - return this.uppTransactionIdField; - } - set - { - this.uppTransactionIdField = value; - } - } - - /// - [XmlElement(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] - public string reqtype - { - get - { - return this.reqtypeField; - } - set - { - this.reqtypeField = value; - } - } - } - - /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.3038")] - [Serializable()] - [System.Diagnostics.DebuggerStepThroughAttribute()] - [System.ComponentModel.DesignerCategoryAttribute("code")] - [XmlType(AnonymousType = true)] - public partial class statusServiceBodyTransactionResponse - { - - private string responseCodeField; - - private string responseMessageField; - - private string refnoField; - - private string amountField; - - private string currencyField; - - private string authorizationCodeField; - - private string pmethodField; - - private string uppTransactionIdField; - - private string maskedCCField; - - private string aliasCCField; - - private string expmField; - - private string expyField; - - private string trxDateField; - - private string trxTimeField; - - private string trtypeField; - - private string settledAmountField; - - private string itemNrField; - - /// - [XmlElement(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] - public string responseCode - { - get - { - return this.responseCodeField; - } - set - { - this.responseCodeField = value; - } - } - - /// - [XmlElement(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] - public string responseMessage - { - get - { - return this.responseMessageField; - } - set - { - this.responseMessageField = value; - } - } - - /// - [XmlElement(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] - public string refno - { - get - { - return this.refnoField; - } - set - { - this.refnoField = value; - } - } - - /// - [XmlElement(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] - public string amount - { - get - { - return this.amountField; - } - set - { - this.amountField = value; - } - } - - /// - [XmlElement(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] - public string currency - { - get - { - return this.currencyField; - } - set - { - this.currencyField = value; - } - } - - /// - [XmlElement(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] - public string authorizationCode - { - get - { - return this.authorizationCodeField; - } - set - { - this.authorizationCodeField = value; - } - } - - /// - [XmlElement(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] - public string pmethod - { - get - { - return this.pmethodField; - } - set - { - this.pmethodField = value; - } - } - - /// - [XmlElement(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] - public string uppTransactionId - { - get - { - return this.uppTransactionIdField; - } - set - { - this.uppTransactionIdField = value; - } - } - - /// - [XmlElement(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] - public string maskedCC - { - get - { - return this.maskedCCField; - } - set - { - this.maskedCCField = value; - } - } - - /// - [XmlElement(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] - public string aliasCC - { - get - { - return this.aliasCCField; - } - set - { - this.aliasCCField = value; - } - } - - /// - [XmlElement(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] - public string expm - { - get - { - return this.expmField; - } - set - { - this.expmField = value; - } - } - - /// - [XmlElement(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] - public string expy - { - get - { - return this.expyField; - } - set - { - this.expyField = value; - } - } - - /// - [XmlElement(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] - public string trxDate - { - get - { - return this.trxDateField; - } - set - { - this.trxDateField = value; - } - } - - /// - [XmlElement(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] - public string trxTime - { - get - { - return this.trxTimeField; - } - set - { - this.trxTimeField = value; - } - } - - /// - [XmlElement(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] - public string trtype - { - get - { - return this.trtypeField; - } - set - { - this.trtypeField = value; - } - } - - /// - [XmlElement(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] - public string settledAmount - { - get - { - return this.settledAmountField; - } - set - { - this.settledAmountField = value; - } - } - - /// - [XmlAttribute()] - public string itemNr - { - get - { - return this.itemNrField; - } - set - { - this.itemNrField = value; - } - } - } - - /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.3038")] - [Serializable()] - [System.Diagnostics.DebuggerStepThroughAttribute()] - [System.ComponentModel.DesignerCategoryAttribute("code")] - [XmlType(AnonymousType = true)] - [XmlRoot(Namespace = "", IsNullable = false)] - public partial class NewDataSet - { - - private statusService[] itemsField; - - /// - [XmlElement("statusService")] - public statusService[] Items - { - get - { - return this.itemsField; - } - set - { - this.itemsField = value; - } - } - } - - /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.3038")] - [System.SerializableAttribute()] - [System.Diagnostics.DebuggerStepThroughAttribute()] - [System.ComponentModel.DesignerCategoryAttribute("code")] - [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)] - public partial class statusServiceBodyError - { - private string errorCodeField; - - private string errorMessageField; - - private string errorDetailField; - - /// - [System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] - public string errorCode - { - get - { - return this.errorCodeField; - } - set - { - this.errorCodeField = value; - } - } - - /// - [System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] - public string errorMessage - { - get - { - return this.errorMessageField; - } - set - { - this.errorMessageField = value; - } - } - - /// - [System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] - public string errorDetail - { - get - { - return this.errorDetailField; - } - set - { - this.errorDetailField = value; - } - } - } - -} - - diff --git a/Datatrans.Checkout/Extensions/DecimalExtensions.cs b/Datatrans.Checkout/Extensions/DecimalExtensions.cs deleted file mode 100644 index 553c47d..0000000 --- a/Datatrans.Checkout/Extensions/DecimalExtensions.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; - -namespace Datatrans.Checkout.Extensions -{ - public static class DecimalExtensions - { - public static decimal NormalizeDecimal(this decimal source) - { - return Math.Abs(source); - } - } -} \ No newline at end of file diff --git a/Datatrans.Checkout/Helpers/RoundingHelper.cs b/Datatrans.Checkout/Helpers/RoundingHelper.cs deleted file mode 100644 index 9eaf7a3..0000000 --- a/Datatrans.Checkout/Helpers/RoundingHelper.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; - -namespace Datatrans.Checkout.Helpers -{ - public static class RoundingHelper - { - public static int Round(this decimal value) - { - return (int)Math.Round(value, MidpointRounding.AwayFromZero); - } - - public static int ToInt(this decimal value) - { - return (value * 100).Round(); - } - } -} \ No newline at end of file diff --git a/Datatrans.Checkout/Managers/DatatransCheckoutPaymentMethod.cs b/Datatrans.Checkout/Managers/DatatransCheckoutPaymentMethod.cs deleted file mode 100644 index 7332b6b..0000000 --- a/Datatrans.Checkout/Managers/DatatransCheckoutPaymentMethod.cs +++ /dev/null @@ -1,480 +0,0 @@ -using Datatrans.Checkout.Core.Model; -using Datatrans.Checkout.Core.Services; -using Datatrans.Checkout.Extensions; -using Datatrans.Checkout.Helpers; -using Datatrans.Checkout.Services; -using Newtonsoft.Json; -using System; -using System.Collections.Specialized; -using VirtoCommerce.Domain.Order.Model; -using VirtoCommerce.Domain.Payment.Model; -using VirtoCommerce.Platform.Core.Common; - -namespace Datatrans.Checkout.Managers -{ - public class DatatransCheckoutPaymentMethod : PaymentMethod - { - private const string _merchantIdSetting = "Datatrans.Checkout.MerchantId"; - private const string _HMACSetting = "Datatrans.Checkout.HMACHex"; - private const string _HMAC2Setting = "Datatrans.Checkout.HMACHEXSign2"; - - private const string _datatransModeStoreSetting = "Datatrans.Checkout.Mode"; - private const string _paymentActionTypeSetting = "Datatrans.Checkout.PaymentActionType"; - private const string _paymentMethodSetting = "Datatrans.Checkout.PaymentMethod"; - private const string _formActionUrlSetting = "Datatrans.Checkout.FormAction"; - private const string _languageSetting = "Datatrans.Checkout.Language"; - - private const string _transactionParamName = "uppTransactionId"; - private const string _paymentMethodCodeParamName = "paymentMethodCode"; - - private const string _serverToServerUsername = "Datatrans.Checkout.ServerToServer.Username"; -#pragma warning disable S2068 - private const string _serverToServerPassword = "Datatrans.Checkout.ServerToServer.Password"; -#pragma warning restore S2068 - private const string _apiEndpoint = "Datatrans.Checkout.APIEndpoint"; - private const string _browserEnpoint = "Datatrans.Checkout.BrowserEndpoint"; - private const string _successfulStatus = "success"; - private const string _errorStatus = "error"; - - #region Settings - - private string ApiMode => GetSetting(_datatransModeStoreSetting); - - private string MerchantId => GetSetting(_merchantIdSetting); - - private string HMACHex => GetSetting(_HMACSetting); - - private string HMACHex2 - { - get - { - var setting = GetSetting(_HMAC2Setting); - - return string.IsNullOrEmpty(setting) ? null : setting; - } - } - - private string PaymentAction => GetSetting(_paymentActionTypeSetting); - - private string PaymentMethod => GetSetting(_paymentMethodSetting); - - private string FormActionUrl => GetSetting(_formActionUrlSetting); - - private string Language => GetSetting(_languageSetting); - - private string Username => GetSetting(_serverToServerUsername); - - private string Password => GetSetting(_serverToServerPassword); - - public bool IsSale => PaymentAction.EqualsInvariant("Sale"); - - public bool IsTest => ApiMode.EqualsInvariant("test"); - - public string ServerToServerApi => GetSetting(_apiEndpoint); - - public string FrontendApi => GetSetting(_browserEnpoint); - - #endregion - - public override PaymentMethodType PaymentMethodType => PaymentMethodType.PreparedForm; - - public override PaymentMethodGroupType PaymentMethodGroupType => PaymentMethodGroupType.Alternative; - - private readonly IDatatransCheckoutService _datatransCheckoutService; - private readonly Func _datatransClientFactory; - private readonly IDatatransCapturePaymentService _capturePaymentService; - private readonly Func _signProviderFactory; - - public DatatransCheckoutPaymentMethod( - IDatatransCheckoutService datatransCheckoutService, - Func datatransClientFactory, - IDatatransCapturePaymentService capturePaymentService, - Func signProviderFactory) - :base("DatatransCheckout") - { - _datatransCheckoutService = datatransCheckoutService; - _datatransClientFactory = datatransClientFactory; - _capturePaymentService = capturePaymentService; - _signProviderFactory = signProviderFactory; - } - - public override ProcessPaymentResult ProcessPayment(ProcessPaymentEvaluationContext context) - { - var result = new ProcessPaymentResult(); - if (context.Order != null && context.Store != null) - { - result = PrepareFormContent(context); - } - return result; - } - - private ProcessPaymentResult PrepareFormContent(ProcessPaymentEvaluationContext context) - { - var formContent = _datatransCheckoutService.GetCheckoutFormContent(new DatatransCheckoutSettings - { - Order = context.Order, - Store = context.Store, - MerchantId = MerchantId, - FormActionUrl = FormActionUrl, - PaymentAction = PaymentAction, - PaymentMethod = PaymentMethod, - ReferenceNumber = context.Order.Number, - Sign = GetSignProvider(HMACHex).Sign(MerchantId, context.Order.Sum.ToInt(), context.Order.Currency, context.Order.Number), - Amount = context.Order.Sum.ToInt(), - PurchaseCurrency = context.Order.Currency, - FrontendApi = FrontendApi, - Language = Language, - InternalPaymentMethodCode = Code, - PaymentMethodCodeParamName = _paymentMethodCodeParamName - }); - - var result = new ProcessPaymentResult - { - IsSuccess = true, - NewPaymentStatus = context.Payment.PaymentStatus = PaymentStatus.Pending, - HtmlForm = formContent, - OuterId = null - }; - - return result; - } - - public override PostProcessPaymentResult PostProcessPayment(PostProcessPaymentEvaluationContext context) - { - var result = new PostProcessPaymentResult(); - - var status = GetParamValue(context.Parameters, "status"); //possible values: error, success - var transactionId = GetParamValue(context.Parameters, _transactionParamName); - - bool.TryParse(GetSetting("Datatrans.Checkout.ErrorTesting"), out var errorTestingMode); - - if (errorTestingMode && IsTest) - { - status = _errorStatus; - - var errorCode = int.TryParse(GetSetting("Datatrans.Checkout.ErrorCode"), out var parsedErrorCode) ? parsedErrorCode : DatatransErrorCodes.DefaultErrorCode; - - context.Parameters["errorCode"] = errorCode.ToString(); - context.Parameters["errorMessage"] = "Error testing mode"; - } - - context.Payment.OuterId = context.OuterId; - if (status.EqualsInvariant(_successfulStatus) && IsSale) - { - var captureResult = CaptureProcessPayment(new CaptureProcessPaymentEvaluationContext - { - Payment = context.Payment, - Order = context.Order, - Parameters = context.Parameters - }); - - if (captureResult.IsSuccess) - { - context.OuterId = transactionId; - result.NewPaymentStatus = context.Payment.PaymentStatus = PaymentStatus.Paid; - context.Payment.IsApproved = true; - context.Payment.CapturedDate = DateTime.UtcNow; - result.IsSuccess = true; - } - } - else if (status.EqualsInvariant(_successfulStatus)) - { - var transactionInfo = GetTransactionStatus(context.Payment.OuterId); - context.Payment.Transactions.Add(new PaymentGatewayTransaction() - { - Note = "Transaction Info", - ResponseData = transactionInfo.ResponseContent, - Status = transactionInfo.ResponseMessage, - ResponseCode = transactionInfo.ResponseCode, - ProcessError = transactionInfo.ErrorMessage, - CurrencyCode = context.Order.Currency, - Amount = context.Order.Sum, - IsProcessed = true, - ProcessedDate = DateTime.UtcNow - }); - - result.NewPaymentStatus = context.Payment.PaymentStatus = PaymentStatus.Authorized; - context.Payment.OuterId = result.OuterId = context.OuterId; - context.Payment.AuthorizedDate = DateTime.UtcNow; - result.IsSuccess = true; - } - else - { - var errorMessage = GetParamValue(context.Parameters, "errorMessage"); - var errorCode = int.TryParse(GetParamValue(context.Parameters, "errorCode"), out var parsedErrorCode) ? parsedErrorCode : DatatransErrorCodes.DefaultErrorCode; - result.ErrorMessage = GetErrorMessage(errorCode, errorMessage); - } - - result.OrderId = context.Order.Id; - return result; - } - - public override CaptureProcessPaymentResult CaptureProcessPayment(CaptureProcessPaymentEvaluationContext context) - { - if (context == null) - { - throw new ArgumentNullException(nameof(context)); - } - - if (context.Payment == null) - { - throw new InvalidOperationException(nameof(context.Payment)); - } - - if (context.Order == null) - { - throw new InvalidOperationException(nameof(context.Order)); - } - - var getAirlineContext = new GetAirlineDataContext(context.Order, context.Payment, context.Parameters); - var airlineData = _capturePaymentService.GetAirlineData(getAirlineContext); - - var request = new DatatransSettlementRequest - { - MerchantId = MerchantId, - TransactionId = context.Payment.OuterId, - ReferenceNumber = context.Order.Number, - Amount = context.Payment.Sum.ToInt(), - Currency = context.Order.Currency, - AirlineData = airlineData, - Sign = GetSignProvider(HMACHex).Sign(MerchantId, context.Payment.Sum.ToInt(), context.Order.Currency, context.Order.Number) - }; - - var paymentTransaction = new PaymentGatewayTransaction - { - Note = "Settle Transaction", - CurrencyCode = context.Order.Currency, - Amount = context.Payment.Sum - }; - context.Payment.Transactions.Add(paymentTransaction); - - var result = new CaptureProcessPaymentResult(); - var datatransClient = CreateDatatransClient(ServerToServerApi); - var settleResult = datatransClient.SettleTransaction(request); - if (!settleResult.ErrorMessage.IsNullOrEmpty()) - { - result.ErrorMessage = GetErrorMessage(settleResult.ResponseCode, settleResult.ResponseMessage); - paymentTransaction.ResponseData = settleResult.ResponseContent; - return result; - } - - var transactionInfo = GetTransactionStatus(context.Payment.OuterId); - paymentTransaction.Note = "Transaction Info after Settle Transaction"; - paymentTransaction.Status = transactionInfo.ResponseMessage; - paymentTransaction.ResponseData = transactionInfo.ResponseContent; - paymentTransaction.ResponseCode = transactionInfo.ResponseCode; - paymentTransaction.ProcessError = transactionInfo.ErrorMessage; - paymentTransaction.IsProcessed = true; - paymentTransaction.ProcessedDate = DateTime.UtcNow; - - result.NewPaymentStatus = context.Payment.PaymentStatus = PaymentStatus.Paid; - context.Payment.CapturedDate = DateTime.UtcNow; - context.Payment.IsApproved = true; - result.IsSuccess = true; - result.OuterId = context.Payment.OuterId; - - return result; - } - - protected virtual DatatransTransactionResponse GetTransactionStatus(string transactionId) - { - var datatransClient = CreateDatatransClient(ServerToServerApi); - return datatransClient.GetTransactionStatus(new DatatransTransactionRequest() - { - MerchantId = MerchantId, - TransactionId = transactionId - }); - } - - public override RefundProcessPaymentResult RefundProcessPayment(RefundProcessPaymentEvaluationContext context) - { - if (context == null) - { - throw new ArgumentNullException(nameof(context)); - } - - if (context.Payment == null) - { - throw new InvalidOperationException(nameof(context.Payment)); - } - - if (context.Order == null) - { - throw new InvalidOperationException(nameof(context.Order)); - } - - if (string.IsNullOrEmpty(context.Payment.OuterId)) - { - throw new InvalidOperationException(nameof(context.Payment.OuterId)); - } - - if (string.IsNullOrEmpty(context.Order.Currency)) - { - throw new InvalidOperationException(nameof(context.Order.Currency)); - } - - if (string.IsNullOrEmpty(context.Order.Number)) - { - throw new InvalidOperationException(nameof(context.Payment.OuterId)); - } - - var result = new RefundProcessPaymentResult(); - - var payment = context.Payment; - - var request = new DatatransRefundRequest - { - TransactionId = payment.OuterId, - Amount = GetNormalizedAmountForRefund(context, payment), - Currency = context.Order.Currency, - MerchantId = MerchantId, - ReferenceNumber = context.Order.Number, - Sign = GetSignProvider(HMACHex).Sign(MerchantId, GetNormalizedAmountForRefund(context, payment), context.Order.Currency, context.Order.Number) - }; - - var datatransClient = CreateDatatransClient(ServerToServerApi); - - var response = datatransClient.Refund(request); - - var transaction = new PaymentGatewayTransaction(); - - payment.Transactions.Add(transaction); - - transaction.ResponseData = response.ResponseData; - - if (!response.ErrorMessage.IsNullOrEmpty()) - { - transaction.ProcessError = response.ErrorMessage; - - result.ErrorMessage = GetErrorMessage(response.ErrorCode, response.ErrorMessage); - result.IsSuccess = false; - return result; - } - - transaction.Amount = GetAmountForRefund(context, payment); - transaction.CurrencyCode = payment.Currency; - transaction.IsProcessed = true; - transaction.Note = "Datatrans refund"; - transaction.ResponseCode = response.ResponseCode; - transaction.Status = response.ResponseMessage; - transaction.ProcessedDate = DateTime.Now; - - result.NewPaymentStatus = IsPartialRefund(context.Parameters) ? PaymentStatus.PartiallyRefunded : PaymentStatus.Refunded; - result.IsSuccess = true; - - return result; - } - - private decimal GetAmountForRefund(RefundProcessPaymentEvaluationContext context, PaymentIn payment) - { - return IsPartialRefund(context.Parameters) - ? GetPartialRefundAmount(context.Parameters) - : payment.Sum; - } - - private int GetNormalizedAmountForRefund(RefundProcessPaymentEvaluationContext context, PaymentIn payment) - { - return GetAmountForRefund(context, payment).NormalizeDecimal().ToInt(); - } - - private decimal GetPartialRefundAmount(NameValueCollection parameters) - { - if (!IsPartialRefund(parameters)) - { - throw new ArgumentException("Parameters doesn't have a RefundAmount parameter"); - } - - return decimal.Parse(parameters["RefundAmount"]); - } - - private bool IsPartialRefund(NameValueCollection parameters) - { - return parameters?["RefundAmount"] != null; - } - - private IDatatransClient CreateDatatransClient(string endpoint) - { - return _datatransClientFactory(endpoint, Username, Password); - } - - public override VoidProcessPaymentResult VoidProcessPayment(VoidProcessPaymentEvaluationContext context) - { - return new VoidProcessPaymentResult { IsSuccess = false, NewPaymentStatus = PaymentStatus.Voided }; - } - - /// - /// Check for transaction Id and payment method code in returned params collection - /// This method is repsonsible for selecting this particular payment method among all active store payment methods - /// - /// - /// - public override ValidatePostProcessRequestResult ValidatePostProcessRequest(NameValueCollection queryString) - { - var transactionId = GetParamValue(queryString, _transactionParamName); - var paymentMethodName = GetParamValue(queryString, _paymentMethodCodeParamName); - var sign2 = GetParamValue(queryString, "sign2"); - var sign = GetParamValue(queryString, "sign"); - var refNo = GetParamValue(queryString, "refNo"); - var merchantId = GetParamValue(queryString, "merchantId"); - var amount = GetParamValue(queryString, "amount"); - var currency = GetParamValue(queryString, "currency"); - var status = GetParamValue(queryString, "status"); - - bool validSignature; - - // Sign2 returns only for successful payments - // So we need to check status additionally - if (!string.IsNullOrEmpty(sign2) && !string.IsNullOrEmpty(HMACHex) && status.EqualsInvariant(_successfulStatus)) - { - validSignature = GetSignProvider(HMACHex2 ?? HMACHex).ValidateSignature(sign2, merchantId, int.Parse(amount), currency, transactionId); - } - // Even if sign2 not received, it doesn't means that payment is scam - // It still could be a valid payment, with status "error" if it contains "sign" parameter - // We don't need additioonal check for a status, cause we know that sign2 passing with only successful payments - // https://docs.datatrans.ch/docs/security-sign - else if (!string.IsNullOrEmpty(sign) && !string.IsNullOrEmpty(HMACHex)) - { - validSignature = GetSignProvider(HMACHex).ValidateSignature(sign, merchantId, int.Parse(amount), currency, refNo); - } - // Sign parameter is required if HMACHex setting is not null - // And payment can't be valid without "sign" - else if (string.IsNullOrEmpty(sign) && !string.IsNullOrEmpty(HMACHex)) - { - validSignature = false; - } - // Case when sign and sign2 parameters is missing, and if HMACHex and HMACHex2 settings is not filled - // We do not need to do anything with validation - else - { - validSignature = true; - } - - return new ValidatePostProcessRequestResult - { - IsSuccess = validSignature && !string.IsNullOrEmpty(transactionId) && paymentMethodName.EqualsInvariant(Code), - OuterId = transactionId - }; - } - - - private string GetParamValue(NameValueCollection queryString, string paramName) - { - if (queryString == null || !queryString.HasKeys()) - { - return null; - } - - return queryString.Get(paramName); - } - - private ISignProvider GetSignProvider(string hmacKey) - { - return _signProviderFactory(hmacKey); - } - - private string GetErrorMessage(object code, string errorMessage) - { - return JsonConvert.SerializeObject(new {Code = code, Message = errorMessage}); - } - } -} \ No newline at end of file diff --git a/Datatrans.Checkout/Module.cs b/Datatrans.Checkout/Module.cs deleted file mode 100644 index 86e4d75..0000000 --- a/Datatrans.Checkout/Module.cs +++ /dev/null @@ -1,53 +0,0 @@ -using Datatrans.Checkout.Core.Services; -using Datatrans.Checkout.Managers; -using Datatrans.Checkout.Services; -using Microsoft.Practices.ServiceLocation; -using Microsoft.Practices.Unity; -using System; -using VirtoCommerce.Domain.Payment.Services; -using VirtoCommerce.Platform.Core.Modularity; -using VirtoCommerce.Platform.Core.Settings; - -namespace Datatrans.Checkout -{ - public class Module : ModuleBase - { - private readonly IUnityContainer _container; - - public Module(IUnityContainer container) - { - _container = container; - } - - public override void Initialize() - { - _container.RegisterType(); - _container.RegisterType(); - - IDatatransClient DatatransClientFactory(string endpoint, string username, string password) => new DatatransClient.DatatransClient(endpoint, username, password); - _container.RegisterInstance((Func) DatatransClientFactory); - - ISignProvider SignProviderFactory(string hmacKey) => new SignProvider(hmacKey); - _container.RegisterInstance((Func) SignProviderFactory); - - var settingsManager = ServiceLocator.Current.GetInstance(); - - Func datatransPaymentMethod = () => - { - var paymentMethod = new DatatransCheckoutPaymentMethod( - _container.Resolve(), - _container.Resolve>(), - _container.Resolve(), - _container.Resolve>()); - paymentMethod.Name = "Datatrans Checkout Gateway"; - paymentMethod.Description = "Datatrans Checkout payment gateway integration"; - paymentMethod.LogoUrl = "https://raw.githubusercontent.com/VirtoCommerce/vc-module-datatrans/master/Datatrans.Checkout/Content/logo.png"; - paymentMethod.Settings = settingsManager.GetModuleSettings("Datatrans.Checkout"); - return paymentMethod; - }; - - var paymentMethodsService = _container.Resolve(); - paymentMethodsService.RegisterPaymentMethod(datatransPaymentMethod); - } - } -} diff --git a/Datatrans.Checkout/Properties/AssemblyInfo.cs b/Datatrans.Checkout/Properties/AssemblyInfo.cs deleted file mode 100644 index 66392c1..0000000 --- a/Datatrans.Checkout/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,4 +0,0 @@ -using System.Reflection; - -[assembly: AssemblyTitle("Datatrans.Checkout")] -[assembly: AssemblyDescription("")] diff --git a/Datatrans.Checkout/Services/DatatransCapturePaymentServiceEmptyImp.cs b/Datatrans.Checkout/Services/DatatransCapturePaymentServiceEmptyImp.cs deleted file mode 100644 index d012e64..0000000 --- a/Datatrans.Checkout/Services/DatatransCapturePaymentServiceEmptyImp.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Datatrans.Checkout.Core.Model; -using Datatrans.Checkout.Core.Services; - -namespace Datatrans.Checkout.Services -{ - /// - /// Mock implementation, should be overridden in custom implementations - /// - public class DatatransCapturePaymentServiceEmptyImp : IDatatransCapturePaymentService - { - #region Implementation of IDatatransCapturePaymentService - - public DatatransAirlineData GetAirlineData(GetAirlineDataContext context) - { - return null; - } - - #endregion - } -} \ No newline at end of file diff --git a/Datatrans.Checkout/Services/DatatransCheckoutService.cs b/Datatrans.Checkout/Services/DatatransCheckoutService.cs deleted file mode 100644 index c432099..0000000 --- a/Datatrans.Checkout/Services/DatatransCheckoutService.cs +++ /dev/null @@ -1,70 +0,0 @@ -using System.IO; -using System.Reflection; -using Datatrans.Checkout.Core.Model; -using Datatrans.Checkout.Core.Services; -using DotLiquid; -using VirtoCommerce.Domain.Store.Model; - -namespace Datatrans.Checkout.Services -{ - public class DatatransCheckoutService : IDatatransCheckoutService - { - /// - /// NOA = authorization only - /// CAA = authorization with immediate settlement in case of successful authorization - /// - public const string DefaultPaymentActionCode = "NOA"; - - /// - /// Returns Datatrans Checkout Card Payment Form built with Datatrans Lighbox - /// - public string GetCheckoutFormContent(DatatransCheckoutSettings context) - { - var assembly = Assembly.GetExecutingAssembly(); - Stream stream = assembly.GetManifestResourceStream("Datatrans.Checkout.Content.paymentForm.liquid"); - if (stream == null) - { - return string.Empty; - } - - StreamReader sr = new StreamReader(stream); - var formContent = sr.ReadToEnd(); - - Template template = Template.Parse(formContent); - var content = template.Render(Hash.FromAnonymousObject(new - { - storeUrl = GetStoreUrl(context.Store), - orderId = context.Order.Number, - amount = context.Amount, - merchantId = context.MerchantId, - referenceNumber = context.ReferenceNumber, - sign = context.Sign, - paymentAction = DefaultPaymentActionCode, - paymentMethod = context.PaymentMethod, - purchaseCurrency = context.PurchaseCurrency, - language = context.Language, - formActionUrl = context.FormActionUrl, - frontendApi = context.FrontendApi, - paymentMethodCode = context.InternalPaymentMethodCode, - paymentMethodCodeParamName = context.PaymentMethodCodeParamName - })); - - return content; - } - - private string GetStoreUrl(Store store) - { - if (!string.IsNullOrEmpty(store.SecureUrl)) - { - return store.SecureUrl; - } - - if (!string.IsNullOrEmpty(store.Url)) - { - return store.Url; - } - - return ""; - } - } -} \ No newline at end of file diff --git a/Datatrans.Checkout/Services/ISignProvider.cs b/Datatrans.Checkout/Services/ISignProvider.cs deleted file mode 100644 index 6edb66e..0000000 --- a/Datatrans.Checkout/Services/ISignProvider.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Datatrans.Checkout.Services -{ - public interface ISignProvider - { - string Sign(string merchantId, int amount, string currency, string refno, string aliasCC = null); - - bool ValidateSignature(string signature, string merchantId, int amount, string currency, string transactionId); - } -} diff --git a/Datatrans.Checkout/Services/SignProvider.cs b/Datatrans.Checkout/Services/SignProvider.cs deleted file mode 100644 index c4edf84..0000000 --- a/Datatrans.Checkout/Services/SignProvider.cs +++ /dev/null @@ -1,83 +0,0 @@ -using System; -using System.Globalization; -using System.Runtime.CompilerServices; -using System.Security.Cryptography; -using System.Text; - -[assembly: InternalsVisibleTo("Datatrans.Checkout.Tests")] -namespace Datatrans.Checkout.Services -{ - internal class SignProvider : ISignProvider - { - private readonly string _hmacHex; - - private byte[] Hmac => _hmac ?? (_hmac = HexDecode(_hmacHex)); - private byte[] _hmac; - - public SignProvider(string hmacKey) - { - if (string.IsNullOrEmpty(hmacKey)) - { - throw new ArgumentNullException(nameof(hmacKey)); - } - - _hmacHex = hmacKey; - } - - public string Sign(string merchantId, int amount, string currency, string refno, string aliasCC = null) - { - if (merchantId == null) - { - throw new ArgumentNullException(nameof(merchantId)); - } - - if (currency == null) - { - throw new ArgumentNullException(nameof(currency)); - } - - if (refno == null) - { - throw new ArgumentNullException(nameof(refno)); - } - - var targetData = string.Join(string.Empty, aliasCC, merchantId, amount.ToString(), currency, refno); - - return GenerateSignature(targetData); - } - - public bool ValidateSignature(string signature, string merchantId, int amount, string currency, string transactionId) - { - var targetData = string.Join(string.Empty, merchantId, amount.ToString(), currency, transactionId); - - var expectedSignature = GenerateSignature(targetData); - - return expectedSignature == signature; - } - - private string GenerateSignature(string source) - { - var toSign = Encoding.ASCII.GetBytes(source); - - using (var hmac = new HMACSHA256(Hmac)) - { - var hash = hmac.ComputeHash(toSign); - return BitConverter.ToString(hash).Replace("-", string.Empty).ToLower(); - } - } - - /// - /// https://stackoverflow.com/a/12187656 - /// - private byte[] HexDecode(string hex) - { - // In these case, key is not a string, it is byte array in hexadecimal string representation - var bytes = new byte[hex.Length / 2]; - for (var i = 0; i < bytes.Length; i++) - { - bytes[i] = byte.Parse(hex.Substring(i * 2, 2), NumberStyles.HexNumber); - } - return bytes; - } - } -} \ No newline at end of file diff --git a/Datatrans.Checkout/Web.Debug.config b/Datatrans.Checkout/Web.Debug.config deleted file mode 100644 index 2e302f9..0000000 --- a/Datatrans.Checkout/Web.Debug.config +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/Datatrans.Checkout/Web.Release.config b/Datatrans.Checkout/Web.Release.config deleted file mode 100644 index c358444..0000000 --- a/Datatrans.Checkout/Web.Release.config +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/Datatrans.Checkout/Web.config b/Datatrans.Checkout/Web.config deleted file mode 100644 index c42c0b0..0000000 --- a/Datatrans.Checkout/Web.config +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/Datatrans.Checkout/app.config b/Datatrans.Checkout/app.config deleted file mode 100644 index a11b43d..0000000 --- a/Datatrans.Checkout/app.config +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/Datatrans.Checkout/module.ignore b/Datatrans.Checkout/module.ignore deleted file mode 100644 index 03996c7..0000000 --- a/Datatrans.Checkout/module.ignore +++ /dev/null @@ -1,3 +0,0 @@ -VirtoCommerce.Domain.dll -DotLiquid.dll -it\DotLiquid.resources.dll \ No newline at end of file diff --git a/Datatrans.Checkout/module.manifest b/Datatrans.Checkout/module.manifest deleted file mode 100644 index e215165..0000000 --- a/Datatrans.Checkout/module.manifest +++ /dev/null @@ -1,135 +0,0 @@ - - - Datatrans.Checkout - 1.1.2 - 2.13.24 - - - - - Datatrans Payment Gateway - APIs and UI for Datatrans payment gateway (using Datatrans Lightbox mode) - - Virto Commerce - Konstantin Savosteev - - First version. - Modules/$(Datatrans.Checkout)/Content/logo.png - - Datatrans.Checkout.dll - Datatrans.Checkout.Module, Datatrans.Checkout - - - - - Datatrans.Checkout.MerchantId - string - Merchant Id - Merchant Id - - - Datatrans.Checkout.HMACHex - string - HMAC key - Your HMAC key in hexadecimal format - - - Datatrans.Checkout.HMACHEXSign2 - string - HMAC key for sign2 (optional) - Your HMAC key in hexadecimal format - - - Datatrans.Checkout.ServerToServer.Username - string - Cross server authorization username - Server to server requests protection - - - Datatrans.Checkout.ServerToServer.Password - password - Cross server authorization password - Server to server requests protection - - - - - Datatrans.Checkout.Mode - string - test - - test - live - - Working mode - Payment gateway mode - - - Datatrans.Checkout.PaymentActionType - string - - Settlement - Sale - - Sale - Payment action type - Payment action type - - - Datatrans.Checkout.PaymentMethod - string - VIS,ECA,AMX - Visa, Mastercard, Amex, Diners, UATP, Paypal and Masterpass - Payment Method - - VIS - Visa, ECA - MasterCard, AMX - American Express, DIN - Diners, MPW - Masterpass, UATP - UATP. - - - - Datatrans.Checkout.Language - string - - en - - en - Language - Purchase locale code used for creating payment. - - - Datatrans.Checkout.FormAction - string - http://localhost/cart/externalpaymentcallback - Process Payment action - If datatrans api call is successful executes redirect to this URL to process payment. Only absolute urls are allowed. - - - Datatrans.Checkout.APIEndpoint - string - https://api.sandbox.datatrans.com - URL for server to server requests - - - Datatrans.Checkout.BrowserEndpoint - string - https://pay.sandbox.datatrans.com - URL for payment page - - - - - Datatrans.Checkout.ErrorTesting - boolean - false - Enable error testing mode - If this switch ON Datatrans module will always send error on transaction post processing. Not available on "live" mode. - - - Datatrans.Checkout.ErrorCode - string - -1000 - Error code - This error code will be send on transaction post processing. - - - - diff --git a/Datatrans.Checkout/packages.config b/Datatrans.Checkout/packages.config deleted file mode 100644 index f9825a0..0000000 --- a/Datatrans.Checkout/packages.config +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Directory.Build.props b/Directory.Build.props new file mode 100644 index 0000000..4834e4f --- /dev/null +++ b/Directory.Build.props @@ -0,0 +1,12 @@ + + + + + 3.800.0 + + $(VersionSuffix)-$(BuildNumber) + + + true + + diff --git a/Jenkinsfile b/Jenkinsfile deleted file mode 100644 index 56ab4cc..0000000 --- a/Jenkinsfile +++ /dev/null @@ -1,2 +0,0 @@ -#!groovy -virtoModule {} diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..3caa727 --- /dev/null +++ b/LICENSE @@ -0,0 +1,12 @@ +Copyright (c) Virto Solutions LTD.  All rights reserved. + +Licensed under the Virto Commerce Open Software License (the "License"); you +may not use this file except in compliance with the License. You may +obtain a copy of the License at + +https://virtocommerce.com/open-source-license + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. diff --git a/NuGet/build.bat b/NuGet/build.bat deleted file mode 100644 index e864f66..0000000 --- a/NuGet/build.bat +++ /dev/null @@ -1,14 +0,0 @@ -SET "SOURCE_DIR=%~dp0%.." -SET "TARGET_DIR=%SOURCE_DIR%\NuGet" - -IF NOT DEFINED ProgramFiles(x86) SET ProgramFiles(x86)=%ProgramFiles% -IF NOT DEFINED MSBUILD_PATH IF EXIST "%ProgramFiles(x86)%\MSBuild\14.0\Bin\MSBuild.exe" SET MSBUILD_PATH=%ProgramFiles(x86)%\MSBuild\14.0\Bin\MSBuild.exe -IF NOT DEFINED MSBUILD_PATH IF EXIST "%ProgramFiles(x86)%\MSBuild\12.0\Bin\MSBuild.exe" SET MSBUILD_PATH=%ProgramFiles(x86)%\MSBuild\12.0\Bin\MSBuild.exe -IF NOT DEFINED MSBUILD_PATH SET MSBUILD_PATH=%WINDIR%\Microsoft.NET\Framework\v4.0.30319\msbuild.exe - -"%MSBUILD_PATH%" "%SOURCE_DIR%\Datatrans.Checkout.sln" /nologo /verbosity:m /t:Build /p:Configuration=Release;Platform="Any CPU" - - -nuget pack "%SOURCE_DIR%\Datatrans.Checkout.Core\Datatrans.Checkout.Core.csproj" -IncludeReferencedProjects -Symbols -Properties Configuration=Release -o "%TARGET_DIR%" - -@pause diff --git a/NuGet/icon.png b/NuGet/icon.png deleted file mode 100644 index 91c90893a511b63bbc796d90c408fae8baed3af6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12302 zcmeHN#~e774D!U5gcW3x(ibT#6J56fZ6XibHXCcZUFZ^ZXa@ zhu^uboP5}8=gizYJ9E$M#(>lma4;z`-@JK)qofGbg#Tas_d`d8za?}Ili$4I6jlOC zYx^vnb{NE2&1dc3i|)JBDagy889;}Z^f}Hn1(i-$lfPB#CQR~XQkaF4%!uJLo0CJPFr2*;p#{<_{*7}bKH9f2T<^CS#HN}Aoq!t0x zno6H@YO5CoI?pw#by|5r#> zlOazGYcL_&dAtdvT-VYvG<`+*?#GDvw|@dE|8`bd%cLTlmCmmY5J?fEqItd#a^odz z2XV(&)we9l^4sbsyc2j-(rtPRB#)T+})cuQtdKo|(Ykv;Kr+rCeLB`(a zrWFl&SyAGK)Xq=S8Yc`Gb@g|MV~yD?%mpwjvl&lVdw8T6R+BafJNMPmOdn$Nh(_7l zAxMHhDcHwtE4X!Dikiu71Kv#x2417SE@y0p<8@#63LF;B9D4}}3RKJux467>@>r4= z$u+kKAY4=k?dM*2`S%yEFR70ls*tz{TsXGJ8os^Q+jCp*n!HB*IqTr$&A==G?&Yh3y&TlCyc%Qa9zY7V%d~>j9!X{U$X&x8| zDL3B70({OPj{$~ReV}L(7N0mn;XoF`t#EyLe^+5?UQ_1W@P57YwL=h8e_ycj?S3WA zFw&xRNZy=L6EQC*hdFoL?z|0W$)lT_DMu`Fffu4O&}*XQe-WTv9s1joqOpazi9cV4 zP0qYtszWz6)dxp5dCV$Cn826LD^mbtA*5IVAMKug&;y+!X+7s>?EPL_d7H=05`q?6 z{_U+-WuwD?4#S4yGy+Ib+rH5tRLyMQ>d#QN5D!f5rwc@JdUxX082$a@ZkuGu;~5(0 zXN2?EAhLams;+KE1&|fOpQZBQgUHuyA#!=(&$pr~MwU134usn)+o1~aZiD6PEbF?)oSZ2IBPuGYA;eqCA0`4E>uxnok?a=e)j+hAzh|+$U<$(=xGXlW zsdo0crfNAKFIekB2gsL54*R}O8<{!s0!LlTDgW(%U^>)hcG7x^zr)g3>|e77N<@Q~ z&1-7J`HZy-F+Hw9*v-Z@hCimA1TJ3I7RJv>0mzz|$uY?3BoIqILHn){91Iq93$Z}N z>sCf|UWV4HYEnor3~A-ZybN#8eIO|r8EaaR*0p0cX^hX;lS%x#%ueVkTdqcixmm85 z+SYw1Cc$HMr6KJtU3)BaoTO#`#edW0hf;+m+(3})OkWVSGh?nAuLMs#0EedC4_Rc7 z_Rj_WK+nsDeyHA=cWSTE`wgyYv|PpCIdrFf?;$qfy7e)1N!jZOhI>qeN}Ov7B_6{| zZDbPn)B~FuJ0P(WuO=L?Q<1fIlF0L?N5|>0)};Gnj2_O&(t{8ck+Fw^OwtR+X<>wA z0SnfT&%0cfxkA);BFpmETdM5APnP=2=s(kbUuKUn|IrMcZ6tZ7t&Uq_(^Qtfwk*-2 zSaq``^ZerKn3)-U&v@NhJHIIKY=PqHf}+FfsoGtw8*5XnR6hl!k@+I?A*;WM(Orvx zFqfp(nxX3krGJwVy@+76XtzjUq@1oRD!X;@GUGZhe|Pt-@~);8p`er*IqLTIc8O+1 zE#%Nq#&HnsNQ&4YOmL)BZx@#d$ci;7;A(6 zZ8vOLQ<~HCpRCGxLh+B#b?|s@ZOw&*ad+_jhxSL^!S>Iknl{$fS@Ol9^Nf+ir}Qa* zf7wo$aIOhV(qv?g0B~vggD#2pLhEYhR|MJ}1?`?UbnLvoQ(3hd+xS|ueMqte&{L=< zDSuaFzFl<{J%|tC#QI<#7f1vy^jvUsp?Z}^IG=NxeE2y=JAEHWImVoZ>oV1rKu_vX z>uh97(-?C`qs$rmukz7H(_@Cg9+1{5a#|J^1r8~}W0|l(4uVPfw-F43H zt<;x3o*%AzzxyMSG8_QJlV#Pg(O@(v0d(gBG|#h;rd0;b?35q?remdlI z;rF@@)!|V`Jhy6&N14*gi>v(i%Up-w+MU;y*)^sSv$LP{*jj&ntk$)(c8*kT^rk#K zO;=&=+nM3}Zho`@pZogfe z{`Wx9WJ1J&cQrV>g4n_W(GrIIfhvtpB(kd(?EUKgx%6hpM1RU|rYXu(f$=lSh7iw| zTAYtce&Dj|J&MzEA{E2sDOv3}HM;+cbFtShb6Qsb4*RS^r{KhrA8o%HC zJ@xlDp$s>VfV2onE)-_MK#lMb1A51B7soglT||)dB~ZIDH26_==4v>;>$$jXUA{Q} ztKw`@Dr&m(aZw~LVSGqrNCn#{O9Bz}${>Oy$uUwlcIn=<)a!O2K7}h_-O|lBOEW=D zCV-flCDS8SxzuyjH5#3t$&Ok)?xm4S8dx+nd~M$mjCS7Z)gP_b9LQztIdedslvF| zqvHU%20L6|OrALxwIM`Qt|i0W(h|&D#zVIrPMx5p7j!S|NY zVML_D<3F{6y5RxeCe{MqW~(j!AfCkz(Nv2j;^$A#^Fd+1A2$ZPmDxx$(iup6NoC9^ zQHvi5l4F1id%(O46zoJrGfDrb9m!Wbd;&K2g2ken;0~GX(~qFX2C2aHvMIaTU+uuR zGS=aTp4l;%7}SGPItrf(1d%zA86@MxTIjIDS%I8sn&r0)4!f_#`o{C6Q+6A_tKpcv zS^lN;wm5lv4SEw5g5Y*Re^pA>69-1q-Eh^`(6ilu2uh~WeX7vb|MaPF_xA$eo6lU1bec(oCbwSd|?E zbZLnUmT!NPCvDe%PKm;qniJOcqy#XC)yZ)wie2|&U(ehU>8MA4(xzUiez9QIL0-9= z4x&7zr?6V=jf`!Ut#A6uFtB-mEqkr2-0*&^XxudH&)ZZ@Cl?n`MXEi}ZY~Kw?D7&r zoV|49CLJC=)be|MUit1^C8N0gN7@y>&lX*FboIY%V0NDK3JNysG|=HxRd>&VToeVX zjz4si;V;X_V_Q-$5T(+{BbaWk<_($}_HkuY%sVEr8`g5f`Y^-;Zp%|${-t2@B+xLw z-g3z^GgKQVJUM2Rcf24p9t*OPVDV*7ElQMW*$*hNcY5fb57^Qwz$W?P+%d>p@|Gn?!1_i!Gk;!cITP$b{{no^67kO~G*yQiN?{*Ev zd{txf{@7llz5j_9MC9vsfT)L~(OQ5H@AHYwJ?& z8=7{{sa0KC^@}jG2nbUVSv5t}rDc`Guf_ycuAmnEdIM1{ciqY$D>MM|$AV1d_&-i^ z$oxPK;>EvqrB8SUTn#l7d?5sS#}jq1nZ5ZZ6L5$HzV;?)k12wMOUU?=kBJm#{H%35 z!T$!mk8+-N(G52zSBXPvH=R-ZooHJ3IEG><6&;3lBX~A>V zD0%f7GW=Me_UOv$g35R0(;R$rg{>GT0xX{heTm^n+urU^n|c=h3RU`vcB0&cc+h0;zJ|=!w3naDT)ro^)rb^*7&$Mf#43Lp z7mYdtzlX8<>vbCqSt`^9pafsR#r_}53< zj)@YTNO^+bNAZRBQ1;Ocvh$F2^rk)&UVN|q17Cy`<=zKYcfQz~0PRxRCb_o3Tb@{J zi;wTX#nDeL;IH=C3+WI`(M=N?U)2i-&~n5RW##X$OD$j7S3;*bW-`Kgogxkc5%6#T zPSFb)6H|W2m}9Zcy-nqu{WfGtu6--@>P1fn%1Y?cBDu^Rv*)eHPAKWA^HOPK1)gMH z`-A1ZINFZ_n-i(iwj1h}SwdW}_d!$PVDtrj){WF}R{NwC@d==jo52GDwzpbDT2|8l zPlDS|tgGQ;Mn2v!RCXgVKDGPI*gutlKAoa*I=5U8wuMVAunc7Y@NIG(fDOytBked&RF!Eq{S- zbQ8Oq(l#2)`@V3Rp#yVrT4k-R$nVZiAMF~<$rqYb+0%}Cs~Aa~(pD)`_X()xFKS+d zE9=4>Ze8B$H3x^i0L-Mwnd^92YGE74P9_iQ1#{@jC9B(hOhM0pm>cpK%jk;lDdL=4 z+9IkFl417Qxp*czdIdtU-Y*jcAEGNcrGNZN0~J1kI|;bo{L=!LjROdI>{`pw<2F-g zMe5S{KX{*Oh`Ke{)}%(@GZA7$dGzHH)vO~ne>MCa!agpw$y{ZMt4R(u|H08jDE#|D zw51DKOaxPzKKkDS1hsMnhKMTXWEnnM-Nr#D8u5XtBQwvM9Q9H^$BFqL1p@RvpEAg( zr|X(gdy~DA7!qR5a>#|SjLRUYvbAjb{c@>|FDQu3DR!y8$_NWAk97TKVw(~*D8bhp zfLzR2Z1o{)JPt#L*5OR`xwQErV-5GrwF8~$)H9S;sd$kYv6drlLNanikfw?M)JV59 zwAGkNyemZOsDlkhQ`x=MobXb>` zPMckhInCa5R>K~*kth6q6Nb^Kqy3|xcqBnF*tt-$moEwJ-Xieq?@+_{9zFeLz0Z4k zNBkMA8G#a=t|H`X5|Qe9*N`B|Y@;wZl)50|~WaU`j66B--f9j_G${7LL6Koexk#%$~o1uQ7AiI@C*Ce?fF*cOHDy1YUjA^8DA1UcMP(HCo(i^JM$l-xzRs?s#%<5 zJy%9CyeSkeW@M%mCBjP~9$Pf~lZdj>pJOX@7CA@rO`9nelDHK<8s?_V(ybT!w=t4q z`UNQGDhkF_-AG|~cpyi*BgE%K@Ic!$kv>a&iqGS*bg}~RML>?XOG=A~f}b_bruV>z z^)$tI=I>2pzAm#G_a=jqu&#p2dyos?p5Q%W5)pSXV>yvR(zYzvDtKc3g?xU{WSQQ} zwu$jSb$!H|s_Sd63?HstH)>3z($1Z8eQ(9j70`2s>OMwA6DZ&^;>9yYC;zudIcZ)W z=*H>AnmhEA5uKI+Ns7tJrL=i1oBV}!F~6aVGsC{xfx?83`_8gcx9iqZM78Gh$!ycX z5Bw+p278;nJ1@+WDz&>O=@*7gIhm#<6DQZzxlJG5*nU|7ed8@(mh3kT!qUmbf+pF4 zi$V}oklgODE!+vEfz$5-=@#u0I|UQ8?AEOi*-%;wsW0`P0WjslO2>y|x-G63vGV;{ zf_?RWFOO>kB(>$vxvnrYHA#!!IcO@Y{Ig(%Qq;$%lJOas zc7z!E>8;;N;O7oa(ME(60!}7!nJyDLLp~QJeP%XJ7+ue0k>E{mI$c9zCQ_2WF7CJB z8AZD#y*2`^_qW}26_c)`Hte6iErRngKw<*TpXVn%#@Pq8wPhw>|Gej1QShfVtTIje zfx$sKKd+Lx_uHm0+Dg7+M?e3>159%I6loPzz_eQg4Gux8GVuZP!2A6GE*d1Q9m*BqD2=uR{AF{9y zN0Csy-r+TR(gts;w*Q&GEs3CgOX+ebjgAm6dqQPeXmV%&DGz74sL70j^z#vI)}x$* zrSFlblRsmGnR~!jPxe4qKhip!H^H9ri!cSlJZf$HS!wzmt})-bubTjaghZAPqGCC; zV@SSc-ae^yQL?>_0dDn#53iukV3kkj7W74Zw~guiueC5E+~2xQ&caNP#O8iM9(2!e z+4_ejFxQ?E4q;Subj;v+@cj>gpIfW15|y11R}SV}I@kC`moBf^5!)L%!fIE$H6bJf zTqjRVLGF?LX~J8(!%bS0T7QWxi!Jf&^vgiAB+qI08s0FQAH9lY$}V)F)A!xEQuOfl zG%g)F<+@zK3x_gbemFDogKlF}2e{$Qh?^p_)_pLlGD=5PSow(`n8-*e#9=*6XAz~`imtw9zLE$~)tSbwklBw15s zw6bv!d{{VHof<9na(2_^iZRn|%5`QV>U3}|I1+zHL4L@pUT8dUn1kwDImGDUN0*e& zS!4&tnC*t|S_paKiXUHqDn`^h1dsI)1tk8GruD(1opw0Bo$^w=9GIj z!wZc_|A%k$8j*O6V!{^$wI1j!2}3lI`m_WS(iVi~EZuR8*tR1?A3=mU973xVK~TG( zSu+fBdQ#c=T^?N3K1Z@p^mg;W$c~1116IohV=?G_vwONVK>`am_VzzL1!ZYxk|W1* z8|YCSl+fPAIhHe#2b>_|M9t%gokSkqk6v;Yk|w2px!Se%9-l#Rh(ZhjX`o^-Q3muf zo=^Z;<&^2u%gi8CI_*$+9pZS0791$#!_98}^s1u}gaw;>R}OJBuVFBb018=xpOt{G z#1>B|U>v}SLgx4aipsx!?zkReZc9sgoGK5r3zyMtPNyhm4I?lYM-P;)_P6W#AY%NW zMM(-<)Q3fNw3-!mZ9S0VxwJE<({)=yBDyVgmS_}t5ca@CSjSsK7OEUCe{w*72!xo3-P!<8`g3CyQk=F)5SC?i(w~%3hIW&h3EB zPVI5dJX0a*va@!pFbw2Ls|DfuZoCW4geo@VTbZH6*%#&cQ;wU;sg+!2C?_dGNjlYE zw@3ukY05r`jSeZkcFJK5I~IOz2F1GKs1$aBA%JA9q2ge?>3`sUp-kMD6<+7h@FS0% zYw(nq1z+q!d9euJZNU%nq49cKo?~l)u4}Rf2s2nBm=_B?F`6vtk*yMhyxer|;kDBFlwhu=mi)3s2Ec?CKyH*LrQ>;CE$1O2J2{TwZzRb01T`)SK#ClE z1F(AKv$(-fR1F0yrohw-P{izfIJJu-4BN=DcjDDC0Z|M3a34negPAMW$q!$Gm zMxhX@f}&+-*?95DoM$nM8x6laQrvgj5&r_Sw~yFgVPr}!^Z#BdX#p8$S z`(Q+Wx*A+BA&2FI4+`SmAF2*nhet^Pdi**7kOQwSprzPdjO*dEq=uGrwi$VkLi7|O zE%FNGj6gvvf`;AFdmO7*HsBpO0}o{$O($L&W~wrX14Yk6MoQ$?EeZQqeU_PFceqqN zxN=m11*&WaMluaA>|6C$U5}P0S_?!wU&2}WAy^K(5p$^j%03_5L9C+;?3K16>NgdM zb-UpnsAIf1`6n&eB;aSmxgp){DD#85iR4t;u*XXypg}YeQ(3w&#PHLgsfpan7UEj< za!d1BfsM`Oh?n;1zv`GsO9m~Tl>kB=`yx!82z$VQLK34dIi}6{GAeeSRm*>uW`iaIz^$fE1Rcf_ zGWEyky!o?H)&4O;Q)9T|-%7?6HSt-&-23qLb>T^N3G5iRoxBO}2G@G`PcvL=J+MWp zRM=SlHkmT$M{#z-+8fXUDg&vkl~&1XpDV!hiF3zeBINd9(Q*k14^f^&@nVAZEST%W zDlEz~H)mwux137wlFPKO<1s-e%26%tjKpQ6<-endX%Fx~37 z(>hxBr|Hr^JaBCMIkwH|VsQqOZ{enU{_C*78PVmBYwXeemsY_qp z%kSdTh#bieA3Ec~E`BUWN747!GjNfi^eIOylEsf5beb<`>t9Z-bw*0BR`c=iu~h~` zTmwB6q&YdwAOl{7ppplc^`0(w7Gfew$zVEfXUHg-N!ZF{lU!BvB&BNOS3?82v6=$q zS&#~7m)*e}rLmo`#MXrfK6~$u=3#MtbJciY9b2ipRAlXhvi(l0rS)Z~nY7ks!_9T= z``yyxbX;j_~(w6|T>n;=hxy0@4z z^tbMGnfB)&O4SGOB~P3d3w}K0;DR+3jRB>%j(Z|UMlH@2I^wB-3$dBtv#MV(4Wzz* z`PMQ|_S+@Q&5U?^RJz|)9A26=b*aJkS-GoJAdZfKh0&vLN1S-X=O}t!)#WfXO_|Z2 z*Xh`D%og5}Pc9)`Jn_`MkHc8_>L+&e*`ycrAX9~E(>~K6I_-o~oHP8SHMA^Q@D0$2 zg%^FK_h~EEXFkKeBM74lRASV1V#N^ixZrle)%m8Wu^9Cn9wS5Csmhl`URQo>@b?PX z>VY4G7y|Jvj}DtgNuS8sHV+6aU^~_)L|RU-WiU#e(}1*O@ZiwvF%0?gnfLQnfBayQ z0|Fjm6wVjS0J3M?dyzBl%2tdte~@YP0(a(eo692Ue=V9Tw)}+=u8q!M$lUC>R|Q|f z85~yZ#}lm{;b#IwJ9zL5p+K``T~WF_Ez*%^qpN(^Gg|fqlRS)gz$xlMuuDpnZN-12 z+=25U*m*@G)`}W>Y1wZQgh4Bb)AVAut}r1_`6m0Vwl%{2EKG=;f9YJ2YJ2jW@w=&% zio|@@yq&=26ZUIlEHNw=h7jBs!hZhx0HDSa&SAb@f5qx=<%Jjjve{@p!>$JQ% zu#upLmP37LiG#R|`9X-x1Kw{91_@i`6Z19=GX1^K7Y@L5Gco z<$p+8e2H8}Cj(#%XIq$OSL~xTg#nR?h|E{|+rDuz8YlH-@XI+u0q8ufyKc<}Rb4a< zXtcx;QcNs`zeB!u^N>sFkeQz{XlI0jJz1Kj@xf!ix_{ws7n^Sj%b8WkPg+%2kGU%-==^Hf6_y>$*s^~I6&vnE`j1}p z$&}pDdnANoLvQ9xX7+U2MT2p!U1eLLyCLRm1fiy|;h_qJ29_5hZ7S|U+=|Wh6 znUI++{y4YA2{nT^Vv=ao(AjyLsAWeatyL8<(?GWha+=u7nuBed52S#&t`j#Z9AAEt zenJT)zZ7Lp!RUBxoMN8VXVUH1$JNE_h*g10xy?BubSPJTPaPny#>kw9z&m#x`W}w# zptpv1P=q9u@%b@7%2^c*E>Ip(VW?v2zXm@rF_k5@GD;8P*`g;=V>K;`|C*gMI*?XS zR8*A~BfCkv$~HG5Cd4${EjahYVV#h6Cz)D6MrQh&ID}-fkrvsiGxatM4-i)Gl~KI3 zgyi@J#2XwLyv=nXSc7e>@vH`#mS2$F*ujr+i=a>-$0g_KpV>D%@&%Gn9XR4uA;3MF z0WW|A){Aq|5JDFLde0}=!&!Xvk=2S@OJB*#kFe+ZQ=t^>Ox@9ZkM9?dM>X|2ET4jQkyBixUj1v&#crHaUEFYOLYrh?C`Fj8=!=Xj`8i zyN2^&#~>Vx#g0U3ly_=1EIfAb?3fQ!9HNzq6NltH5h~I!9D3cTD_*npU$|lO#vA%! zWuwf{6N}ui!A+BZ&;U#1_N2JUjsMldMM*%+WjUhVF7A_BQ_PKuebN1}s#_(erBuam z##F5WX@a+ZbyA&4H=xaly+Np>w!)>qD(eQ{du{q_Pa)2U;RBG}Z`^k3Br#EoDe7uf zr=Q`pJUiNQ0e`}r8j3cQR1X*W_+J9YQy406lzTUegxBlKECMclbcz6C z)5!{8J#@xqKVH)pni7e?ML09M4{}#wJG{uUP83l(ntz*-RqVa!g^!$CmI0g@u53Z9 zpWkiF_BB-sq91A(PQV8knHH4dQefo5FNh2RbG#jes3b2p{Gx+@>F$493dZ~52Hf(Uf${lezS>^pNIe7ew^ zp#DjMhK9LbXE`SMq-}LGu~)jD87$U!kf3i~xE+ym4Rq%8@@f_$1~Ui3E3vS5 zGxN<&GudB?g83ap`gCb{vR=TOgZPJsW=>^i{HwZf@N@epWU%S}1Z+w62|b{JPhvK5 zswVz8%StM#MiV5G%TqtFUuD6lghJLHm@lux@-^UI9r*>;+pM5`0GgUnT8L2aFtM7Fl z3L4jvgZVJwAYbOpj^zy2RCHUqLX@gQiD^vKvbSYs2i$yE=(8bv%#}Kbv#v%Cr=k2v z(IGQJ439c-9b8-M5ASBKmdn%byQ^KDE1;@FtN-n!_cCD=3be1NDq=Aj*?-!uf{WQb z$_E@4=5EE{+O2gf%Q#?G@ogQPGh#MtL@qx#l66;y)+{fq;lXt~Hyh}QW5f-h5pV^- zTY7qW1$C&^3_hwiO;7W1r@o<voZ8+E+5OZkmSPhtAsS)0jKB!=>;omyOdY2` z^b%olII_+dI-g`n;Kx!VI;M2sIxe`Coj^riyLBQuX>7XaCCbWQV99$_hii5jHtiqy z#2;Dd0y0=#>Ka4%r|8pVg(%`i*XUbjtBM3_iZHzkeaKu-1MSkge?&Ul8^LV`A_1C* zNvr8ImM*0X!8?4|l2O#+7!X80ERccBe+T=8MgNkLvy_^Mwvk62J5uC9g#X zNV10y!6|nwV!sdTawXPiw6-JBaM=aa6c7pXW#iU+&0hb_Ge(v6El!gf0)CeN;s_q# zN!3&E!2#A|2O;eWNb!e>ezv`=$=ROZ`SkP7U}|#w?8ff6xCA_ + True + True + True + True + True + diff --git a/docs/media/diagram-db-model.drawio b/docs/media/diagram-db-model.drawio new file mode 100644 index 0000000..7d64fff --- /dev/null +++ b/docs/media/diagram-db-model.drawio @@ -0,0 +1 @@ +7Vtdc5s4FP01zOw+NMOHsZ3HmNrtTO1tJkl3H3cUkEFTjBghf/XXr4QkMJadQLeO1dgzngQuF4HuOTqSThzLCxabTwTkyQxHMLVcO9pY3kfLdR3bG7JfPLIVkb49EIGYoEgm1YFH9AOqO2V0iSJYNBIpxilFeTMY4iyDIW3EACF43Uyb47T51BzEUAs8hiDVo/+giCYiOvTtOv4ZojhRT3ZseWUBVLIMFAmI8LoRghs6wRmVr3gPyQJkMKPsygyQ75BY/jihlPf0znIn7DPn2TcxxnEKQY6KmxAvWDgsWMpkDhYo5WXeaWgkG2KP88aWFxCMqThabAKYcqwUDOKdJkeuVnUgvN0WNwQfVtvpd5tmn9fe33Q2i+8Hzx9kKyuQLmV9ZW3oVhUcRqz+8pQ9CtHtA0wBRTgb11dGMIvuOLosafzwAxL8hGcgY50fFRQQWl/DmUyfIPZ63kdHpchzm53rXZPvWeAlCeEL/XF7kpKAxJC+kNiXgEcNtsnKfYJ4ASnZsoR1zbGKSckuv1SQlEVZNVkKJJPiqsHqGfcYlcSSA9PryXbksBwoSqomRNflXbsw7zXU22uov9+QKI3WEDvY6XgdKlnUhVHuO6OU15JRzsAwSvXsJhOc4c9Sqt9syLX9N6WUzqivJIKk0HjFFD3nhxQ8lwwqSSCnMI+zgE1KFKCM6a9gSYjTFOQFKtNFJEFpNAVbvKSqIXU2mqMNjB7EDMZzGf+mrLFCUozPBYrV/DJIUZyx45BRjj9xRGDB3mUKCiozjpJyBQmFmxdZpLDx90BWw32HZa5/iGWefZxQDQS7wuW9LgAKKNZ1ikD6wBYKIItLzJqQ8LpGBOdPavTxQM6JBsl4BcVUXRafDfUAp5gjmwlBKNPKzvkj9mHdDewb3/LZCwTs3KnP2YenExrgrKAEoBIOyIBaQw7WiOJcPieFc/UaRBaTHz9jStnMfwzWF2n9OtYSW68ltCdDtqche/+lC7aY9XWelqqdoCiCmRiSfJ0IarwPQHmw/lXN98HYH4gt8fBa47EDgPeW9fe1+mMuhP+ymwLXurOFav/19Yn//DadWtVS1yR4lC6K3FGRgxBl8VTc2d/Dzz8Ffhvr6Hhy3xLP/iUr5eFV2a9Ryv65lXKgITv54nQB943GYksA+q0BOJc0DrWCh8uC9Vmoo3tAGo3D4lVd/OVgmaKDt1cdPI0O3p5bB5Vr+JPQmqWCt63Lfy4VdHQ/T6wQI0Ahi8tfFyGD7dEyRQYdfef8mKB8UYrW1evQvA532FLeTud1OPqW+IKmrg6ba6f97swUt8PRt9vvye6oqGvwdKZvkAspiFfPoyuIxsxy+t74giSzw3Kzu2Se3fZw9G34b+17VFw1WCP1zXNlCl+U7dEBK1Ok0P1/u+OrFBrsfLj6VtzAwdey/hVRzdVBVd5Da8ULdD86IGaMGur2RyA9/Kv9Ye18taPzVz3sk0F2tT9aDsffz/5w37f94Zpvf7i6/fHaHzUvyfvogKAxU9zV+ziVXp7d+3B178PAwdi2/uYbH65ufFTqmIEFX+mHCSB/+PafF7PoN8kCYaf1P7eIr4LX/5Hkjf8D \ No newline at end of file diff --git a/docs/media/diagram-db-model.png b/docs/media/diagram-db-model.png new file mode 100644 index 0000000000000000000000000000000000000000..834662991266273e35cd3e6dbd66f480d99c60f6 GIT binary patch literal 19704 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 P(ToA1YoY@#pTzxN!UK=I literal 0 HcmV?d00001 diff --git a/module.ignore b/module.ignore new file mode 100644 index 0000000..e69de29 diff --git a/src/VirtoCommerce.Datatrans.Core/Events/.keep b/src/VirtoCommerce.Datatrans.Core/Events/.keep new file mode 100644 index 0000000..e69de29 diff --git a/src/VirtoCommerce.Datatrans.Core/Models/DatatransAuthorizeAuthenticatedRequest.cs b/src/VirtoCommerce.Datatrans.Core/Models/DatatransAuthorizeAuthenticatedRequest.cs new file mode 100644 index 0000000..cd6429e --- /dev/null +++ b/src/VirtoCommerce.Datatrans.Core/Models/DatatransAuthorizeAuthenticatedRequest.cs @@ -0,0 +1,9 @@ +namespace VirtoCommerce.Datatrans.Core.Models; + +public class DatatransAuthorizeAuthenticatedRequest +{ + public string Token { get; set; } + public string ThreeDSResult { get; set; } + public string PaRes { get; set; } + public object Extra { get; set; } +} diff --git a/src/VirtoCommerce.Datatrans.Core/Models/DatatransAuthorizeResponse.cs b/src/VirtoCommerce.Datatrans.Core/Models/DatatransAuthorizeResponse.cs new file mode 100644 index 0000000..26e7f8b --- /dev/null +++ b/src/VirtoCommerce.Datatrans.Core/Models/DatatransAuthorizeResponse.cs @@ -0,0 +1,9 @@ +namespace VirtoCommerce.Datatrans.Core.Models; + +public class DatatransAuthorizeResponse +{ + public string TransactionId { get; set; } + public string State { get; set; } + public DatatransError Error { get; set; } + public object Raw { get; set; } +} diff --git a/src/VirtoCommerce.Datatrans.Core/Models/DatatransCaptureRequest.cs b/src/VirtoCommerce.Datatrans.Core/Models/DatatransCaptureRequest.cs new file mode 100644 index 0000000..3a1a427 --- /dev/null +++ b/src/VirtoCommerce.Datatrans.Core/Models/DatatransCaptureRequest.cs @@ -0,0 +1,8 @@ +namespace VirtoCommerce.Datatrans.Core.Models; + +public class DatatransCaptureRequest +{ + public long AmountMinor { get; set; } + public string Currency { get; set; } + public string Reference { get; set; } +} diff --git a/src/VirtoCommerce.Datatrans.Core/Models/DatatransCaptureResponse.cs b/src/VirtoCommerce.Datatrans.Core/Models/DatatransCaptureResponse.cs new file mode 100644 index 0000000..aa27e85 --- /dev/null +++ b/src/VirtoCommerce.Datatrans.Core/Models/DatatransCaptureResponse.cs @@ -0,0 +1,9 @@ +namespace VirtoCommerce.Datatrans.Core.Models; + +public class DatatransCaptureResponse +{ + public string TransactionId { get; set; } + public string State { get; set; } + public DatatransError Error { get; set; } + public object Raw { get; set; } +} diff --git a/src/VirtoCommerce.Datatrans.Core/Models/DatatransError.cs b/src/VirtoCommerce.Datatrans.Core/Models/DatatransError.cs new file mode 100644 index 0000000..b64af8b --- /dev/null +++ b/src/VirtoCommerce.Datatrans.Core/Models/DatatransError.cs @@ -0,0 +1,8 @@ +namespace VirtoCommerce.Datatrans.Core.Models; + +public class DatatransError +{ + public string Code { get; set; } + public string Message { get; set; } + public object Raw { get; set; } +} diff --git a/src/VirtoCommerce.Datatrans.Core/Models/DatatransInitRequest.cs b/src/VirtoCommerce.Datatrans.Core/Models/DatatransInitRequest.cs new file mode 100644 index 0000000..98f7661 --- /dev/null +++ b/src/VirtoCommerce.Datatrans.Core/Models/DatatransInitRequest.cs @@ -0,0 +1,12 @@ +namespace VirtoCommerce.Datatrans.Core.Models; +public class DatatransInitRequest +{ + public long AmountMinor { get; set; } + public string Currency { get; set; } + public string OrderId { get; set; } + public string ReturnUrl { get; set; } + public string PushUrl { get; set; } + public string Description { get; set; } + public string PaymentMethod { get; set; } + public object Metadata { get; set; } +} diff --git a/src/VirtoCommerce.Datatrans.Core/Models/DatatransInitResponse.cs b/src/VirtoCommerce.Datatrans.Core/Models/DatatransInitResponse.cs new file mode 100644 index 0000000..cfd79fb --- /dev/null +++ b/src/VirtoCommerce.Datatrans.Core/Models/DatatransInitResponse.cs @@ -0,0 +1,7 @@ +namespace VirtoCommerce.Datatrans.Core.Models; + +public class DatatransInitResponse +{ + public string TransactionId { get; set; } + public DatatransError Error { get; set; } +} diff --git a/src/VirtoCommerce.Datatrans.Core/Models/DatatransOptions.cs b/src/VirtoCommerce.Datatrans.Core/Models/DatatransOptions.cs new file mode 100644 index 0000000..51b6634 --- /dev/null +++ b/src/VirtoCommerce.Datatrans.Core/Models/DatatransOptions.cs @@ -0,0 +1,43 @@ +namespace VirtoCommerce.Datatrans.Core.Models; + +public class DatatransOptions +{ + public string SandboxBaseUrl { get; set; } = "https://api.sandbox.datatrans.com"; + public string ProductionBaseUrl { get; set; } = "https://api.datatrans.com"; + + public string SandboxSecureFieldsScriptUrl { get; set; } = "https://pay.sandbox.datatrans.com/upp/payment/js/secure-fields-2.0.0.min.js"; + public string ProductionSecureFieldsScriptUrl { get; set; } = "https://pay.datatrans.com/upp/payment/js/secure-fields-2.0.0.min.js"; + + public string SandboxStartUrlBase { get; set; } = "https://pay.sandbox.datatrans.com/v1/start/"; + public string ProductionStartUrlBase { get; set; } = "https://pay.datatrans.com/v1/start/"; + + public bool UseSandbox { get; set; } = true; + + public string ApiUser { get; set; } + public string ApiPassword { get; set; } // или API key/secret + + public string PushSignatureSecret { get; set; } + + public DatatransApiRoutes Routes { get; set; } = new(); +} + +public class DatatransApiRoutes +{ + // POST + public string InitPath { get; set; } = "/v1/transactions"; + + // GET + public string TxnPath { get; set; } = "/v1/transactions/{transactionId}"; + + // POST + public string AuthorizeAuthenticatedPath { get; set; } = "/v1/transactions/{transactionId}/authorize"; + + // POST + public string CapturePath { get; set; } = "/v1/transactions/{transactionId}/capture"; + + // POST + public string VoidPath { get; set; } = "/v1/transactions/{transactionId}/cancel"; + + // POST + public string RefundPath { get; set; } = "/v1/transactions/{transactionId}/credit"; +} diff --git a/src/VirtoCommerce.Datatrans.Core/Models/DatatransPaymentMethodOptions.cs b/src/VirtoCommerce.Datatrans.Core/Models/DatatransPaymentMethodOptions.cs new file mode 100644 index 0000000..c9a1221 --- /dev/null +++ b/src/VirtoCommerce.Datatrans.Core/Models/DatatransPaymentMethodOptions.cs @@ -0,0 +1,7 @@ +namespace VirtoCommerce.Datatrans.Core.Models; + +public class DatatransPaymentMethodOptions +{ + public string MerchantId { get; set; } + public string Secret { get; set; } +} diff --git a/src/VirtoCommerce.Datatrans.Core/Models/DatatransPushPayload.cs b/src/VirtoCommerce.Datatrans.Core/Models/DatatransPushPayload.cs new file mode 100644 index 0000000..6075d25 --- /dev/null +++ b/src/VirtoCommerce.Datatrans.Core/Models/DatatransPushPayload.cs @@ -0,0 +1,14 @@ +using System.Collections.Specialized; + +namespace VirtoCommerce.Datatrans.Core.Models; + +public class DatatransPushPayload +{ + public string TransactionId { get; set; } + public string OrderId { get; set; } + public string State { get; set; } + public long AmountMinor { get; set; } + public string Currency { get; set; } + public string Signature { get; set; } // если Datatrans присылает подпись/хеш + public NameValueCollection Raw { get; set; } +} diff --git a/src/VirtoCommerce.Datatrans.Core/Models/DatatransRefundRequest.cs b/src/VirtoCommerce.Datatrans.Core/Models/DatatransRefundRequest.cs new file mode 100644 index 0000000..4c87a6d --- /dev/null +++ b/src/VirtoCommerce.Datatrans.Core/Models/DatatransRefundRequest.cs @@ -0,0 +1,8 @@ +namespace VirtoCommerce.Datatrans.Core.Models; + +public class DatatransRefundRequest +{ + public long AmountMinor { get; set; } + public string Currency { get; set; } + public string Reason { get; set; } +} diff --git a/src/VirtoCommerce.Datatrans.Core/Models/DatatransRefundResponse.cs b/src/VirtoCommerce.Datatrans.Core/Models/DatatransRefundResponse.cs new file mode 100644 index 0000000..a6a6557 --- /dev/null +++ b/src/VirtoCommerce.Datatrans.Core/Models/DatatransRefundResponse.cs @@ -0,0 +1,9 @@ +namespace VirtoCommerce.Datatrans.Core.Models; + +public class DatatransRefundResponse +{ + public string TransactionId { get; set; } + public string State { get; set; } // refunded/partially_refunded/… + public DatatransError Error { get; set; } + public object Raw { get; set; } +} diff --git a/src/VirtoCommerce.Datatrans.Core/Models/DatatransRequest.cs b/src/VirtoCommerce.Datatrans.Core/Models/DatatransRequest.cs new file mode 100644 index 0000000..7fba2c2 --- /dev/null +++ b/src/VirtoCommerce.Datatrans.Core/Models/DatatransRequest.cs @@ -0,0 +1,9 @@ +namespace VirtoCommerce.Datatrans.Core.Models; + +public class DatatransRequest +{ + public string OrderId { get; set; } + public string Currency { get; set; } + public decimal Amount { get; set; } + +} diff --git a/src/VirtoCommerce.Datatrans.Core/Models/DatatransResponse.cs b/src/VirtoCommerce.Datatrans.Core/Models/DatatransResponse.cs new file mode 100644 index 0000000..2fb30aa --- /dev/null +++ b/src/VirtoCommerce.Datatrans.Core/Models/DatatransResponse.cs @@ -0,0 +1,7 @@ +namespace VirtoCommerce.Datatrans.Core.Models; + +public class DatatransResponse +{ + public string TransactionId { get; set; } + public DatatransError Error { get; set; } +} diff --git a/src/VirtoCommerce.Datatrans.Core/Models/DatatransSignatureInput.cs b/src/VirtoCommerce.Datatrans.Core/Models/DatatransSignatureInput.cs new file mode 100644 index 0000000..c61880e --- /dev/null +++ b/src/VirtoCommerce.Datatrans.Core/Models/DatatransSignatureInput.cs @@ -0,0 +1,7 @@ +namespace VirtoCommerce.Datatrans.Core.Models; + +public class DatatransSignatureInput +{ + public string Signature { get; set; } + public string PayloadToSign { get; set; } +} diff --git a/src/VirtoCommerce.Datatrans.Core/Models/DatatransTransaction.cs b/src/VirtoCommerce.Datatrans.Core/Models/DatatransTransaction.cs new file mode 100644 index 0000000..9dec011 --- /dev/null +++ b/src/VirtoCommerce.Datatrans.Core/Models/DatatransTransaction.cs @@ -0,0 +1,12 @@ +namespace VirtoCommerce.Datatrans.Core.Models; + +public class DatatransTransaction +{ + public string TransactionId { get; set; } + public string State { get; set; } + public long AmountMinor { get; set; } + public string Currency { get; set; } + public string AuthCode { get; set; } + public DatatransError Error { get; set; } + public object Raw { get; set; } +} diff --git a/src/VirtoCommerce.Datatrans.Core/Models/DatatransVoidResponse.cs b/src/VirtoCommerce.Datatrans.Core/Models/DatatransVoidResponse.cs new file mode 100644 index 0000000..3216150 --- /dev/null +++ b/src/VirtoCommerce.Datatrans.Core/Models/DatatransVoidResponse.cs @@ -0,0 +1,9 @@ +namespace VirtoCommerce.Datatrans.Core.Models; + +public class DatatransVoidResponse +{ + public string TransactionId { get; set; } + public string State { get; set; } // voided/canceled + public DatatransError Error { get; set; } + public object Raw { get; set; } +} diff --git a/src/VirtoCommerce.Datatrans.Core/ModuleConstants.cs b/src/VirtoCommerce.Datatrans.Core/ModuleConstants.cs new file mode 100644 index 0000000..96e9545 --- /dev/null +++ b/src/VirtoCommerce.Datatrans.Core/ModuleConstants.cs @@ -0,0 +1,38 @@ +using System.Collections.Generic; +using VirtoCommerce.Platform.Core.Settings; + +namespace VirtoCommerce.Datatrans.Core; + +public static class ModuleConstants +{ + public static class Settings + { + public static class General + { + public static SettingDescriptor Sandbox { get; } = new() + { + Name = "VirtoCommerce.Payment.Datatrans.Sandbox", + GroupName = "Payment|Datatrans", + ValueType = SettingValueType.Boolean, + DefaultValue = true, + }; + + + public static IEnumerable AllGeneralSettings + { + get + { + yield return Sandbox; + } + } + } + + public static IEnumerable AllSettings + { + get + { + return General.AllGeneralSettings; + } + } + } +} diff --git a/src/VirtoCommerce.Datatrans.Core/Notifications/.keep b/src/VirtoCommerce.Datatrans.Core/Notifications/.keep new file mode 100644 index 0000000..e69de29 diff --git a/src/VirtoCommerce.Datatrans.Core/Services/IDatatransClient.cs b/src/VirtoCommerce.Datatrans.Core/Services/IDatatransClient.cs new file mode 100644 index 0000000..4aa6635 --- /dev/null +++ b/src/VirtoCommerce.Datatrans.Core/Services/IDatatransClient.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Specialized; +using System.Threading; +using System.Threading.Tasks; +using VirtoCommerce.Datatrans.Core.Models; + +namespace VirtoCommerce.Datatrans.Core.Services; + +public interface IDatatransClient +{ + Task GetTransactionId(DatatransRequest request, CancellationToken cancellationToken = default); + + + + Task InitTransactionAsync(DatatransInitRequest request, CancellationToken ct = default); + Task GetTransactionId(DatatransInitRequest request, CancellationToken ct = default); + Task GetTransactionAsync(string transactionId, CancellationToken ct = default); + Task AuthorizeAuthenticatedAsync(string transactionId, DatatransAuthorizeAuthenticatedRequest request, CancellationToken ct = default); + Task CaptureAsync(string transactionId, DatatransCaptureRequest request, CancellationToken ct = default); + Task VoidAsync(string transactionId, CancellationToken ct = default); + Task RefundAsync(string transactionId, DatatransRefundRequest request, CancellationToken ct = default); + Uri BuildStartPaymentUri(string transactionId); + string GetSecureFieldsScriptUrl(); + DatatransPushPayload ParsePushPayload(NameValueCollection formOrQuery); + bool ValidatePushSignature(DatatransSignatureInput input); +} diff --git a/src/VirtoCommerce.Datatrans.Core/VirtoCommerce.Datatrans.Core.csproj b/src/VirtoCommerce.Datatrans.Core/VirtoCommerce.Datatrans.Core.csproj new file mode 100644 index 0000000..a3c0217 --- /dev/null +++ b/src/VirtoCommerce.Datatrans.Core/VirtoCommerce.Datatrans.Core.csproj @@ -0,0 +1,16 @@ + + + net8.0 + + + + false + + + + + + + + + diff --git a/src/VirtoCommerce.Datatrans.Data/Providers/DatatransPaymentMethod.cs b/src/VirtoCommerce.Datatrans.Data/Providers/DatatransPaymentMethod.cs new file mode 100644 index 0000000..6c1a79b --- /dev/null +++ b/src/VirtoCommerce.Datatrans.Data/Providers/DatatransPaymentMethod.cs @@ -0,0 +1,212 @@ +using System; +using System.Collections.Specialized; +using System.Threading.Tasks; +using VirtoCommerce.Datatrans.Core.Models; +using VirtoCommerce.Datatrans.Core.Services; +using VirtoCommerce.OrdersModule.Core.Model; +using VirtoCommerce.PaymentModule.Core.Model; +using VirtoCommerce.PaymentModule.Model.Requests; +using VirtoCommerce.Platform.Core.Common; + +namespace VirtoCommerce.Datatrans.Data.Providers; + +public class DatatransPaymentMethod(IDatatransClient datatransClient) : PaymentMethod(nameof(DatatransPaymentMethod)), ISupportCaptureFlow, ISupportRefundFlow +{ + public override PaymentMethodType PaymentMethodType => PaymentMethodType.Standard; + public override PaymentMethodGroupType PaymentMethodGroupType => PaymentMethodGroupType.BankCard; + + #region overrides + + public override ProcessPaymentRequestResult ProcessPayment(ProcessPaymentRequest request) + { + return ProcessPaymentAsync(request).GetAwaiter().GetResult(); + } + + public override PostProcessPaymentRequestResult PostProcessPayment(PostProcessPaymentRequest request) + { + return PostProcessPaymentAsync(request).GetAwaiter().GetResult(); + } + + public override VoidPaymentRequestResult VoidProcessPayment(VoidPaymentRequest request) + { + return VoidProcessPaymentAsync(request).GetAwaiter().GetResult(); + } + + public override CapturePaymentRequestResult CaptureProcessPayment(CapturePaymentRequest context) + { + return CaptureProcessPaymentAsync(context).GetAwaiter().GetResult(); + } + + public override RefundPaymentRequestResult RefundProcessPayment(RefundPaymentRequest context) + { + return RefundProcessPaymentAsync(context).GetAwaiter().GetResult(); + } + + public override ValidatePostProcessRequestResult ValidatePostProcessRequest(NameValueCollection queryString) + { + var tx = queryString["transactionId"] ?? queryString["transId"] ?? queryString["transaction-id"]; + var result = new ValidatePostProcessRequestResult + { + IsSuccess = !string.IsNullOrEmpty(tx), + OuterId = tx, + }; + return result; + } + + #endregion + + #region protected async methods + + protected virtual async Task ProcessPaymentAsync(ProcessPaymentRequest request) + { + var datatransRequest = GenerateRequest(request); + + var transactionResponse = await datatransClient.GetTransactionId(datatransRequest); + var result = new ProcessPaymentRequestResult + { + IsSuccess = transactionResponse.Error == null, + NewPaymentStatus = transactionResponse.Error == null ? PaymentStatus.Pending : PaymentStatus.Voided, + ErrorMessage = transactionResponse.Error?.Message, + PublicParameters = new() + { + ["transactionId"] = transactionResponse.TransactionId, + ["clientScript"] = "https://pay.sandbox.datatrans.com/upp/payment/js/secure-fields-2.0.0.min.js", // todo: replace with SANDBOX flag + } + }; + + var payment = (PaymentIn)request.Payment; + payment.OuterId = transactionResponse.TransactionId; + payment.PaymentStatus = result.NewPaymentStatus; + payment.Status = payment.PaymentStatus.ToString(); + + return result; + } + + protected virtual Task PostProcessPaymentAsync(PostProcessPaymentRequest request) + { + var payment = (PaymentIn)request.Payment; + var transactionId = request.OuterId + ?? request.Parameters?.GetValueOrDefault("transactionId") + ?? payment?.OuterId; + + if (string.IsNullOrEmpty(transactionId)) + { + return new PostProcessPaymentRequestResult + { + IsSuccess = false, + ErrorMessage = "transactionId not found" + }; + } + + // 1) запросим Datatrans о состоянии транзакции + var tx = await datatransClient.GetTransactionAsync(transactionId); // сам метод назови как хочешь + + // 2) мэппинг статуса + var (status, err) = MapDatatransStatus(tx); // твоя приватная функция + + // 3) обновим VC-платёж + payment.OuterId = transactionId; + payment.PaymentStatus = status; + payment.Status = status.ToString(); + + if (status == PaymentStatus.Paid && payment.CapturedDate == null) + { + payment.CapturedDate = DateTime.UtcNow; + payment.CapturedAmount = payment.Sum; // при partial capture укажи фактическую сумму + } + + return new PostProcessPaymentRequestResult + { + IsSuccess = err is null && status is PaymentStatus.Authorized or PaymentStatus.Paid, + NewPaymentStatus = status, + ErrorMessage = err + }; + + // 2 + + //var token = request.Parameters.Get("token"); + //var payment = (PaymentIn)request.Payment; + //var order = (CustomerOrder)request.Order; + + //var clientRequest = PrepareProcessPaymentRequest(token, payment, order); + + //var paymentResult = await datatransClient.AuthorizePayment(clientRequest); + + //var result = GetPostPaymentResult(paymentResult, payment, order); + //return result; + + // 1 + + //var result = new PostProcessPaymentRequestResult + //{ + // IsSuccess = false, + // NewPaymentStatus = PaymentStatus.Pending, + //}; + + //if (request?.Payment == null) + //{ + // result.IsSuccess = false; + // result.ErrorMessage = "Payment is null."; + // return Task.FromResult(result); + //} + + //var payment = (PaymentIn)request.Payment; + + //result.IsSuccess = true; + //result.NewPaymentStatus = payment.PaymentStatus; + + //payment.PaymentStatus = result.NewPaymentStatus; + //payment.Status = payment.PaymentStatus.ToString(); + + //return Task.FromResult(result); + } + + private static (PaymentStatus status, string error) MapDatatransStatus(DatatransTransaction tx) + { + // Примеры, проверь реальные поля ответа: + return tx.State switch + { + "authorized" => (PaymentStatus.Authorized, null), + "settled" or "captured" => (PaymentStatus.Paid, null), + "canceled" or "voided" => (PaymentStatus.Voided, null), + "failed" => (PaymentStatus.Voided, tx.Error?.Message ?? "Payment failed"), + _ => (PaymentStatus.Pending, null), + }; + } + + + + protected virtual Task VoidProcessPaymentAsync(VoidPaymentRequest request) + { + return Task.FromResult(new VoidPaymentRequestResult()); + } + + protected virtual Task CaptureProcessPaymentAsync(CapturePaymentRequest context) + { + return Task.FromResult(new CapturePaymentRequestResult()); + } + + protected virtual Task RefundProcessPaymentAsync(RefundPaymentRequest context) + { + return Task.FromResult(new RefundPaymentRequestResult()); + } + + #endregion + + #region extension points + + protected virtual DatatransRequest GenerateRequest(ProcessPaymentRequest request) + { + var order = (CustomerOrder)request.Order; + + var result = AbstractTypeFactory.TryCreateInstance(); + + result.Amount = order.Total * 100; // should be in coins? look at https://api-reference.datatrans.ch/#tag/v1transactions/operation/init + result.Currency = order.Currency; + result.OrderId = order.Id; + + return result; + } + + #endregion +} diff --git a/src/VirtoCommerce.Datatrans.Data/Services/DatatransClient.cs b/src/VirtoCommerce.Datatrans.Data/Services/DatatransClient.cs new file mode 100644 index 0000000..7f2a4c2 --- /dev/null +++ b/src/VirtoCommerce.Datatrans.Data/Services/DatatransClient.cs @@ -0,0 +1,62 @@ +using System; +using System.Net.Http; +using System.Net.Http.Json; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.Options; +using VirtoCommerce.Datatrans.Core.Models; +using VirtoCommerce.Datatrans.Core.Services; + +namespace VirtoCommerce.Datatrans.Data.Services; + +public class DatatransClient(IHttpClientFactory httpClientFactory, IOptions options) : IDatatransClient +{ + private readonly DatatransOptions _options = options.Value; + + private string BaseStartUrl => _options.UseSandbox ? _options.SandboxStartUrlBase : _options.ProductionStartUrlBase; + private string SecureScriptUrl => _options.UseSandbox ? _options.SandboxSecureFieldsScriptUrl : _options.ProductionSecureFieldsScriptUrl; + + public string GetSecureFieldsScriptUrl() => SecureScriptUrl; + + public Uri BuildStartPaymentUri(string transactionId) + { + return new Uri($"{BaseStartUrl}{Uri.EscapeDataString(transactionId)}"); + } + + public async Task GetTransactionId(DatatransRequest request, CancellationToken cancellationToken = default) + { + var httpClient = httpClientFactory.CreateClient(); + + var token = GetToken(); + + var requestMessage = new HttpRequestMessage + { + RequestUri = new Uri("https://api.sandbox.datatrans.com/v1/transactions/secureFields"), + Method = HttpMethod.Post, + Headers = + { + { "Authorization", $"Basic {token}" }, + { "User-Agent", "VirtoCommerce/3.0" }, + { "Idempotency-Key", request.OrderId }, // Using OrderId as Idempotency-Key for simplicity + }, + Content = JsonContent.Create(new // should it be a model? + { + request.Currency, + request.Amount, + returnUrl = "https://localhost:3000", // storeUrl?? + }), + }; + var response = await httpClient.SendAsync(requestMessage, cancellationToken); + + var result = await response.Content.ReadFromJsonAsync(cancellationToken); + return result; + } + + + private string GetToken() + { + var merchantId = "1110020617"; // todo: get from settings + var password = "eVZ5bq237EUzbpOF"; + return Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes($"{merchantId}:{password}")); + } +} diff --git a/src/VirtoCommerce.Datatrans.Data/VirtoCommerce.Datatrans.Data.csproj b/src/VirtoCommerce.Datatrans.Data/VirtoCommerce.Datatrans.Data.csproj new file mode 100644 index 0000000..8e7f75a --- /dev/null +++ b/src/VirtoCommerce.Datatrans.Data/VirtoCommerce.Datatrans.Data.csproj @@ -0,0 +1,19 @@ + + + net8.0 + + + + false + + + + + + + + + + + + diff --git a/src/VirtoCommerce.Datatrans.Web/Content/logo.png b/src/VirtoCommerce.Datatrans.Web/Content/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..ca22993d6af972f18e48f7c2996f620c8cffb9f9 GIT binary patch literal 14153 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.Bind(Configuration.GetSection("Payments:Datatrans")).ValidateDataAnnotations(); + + serviceCollection.AddTransient(); + + serviceCollection.AddTransient(); + } + + public void PostInitialize(IApplicationBuilder appBuilder) + { + var settingsRegistrar = appBuilder.ApplicationServices.GetRequiredService(); + settingsRegistrar.RegisterSettings(ModuleConstants.Settings.AllSettings, ModuleInfo.Id); + + var paymentMethodsRegistrar = appBuilder.ApplicationServices.GetRequiredService(); + paymentMethodsRegistrar.RegisterPaymentMethod(() => appBuilder.ApplicationServices.GetService()); + + settingsRegistrar.RegisterSettingsForType(ModuleConstants.Settings.General.AllGeneralSettings, nameof(DatatransPaymentMethod)); + + } + + public void Uninstall() + { + // Nothing to do here + } +} diff --git a/src/VirtoCommerce.Datatrans.Web/VirtoCommerce.Datatrans.Web.csproj b/src/VirtoCommerce.Datatrans.Web/VirtoCommerce.Datatrans.Web.csproj new file mode 100644 index 0000000..553714d --- /dev/null +++ b/src/VirtoCommerce.Datatrans.Web/VirtoCommerce.Datatrans.Web.csproj @@ -0,0 +1,23 @@ + + + net8.0 + Library + false + true + 1591 + + + + false + + + + + + + + + + + + diff --git a/src/VirtoCommerce.Datatrans.Web/module.manifest b/src/VirtoCommerce.Datatrans.Web/module.manifest new file mode 100644 index 0000000..de9d24a --- /dev/null +++ b/src/VirtoCommerce.Datatrans.Web/module.manifest @@ -0,0 +1,33 @@ + + + VirtoCommerce.Datatrans + 3.800.0 + + + 3.904.0 + + + + + VirtoCommerce Datatrans + VirtoCommerce Datatrans + + + basilkot + + + VirtoCommerce + + + https://github.com/VirtoCommerce/vc-module-datatrans + Modules/$(VirtoCommerce.Datatrans)/Content/logo.png + false + + VirtoCommerce.Datatrans.Web.dll + VirtoCommerce.Datatrans.Web.Module, VirtoCommerce.Datatrans.Web + + First version. + Copyright © 2025 VirtoCommerce. All rights reserved + extension module + false + diff --git a/src/VirtoCommerce.Datatrans.Web/package-lock.json b/src/VirtoCommerce.Datatrans.Web/package-lock.json new file mode 100644 index 0000000..76b90d2 --- /dev/null +++ b/src/VirtoCommerce.Datatrans.Web/package-lock.json @@ -0,0 +1,1985 @@ +{ + "name": "vc-module", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "vc-module", + "version": "1.0.0", + "devDependencies": { + "clean-webpack-plugin": "^4.0.0", + "css-loader": "^6.5.1", + "mini-css-extract-plugin": "^2.5.1", + "webpack": "^5.68.0", + "webpack-cli": "^4.9.2" + } + }, + "node_modules/@discoveryjs/json-ext": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "dev": true, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", + "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.17", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", + "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" + } + }, + "node_modules/@types/eslint": { + "version": "8.21.1", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.21.1.tgz", + "integrity": "sha512-rc9K8ZpVjNcLs8Fp0dkozd5Pt2Apk1glO4Vgz8ix1u6yFByxfqo5Yavpy65o+93TAe24jr7v+eSBtFLvOQtCRQ==", + "dev": true, + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/eslint-scope": { + "version": "3.7.4", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.4.tgz", + "integrity": "sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==", + "dev": true, + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "node_modules/@types/estree": { + "version": "0.0.51", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", + "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==", + "dev": true + }, + "node_modules/@types/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==", + "dev": true, + "dependencies": { + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "dev": true + }, + "node_modules/@types/minimatch": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", + "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==", + "dev": true + }, + "node_modules/@types/node": { + "version": "18.14.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.14.0.tgz", + "integrity": "sha512-5EWrvLmglK+imbCJY0+INViFWUHg1AHel1sq4ZVSfdcNqGy9Edv3UB9IIzzg+xPaUcAgZYcfVs2fBcwDeZzU0A==", + "dev": true + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", + "integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==", + "dev": true, + "dependencies": { + "@webassemblyjs/helper-numbers": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz", + "integrity": "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz", + "integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz", + "integrity": "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz", + "integrity": "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==", + "dev": true, + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.11.1", + "@webassemblyjs/helper-api-error": "1.11.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz", + "integrity": "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz", + "integrity": "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz", + "integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==", + "dev": true, + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz", + "integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==", + "dev": true, + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz", + "integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==", + "dev": true + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz", + "integrity": "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/helper-wasm-section": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1", + "@webassemblyjs/wasm-opt": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "@webassemblyjs/wast-printer": "1.11.1" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz", + "integrity": "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/ieee754": "1.11.1", + "@webassemblyjs/leb128": "1.11.1", + "@webassemblyjs/utf8": "1.11.1" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz", + "integrity": "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz", + "integrity": "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-api-error": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/ieee754": "1.11.1", + "@webassemblyjs/leb128": "1.11.1", + "@webassemblyjs/utf8": "1.11.1" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz", + "integrity": "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webpack-cli/configtest": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.2.0.tgz", + "integrity": "sha512-4FB8Tj6xyVkyqjj1OaTqCjXYULB9FMkqQ8yGrZjRDrYh0nOE+7Lhs45WioWQQMV+ceFlE368Ukhe6xdvJM9Egg==", + "dev": true, + "peerDependencies": { + "webpack": "4.x.x || 5.x.x", + "webpack-cli": "4.x.x" + } + }, + "node_modules/@webpack-cli/info": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.5.0.tgz", + "integrity": "sha512-e8tSXZpw2hPl2uMJY6fsMswaok5FdlGNRTktvFk2sD8RjH0hE2+XistawJx1vmKteh4NmGmNUrp+Tb2w+udPcQ==", + "dev": true, + "dependencies": { + "envinfo": "^7.7.3" + }, + "peerDependencies": { + "webpack-cli": "4.x.x" + } + }, + "node_modules/@webpack-cli/serve": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.7.0.tgz", + "integrity": "sha512-oxnCNGj88fL+xzV+dacXs44HcDwf1ovs3AuEzvP7mqXw7fQntqIhQ1BRmynh4qEKQSSSRSWVyXRjmTbZIX9V2Q==", + "dev": true, + "peerDependencies": { + "webpack-cli": "4.x.x" + }, + "peerDependenciesMeta": { + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true + }, + "node_modules/acorn": { + "version": "8.8.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", + "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-import-assertions": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", + "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==", + "dev": true, + "peerDependencies": { + "acorn": "^8" + } + }, + "node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dev": true, + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng==", + "dev": true, + "dependencies": { + "array-uniq": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/browserslist": { + "version": "4.21.5", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz", + "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001449", + "electron-to-chromium": "^1.4.284", + "node-releases": "^2.0.8", + "update-browserslist-db": "^1.0.10" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001457", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001457.tgz", + "integrity": "sha512-SDIV6bgE1aVbK6XyxdURbUE89zY7+k1BBBaOwYwkNCglXlel/E7mELiHC64HQ+W0xSKlqWhV9Wh7iHxUjMs4fA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + } + ] + }, + "node_modules/chrome-trace-event": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.2.tgz", + "integrity": "sha512-9e/zx1jw7B4CO+c/RXoCsfg/x1AfUBioy4owYH0bJprEYAx5hRFLRhWBqHAG57D0ZM4H7vxbP7bPe0VwhQRYDQ==", + "dev": true, + "dependencies": { + "tslib": "^1.9.0" + }, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/clean-webpack-plugin": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/clean-webpack-plugin/-/clean-webpack-plugin-4.0.0.tgz", + "integrity": "sha512-WuWE1nyTNAyW5T7oNyys2EN0cfP2fdRxhxnIQWiAp0bMabPdHhoGxM8A6YL2GhqwgrPnnaemVE7nv5XJ2Fhh2w==", + "dev": true, + "dependencies": { + "del": "^4.1.1" + }, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "webpack": ">=4.0.0 <6.0.0" + } + }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/colorette": { + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz", + "integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==", + "dev": true + }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/css-loader": { + "version": "6.7.3", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.7.3.tgz", + "integrity": "sha512-qhOH1KlBMnZP8FzRO6YCH9UHXQhVMcEGLyNdb7Hv2cpcmJbW0YrddO+tG1ab5nT41KpHIYGsbeHqxB9xPu1pKQ==", + "dev": true, + "dependencies": { + "icss-utils": "^5.1.0", + "postcss": "^8.4.19", + "postcss-modules-extract-imports": "^3.0.0", + "postcss-modules-local-by-default": "^4.0.0", + "postcss-modules-scope": "^3.0.0", + "postcss-modules-values": "^4.0.0", + "postcss-value-parser": "^4.2.0", + "semver": "^7.3.8" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/del": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/del/-/del-4.1.1.tgz", + "integrity": "sha512-QwGuEUouP2kVwQenAsOof5Fv8K9t3D8Ca8NxcXKrIpEHjTXK5J2nXLdP+ALI1cgv8wj7KuwBhTwBkOZSJKM5XQ==", + "dev": true, + "dependencies": { + "@types/glob": "^7.1.1", + "globby": "^6.1.0", + "is-path-cwd": "^2.0.0", + "is-path-in-cwd": "^2.0.0", + "p-map": "^2.0.0", + "pify": "^4.0.1", + "rimraf": "^2.6.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.4.305", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.305.tgz", + "integrity": "sha512-WETy6tG0CT5gm1O+xCbyapWNsCcmIvrn4NHViIGYo2AT8FV2qUCXdaB+WqYxSv/vS5mFqhBYnfZAAkVArjBmUg==", + "dev": true + }, + "node_modules/enhanced-resolve": { + "version": "5.12.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.12.0.tgz", + "integrity": "sha512-QHTXI/sZQmko1cbDoNAa3mJ5qhWUUNAq3vR0/YiD379fWQrcfuoX1+HW2S0MTt7XmoPLapdaDKUtelUSPic7hQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/envinfo": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz", + "integrity": "sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==", + "dev": true, + "bin": { + "envinfo": "dist/cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/es-module-lexer": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", + "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==", + "dev": true + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fastest-levenshtein": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", + "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", + "dev": true, + "engines": { + "node": ">= 4.9.1" + } + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true + }, + "node_modules/globby": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", + "integrity": "sha512-KVbFv2TQtbzCoxAnfD6JcHZTYCzyliEaaeM/gH8qQdkKr5s0OP9scEgvdcngyk7AVdY6YVW/TJHd+lQ/Df3Daw==", + "dev": true, + "dependencies": { + "array-union": "^1.0.1", + "glob": "^7.0.3", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/globby/node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "dev": true + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/icss-utils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", + "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/import-local": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "dev": true, + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/interpret": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz", + "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-core-module": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-path-cwd": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", + "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/is-path-in-cwd": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-2.1.0.tgz", + "integrity": "sha512-rNocXHgipO+rvnP6dk3zI20RpOtrAM/kzbB258Uw5BWr3TpXi861yzjo16Dn4hUox07iw5AyeMLHWsujkjzvRQ==", + "dev": true, + "dependencies": { + "is-path-inside": "^2.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/is-path-inside": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-2.1.0.tgz", + "integrity": "sha512-wiyhTzfDWsvwAW53OBWF5zuvaOGlZ6PwYxAbPVDhpm+gM09xKQGjBq/8uYN12aDvMxnAnq3dxTyoSoRNmg5YFg==", + "dev": true, + "dependencies": { + "path-is-inside": "^1.0.2" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dev": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "dev": true, + "engines": { + "node": ">=6.11.5" + } + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mini-css-extract-plugin": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.7.2.tgz", + "integrity": "sha512-EdlUizq13o0Pd+uCp+WO/JpkLvHRVGt97RqfeGhXqAcorYo1ypJSpkV+WDT0vY/kmh/p7wRdJNJtuyK540PXDw==", + "dev": true, + "dependencies": { + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/nanoid": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", + "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "dev": true, + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "node_modules/node-releases": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz", + "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==", + "dev": true + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-map": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", + "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==", + "dev": true + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==", + "dev": true, + "dependencies": { + "pinkie": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/postcss": { + "version": "8.4.21", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.21.tgz", + "integrity": "sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + } + ], + "dependencies": { + "nanoid": "^3.3.4", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-modules-extract-imports": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", + "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-local-by-default": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz", + "integrity": "sha512-sT7ihtmGSF9yhm6ggikHdV0hlziDTX7oFoXtuVWeDd3hHObNkcHRo9V3yg7vCAY7cONyxJC/XXCmmiHHcvX7bQ==", + "dev": true, + "dependencies": { + "icss-utils": "^5.0.0", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.1.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-scope": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz", + "integrity": "sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.4" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-values": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", + "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", + "dev": true, + "dependencies": { + "icss-utils": "^5.0.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.0.11", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.11.tgz", + "integrity": "sha512-zbARubNdogI9j7WY4nQJBiNqQf3sLS3wCP4WfOidu+p28LofJqDH1tcXypGrcmMHhDk2t9wGhCsYe/+szLTy1g==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true + }, + "node_modules/punycode": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/rechoir": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.1.tgz", + "integrity": "sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg==", + "dev": true, + "dependencies": { + "resolve": "^1.9.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/schema-utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", + "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.8.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/semver": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz", + "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/terser": { + "version": "5.16.4", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.16.4.tgz", + "integrity": "sha512-5yEGuZ3DZradbogeYQ1NaGz7rXVBDWujWlx1PT8efXO6Txn+eWbfKqB2bTDVmFXmePFkoLU6XI8UektMIEA0ug==", + "dev": true, + "dependencies": { + "@jridgewell/source-map": "^0.3.2", + "acorn": "^8.5.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.3.6", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.6.tgz", + "integrity": "sha512-kfLFk+PoLUQIbLmB1+PZDMRSZS99Mp+/MHqDNmMA6tOItzRt+Npe3E+fsMs5mfcM0wCtrrdU387UnV+vnSffXQ==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.14", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.0", + "terser": "^5.14.1" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, + "node_modules/terser-webpack-plugin/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/terser-webpack-plugin/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/terser-webpack-plugin/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/terser-webpack-plugin/node_modules/schema-utils": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", + "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/tslib": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", + "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==", + "dev": true + }, + "node_modules/update-browserslist-db": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", + "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "browserslist-lint": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "node_modules/watchpack": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", + "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", + "dev": true, + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack": { + "version": "5.75.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.75.0.tgz", + "integrity": "sha512-piaIaoVJlqMsPtX/+3KTTO6jfvrSYgauFVdt8cr9LTHKmcq/AMd4mhzsiP7ZF/PGRNPGA8336jldh9l2Kt2ogQ==", + "dev": true, + "dependencies": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^0.0.51", + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/wasm-edit": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "acorn": "^8.7.1", + "acorn-import-assertions": "^1.7.6", + "browserslist": "^4.14.5", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.10.0", + "es-module-lexer": "^0.9.0", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.9", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.1.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.1.3", + "watchpack": "^2.4.0", + "webpack-sources": "^3.2.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-cli": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.10.0.tgz", + "integrity": "sha512-NLhDfH/h4O6UOy+0LSso42xvYypClINuMNBVVzX4vX98TmTaTUxwRbXdhucbFMd2qLaCTcLq/PdYrvi8onw90w==", + "dev": true, + "dependencies": { + "@discoveryjs/json-ext": "^0.5.0", + "@webpack-cli/configtest": "^1.2.0", + "@webpack-cli/info": "^1.5.0", + "@webpack-cli/serve": "^1.7.0", + "colorette": "^2.0.14", + "commander": "^7.0.0", + "cross-spawn": "^7.0.3", + "fastest-levenshtein": "^1.0.12", + "import-local": "^3.0.2", + "interpret": "^2.2.0", + "rechoir": "^0.7.0", + "webpack-merge": "^5.7.3" + }, + "bin": { + "webpack-cli": "bin/cli.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "4.x.x || 5.x.x" + }, + "peerDependenciesMeta": { + "@webpack-cli/generators": { + "optional": true + }, + "@webpack-cli/migrate": { + "optional": true + }, + "webpack-bundle-analyzer": { + "optional": true + }, + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/webpack-cli/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/webpack-merge": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.8.0.tgz", + "integrity": "sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q==", + "dev": true, + "dependencies": { + "clone-deep": "^4.0.1", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/webpack/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/webpack/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/webpack/node_modules/schema-utils": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", + "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wildcard": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz", + "integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==", + "dev": true + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + } + } +} diff --git a/src/VirtoCommerce.Datatrans.Web/package.json b/src/VirtoCommerce.Datatrans.Web/package.json new file mode 100644 index 0000000..20684a4 --- /dev/null +++ b/src/VirtoCommerce.Datatrans.Web/package.json @@ -0,0 +1,20 @@ +{ + "version": "1.0.0", + "name": "vc-module", + "private": true, + "scripts": { + "webpack:dev": "webpack --mode=development", + "webpack:watch": "webpack --watch --mode=development", + "webpack:build": "webpack --mode=production" + }, + "devDependencies": { + "clean-webpack-plugin": "^4.0.0", + "css-loader": "^6.5.1", + "mini-css-extract-plugin": "^2.5.1", + "webpack": "^5.68.0", + "webpack-cli": "^4.10.0" + }, + "webpack": { + "stats": "verbose" + } +} diff --git a/src/VirtoCommerce.Datatrans.Web/webpack.config.js b/src/VirtoCommerce.Datatrans.Web/webpack.config.js new file mode 100644 index 0000000..8322c67 --- /dev/null +++ b/src/VirtoCommerce.Datatrans.Web/webpack.config.js @@ -0,0 +1,51 @@ +const namespace = 'VirtoCommerce.Datatrans' + +const glob = require('glob'); +const path = require('path'); +const webpack = require('webpack'); +const MiniCssExtractPlugin = require('mini-css-extract-plugin'); +const { CleanWebpackPlugin } = require('clean-webpack-plugin'); + +const rootPath = path.resolve(__dirname, 'dist'); + +function getEntryPoints() { + return [ + ...glob.sync('./Scripts/**/*.js', { nosort: true }), + ...glob.sync('./Content/**/*.css', { nosort: true }), + ]; +} + +module.exports = (env, argv) => { + const isProduction = argv.mode === 'production'; + + return { + entry: getEntryPoints(), + devtool: false, + output: { + path: rootPath, + filename: 'app.js', + }, + module: { + rules: [ + { + test: /\.css$/, + use: [MiniCssExtractPlugin.loader, 'css-loader'], + } + ] + }, + plugins: [ + new CleanWebpackPlugin(), + isProduction ? + new webpack.SourceMapDevToolPlugin({ + namespace: namespace, + filename: '[file].map[query]' + }) : + new webpack.SourceMapDevToolPlugin({ + namespace: namespace + }), + new MiniCssExtractPlugin({ + filename: 'style.css', + }), + ], + }; +}; diff --git a/tests/VirtoCommerce.Datatrans.Tests/Test.cs b/tests/VirtoCommerce.Datatrans.Tests/Test.cs new file mode 100644 index 0000000..be4d654 --- /dev/null +++ b/tests/VirtoCommerce.Datatrans.Tests/Test.cs @@ -0,0 +1,13 @@ +using Xunit; + +namespace VirtoCommerce.Datatrans.Tests; + +[Trait("Category", "Unit")] +public class Test +{ + [Fact] + public void Run_Test() + { + Assert.Equal(0, 0); + } +} diff --git a/tests/VirtoCommerce.Datatrans.Tests/VirtoCommerce.Datatrans.Tests.csproj b/tests/VirtoCommerce.Datatrans.Tests/VirtoCommerce.Datatrans.Tests.csproj new file mode 100644 index 0000000..458e70d --- /dev/null +++ b/tests/VirtoCommerce.Datatrans.Tests/VirtoCommerce.Datatrans.Tests.csproj @@ -0,0 +1,24 @@ + + + net8.0 + false + + + + true + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + + + + From f9cce8618cb5ced9197c0155c69a238ccdc53701 Mon Sep 17 00:00:00 2001 From: Basil Kotov Date: Tue, 14 Oct 2025 11:18:47 +0100 Subject: [PATCH 02/29] new implementation --- .../DatatransAuthorizeAuthenticatedRequest.cs | 6 +- .../Models/DatatransAuthorizeResponse.cs | 9 +- .../Models/DatatransCaptureRequest.cs | 4 +- .../Models/DatatransCaptureResponse.cs | 8 +- .../Models/DatatransInitRequest.cs | 9 +- .../Models/DatatransInitResponse.cs | 3 +- .../Models/DatatransOptions.cs | 8 +- .../Models/DatatransPaymentMethodOptions.cs | 7 - .../Models/DatatransPushPayload.cs | 14 - .../Models/DatatransRefundRequest.cs | 6 +- .../Models/DatatransRefundResponse.cs | 8 +- .../Models/DatatransRequest.cs | 9 - ...nsResponse.cs => DatatransResponseBase.cs} | 3 +- .../Models/DatatransSignatureInput.cs | 7 - .../Models/DatatransTransaction.cs | 58 ++- .../Models/DatatransVoidResponse.cs | 8 +- .../Services/IDatatransClient.cs | 16 +- .../Providers/DatatransPaymentMethod.cs | 430 ++++++++++++++---- .../Services/DatatransClient.cs | 116 +++-- .../Controllers/DatatransController.cs | 83 ++++ src/VirtoCommerce.Datatrans.Web/Module.cs | 20 +- 21 files changed, 619 insertions(+), 213 deletions(-) delete mode 100644 src/VirtoCommerce.Datatrans.Core/Models/DatatransPaymentMethodOptions.cs delete mode 100644 src/VirtoCommerce.Datatrans.Core/Models/DatatransPushPayload.cs delete mode 100644 src/VirtoCommerce.Datatrans.Core/Models/DatatransRequest.cs rename src/VirtoCommerce.Datatrans.Core/Models/{DatatransResponse.cs => DatatransResponseBase.cs} (56%) delete mode 100644 src/VirtoCommerce.Datatrans.Core/Models/DatatransSignatureInput.cs create mode 100644 src/VirtoCommerce.Datatrans.Web/Controllers/DatatransController.cs diff --git a/src/VirtoCommerce.Datatrans.Core/Models/DatatransAuthorizeAuthenticatedRequest.cs b/src/VirtoCommerce.Datatrans.Core/Models/DatatransAuthorizeAuthenticatedRequest.cs index cd6429e..db9c1b9 100644 --- a/src/VirtoCommerce.Datatrans.Core/Models/DatatransAuthorizeAuthenticatedRequest.cs +++ b/src/VirtoCommerce.Datatrans.Core/Models/DatatransAuthorizeAuthenticatedRequest.cs @@ -2,8 +2,6 @@ namespace VirtoCommerce.Datatrans.Core.Models; public class DatatransAuthorizeAuthenticatedRequest { - public string Token { get; set; } - public string ThreeDSResult { get; set; } - public string PaRes { get; set; } - public object Extra { get; set; } + public string Refno { get; set; } + public long Amount { get; set; } } diff --git a/src/VirtoCommerce.Datatrans.Core/Models/DatatransAuthorizeResponse.cs b/src/VirtoCommerce.Datatrans.Core/Models/DatatransAuthorizeResponse.cs index 26e7f8b..8b7b897 100644 --- a/src/VirtoCommerce.Datatrans.Core/Models/DatatransAuthorizeResponse.cs +++ b/src/VirtoCommerce.Datatrans.Core/Models/DatatransAuthorizeResponse.cs @@ -1,9 +1,6 @@ -namespace VirtoCommerce.Datatrans.Core.Models; +namespace VirtoCommerce.Datatrans.Core.Models; -public class DatatransAuthorizeResponse +public class DatatransAuthorizeResponse : DatatransResponseBase { - public string TransactionId { get; set; } - public string State { get; set; } - public DatatransError Error { get; set; } - public object Raw { get; set; } + public string AcquirerAuthorizationCode { get; set; } } diff --git a/src/VirtoCommerce.Datatrans.Core/Models/DatatransCaptureRequest.cs b/src/VirtoCommerce.Datatrans.Core/Models/DatatransCaptureRequest.cs index 3a1a427..5f56faa 100644 --- a/src/VirtoCommerce.Datatrans.Core/Models/DatatransCaptureRequest.cs +++ b/src/VirtoCommerce.Datatrans.Core/Models/DatatransCaptureRequest.cs @@ -2,7 +2,7 @@ namespace VirtoCommerce.Datatrans.Core.Models; public class DatatransCaptureRequest { - public long AmountMinor { get; set; } + public long Amount { get; set; } public string Currency { get; set; } - public string Reference { get; set; } + public string Refno { get; set; } } diff --git a/src/VirtoCommerce.Datatrans.Core/Models/DatatransCaptureResponse.cs b/src/VirtoCommerce.Datatrans.Core/Models/DatatransCaptureResponse.cs index aa27e85..ed5ae83 100644 --- a/src/VirtoCommerce.Datatrans.Core/Models/DatatransCaptureResponse.cs +++ b/src/VirtoCommerce.Datatrans.Core/Models/DatatransCaptureResponse.cs @@ -1,9 +1,5 @@ -namespace VirtoCommerce.Datatrans.Core.Models; +namespace VirtoCommerce.Datatrans.Core.Models; -public class DatatransCaptureResponse +public class DatatransCaptureResponse : DatatransResponseBase { - public string TransactionId { get; set; } - public string State { get; set; } - public DatatransError Error { get; set; } - public object Raw { get; set; } } diff --git a/src/VirtoCommerce.Datatrans.Core/Models/DatatransInitRequest.cs b/src/VirtoCommerce.Datatrans.Core/Models/DatatransInitRequest.cs index 98f7661..a874835 100644 --- a/src/VirtoCommerce.Datatrans.Core/Models/DatatransInitRequest.cs +++ b/src/VirtoCommerce.Datatrans.Core/Models/DatatransInitRequest.cs @@ -1,12 +1,9 @@ namespace VirtoCommerce.Datatrans.Core.Models; + public class DatatransInitRequest { - public long AmountMinor { get; set; } + public long Amount { get; set; } public string Currency { get; set; } - public string OrderId { get; set; } public string ReturnUrl { get; set; } - public string PushUrl { get; set; } - public string Description { get; set; } - public string PaymentMethod { get; set; } - public object Metadata { get; set; } + public string ReturnMethod { get; set; } = "GET"; } diff --git a/src/VirtoCommerce.Datatrans.Core/Models/DatatransInitResponse.cs b/src/VirtoCommerce.Datatrans.Core/Models/DatatransInitResponse.cs index cfd79fb..1074c8f 100644 --- a/src/VirtoCommerce.Datatrans.Core/Models/DatatransInitResponse.cs +++ b/src/VirtoCommerce.Datatrans.Core/Models/DatatransInitResponse.cs @@ -1,7 +1,6 @@ namespace VirtoCommerce.Datatrans.Core.Models; -public class DatatransInitResponse +public class DatatransInitResponse : DatatransResponseBase { public string TransactionId { get; set; } - public DatatransError Error { get; set; } } diff --git a/src/VirtoCommerce.Datatrans.Core/Models/DatatransOptions.cs b/src/VirtoCommerce.Datatrans.Core/Models/DatatransOptions.cs index 51b6634..7b9f936 100644 --- a/src/VirtoCommerce.Datatrans.Core/Models/DatatransOptions.cs +++ b/src/VirtoCommerce.Datatrans.Core/Models/DatatransOptions.cs @@ -13,10 +13,8 @@ public class DatatransOptions public bool UseSandbox { get; set; } = true; - public string ApiUser { get; set; } - public string ApiPassword { get; set; } // или API key/secret - - public string PushSignatureSecret { get; set; } + public string MerchantId { get; set; } + public string Secret { get; set; } public DatatransApiRoutes Routes { get; set; } = new(); } @@ -24,7 +22,7 @@ public class DatatransOptions public class DatatransApiRoutes { // POST - public string InitPath { get; set; } = "/v1/transactions"; + public string SecureFieldsPath { get; set; } = "/v1/transactions/secureFields"; // GET public string TxnPath { get; set; } = "/v1/transactions/{transactionId}"; diff --git a/src/VirtoCommerce.Datatrans.Core/Models/DatatransPaymentMethodOptions.cs b/src/VirtoCommerce.Datatrans.Core/Models/DatatransPaymentMethodOptions.cs deleted file mode 100644 index c9a1221..0000000 --- a/src/VirtoCommerce.Datatrans.Core/Models/DatatransPaymentMethodOptions.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace VirtoCommerce.Datatrans.Core.Models; - -public class DatatransPaymentMethodOptions -{ - public string MerchantId { get; set; } - public string Secret { get; set; } -} diff --git a/src/VirtoCommerce.Datatrans.Core/Models/DatatransPushPayload.cs b/src/VirtoCommerce.Datatrans.Core/Models/DatatransPushPayload.cs deleted file mode 100644 index 6075d25..0000000 --- a/src/VirtoCommerce.Datatrans.Core/Models/DatatransPushPayload.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.Collections.Specialized; - -namespace VirtoCommerce.Datatrans.Core.Models; - -public class DatatransPushPayload -{ - public string TransactionId { get; set; } - public string OrderId { get; set; } - public string State { get; set; } - public long AmountMinor { get; set; } - public string Currency { get; set; } - public string Signature { get; set; } // если Datatrans присылает подпись/хеш - public NameValueCollection Raw { get; set; } -} diff --git a/src/VirtoCommerce.Datatrans.Core/Models/DatatransRefundRequest.cs b/src/VirtoCommerce.Datatrans.Core/Models/DatatransRefundRequest.cs index 4c87a6d..373d94e 100644 --- a/src/VirtoCommerce.Datatrans.Core/Models/DatatransRefundRequest.cs +++ b/src/VirtoCommerce.Datatrans.Core/Models/DatatransRefundRequest.cs @@ -1,8 +1,8 @@ -namespace VirtoCommerce.Datatrans.Core.Models; +namespace VirtoCommerce.Datatrans.Core.Models; public class DatatransRefundRequest { - public long AmountMinor { get; set; } + public long Amount { get; set; } public string Currency { get; set; } - public string Reason { get; set; } + public string Refno { get; set; } } diff --git a/src/VirtoCommerce.Datatrans.Core/Models/DatatransRefundResponse.cs b/src/VirtoCommerce.Datatrans.Core/Models/DatatransRefundResponse.cs index a6a6557..826a6aa 100644 --- a/src/VirtoCommerce.Datatrans.Core/Models/DatatransRefundResponse.cs +++ b/src/VirtoCommerce.Datatrans.Core/Models/DatatransRefundResponse.cs @@ -1,9 +1,7 @@ -namespace VirtoCommerce.Datatrans.Core.Models; +namespace VirtoCommerce.Datatrans.Core.Models; -public class DatatransRefundResponse +public class DatatransRefundResponse : DatatransResponseBase { public string TransactionId { get; set; } - public string State { get; set; } // refunded/partially_refunded/… - public DatatransError Error { get; set; } - public object Raw { get; set; } + public string AcquirerAuthorizationCode { get; set; } } diff --git a/src/VirtoCommerce.Datatrans.Core/Models/DatatransRequest.cs b/src/VirtoCommerce.Datatrans.Core/Models/DatatransRequest.cs deleted file mode 100644 index 7fba2c2..0000000 --- a/src/VirtoCommerce.Datatrans.Core/Models/DatatransRequest.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace VirtoCommerce.Datatrans.Core.Models; - -public class DatatransRequest -{ - public string OrderId { get; set; } - public string Currency { get; set; } - public decimal Amount { get; set; } - -} diff --git a/src/VirtoCommerce.Datatrans.Core/Models/DatatransResponse.cs b/src/VirtoCommerce.Datatrans.Core/Models/DatatransResponseBase.cs similarity index 56% rename from src/VirtoCommerce.Datatrans.Core/Models/DatatransResponse.cs rename to src/VirtoCommerce.Datatrans.Core/Models/DatatransResponseBase.cs index 2fb30aa..cac3adf 100644 --- a/src/VirtoCommerce.Datatrans.Core/Models/DatatransResponse.cs +++ b/src/VirtoCommerce.Datatrans.Core/Models/DatatransResponseBase.cs @@ -1,7 +1,6 @@ namespace VirtoCommerce.Datatrans.Core.Models; -public class DatatransResponse +public class DatatransResponseBase { - public string TransactionId { get; set; } public DatatransError Error { get; set; } } diff --git a/src/VirtoCommerce.Datatrans.Core/Models/DatatransSignatureInput.cs b/src/VirtoCommerce.Datatrans.Core/Models/DatatransSignatureInput.cs deleted file mode 100644 index c61880e..0000000 --- a/src/VirtoCommerce.Datatrans.Core/Models/DatatransSignatureInput.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace VirtoCommerce.Datatrans.Core.Models; - -public class DatatransSignatureInput -{ - public string Signature { get; set; } - public string PayloadToSign { get; set; } -} diff --git a/src/VirtoCommerce.Datatrans.Core/Models/DatatransTransaction.cs b/src/VirtoCommerce.Datatrans.Core/Models/DatatransTransaction.cs index 9dec011..d8f0fa3 100644 --- a/src/VirtoCommerce.Datatrans.Core/Models/DatatransTransaction.cs +++ b/src/VirtoCommerce.Datatrans.Core/Models/DatatransTransaction.cs @@ -1,12 +1,58 @@ +using Newtonsoft.Json; + namespace VirtoCommerce.Datatrans.Core.Models; -public class DatatransTransaction +public class DatatransTransaction : DatatransResponseBase { public string TransactionId { get; set; } - public string State { get; set; } - public long AmountMinor { get; set; } + public string MerchantId { get; set; } + public string Type { get; set; } + public string Status { get; set; } public string Currency { get; set; } - public string AuthCode { get; set; } - public DatatransError Error { get; set; } - public object Raw { get; set; } + public string Refno { get; set; } + public string PaymentMethod { get; set; } + public string AcquirerAuthorizationCode { get; set; } + public DatatransTransactionDetail Detail { get; set; } + public DatatransTransactionCard Card { get; set; } +} + +public class DatatransTransactionAmount +{ + public long Amount { get; set; } +} + +public class DatatransTransactionDetail +{ + public DatatransTransactionAmount Authorize { get; set; } +} + +public class DatatransTransactionCard +{ + public string Alias { get; set; } + public string Fingerprint { get; set; } + public string Masked { get; set; } + public string ExpiryMonth { get; set; } + public string ExpiryYear { get; set; } + public DatatransTransactionCardInfo Info { get; set; } + + [JsonProperty("3D")] + public DatatransTransactionCard3D ThreeD + { + get; set; + } +} + +public class DatatransTransactionCardInfo +{ + public string Brand { get; set; } + public string Type { get; set; } + public string Usage { get; set; } + public string Country { get; set; } + public string Issuer { get; set; } +} + +public class DatatransTransactionCard3D +{ + public string AuthenticationResponse { get; set; } + public string TransStatusReason { get; set; } } diff --git a/src/VirtoCommerce.Datatrans.Core/Models/DatatransVoidResponse.cs b/src/VirtoCommerce.Datatrans.Core/Models/DatatransVoidResponse.cs index 3216150..d2fee2c 100644 --- a/src/VirtoCommerce.Datatrans.Core/Models/DatatransVoidResponse.cs +++ b/src/VirtoCommerce.Datatrans.Core/Models/DatatransVoidResponse.cs @@ -1,9 +1,5 @@ -namespace VirtoCommerce.Datatrans.Core.Models; +namespace VirtoCommerce.Datatrans.Core.Models; -public class DatatransVoidResponse +public class DatatransVoidResponse : DatatransResponseBase { - public string TransactionId { get; set; } - public string State { get; set; } // voided/canceled - public DatatransError Error { get; set; } - public object Raw { get; set; } } diff --git a/src/VirtoCommerce.Datatrans.Core/Services/IDatatransClient.cs b/src/VirtoCommerce.Datatrans.Core/Services/IDatatransClient.cs index 4aa6635..48b0f9e 100644 --- a/src/VirtoCommerce.Datatrans.Core/Services/IDatatransClient.cs +++ b/src/VirtoCommerce.Datatrans.Core/Services/IDatatransClient.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Specialized; using System.Threading; using System.Threading.Tasks; using VirtoCommerce.Datatrans.Core.Models; @@ -8,19 +7,20 @@ namespace VirtoCommerce.Datatrans.Core.Services; public interface IDatatransClient { - Task GetTransactionId(DatatransRequest request, CancellationToken cancellationToken = default); + Task InitTransactionAsync(DatatransInitRequest request, CancellationToken ct = default); + Task GetTransactionAsync(string transactionId, CancellationToken ct = default); + Task AuthorizeAuthenticatedAsync(string transactionId, DatatransAuthorizeAuthenticatedRequest request, + CancellationToken ct = default); - Task InitTransactionAsync(DatatransInitRequest request, CancellationToken ct = default); - Task GetTransactionId(DatatransInitRequest request, CancellationToken ct = default); - Task GetTransactionAsync(string transactionId, CancellationToken ct = default); - Task AuthorizeAuthenticatedAsync(string transactionId, DatatransAuthorizeAuthenticatedRequest request, CancellationToken ct = default); Task CaptureAsync(string transactionId, DatatransCaptureRequest request, CancellationToken ct = default); + Task VoidAsync(string transactionId, CancellationToken ct = default); + Task RefundAsync(string transactionId, DatatransRefundRequest request, CancellationToken ct = default); + Uri BuildStartPaymentUri(string transactionId); + string GetSecureFieldsScriptUrl(); - DatatransPushPayload ParsePushPayload(NameValueCollection formOrQuery); - bool ValidatePushSignature(DatatransSignatureInput input); } diff --git a/src/VirtoCommerce.Datatrans.Data/Providers/DatatransPaymentMethod.cs b/src/VirtoCommerce.Datatrans.Data/Providers/DatatransPaymentMethod.cs index 6c1a79b..fd60f8c 100644 --- a/src/VirtoCommerce.Datatrans.Data/Providers/DatatransPaymentMethod.cs +++ b/src/VirtoCommerce.Datatrans.Data/Providers/DatatransPaymentMethod.cs @@ -1,12 +1,17 @@ using System; +using System.Collections.Generic; using System.Collections.Specialized; +using System.Linq; +using System.Threading; using System.Threading.Tasks; +using Newtonsoft.Json; using VirtoCommerce.Datatrans.Core.Models; using VirtoCommerce.Datatrans.Core.Services; using VirtoCommerce.OrdersModule.Core.Model; using VirtoCommerce.PaymentModule.Core.Model; using VirtoCommerce.PaymentModule.Model.Requests; using VirtoCommerce.Platform.Core.Common; +using VirtoCommerce.StoreModule.Core.Model; namespace VirtoCommerce.Datatrans.Data.Providers; @@ -44,7 +49,7 @@ public override RefundPaymentRequestResult RefundProcessPayment(RefundPaymentReq public override ValidatePostProcessRequestResult ValidatePostProcessRequest(NameValueCollection queryString) { - var tx = queryString["transactionId"] ?? queryString["transId"] ?? queryString["transaction-id"]; + var tx = queryString["transactionId"]; var result = new ValidatePostProcessRequestResult { IsSuccess = !string.IsNullOrEmpty(tx), @@ -59,35 +64,26 @@ public override ValidatePostProcessRequestResult ValidatePostProcessRequest(Name protected virtual async Task ProcessPaymentAsync(ProcessPaymentRequest request) { - var datatransRequest = GenerateRequest(request); + var payment = (PaymentIn)request.Payment; - var transactionResponse = await datatransClient.GetTransactionId(datatransRequest); - var result = new ProcessPaymentRequestResult - { - IsSuccess = transactionResponse.Error == null, - NewPaymentStatus = transactionResponse.Error == null ? PaymentStatus.Pending : PaymentStatus.Voided, - ErrorMessage = transactionResponse.Error?.Message, - PublicParameters = new() - { - ["transactionId"] = transactionResponse.TransactionId, - ["clientScript"] = "https://pay.sandbox.datatrans.com/upp/payment/js/secure-fields-2.0.0.min.js", // todo: replace with SANDBOX flag - } - }; + var initRequest = CreateInitRequest(request); + var initResponse = await datatransClient.InitTransactionAsync(initRequest); - var payment = (PaymentIn)request.Payment; - payment.OuterId = transactionResponse.TransactionId; - payment.PaymentStatus = result.NewPaymentStatus; + var ok = initResponse.Error is null && !string.IsNullOrEmpty(initResponse.TransactionId); + + payment.OuterId = initResponse.TransactionId; + payment.PaymentStatus = ok ? PaymentStatus.Pending : PaymentStatus.Voided; payment.Status = payment.PaymentStatus.ToString(); - return result; + return CreateInitRequestResult(initResponse, request); } - protected virtual Task PostProcessPaymentAsync(PostProcessPaymentRequest request) + protected virtual async Task PostProcessPaymentAsync(PostProcessPaymentRequest request, CancellationToken cancellationToken = default) { var payment = (PaymentIn)request.Payment; - var transactionId = request.OuterId - ?? request.Parameters?.GetValueOrDefault("transactionId") - ?? payment?.OuterId; + var order = (CustomerOrder)request.Order; + + var transactionId = request.Parameters?.Get("transactionId"); if (string.IsNullOrEmpty(transactionId)) { @@ -98,115 +94,381 @@ protected virtual Task PostProcessPaymentAsync( }; } - // 1) запросим Datatrans о состоянии транзакции - var tx = await datatransClient.GetTransactionAsync(transactionId); // сам метод назови как хочешь + var transaction = await datatransClient.GetTransactionAsync(transactionId, cancellationToken); + + if (transaction.Status is "authenticated") + { + transaction.Refno = Guid.NewGuid().ToString().Replace("-", "").ToLower(); + var authReq = CreateAuthorizeRequest(request, transaction); + var authResp = await datatransClient.AuthorizeAuthenticatedAsync(transactionId, authReq, cancellationToken); + + transaction = await datatransClient.GetTransactionAsync(transactionId, cancellationToken); + } + + var result = GetDatatransPostResult(transaction, payment, order); + + return result; + } + + protected virtual async Task VoidProcessPaymentAsync(VoidPaymentRequest request) + { + var payment = (PaymentIn)request.Payment; + var transactionId = GetTransactionId(request); + + if (payment.PaymentStatus == PaymentStatus.Voided) + { + return new VoidPaymentRequestResult + { + IsSuccess = true, + NewPaymentStatus = PaymentStatus.Voided + }; + } + + if (payment.PaymentStatus == PaymentStatus.Paid || payment.CapturedDate.HasValue) + { + return new VoidPaymentRequestResult + { + IsSuccess = false, + ErrorMessage = "Cannot void a captured payment. Use refund instead." + }; + } - // 2) мэппинг статуса - var (status, err) = MapDatatransStatus(tx); // твоя приватная функция + var response = await datatransClient.VoidAsync(transactionId); + + if (response.Error != null) + { + var transaction = await datatransClient.GetTransactionAsync(transactionId); + payment.OuterId = transactionId; + payment.PaymentStatus = ConvertStatus(transaction.Status); + } + + payment.Status = payment.PaymentStatus.ToString(); + + return new VoidPaymentRequestResult + { + IsSuccess = response.Error != null, + NewPaymentStatus = payment.PaymentStatus, + ErrorMessage = response.Error?.Message, + }; + } + + protected virtual async Task CaptureProcessPaymentAsync(CapturePaymentRequest context) + { + var payment = (PaymentIn)context.Payment; + var transactionId = GetTransactionId(context); + + var alreadyCaptured = payment.Captures.Sum(x => x.Amount); + var total = payment.Sum; + + var amountToCapture = context.CaptureAmount ?? (total - alreadyCaptured); + + if (amountToCapture <= 0m) + { + return new CapturePaymentRequestResult + { + IsSuccess = true, + NewPaymentStatus = payment.PaymentStatus, + ErrorMessage = null + }; + } + + var transaction = await datatransClient.GetTransactionAsync(transactionId); + var amountMinor = ToMinorUnits(amountToCapture); + + var captureRequest = new DatatransCaptureRequest + { + Amount = amountMinor, + Currency = payment.Currency, + Refno = transaction.Refno, + }; + + var response = await datatransClient.CaptureAsync(transactionId, captureRequest); - // 3) обновим VC-платёж payment.OuterId = transactionId; - payment.PaymentStatus = status; - payment.Status = status.ToString(); - if (status == PaymentStatus.Paid && payment.CapturedDate == null) + if (response.Error != null) + { + transaction = await datatransClient.GetTransactionAsync(transactionId); + payment.PaymentStatus = ConvertStatus(transaction.Status); + payment.CapturedDate ??= DateTime.UtcNow; + } + else { - payment.CapturedDate = DateTime.UtcNow; - payment.CapturedAmount = payment.Sum; // при partial capture укажи фактическую сумму + payment.PaymentStatus = PaymentStatus.Error; } - return new PostProcessPaymentRequestResult + payment.Status = payment.PaymentStatus.ToString(); + + return new CapturePaymentRequestResult { - IsSuccess = err is null && status is PaymentStatus.Authorized or PaymentStatus.Paid, - NewPaymentStatus = status, - ErrorMessage = err + IsSuccess = response.Error != null, + NewPaymentStatus = payment.PaymentStatus, + ErrorMessage = response.Error?.Message, }; + } + + protected virtual async Task RefundProcessPaymentAsync(RefundPaymentRequest context) + { + var payment = (PaymentIn)context.Payment; + var order = (CustomerOrder)context.Order; + var transactionId = GetTransactionId(context); + + if (!payment.CapturedDate.HasValue) + { + return new RefundPaymentRequestResult + { + IsSuccess = false, + ErrorMessage = "No captured amount to refund." + }; + } + + if (payment.PaymentStatus == PaymentStatus.Refunded) + { + return new RefundPaymentRequestResult + { + IsSuccess = false, + ErrorMessage = "Refund amount exceeds captured amount." + }; + } - // 2 + var amountToRefund = context.AmountToRefund; - //var token = request.Parameters.Get("token"); - //var payment = (PaymentIn)request.Payment; - //var order = (CustomerOrder)request.Order; + if (amountToRefund <= 0m) + { + return new RefundPaymentRequestResult + { + IsSuccess = false, + ErrorMessage = "Refund amount must be greater than zero." + }; + } - //var clientRequest = PrepareProcessPaymentRequest(token, payment, order); + var transaction = await datatransClient.GetTransactionAsync(transactionId); + var amountMinor = ToMinorUnits(amountToRefund); - //var paymentResult = await datatransClient.AuthorizePayment(clientRequest); + var request = new DatatransRefundRequest + { + Amount = amountMinor, + Currency = payment.Currency, + Refno = transaction.Refno, + }; - //var result = GetPostPaymentResult(paymentResult, payment, order); - //return result; + var response = await datatransClient.RefundAsync(transactionId, request); - // 1 + if (response.Error != null) + { + transaction = await datatransClient.GetTransactionAsync(transactionId); + payment.PaymentStatus = ConvertStatus(transaction.Status); + } - //var result = new PostProcessPaymentRequestResult - //{ - // IsSuccess = false, - // NewPaymentStatus = PaymentStatus.Pending, - //}; + payment.Status = payment.PaymentStatus.ToString(); - //if (request?.Payment == null) - //{ - // result.IsSuccess = false; - // result.ErrorMessage = "Payment is null."; - // return Task.FromResult(result); - //} + return new RefundPaymentRequestResult + { + IsSuccess = response.Error != null, + NewPaymentStatus = payment.PaymentStatus, + ErrorMessage = response.Error?.Message, + }; + } - //var payment = (PaymentIn)request.Payment; + #endregion - //result.IsSuccess = true; - //result.NewPaymentStatus = payment.PaymentStatus; + #region extension points + + protected virtual DatatransInitRequest CreateInitRequest(ProcessPaymentRequest request) + { + var payment = (PaymentIn)request.Payment; + var order = (CustomerOrder)request.Order; + var store = (Store)request.Store; - //payment.PaymentStatus = result.NewPaymentStatus; - //payment.Status = payment.PaymentStatus.ToString(); + var url = (store.SecureUrl.IsNullOrEmpty() ? store.Url : store.SecureUrl)?.TrimEnd('/'); - //return Task.FromResult(result); + var result = AbstractTypeFactory.TryCreateInstance(); + result.Amount = ToMinorUnits(payment.Sum); + result.Currency = payment.Currency ?? order.Currency; + result.ReturnUrl = $"{url}/account/orders/{order.Id}/payment"; + return result; } - private static (PaymentStatus status, string error) MapDatatransStatus(DatatransTransaction tx) + protected virtual ProcessPaymentRequestResult CreateInitRequestResult(DatatransInitResponse initResponse, ProcessPaymentRequest request) { - // Примеры, проверь реальные поля ответа: - return tx.State switch + var payment = (PaymentIn)request.Payment; + + return new ProcessPaymentRequestResult { - "authorized" => (PaymentStatus.Authorized, null), - "settled" or "captured" => (PaymentStatus.Paid, null), - "canceled" or "voided" => (PaymentStatus.Voided, null), - "failed" => (PaymentStatus.Voided, tx.Error?.Message ?? "Payment failed"), - _ => (PaymentStatus.Pending, null), + IsSuccess = initResponse.Error != null, + NewPaymentStatus = payment.PaymentStatus, + ErrorMessage = initResponse.Error?.Message, + PublicParameters = new() + { + ["transactionId"] = initResponse.TransactionId, + ["clientScript"] = datatransClient.GetSecureFieldsScriptUrl(), + ["startUrl"] = datatransClient.BuildStartPaymentUri(initResponse.TransactionId).ToString(), + }, }; } + protected virtual DatatransAuthorizeAuthenticatedRequest CreateAuthorizeRequest(PostProcessPaymentRequest request, DatatransTransaction transaction) + { + var result = AbstractTypeFactory.TryCreateInstance(); + result.Amount = transaction.Detail.Authorize.Amount; + result.Refno = transaction.Refno; - protected virtual Task VoidProcessPaymentAsync(VoidPaymentRequest request) - { - return Task.FromResult(new VoidPaymentRequestResult()); + return result; } - protected virtual Task CaptureProcessPaymentAsync(CapturePaymentRequest context) + #endregion + + #region Helpers + + private string GetTransactionId(PaymentRequestBase context) { - return Task.FromResult(new CapturePaymentRequestResult()); + var payment = (PaymentIn)context.Payment; + + var transactionId = + payment?.OuterId + ?? context.Parameters?.Get("transactionId") + ?? context.OuterId; + + return transactionId; } - protected virtual Task RefundProcessPaymentAsync(RefundPaymentRequest context) + private static long ToMinorUnits(decimal amount) { - return Task.FromResult(new RefundPaymentRequestResult()); + return (long)Math.Round(amount * 100m, MidpointRounding.AwayFromZero); } #endregion - #region extension points + #region post process status mappers - protected virtual DatatransRequest GenerateRequest(ProcessPaymentRequest request) + private PostProcessPaymentRequestResult GetDatatransPostResult( + DatatransTransaction transaction, + PaymentIn payment, + CustomerOrder order + ) { - var order = (CustomerOrder)request.Order; + var newStatus = ConvertStatus(transaction.Status); + return newStatus switch + { + PaymentStatus.Authorized or PaymentStatus.Paid => PaymentApproved(transaction, newStatus, payment, order), + PaymentStatus.Declined => PaymentDeclined(transaction, payment), + PaymentStatus.Pending => PaymentPending(transaction, payment), + _ => PaymentInvalid(transaction, payment), + }; + } - var result = AbstractTypeFactory.TryCreateInstance(); + private PostProcessPaymentRequestResult PaymentApproved(DatatransTransaction tx, PaymentStatus newStatus, PaymentIn payment, CustomerOrder order) + { + var result = new PostProcessPaymentRequestResult + { + NewPaymentStatus = newStatus, + OrderId = order.Id, + OuterId = tx.TransactionId, + IsSuccess = true, + }; + + payment.PaymentStatus = newStatus; + payment.Status = newStatus.ToString(); + payment.IsApproved = true; + payment.OuterId = tx.TransactionId; + payment.AuthorizedDate ??= DateTime.UtcNow; + + payment.CapturedDate ??= DateTime.UtcNow; + payment.Captures ??= new List(); + payment.Captures.Add(new Capture + { + TransactionId = tx.TransactionId, + Amount = payment.Sum, + Currency = payment.Currency, + CreatedDate = DateTime.UtcNow, + OuterId = tx.TransactionId, + }); + + var note = $"Transaction ID: {tx.TransactionId}"; + if (!string.IsNullOrEmpty(tx.MerchantId)) + { + note += $", Merchant ID: {tx.MerchantId}"; + } + + payment.Comment = $"Paid successfully via Datatrans. {note}{Environment.NewLine}"; + order.Status = "Processing"; - result.Amount = order.Total * 100; // should be in coins? look at https://api-reference.datatrans.ch/#tag/v1transactions/operation/init - result.Currency = order.Currency; - result.OrderId = order.Id; + var transaction = new PaymentGatewayTransaction + { + IsProcessed = true, + ProcessedDate = DateTime.UtcNow, + CurrencyCode = payment.Currency, + Amount = payment.Sum, + Note = note, + ResponseData = JsonConvert.SerializeObject(tx) + }; + + payment.Transactions ??= new List(); + payment.Transactions.Add(transaction); return result; } + private PostProcessPaymentRequestResult PaymentDeclined(DatatransTransaction tx, PaymentIn payment) + { + var msg = tx.Error != null ? JsonConvert.SerializeObject(tx.Error) : "Invalid Datatrans response"; + var errorMessage = $"Your transaction was declined: {msg}"; + + payment.Status = PaymentStatus.Declined.ToString(); + payment.ProcessPaymentResult = new ProcessPaymentRequestResult { ErrorMessage = errorMessage }; + payment.Comment = $"{errorMessage}{Environment.NewLine}"; + + return new PostProcessPaymentRequestResult + { + NewPaymentStatus = PaymentStatus.Declined, + ErrorMessage = errorMessage, + }; + } + + private PostProcessPaymentRequestResult PaymentPending(DatatransTransaction tx, PaymentIn payment) + { + var msg = tx.Error != null ? JsonConvert.SerializeObject(tx.Error) : "Invalid Datatrans response"; + var errorMessage = $"Your transaction is pending: {msg}"; + + payment.ProcessPaymentResult = new ProcessPaymentRequestResult { ErrorMessage = errorMessage }; + payment.Comment = $"{errorMessage}{Environment.NewLine}"; + payment.OuterId ??= tx.TransactionId; + + return new PostProcessPaymentRequestResult + { + ErrorMessage = errorMessage, + IsSuccess = true, + OuterId = tx.TransactionId + }; + } + + private PostProcessPaymentRequestResult PaymentInvalid(DatatransTransaction tx, PaymentIn payment) + { + var msg = tx.Error != null ? JsonConvert.SerializeObject(tx.Error) : "Invalid Datatrans response"; + var errorMessage = $"There was an error processing your transaction: {msg}"; + + payment.Status = PaymentStatus.Error.ToString(); + payment.ProcessPaymentResult = new ProcessPaymentRequestResult { ErrorMessage = errorMessage }; + payment.Comment = $"{errorMessage}{Environment.NewLine}"; + + return new PostProcessPaymentRequestResult { ErrorMessage = errorMessage }; + } + + private static PaymentStatus ConvertStatus(string status) + { + return status switch + { + "initialized" => PaymentStatus.Pending, + "authenticated" => PaymentStatus.Pending, + "authorized" => PaymentStatus.Authorized, + "settled" => PaymentStatus.Paid, + "canceled" => PaymentStatus.Voided, + "transmitted" => PaymentStatus.Pending, + "failed" => PaymentStatus.Declined, + _ => PaymentStatus.Error + }; + } + #endregion } diff --git a/src/VirtoCommerce.Datatrans.Data/Services/DatatransClient.cs b/src/VirtoCommerce.Datatrans.Data/Services/DatatransClient.cs index 7f2a4c2..8351f97 100644 --- a/src/VirtoCommerce.Datatrans.Data/Services/DatatransClient.cs +++ b/src/VirtoCommerce.Datatrans.Data/Services/DatatransClient.cs @@ -1,11 +1,15 @@ using System; using System.Net.Http; -using System.Net.Http.Json; +using System.Text; +using System.Text.Json; using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Options; +using Newtonsoft.Json; using VirtoCommerce.Datatrans.Core.Models; using VirtoCommerce.Datatrans.Core.Services; +using VirtoCommerce.Platform.Core.Common; +using JsonSerializer = System.Text.Json.JsonSerializer; namespace VirtoCommerce.Datatrans.Data.Services; @@ -13,50 +17,102 @@ public class DatatransClient(IHttpClientFactory httpClientFactory, IOptions _options.UseSandbox ? _options.SandboxStartUrlBase : _options.ProductionStartUrlBase; private string SecureScriptUrl => _options.UseSandbox ? _options.SandboxSecureFieldsScriptUrl : _options.ProductionSecureFieldsScriptUrl; - public string GetSecureFieldsScriptUrl() => SecureScriptUrl; - public Uri BuildStartPaymentUri(string transactionId) { return new Uri($"{BaseStartUrl}{Uri.EscapeDataString(transactionId)}"); } - public async Task GetTransactionId(DatatransRequest request, CancellationToken cancellationToken = default) + public string GetSecureFieldsScriptUrl() => SecureScriptUrl; + + public async Task InitTransactionAsync(DatatransInitRequest request, CancellationToken ct = default) { - var httpClient = httpClientFactory.CreateClient(); + var resp = await SendAsync(HttpMethod.Post, _options.Routes.SecureFieldsPath, request, ct); + return ParseResponse(resp); + } - var token = GetToken(); + public async Task GetTransactionAsync(string transactionId, CancellationToken ct = default) + { + var path = _options.Routes.TxnPath.Replace("{transactionId}", Uri.EscapeDataString(transactionId)); + var resp = await SendAsync(HttpMethod.Get, path, null, ct); + return ParseResponse(resp); + } - var requestMessage = new HttpRequestMessage - { - RequestUri = new Uri("https://api.sandbox.datatrans.com/v1/transactions/secureFields"), - Method = HttpMethod.Post, - Headers = - { - { "Authorization", $"Basic {token}" }, - { "User-Agent", "VirtoCommerce/3.0" }, - { "Idempotency-Key", request.OrderId }, // Using OrderId as Idempotency-Key for simplicity - }, - Content = JsonContent.Create(new // should it be a model? - { - request.Currency, - request.Amount, - returnUrl = "https://localhost:3000", // storeUrl?? - }), - }; - var response = await httpClient.SendAsync(requestMessage, cancellationToken); + public async Task AuthorizeAuthenticatedAsync(string transactionId, DatatransAuthorizeAuthenticatedRequest request, CancellationToken ct = default) + { + var path = _options.Routes.AuthorizeAuthenticatedPath.Replace("{transactionId}", Uri.EscapeDataString(transactionId)); + var resp = await SendAsync(HttpMethod.Post, path, request, ct); + return ParseResponse(resp); + } + + public async Task CaptureAsync(string transactionId, DatatransCaptureRequest request, CancellationToken ct = default) + { + var path = _options.Routes.CapturePath.Replace("{transactionId}", Uri.EscapeDataString(transactionId)); + var resp = await SendAsync(HttpMethod.Post, path, request, ct); + return ParseResponse(resp); + } - var result = await response.Content.ReadFromJsonAsync(cancellationToken); - return result; + public async Task VoidAsync(string transactionId, CancellationToken ct = default) + { + var path = _options.Routes.VoidPath.Replace("{transactionId}", Uri.EscapeDataString(transactionId)); + var resp = await SendAsync(HttpMethod.Post, path, new { }, ct); + return ParseResponse(resp); } + public async Task RefundAsync(string transactionId, DatatransRefundRequest request, CancellationToken ct = default) + { + var path = _options.Routes.RefundPath.Replace("{transactionId}", Uri.EscapeDataString(transactionId)); + var resp = await SendAsync(HttpMethod.Post, path, request, ct); + return ParseResponse(resp); + } - private string GetToken() + private async Task SendAsync(HttpMethod method, string path, object body, CancellationToken ct) { - var merchantId = "1110020617"; // todo: get from settings - var password = "eVZ5bq237EUzbpOF"; - return Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes($"{merchantId}:{password}")); + using var msg = new HttpRequestMessage(method, path); + + if (body is not null) + { + var json = JsonSerializer.Serialize(body, _json); + msg.Content = new StringContent(json, Encoding.UTF8, "application/json"); + } + + var httpClient = httpClientFactory.CreateClient("Datatrans"); + + using var resp = await httpClient.SendAsync(msg, ct); + var content = await resp.Content.ReadAsStringAsync(ct); + + return content; + } + + private static T ParseResponse(string json) where T : DatatransResponseBase, new() + { + try + { + if (json.IsNullOrEmpty()) + { + return new T(); + } + + return JsonConvert.DeserializeObject(json); + } + catch (Exception exception) + { + return new T + { + Error = new DatatransError + { + Message = exception.Message, + Raw = json + } + }; + } } } diff --git a/src/VirtoCommerce.Datatrans.Web/Controllers/DatatransController.cs b/src/VirtoCommerce.Datatrans.Web/Controllers/DatatransController.cs new file mode 100644 index 0000000..4ff28ad --- /dev/null +++ b/src/VirtoCommerce.Datatrans.Web/Controllers/DatatransController.cs @@ -0,0 +1,83 @@ +using System; +using System.Collections.Specialized; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using VirtoCommerce.Datatrans.Data.Providers; +using VirtoCommerce.OrdersModule.Core.Services; +using VirtoCommerce.PaymentModule.Core.Services; +using VirtoCommerce.PaymentModule.Model.Requests; +using VirtoCommerce.Platform.Core.Common; + +namespace VirtoCommerce.Datatrans.Web.Controllers; + +[Route("api/payments/datatrans")] +public class DatatransController(IPaymentMethodsService paymentMethods, + IPaymentService payments) : Controller +{ + [HttpPost("push")] + public async Task Push(CancellationToken cancellationToken = default) + { + // Datatrans шлёт form-urlencoded + var form = Request.HasFormContentType + ? Request.Form + : throw new InvalidOperationException("Expected form data"); + + var query = new NameValueCollection(); + foreach (var kvp in form) + { + query[kvp.Key] = kvp.Value; + } + + return await HandleCallback(query, cancellationToken); + } + + private async Task HandleCallback(NameValueCollection query, CancellationToken cancellationToken = default) + { + var method = await paymentMethods.GetByIdAsync(nameof(DatatransPaymentMethod)); + if (method == null) + { + return NotFound("Datatrans payment method not found"); + } + + var datatrans = method as DatatransPaymentMethod; + if (datatrans == null) + { + return BadRequest("Payment method type mismatch"); + } + + var validate = datatrans.ValidatePostProcessRequest(query); + if (!validate.IsSuccess) + { + return BadRequest("Invalid Datatrans callback"); + } + + var transactionId = validate.OuterId; + if (string.IsNullOrEmpty(transactionId)) + { + return BadRequest("TransactionId not found"); + } + + var payment = await payments.GetByOuterIdAsync(transactionId); + if (payment == null) + { + return NotFound($"Payment with transactionId={transactionId} not found"); + } + + var postReq = new PostProcessPaymentRequest + { + Payment = payment, + OuterId = transactionId, + Parameters = query + }; + + var result = datatrans.PostProcessPayment(postReq); + + if (result.IsSuccess) + { + await payments.SaveChangesAsync([payment]); + } + + return Ok(); + } +} diff --git a/src/VirtoCommerce.Datatrans.Web/Module.cs b/src/VirtoCommerce.Datatrans.Web/Module.cs index f15e9f6..1949a03 100644 --- a/src/VirtoCommerce.Datatrans.Web/Module.cs +++ b/src/VirtoCommerce.Datatrans.Web/Module.cs @@ -1,6 +1,10 @@ +using System; +using System.Net.Http.Headers; +using System.Text; using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; using VirtoCommerce.Datatrans.Core; using VirtoCommerce.Datatrans.Core.Models; using VirtoCommerce.Datatrans.Core.Services; @@ -19,11 +23,25 @@ public class Module : IModule, IHasConfiguration public void Initialize(IServiceCollection serviceCollection) { - serviceCollection.AddOptions().Bind(Configuration.GetSection("Payments:Datatrans")).ValidateDataAnnotations(); + serviceCollection.AddOptions().Bind(Configuration.GetSection("Payments:Datatrans")).ValidateDataAnnotations(); serviceCollection.AddTransient(); serviceCollection.AddTransient(); + + serviceCollection.AddHttpClient("Datatrans", (sp, http) => + { + var opt = sp.GetRequiredService>().Value; + http.BaseAddress = new Uri(opt.UseSandbox ? opt.SandboxBaseUrl : opt.ProductionBaseUrl); + http.Timeout = TimeSpan.FromSeconds(30); + + if (!string.IsNullOrEmpty(opt.MerchantId)) + { + var bytes = Encoding.UTF8.GetBytes($"{opt.MerchantId}:{opt.Secret}"); + http.DefaultRequestHeaders.Authorization = + new AuthenticationHeaderValue("Basic", Convert.ToBase64String(bytes)); + } + }); } public void PostInitialize(IApplicationBuilder appBuilder) From 3a72dceade94496f698d604abe00d7c89e2d387e Mon Sep 17 00:00:00 2001 From: Basil Kotov Date: Tue, 14 Oct 2025 11:29:30 +0100 Subject: [PATCH 03/29] update workflow --- .deployment/module/argoDeploy.json | 29 +++ .deployment/module/cloudDeploy.json | 29 +++ .github/CODEOWNERS | 16 ++ .github/ISSUE_TEMPLATE.md | 15 ++ .github/pull_request_template.md | 6 + .github/workflows/deploy-pr.yml | 44 ++++ .github/workflows/deploy.yml | 78 ++++++ .github/workflows/module-ci.yml | 272 ++++++++++++++++++++ .github/workflows/module-release-hotfix.yml | 82 ++++++ .github/workflows/msteams.yml | 54 ++++ .github/workflows/publish-nugets.yml | 38 +++ .github/workflows/release.yml | 12 + 12 files changed, 675 insertions(+) create mode 100644 .deployment/module/argoDeploy.json create mode 100644 .deployment/module/cloudDeploy.json create mode 100644 .github/CODEOWNERS create mode 100644 .github/ISSUE_TEMPLATE.md create mode 100644 .github/pull_request_template.md create mode 100644 .github/workflows/deploy-pr.yml create mode 100644 .github/workflows/deploy.yml create mode 100644 .github/workflows/module-ci.yml create mode 100644 .github/workflows/module-release-hotfix.yml create mode 100644 .github/workflows/msteams.yml create mode 100644 .github/workflows/publish-nugets.yml create mode 100644 .github/workflows/release.yml diff --git a/.deployment/module/argoDeploy.json b/.deployment/module/argoDeploy.json new file mode 100644 index 0000000..80721c6 --- /dev/null +++ b/.deployment/module/argoDeploy.json @@ -0,0 +1,29 @@ +{ + "artifactKey": "VirtoCommerce.Datatrans", + "deployRepo": "vc-deploy-dev", + "cmPath": "platform-dev/resources/deployment-cm.yaml", + "dev": { + "deployAppName": "vcplatform-dev", + "deployBranch": "dev", + "environmentId": "dev", + "environmentName": "Development", + "environmentType": "staging", + "environmentUrl": "https://vcplatform-platform.dev.govirto.com/" + }, + "qa": { + "deployAppName": "vcplatform-qa", + "deployBranch": "qa", + "environmentId": "qa", + "environmentName": "QA", + "environmentType": "testing", + "environmentUrl": "https://vcplatform-platform.qa.govirto.com/" + }, + "prod": { + "deployAppName": "vcplatform-demo", + "deployBranch": "demo", + "environmentId": "prod", + "environmentName": "Demo", + "environmentType": "production", + "environmentUrl": "https://vcplatform-platform.demo.govirto.com/" + } +} \ No newline at end of file diff --git a/.deployment/module/cloudDeploy.json b/.deployment/module/cloudDeploy.json new file mode 100644 index 0000000..8042bad --- /dev/null +++ b/.deployment/module/cloudDeploy.json @@ -0,0 +1,29 @@ +{ + "artifactKey": "VirtoCommerce.Datatrans", + "deployRepo": "vc-deploy-dev", + "cmPath": "backend/packages.json", + "dev": { + "deployAppName": "vcptcore-dev", + "deployBranch": "vcptcore-dev", + "environmentId": "dev", + "environmentName": "Development", + "environmentType": "staging", + "environmentUrl": "https://vcptcore-dev.govirto.com/" + }, + "qa": { + "deployAppName": "vcptcore-qa", + "deployBranch": "vcptcore-qa", + "environmentId": "qa", + "environmentName": "QA", + "environmentType": "testing", + "environmentUrl": "https://vcptcore-qa.govirto.com/" + }, + "prod": { + "deployAppName": "vcptcore-demo", + "deployBranch": "vcptcore-demo", + "environmentId": "prod", + "environmentName": "Demo", + "environmentType": "production", + "environmentUrl": "https://vcptcore-demo.govirto.com/" + } +} \ No newline at end of file diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..22e3547 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,16 @@ +# Common settings + +.github/* @VirtoCommerce/platform +.gitignore @VirtoCommerce/platform +.dockerignore @VirtoCommerce/platform + +# Main Code and Tests + +src/* @VirtoCommerce/platform +tests/* @VirtoCommerce/platform +.editorconfig @VirtoCommerce/platform +3rd-party-components.md @VirtoCommerce/platform +VirtoCommerce.Platform.sln @VirtoCommerce/platform + +# Docs +docs/* @VirtoCommerce/platform diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100644 index 0000000..2643856 --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,15 @@ +Please provide detailed information about your issue, thank you! + +Version info: +- Browser version: +- Platform version: +- Module version: + +### Expected behavior + +### Actual behavior + +### Steps to reproduce +1. +2. +3. diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..bc91331 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,6 @@ +## Description + +## References +### QA-test: +### Jira-link: +### Artifact URL: diff --git a/.github/workflows/deploy-pr.yml b/.github/workflows/deploy-pr.yml new file mode 100644 index 0000000..d93ddf7 --- /dev/null +++ b/.github/workflows/deploy-pr.yml @@ -0,0 +1,44 @@ +# v1.0 + +name: Deploy to environments +on: + pull_request: + paths-ignore: + - '.github/**' + - 'docs/**' + - 'build/**' + - 'README.md' + - 'LICENSE' + - '**/argoDeploy.json' + branches: [dev] + types: [labeled, closed] + +jobs: + deploy: + runs-on: ubuntu-latest + env: + GITHUB_TOKEN: ${{ secrets.REPO_TOKEN }} + + steps: + - name: Read deployment config + if: contains(github.event.pull_request.labels.*.name, 'deploy-qa') + uses: VirtoCommerce/vc-github-actions/get-deploy-param@master + id: deployConfig + + - name: Gets artifact link + if: contains(github.event.pull_request.labels.*.name, 'deploy-qa') + uses: VirtoCommerce/vc-github-actions/get-artifact-link@master + id: artifactLink + with: + downloadComment: 'Artifact URL:' + + - name: Create deploy PR in QA + if: github.event.action != 'closed' && contains(github.event.pull_request.labels.*.name, 'deploy-qa') + uses: VirtoCommerce/vc-github-actions/create-deploy-pr@master + with: + deployRepo: ${{ steps.deployConfig.outputs.deployRepo }} + deployBranch: ${{ fromJSON(steps.deployConfig.outputs.deployConfig).qa.deployBranch }} + artifactKey: ${{ steps.deployConfig.outputs.artifactKey }} + artifactUrl: ${{ steps.artifactLink.outputs.artifactUrl }} + taskNumber: ${{ steps.artifactLink.outputs.qaTaskNumber }} + cmPath: ${{ steps.deployConfig.outputs.cmPath }} diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 0000000..0cf6499 --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,78 @@ +# v1.0 + +name: VC deployment +on: + workflow_dispatch: + inputs: + artifactUrl: + description: 'Full link to artifact docker image or artifact download url' + required: true + deployBranch: + description: 'ArgoCd branch name' + required: true + default: 'dev' + +jobs: + cd: + runs-on: ubuntu-latest + env: + GITHUB_TOKEN: ${{ secrets.REPO_TOKEN }} + + steps: + + - name: Read deployment config + uses: VirtoCommerce/vc-github-actions/get-deploy-param@master + id: deployConfig + with: + envName: ${{ github.event.inputs.deployBranch }} + + - name: Start deployment + uses: bobheadxi/deployments@master + id: deployment + with: + step: start + token: ${{ secrets.GITHUB_TOKEN }} + env: Development + no_override: false + + - name: Update deployment-cm + uses: VirtoCommerce/vc-github-actions/create-deploy-pr@master + with: + deployRepo: ${{ steps.deployConfig.outputs.deployRepo }} + deployBranch: ${{ steps.deployConfig.outputs.deployBranch }} + artifactKey: ${{ steps.deployConfig.outputs.artifactKey }} + artifactUrl: ${{ github.event.inputs.artifactUrl }} + taskNumber: "undefined" + forceCommit: "true" + cmPath: ${{ steps.deployConfig.outputs.cmPath }} + + - name: Wait for environment is up + shell: pwsh + timeout-minutes: 15 + run: | + do { + Start-Sleep -s 15 + $statusBage = (Invoke-WebRequest -Uri "https://argo.govirto.com/api/badge?name=${{ steps.deployConfig.outputs.deployAppName }}").Content + + $syncedAndHealthy = $statusBage.Contains('>Healthy<') -and $statusBage.Contains('>Synced<') + if (-not $syncedAndHealthy) { + Write-Host "Sync pending..." + } + } + while (-not $syncedAndHealthy) + - name: BUILD_STATE::successful + if: success() + run: echo "BUILD_STATE=successful" >> $GITHUB_ENV + + - name: BUILD_STATE::failed + if: failure() + run: echo "BUILD_STATE=failed" >> $GITHUB_ENV + + - name: Update GitHub deployment status + uses: bobheadxi/deployments@master + if: always() + with: + step: finish + token: ${{ secrets.GITHUB_TOKEN }} + status: ${{ job.status }} + deployment_id: ${{ steps.deployment.outputs.deployment_id }} diff --git a/.github/workflows/module-ci.yml b/.github/workflows/module-ci.yml new file mode 100644 index 0000000..3537d12 --- /dev/null +++ b/.github/workflows/module-ci.yml @@ -0,0 +1,272 @@ +# v3.800.12 +# https://virtocommerce.atlassian.net/browse/VCST-2469 +name: Module CI + +on: + workflow_dispatch: + push: + paths-ignore: + - '.github/**' + - 'docs/**' + - 'build/**' + - 'README.md' + - 'LICENSE' + - '**/argoDeploy.json' + - '**/cloudDeploy.json' + - samples/** + branches: + [master, main, dev] + pull_request: + branches: + [master, main, dev] + paths-ignore: + - 'docs/**' + - 'build/**' + - 'README.md' + - 'LICENSE' + - '**/argoDeploy.json' + - '**/cloudDeploy.json' + - samples/** + +jobs: + ci: + if: ${{ github.actor != 'dependabot[bot]' && + (github.event.pull_request.head.repo.full_name == github.repository || + github.event.pull_request.head.repo.full_name == '') }} # Check that PR not from forked repo and not from Dependabot + runs-on: ubuntu-24.04 + env: + CLOUD_INSTANCE_BASE_URL: ${{secrets.CLOUD_INSTANCE_BASE_URL}} + CLIENT_ID: ${{secrets.CLIENT_ID}} + CLIENT_SECRET: ${{secrets.CLIENT_SECRET}} + SONAR_TOKEN: ${{secrets.SONAR_TOKEN}} + GITHUB_TOKEN: ${{ secrets.REPO_TOKEN }} + NUGET_KEY: ${{ secrets.NUGET_KEY }} + BLOB_SAS: ${{ secrets.BLOB_TOKEN }} + VERSION_SUFFIX: '' + BUILD_STATE: 'failed' + RELEASE_STATUS: 'false' + + outputs: + artifactUrl: ${{ steps.artifactUrl.outputs.download_url }} + blobId: ${{ steps.blobRelease.outputs.blobId }} + jira-keys: ${{ steps.jira_keys.outputs.jira-keys }} + version: ${{ steps.artifact_ver.outputs.shortVersion }} + moduleId: ${{ steps.artifact_ver.outputs.moduleId }} + matrix: ${{ steps.deployment-matrix.outputs.matrix }} + run-e2e: ${{ steps.run-e2e.outputs.result }} + + steps: + + - name: Set up Node 20 + uses: actions/setup-node@v4 + with: + node-version: '20' + + - name: Set up Java 17 + uses: actions/setup-java@v4 + with: + distribution: 'temurin' + java-version: '17' + + - name: Set RELEASE_STATUS + if: ${{ (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/main') && github.event_name == 'push' }} + run: | + echo "RELEASE_STATUS=true" >> $GITHUB_ENV + + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Install VirtoCommerce.GlobalTool + uses: VirtoCommerce/vc-github-actions/setup-vcbuild@master + + - name: Install dotnet-sonarscanner + run: dotnet tool install --global dotnet-sonarscanner + + - name: Get Changelog + id: changelog + uses: VirtoCommerce/vc-github-actions/changelog-generator@master + + - name: Get Artifact Version + uses: VirtoCommerce/vc-github-actions/get-image-version@master + id: artifact_ver + + - name: Set VERSION_SUFFIX variable + run: | + if [ '${{ github.event_name }}' = 'workflow_dispatch' ]; then + echo "VERSION_SUFFIX=${{ steps.artifact_ver.outputs.fullSuffix }}" >> $GITHUB_ENV + else + echo "VERSION_SUFFIX=${{ steps.artifact_ver.outputs.suffix }}" >> $GITHUB_ENV + fi; + - name: Add version suffix + if: ${{ github.ref != 'refs/heads/master' && github.ref != 'refs/heads/main' }} + uses: VirtoCommerce/vc-github-actions/add-version-suffix@master + with: + versionSuffix: ${{ env.VERSION_SUFFIX }} + + - name: SonarCloud Begin + uses: VirtoCommerce/vc-github-actions/sonar-scanner-begin@master + with: + repoOrg: ${{ github.repository_owner }} + sonarOrg: ${{secrets.SONAR_ORG_KEY}} + + - name: Build + run: vc-build Compile + + - name: Unit Tests + run: vc-build Test -skip + + - name: SonarCloud End + uses: VirtoCommerce/vc-github-actions/sonar-scanner-end@master + + - name: Quality Gate + uses: VirtoCommerce/vc-github-actions/sonar-quality-gate@master + with: + login: ${{secrets.SONAR_TOKEN}} + + - name: Packaging + run: vc-build Compress -skip Clean+Restore+Compile+Test + + - name: Publish Nuget + if: ${{ github.ref == 'refs/heads/master' || github.ref == 'refs/heads/main' }} + uses: VirtoCommerce/vc-github-actions/publish-nuget@master + + - name: Publish to Blob + if: ${{ github.ref == 'refs/heads/master' || github.ref == 'refs/heads/main' || github.ref == 'refs/heads/dev' || github.event_name == 'pull_request' || (github.event_name == 'workflow_dispatch' && github.ref != 'refs/heads/master') || (github.event_name == 'workflow_dispatch' && github.ref != 'refs/heads/main') }} + id: blobRelease + uses: VirtoCommerce/vc-github-actions/publish-blob-release@master + with: + blobSAS: ${{ secrets.BLOB_TOKEN }} + blobUrl: ${{ vars.BLOB_URL }} + + - name: Add Jira link + if: ${{ github.event_name == 'pull_request' }} + uses: VirtoCommerce/vc-github-actions/publish-jira-link@master + with: + branchName: ${{ github.head_ref }} + repoOrg: ${{ github.repository_owner }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Add link to PR + if: ${{ github.event_name == 'pull_request' }} + uses: VirtoCommerce/vc-github-actions/publish-artifact-link@master + with: + artifactUrl: ${{ steps.blobRelease.outputs.packageUrl }} + repoOrg: ${{ github.repository_owner }} + downloadComment: 'Artifact URL:' + + - name: Publish Github Release + if: ${{ github.ref == 'refs/heads/master' || github.ref == 'refs/heads/main' }} + id: githubRelease + with: + changelog: ${{ steps.changelog.outputs.changelog }} + organization: ${{ github.repository_owner }} + uses: VirtoCommerce/vc-github-actions/publish-github-release@master + + - name: Set artifactUrl value + id: artifactUrl + run: | + if [ '${{ github.ref }}' = 'refs/heads/master' ] || [ '${{ github.ref }}' = 'refs/heads/main' ]; then + echo "download_url=${{ steps.githubRelease.outputs.downloadUrl }}" >> $GITHUB_OUTPUT + else + echo "download_url=${{ steps.blobRelease.outputs.packageUrl }}" >> $GITHUB_OUTPUT + fi; + + - name: Create deployment matrix + if: ${{ github.ref == 'refs/heads/dev' || github.ref == 'refs/heads/master' || github.ref == 'refs/heads/main' }} + uses: VirtoCommerce/vc-github-actions/cloud-create-deploy-matrix@master + id: deployment-matrix + with: + deployConfigPath: '.deployment/module/cloudDeploy.json' + releaseBranch: 'master' + + - name: Check commit message for version number + id: run-e2e + run: | + if [[ "${{ github.event.head_commit.message }}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; + then + echo "result=false" >> $GITHUB_OUTPUT + else + echo "result=true" >> $GITHUB_OUTPUT + fi + + - name: Setup Git Credentials + if: ${{ (github.ref == 'refs/heads/dev' && github.event_name != 'workflow_dispatch') || github.ref == 'refs/heads/master' || github.ref == 'refs/heads/main' }} + uses: VirtoCommerce/vc-github-actions/setup-git-credentials-github@master + with: + githubToken: ${{ secrets.REPO_TOKEN }} + + - name: Publish Manifest + if: ${{ (github.ref == 'refs/heads/dev' && github.event_name != 'workflow_dispatch') || github.ref == 'refs/heads/master' || github.ref == 'refs/heads/main' }} + uses: VirtoCommerce/vc-github-actions/publish-manifest@master + with: + packageUrl: ${{ steps.artifactUrl.outputs.download_url }} + + - name: Parse Jira Keys from All Commits + uses: VirtoCommerce/vc-github-actions/get-jira-keys@master + if: always() + id: jira_keys + with: + release: ${{ env.RELEASE_STATUS }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Push Build Info to Jira + if: ${{ env.CLOUD_INSTANCE_BASE_URL != 0 && env.CLIENT_ID != 0 && env.CLIENT_SECRET != 0 && steps.jira_keys.outputs.jira-keys != '' && always() }} + id: push_build_info_to_jira + uses: VirtoCommerce/jira-upload-build-info@master + with: + cloud-instance-base-url: '${{ secrets.CLOUD_INSTANCE_BASE_URL }}' + client-id: '${{ secrets.CLIENT_ID }}' + client-secret: '${{ secrets.CLIENT_SECRET }}' + pipeline-id: '${{ github.repository }} ${{ github.workflow }}' + build-number: ${{ github.run_number }} + build-display-name: 'Workflow: ${{ github.workflow }} (#${{ github.run_number }})' + build-state: '${{ env.BUILD_STATE }}' + build-url: '${{github.event.repository.url}}/actions/runs/${{github.run_id}}' + update-sequence-number: '${{ github.run_id }}' + last-updated: '${{github.event.head_commit.timestamp}}' + issue-keys: '${{ steps.jira_keys.outputs.jira-keys }}' + commit-id: '${{ github.sha }}' + repo-url: '${{ github.event.repository.url }}' + build-ref-url: '${{ github.event.repository.url }}/actions/runs/${{ github.run_id }}' + + - name: Confirm Jira Build Output + if: success() + run: | + echo "Jira Upload Build Info response: ${{ steps.push_build_info_to_jira.outputs.response }}" + + module-katalon-tests: + if: ${{ ((github.ref == 'refs/heads/dev') && (github.event_name == 'push') && (needs.ci.outputs.run-e2e == 'true')) || + (github.event_name == 'workflow_dispatch') || (github.base_ref == 'dev') && (github.event_name == 'pull_request') }} + needs: 'ci' + uses: VirtoCommerce/.github/.github/workflows/e2e.yml@v3.800.12 + + with: + katalonRepo: 'VirtoCommerce/vc-quality-gate-katalon' + katalonRepoBranch: 'dev' + testSuite: 'Test Suites/Modules/Platform_collection' + installModules: 'true' + installCustomModule: 'true' + customModuleId: ${{ needs.ci.outputs.moduleId }} + customModuleUrl: ${{ needs.ci.outputs.artifactUrl }} + platformDockerTag: 'dev-linux-latest' + storefrontDockerTag: 'dev-linux-latest' + secrets: + envPAT: ${{ secrets.REPO_TOKEN }} + katalonApiKey: ${{ secrets.KATALON_API_KEY }} + + deploy-cloud: + if: ${{ (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/main' || github.ref == 'refs/heads/dev') && github.event_name == 'push' }} + needs: ci + uses: VirtoCommerce/.github/.github/workflows/deploy-cloud.yml@v3.800.12 + with: + releaseSource: module + moduleId: ${{ needs.ci.outputs.moduleId }} + moduleVer: ${{ needs.ci.outputs.version }} + moduleBlob: ${{ needs.ci.outputs.blobId }} + jiraKeys: ${{ needs.ci.outputs.jira-keys }} + argoServer: 'argo.virtocommerce.cloud' + matrix: '{"include":${{ needs.ci.outputs.matrix }}}' + secrets: inherit diff --git a/.github/workflows/module-release-hotfix.yml b/.github/workflows/module-release-hotfix.yml new file mode 100644 index 0000000..444091c --- /dev/null +++ b/.github/workflows/module-release-hotfix.yml @@ -0,0 +1,82 @@ +# v3.800.12 +# https://virtocommerce.atlassian.net/browse/VCST-2469 +name: Release hotfix + +on: + workflow_dispatch: + inputs: + incrementPatch: + description: 'Increment patch version.' + required: true + default: true + type: boolean + +jobs: + test: + uses: VirtoCommerce/.github/.github/workflows/test-and-sonar.yml@v3.800.12 + secrets: + sonarToken: ${{ secrets.SONAR_TOKEN }} + + build: + uses: VirtoCommerce/.github/.github/workflows/build.yml@v3.800.12 + with: + uploadPackage: 'true' + uploadDocker: 'false' + forceVersionSuffix: 'false' + incrementPatch: ${{ github.event.inputs.incrementPatch }} + secrets: + envPAT: ${{ secrets.REPO_TOKEN }} + + get-metadata: + runs-on: ubuntu-24.04 + env: + GITHUB_TOKEN: ${{ secrets.REPO_TOKEN }} + outputs: + changelog: ${{ steps.changelog.outputs.changelog }} + steps: + + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Get Changelog + id: changelog + uses: VirtoCommerce/vc-github-actions/changelog-generator@master + + publish-github-release: + needs: + [build, test, get-metadata] + uses: VirtoCommerce/.github/.github/workflows/publish-github.yml@v3.800.12 + with: + fullKey: ${{ needs.build.outputs.packageFullKey }} + changeLog: '${{ needs.get-metadata.outputs.changeLog }}' + incrementPatch: ${{ github.event.inputs.incrementPatch }} + makeLatest: 'false' + + secrets: + envPAT: ${{ secrets.GITHUB_TOKEN }} + nugetKey: ${{ secrets.NUGET_KEY }} + + increment-version: + needs: + [publish-github-release] + if: ${{ github.event.inputs.incrementPatch == 'true' }} + runs-on: ubuntu-24.04 + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Install VirtoCommerce.GlobalTool + uses: VirtoCommerce/vc-github-actions/setup-vcbuild@master + + - name: Setup Git Credentials + uses: VirtoCommerce/vc-github-actions/setup-git-credentials-github@master + with: + githubToken: ${{ secrets.REPO_TOKEN }} + + - name: Increment Version + run: | + vc-build IncrementPatch + git add Directory.Build.props *module.manifest + git commit -m "ci: Auto IncrementPatch" + git push diff --git a/.github/workflows/msteams.yml b/.github/workflows/msteams.yml new file mode 100644 index 0000000..953c9fc --- /dev/null +++ b/.github/workflows/msteams.yml @@ -0,0 +1,54 @@ +name: Send message to Teams (regression PR) + +on: + pull_request: + branches: + [regression] + +jobs: + notify: + runs-on: ubuntu-latest + steps: + + - name: Send a message to Microsoft Teams + uses: VirtoCommerce/vc-github-actions/msteams-send-message@master + with: + body: '{ + "@type": "MessageCard", + "@context": "http://schema.org/extensions", + "themeColor": "0076D7", + "summary": "On ${{github.repository}} repository", + "sections": [ + { + "activityTitle": "Regression PR created/updated", + "activitySubtitle": "By [${{ github.event.pull_request.user.login }}](${{ github.event.pull_request.user.url }}) on **[${{github.repository}}](${{github.server_url}}/${{github.repository}})** repository", + "activityImage":"${{ github.event.pull_request.user.avatar_url }}", + "facts": [ + { + "name": "Repository", + "value": "[${{github.repository}}](${{github.server_url}}/${{github.repository}})" + }, + { + "name": "Pull request", + "value": "[${{ github.event.pull_request.number }}](${{ github.event.pull_request._links.html.href }})" + }, + { + "name": "Pull request title", + "value": "${{ github.event.pull_request.title }}" + } + + ], + "markdown": true + } + ], + "potentialAction": [ { + "@type": "OpenUri", + "name": "View Pull Request", + "targets": [{ + "os": "default", + "uri": "${{ github.event.pull_request._links.html.href }}" + }] + }] + +}' # the body of the message + webhook_uri: ${{ secrets.PLATFORM_TEAMS_URI }} diff --git a/.github/workflows/publish-nugets.yml b/.github/workflows/publish-nugets.yml new file mode 100644 index 0000000..f07933d --- /dev/null +++ b/.github/workflows/publish-nugets.yml @@ -0,0 +1,38 @@ +# v3.800.12 +# https://virtocommerce.atlassian.net/browse/VCST-2469 +name: Publish nuget + +on: + workflow_dispatch: + inputs: + publishAlpha: + description: 'Publish nuget as alpha version.' + required: true + default: true + type: boolean + +jobs: + test: + uses: VirtoCommerce/.github/.github/workflows/test-and-sonar.yml@v3.800.12 + secrets: + sonarToken: ${{ secrets.SONAR_TOKEN }} + + build: + uses: VirtoCommerce/.github/.github/workflows/build.yml@v3.800.12 + with: + uploadPackage: 'true' + uploadDocker: 'false' + forceVersionSuffix: ${{ github.event.inputs.publishAlpha }} + secrets: + envPAT: ${{ secrets.REPO_TOKEN }} + + publish-nuget: + needs: + [build, test] + uses: VirtoCommerce/.github/.github/workflows/publish-github.yml@v3.800.12 + with: + fullKey: ${{ needs.build.outputs.packageFullKey }} + forceGithub: false + secrets: + envPAT: ${{ secrets.GITHUB_TOKEN }} + nugetKey: ${{ secrets.NUGET_KEY }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..19c5caf --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,12 @@ +# v3.800.12 +# https://virtocommerce.atlassian.net/browse/VCST-2469 +name: Release + +on: + workflow_dispatch: + +jobs: + release: + uses: VirtoCommerce/.github/.github/workflows/release.yml@v3.800.12 + secrets: + envPAT: ${{ secrets.REPO_TOKEN }} \ No newline at end of file From 269740102be75ca62b9d40dde0be170812ca55ec Mon Sep 17 00:00:00 2001 From: Basil Kotov Date: Tue, 14 Oct 2025 13:45:51 +0100 Subject: [PATCH 04/29] update dependencies in manifest --- src/VirtoCommerce.Datatrans.Web/module.manifest | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/VirtoCommerce.Datatrans.Web/module.manifest b/src/VirtoCommerce.Datatrans.Web/module.manifest index de9d24a..8df26fd 100644 --- a/src/VirtoCommerce.Datatrans.Web/module.manifest +++ b/src/VirtoCommerce.Datatrans.Web/module.manifest @@ -6,7 +6,9 @@ 3.904.0 - + + + VirtoCommerce Datatrans From 2f3d0a7a9c81c0361b010e6b7bb7c28ad6cff49a Mon Sep 17 00:00:00 2001 From: Basil Kotov Date: Tue, 14 Oct 2025 14:24:58 +0100 Subject: [PATCH 05/29] fix manifest --- src/VirtoCommerce.Datatrans.Web/module.manifest | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/VirtoCommerce.Datatrans.Web/module.manifest b/src/VirtoCommerce.Datatrans.Web/module.manifest index 8df26fd..ac4b0f9 100644 --- a/src/VirtoCommerce.Datatrans.Web/module.manifest +++ b/src/VirtoCommerce.Datatrans.Web/module.manifest @@ -6,9 +6,9 @@ 3.904.0 - - - + + + VirtoCommerce Datatrans From 5313cd87da7f90717bf82084de9862c44f55342f Mon Sep 17 00:00:00 2001 From: Basil Kotov Date: Tue, 14 Oct 2025 14:29:36 +0100 Subject: [PATCH 06/29] remove unused files --- .../package-lock.json | 1985 ----------------- src/VirtoCommerce.Datatrans.Web/package.json | 20 - .../webpack.config.js | 51 - 3 files changed, 2056 deletions(-) delete mode 100644 src/VirtoCommerce.Datatrans.Web/package-lock.json delete mode 100644 src/VirtoCommerce.Datatrans.Web/package.json delete mode 100644 src/VirtoCommerce.Datatrans.Web/webpack.config.js diff --git a/src/VirtoCommerce.Datatrans.Web/package-lock.json b/src/VirtoCommerce.Datatrans.Web/package-lock.json deleted file mode 100644 index 76b90d2..0000000 --- a/src/VirtoCommerce.Datatrans.Web/package-lock.json +++ /dev/null @@ -1,1985 +0,0 @@ -{ - "name": "vc-module", - "version": "1.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "vc-module", - "version": "1.0.0", - "devDependencies": { - "clean-webpack-plugin": "^4.0.0", - "css-loader": "^6.5.1", - "mini-css-extract-plugin": "^2.5.1", - "webpack": "^5.68.0", - "webpack-cli": "^4.9.2" - } - }, - "node_modules/@discoveryjs/json-ext": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", - "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", - "dev": true, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", - "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", - "dev": true, - "dependencies": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/source-map": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", - "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", - "dev": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", - "dev": true - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.17", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", - "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", - "dev": true, - "dependencies": { - "@jridgewell/resolve-uri": "3.1.0", - "@jridgewell/sourcemap-codec": "1.4.14" - } - }, - "node_modules/@types/eslint": { - "version": "8.21.1", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.21.1.tgz", - "integrity": "sha512-rc9K8ZpVjNcLs8Fp0dkozd5Pt2Apk1glO4Vgz8ix1u6yFByxfqo5Yavpy65o+93TAe24jr7v+eSBtFLvOQtCRQ==", - "dev": true, - "dependencies": { - "@types/estree": "*", - "@types/json-schema": "*" - } - }, - "node_modules/@types/eslint-scope": { - "version": "3.7.4", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.4.tgz", - "integrity": "sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==", - "dev": true, - "dependencies": { - "@types/eslint": "*", - "@types/estree": "*" - } - }, - "node_modules/@types/estree": { - "version": "0.0.51", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", - "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==", - "dev": true - }, - "node_modules/@types/glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==", - "dev": true, - "dependencies": { - "@types/minimatch": "*", - "@types/node": "*" - } - }, - "node_modules/@types/json-schema": { - "version": "7.0.11", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", - "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", - "dev": true - }, - "node_modules/@types/minimatch": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", - "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==", - "dev": true - }, - "node_modules/@types/node": { - "version": "18.14.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.14.0.tgz", - "integrity": "sha512-5EWrvLmglK+imbCJY0+INViFWUHg1AHel1sq4ZVSfdcNqGy9Edv3UB9IIzzg+xPaUcAgZYcfVs2fBcwDeZzU0A==", - "dev": true - }, - "node_modules/@webassemblyjs/ast": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", - "integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==", - "dev": true, - "dependencies": { - "@webassemblyjs/helper-numbers": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1" - } - }, - "node_modules/@webassemblyjs/floating-point-hex-parser": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz", - "integrity": "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==", - "dev": true - }, - "node_modules/@webassemblyjs/helper-api-error": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz", - "integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==", - "dev": true - }, - "node_modules/@webassemblyjs/helper-buffer": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz", - "integrity": "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==", - "dev": true - }, - "node_modules/@webassemblyjs/helper-numbers": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz", - "integrity": "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==", - "dev": true, - "dependencies": { - "@webassemblyjs/floating-point-hex-parser": "1.11.1", - "@webassemblyjs/helper-api-error": "1.11.1", - "@xtuc/long": "4.2.2" - } - }, - "node_modules/@webassemblyjs/helper-wasm-bytecode": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz", - "integrity": "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==", - "dev": true - }, - "node_modules/@webassemblyjs/helper-wasm-section": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz", - "integrity": "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==", - "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1" - } - }, - "node_modules/@webassemblyjs/ieee754": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz", - "integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==", - "dev": true, - "dependencies": { - "@xtuc/ieee754": "^1.2.0" - } - }, - "node_modules/@webassemblyjs/leb128": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz", - "integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==", - "dev": true, - "dependencies": { - "@xtuc/long": "4.2.2" - } - }, - "node_modules/@webassemblyjs/utf8": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz", - "integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==", - "dev": true - }, - "node_modules/@webassemblyjs/wasm-edit": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz", - "integrity": "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==", - "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/helper-wasm-section": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1", - "@webassemblyjs/wasm-opt": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1", - "@webassemblyjs/wast-printer": "1.11.1" - } - }, - "node_modules/@webassemblyjs/wasm-gen": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz", - "integrity": "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==", - "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/ieee754": "1.11.1", - "@webassemblyjs/leb128": "1.11.1", - "@webassemblyjs/utf8": "1.11.1" - } - }, - "node_modules/@webassemblyjs/wasm-opt": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz", - "integrity": "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==", - "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1" - } - }, - "node_modules/@webassemblyjs/wasm-parser": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz", - "integrity": "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==", - "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-api-error": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/ieee754": "1.11.1", - "@webassemblyjs/leb128": "1.11.1", - "@webassemblyjs/utf8": "1.11.1" - } - }, - "node_modules/@webassemblyjs/wast-printer": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz", - "integrity": "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==", - "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@xtuc/long": "4.2.2" - } - }, - "node_modules/@webpack-cli/configtest": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.2.0.tgz", - "integrity": "sha512-4FB8Tj6xyVkyqjj1OaTqCjXYULB9FMkqQ8yGrZjRDrYh0nOE+7Lhs45WioWQQMV+ceFlE368Ukhe6xdvJM9Egg==", - "dev": true, - "peerDependencies": { - "webpack": "4.x.x || 5.x.x", - "webpack-cli": "4.x.x" - } - }, - "node_modules/@webpack-cli/info": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.5.0.tgz", - "integrity": "sha512-e8tSXZpw2hPl2uMJY6fsMswaok5FdlGNRTktvFk2sD8RjH0hE2+XistawJx1vmKteh4NmGmNUrp+Tb2w+udPcQ==", - "dev": true, - "dependencies": { - "envinfo": "^7.7.3" - }, - "peerDependencies": { - "webpack-cli": "4.x.x" - } - }, - "node_modules/@webpack-cli/serve": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.7.0.tgz", - "integrity": "sha512-oxnCNGj88fL+xzV+dacXs44HcDwf1ovs3AuEzvP7mqXw7fQntqIhQ1BRmynh4qEKQSSSRSWVyXRjmTbZIX9V2Q==", - "dev": true, - "peerDependencies": { - "webpack-cli": "4.x.x" - }, - "peerDependenciesMeta": { - "webpack-dev-server": { - "optional": true - } - } - }, - "node_modules/@xtuc/ieee754": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", - "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", - "dev": true - }, - "node_modules/@xtuc/long": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", - "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", - "dev": true - }, - "node_modules/acorn": { - "version": "8.8.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", - "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-import-assertions": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", - "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==", - "dev": true, - "peerDependencies": { - "acorn": "^8" - } - }, - "node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ajv-formats": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", - "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", - "dev": true, - "dependencies": { - "ajv": "^8.0.0" - }, - "peerDependencies": { - "ajv": "^8.0.0" - }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } - } - }, - "node_modules/ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.3" - }, - "peerDependencies": { - "ajv": "^8.8.2" - } - }, - "node_modules/array-union": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", - "integrity": "sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng==", - "dev": true, - "dependencies": { - "array-uniq": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/array-uniq": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", - "integrity": "sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/browserslist": { - "version": "4.21.5", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz", - "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - } - ], - "dependencies": { - "caniuse-lite": "^1.0.30001449", - "electron-to-chromium": "^1.4.284", - "node-releases": "^2.0.8", - "update-browserslist-db": "^1.0.10" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001457", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001457.tgz", - "integrity": "sha512-SDIV6bgE1aVbK6XyxdURbUE89zY7+k1BBBaOwYwkNCglXlel/E7mELiHC64HQ+W0xSKlqWhV9Wh7iHxUjMs4fA==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - } - ] - }, - "node_modules/chrome-trace-event": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.2.tgz", - "integrity": "sha512-9e/zx1jw7B4CO+c/RXoCsfg/x1AfUBioy4owYH0bJprEYAx5hRFLRhWBqHAG57D0ZM4H7vxbP7bPe0VwhQRYDQ==", - "dev": true, - "dependencies": { - "tslib": "^1.9.0" - }, - "engines": { - "node": ">=6.0" - } - }, - "node_modules/clean-webpack-plugin": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/clean-webpack-plugin/-/clean-webpack-plugin-4.0.0.tgz", - "integrity": "sha512-WuWE1nyTNAyW5T7oNyys2EN0cfP2fdRxhxnIQWiAp0bMabPdHhoGxM8A6YL2GhqwgrPnnaemVE7nv5XJ2Fhh2w==", - "dev": true, - "dependencies": { - "del": "^4.1.1" - }, - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "webpack": ">=4.0.0 <6.0.0" - } - }, - "node_modules/clone-deep": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", - "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", - "dev": true, - "dependencies": { - "is-plain-object": "^2.0.4", - "kind-of": "^6.0.2", - "shallow-clone": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/colorette": { - "version": "2.0.19", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz", - "integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==", - "dev": true - }, - "node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true - }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/css-loader": { - "version": "6.7.3", - "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.7.3.tgz", - "integrity": "sha512-qhOH1KlBMnZP8FzRO6YCH9UHXQhVMcEGLyNdb7Hv2cpcmJbW0YrddO+tG1ab5nT41KpHIYGsbeHqxB9xPu1pKQ==", - "dev": true, - "dependencies": { - "icss-utils": "^5.1.0", - "postcss": "^8.4.19", - "postcss-modules-extract-imports": "^3.0.0", - "postcss-modules-local-by-default": "^4.0.0", - "postcss-modules-scope": "^3.0.0", - "postcss-modules-values": "^4.0.0", - "postcss-value-parser": "^4.2.0", - "semver": "^7.3.8" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.0.0" - } - }, - "node_modules/cssesc": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", - "dev": true, - "bin": { - "cssesc": "bin/cssesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/del": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/del/-/del-4.1.1.tgz", - "integrity": "sha512-QwGuEUouP2kVwQenAsOof5Fv8K9t3D8Ca8NxcXKrIpEHjTXK5J2nXLdP+ALI1cgv8wj7KuwBhTwBkOZSJKM5XQ==", - "dev": true, - "dependencies": { - "@types/glob": "^7.1.1", - "globby": "^6.1.0", - "is-path-cwd": "^2.0.0", - "is-path-in-cwd": "^2.0.0", - "p-map": "^2.0.0", - "pify": "^4.0.1", - "rimraf": "^2.6.3" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/electron-to-chromium": { - "version": "1.4.305", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.305.tgz", - "integrity": "sha512-WETy6tG0CT5gm1O+xCbyapWNsCcmIvrn4NHViIGYo2AT8FV2qUCXdaB+WqYxSv/vS5mFqhBYnfZAAkVArjBmUg==", - "dev": true - }, - "node_modules/enhanced-resolve": { - "version": "5.12.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.12.0.tgz", - "integrity": "sha512-QHTXI/sZQmko1cbDoNAa3mJ5qhWUUNAq3vR0/YiD379fWQrcfuoX1+HW2S0MTt7XmoPLapdaDKUtelUSPic7hQ==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/envinfo": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz", - "integrity": "sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==", - "dev": true, - "bin": { - "envinfo": "dist/cli.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/es-module-lexer": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", - "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==", - "dev": true - }, - "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esrecurse/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/events": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", - "dev": true, - "engines": { - "node": ">=0.8.x" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "node_modules/fastest-levenshtein": { - "version": "1.0.16", - "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", - "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", - "dev": true, - "engines": { - "node": ">= 4.9.1" - } - }, - "node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true - }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-to-regexp": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", - "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", - "dev": true - }, - "node_modules/globby": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", - "integrity": "sha512-KVbFv2TQtbzCoxAnfD6JcHZTYCzyliEaaeM/gH8qQdkKr5s0OP9scEgvdcngyk7AVdY6YVW/TJHd+lQ/Df3Daw==", - "dev": true, - "dependencies": { - "array-union": "^1.0.1", - "glob": "^7.0.3", - "object-assign": "^4.0.1", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/globby/node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", - "dev": true - }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/icss-utils": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", - "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", - "dev": true, - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/import-local": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", - "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", - "dev": true, - "dependencies": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" - }, - "bin": { - "import-local-fixture": "fixtures/cli.js" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "node_modules/interpret": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz", - "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==", - "dev": true, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/is-core-module": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", - "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", - "dev": true, - "dependencies": { - "has": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-path-cwd": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", - "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/is-path-in-cwd": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-2.1.0.tgz", - "integrity": "sha512-rNocXHgipO+rvnP6dk3zI20RpOtrAM/kzbB258Uw5BWr3TpXi861yzjo16Dn4hUox07iw5AyeMLHWsujkjzvRQ==", - "dev": true, - "dependencies": { - "is-path-inside": "^2.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/is-path-inside": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-2.1.0.tgz", - "integrity": "sha512-wiyhTzfDWsvwAW53OBWF5zuvaOGlZ6PwYxAbPVDhpm+gM09xKQGjBq/8uYN12aDvMxnAnq3dxTyoSoRNmg5YFg==", - "dev": true, - "dependencies": { - "path-is-inside": "^1.0.2" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true - }, - "node_modules/isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/jest-worker": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", - "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", - "dev": true, - "dependencies": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": ">= 10.13.0" - } - }, - "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true - }, - "node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, - "node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/loader-runner": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", - "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", - "dev": true, - "engines": { - "node": ">=6.11.5" - } - }, - "node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mini-css-extract-plugin": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.7.2.tgz", - "integrity": "sha512-EdlUizq13o0Pd+uCp+WO/JpkLvHRVGt97RqfeGhXqAcorYo1ypJSpkV+WDT0vY/kmh/p7wRdJNJtuyK540PXDw==", - "dev": true, - "dependencies": { - "schema-utils": "^4.0.0" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.0.0" - } - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/nanoid": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", - "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", - "dev": true, - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/neo-async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "dev": true - }, - "node_modules/node-releases": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz", - "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==", - "dev": true - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/p-map": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", - "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-is-inside": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", - "integrity": "sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==", - "dev": true - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true - }, - "node_modules/pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/pinkie": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/pinkie-promise": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==", - "dev": true, - "dependencies": { - "pinkie": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "dependencies": { - "find-up": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/postcss": { - "version": "8.4.21", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.21.tgz", - "integrity": "sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - } - ], - "dependencies": { - "nanoid": "^3.3.4", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/postcss-modules-extract-imports": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", - "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==", - "dev": true, - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/postcss-modules-local-by-default": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz", - "integrity": "sha512-sT7ihtmGSF9yhm6ggikHdV0hlziDTX7oFoXtuVWeDd3hHObNkcHRo9V3yg7vCAY7cONyxJC/XXCmmiHHcvX7bQ==", - "dev": true, - "dependencies": { - "icss-utils": "^5.0.0", - "postcss-selector-parser": "^6.0.2", - "postcss-value-parser": "^4.1.0" - }, - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/postcss-modules-scope": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz", - "integrity": "sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==", - "dev": true, - "dependencies": { - "postcss-selector-parser": "^6.0.4" - }, - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/postcss-modules-values": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", - "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", - "dev": true, - "dependencies": { - "icss-utils": "^5.0.0" - }, - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/postcss-selector-parser": { - "version": "6.0.11", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.11.tgz", - "integrity": "sha512-zbARubNdogI9j7WY4nQJBiNqQf3sLS3wCP4WfOidu+p28LofJqDH1tcXypGrcmMHhDk2t9wGhCsYe/+szLTy1g==", - "dev": true, - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-value-parser": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", - "dev": true - }, - "node_modules/punycode": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", - "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, - "node_modules/rechoir": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.1.tgz", - "integrity": "sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg==", - "dev": true, - "dependencies": { - "resolve": "^1.9.0" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/resolve": { - "version": "1.22.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", - "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", - "dev": true, - "dependencies": { - "is-core-module": "^2.9.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-cwd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", - "dev": true, - "dependencies": { - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/schema-utils": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", - "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.8.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.0.0" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/serialize-javascript": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz", - "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==", - "dev": true, - "dependencies": { - "randombytes": "^2.1.0" - } - }, - "node_modules/shallow-clone": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", - "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "dev": true, - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/tapable": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", - "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/terser": { - "version": "5.16.4", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.16.4.tgz", - "integrity": "sha512-5yEGuZ3DZradbogeYQ1NaGz7rXVBDWujWlx1PT8efXO6Txn+eWbfKqB2bTDVmFXmePFkoLU6XI8UektMIEA0ug==", - "dev": true, - "dependencies": { - "@jridgewell/source-map": "^0.3.2", - "acorn": "^8.5.0", - "commander": "^2.20.0", - "source-map-support": "~0.5.20" - }, - "bin": { - "terser": "bin/terser" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/terser-webpack-plugin": { - "version": "5.3.6", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.6.tgz", - "integrity": "sha512-kfLFk+PoLUQIbLmB1+PZDMRSZS99Mp+/MHqDNmMA6tOItzRt+Npe3E+fsMs5mfcM0wCtrrdU387UnV+vnSffXQ==", - "dev": true, - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.14", - "jest-worker": "^27.4.5", - "schema-utils": "^3.1.1", - "serialize-javascript": "^6.0.0", - "terser": "^5.14.1" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.1.0" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "esbuild": { - "optional": true - }, - "uglify-js": { - "optional": true - } - } - }, - "node_modules/terser-webpack-plugin/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/terser-webpack-plugin/node_modules/ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true, - "peerDependencies": { - "ajv": "^6.9.1" - } - }, - "node_modules/terser-webpack-plugin/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/terser-webpack-plugin/node_modules/schema-utils": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", - "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/tslib": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", - "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==", - "dev": true - }, - "node_modules/update-browserslist-db": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", - "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - } - ], - "dependencies": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" - }, - "bin": { - "browserslist-lint": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true - }, - "node_modules/watchpack": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", - "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", - "dev": true, - "dependencies": { - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.1.2" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/webpack": { - "version": "5.75.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.75.0.tgz", - "integrity": "sha512-piaIaoVJlqMsPtX/+3KTTO6jfvrSYgauFVdt8cr9LTHKmcq/AMd4mhzsiP7ZF/PGRNPGA8336jldh9l2Kt2ogQ==", - "dev": true, - "dependencies": { - "@types/eslint-scope": "^3.7.3", - "@types/estree": "^0.0.51", - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/wasm-edit": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1", - "acorn": "^8.7.1", - "acorn-import-assertions": "^1.7.6", - "browserslist": "^4.14.5", - "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.10.0", - "es-module-lexer": "^0.9.0", - "eslint-scope": "5.1.1", - "events": "^3.2.0", - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.2.9", - "json-parse-even-better-errors": "^2.3.1", - "loader-runner": "^4.2.0", - "mime-types": "^2.1.27", - "neo-async": "^2.6.2", - "schema-utils": "^3.1.0", - "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.1.3", - "watchpack": "^2.4.0", - "webpack-sources": "^3.2.3" - }, - "bin": { - "webpack": "bin/webpack.js" - }, - "engines": { - "node": ">=10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependenciesMeta": { - "webpack-cli": { - "optional": true - } - } - }, - "node_modules/webpack-cli": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.10.0.tgz", - "integrity": "sha512-NLhDfH/h4O6UOy+0LSso42xvYypClINuMNBVVzX4vX98TmTaTUxwRbXdhucbFMd2qLaCTcLq/PdYrvi8onw90w==", - "dev": true, - "dependencies": { - "@discoveryjs/json-ext": "^0.5.0", - "@webpack-cli/configtest": "^1.2.0", - "@webpack-cli/info": "^1.5.0", - "@webpack-cli/serve": "^1.7.0", - "colorette": "^2.0.14", - "commander": "^7.0.0", - "cross-spawn": "^7.0.3", - "fastest-levenshtein": "^1.0.12", - "import-local": "^3.0.2", - "interpret": "^2.2.0", - "rechoir": "^0.7.0", - "webpack-merge": "^5.7.3" - }, - "bin": { - "webpack-cli": "bin/cli.js" - }, - "engines": { - "node": ">=10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "4.x.x || 5.x.x" - }, - "peerDependenciesMeta": { - "@webpack-cli/generators": { - "optional": true - }, - "@webpack-cli/migrate": { - "optional": true - }, - "webpack-bundle-analyzer": { - "optional": true - }, - "webpack-dev-server": { - "optional": true - } - } - }, - "node_modules/webpack-cli/node_modules/commander": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", - "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", - "dev": true, - "engines": { - "node": ">= 10" - } - }, - "node_modules/webpack-merge": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.8.0.tgz", - "integrity": "sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q==", - "dev": true, - "dependencies": { - "clone-deep": "^4.0.1", - "wildcard": "^2.0.0" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/webpack-sources": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", - "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", - "dev": true, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/webpack/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/webpack/node_modules/ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true, - "peerDependencies": { - "ajv": "^6.9.1" - } - }, - "node_modules/webpack/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/webpack/node_modules/schema-utils": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", - "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/wildcard": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz", - "integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==", - "dev": true - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true - }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - } - } -} diff --git a/src/VirtoCommerce.Datatrans.Web/package.json b/src/VirtoCommerce.Datatrans.Web/package.json deleted file mode 100644 index 20684a4..0000000 --- a/src/VirtoCommerce.Datatrans.Web/package.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "version": "1.0.0", - "name": "vc-module", - "private": true, - "scripts": { - "webpack:dev": "webpack --mode=development", - "webpack:watch": "webpack --watch --mode=development", - "webpack:build": "webpack --mode=production" - }, - "devDependencies": { - "clean-webpack-plugin": "^4.0.0", - "css-loader": "^6.5.1", - "mini-css-extract-plugin": "^2.5.1", - "webpack": "^5.68.0", - "webpack-cli": "^4.10.0" - }, - "webpack": { - "stats": "verbose" - } -} diff --git a/src/VirtoCommerce.Datatrans.Web/webpack.config.js b/src/VirtoCommerce.Datatrans.Web/webpack.config.js deleted file mode 100644 index 8322c67..0000000 --- a/src/VirtoCommerce.Datatrans.Web/webpack.config.js +++ /dev/null @@ -1,51 +0,0 @@ -const namespace = 'VirtoCommerce.Datatrans' - -const glob = require('glob'); -const path = require('path'); -const webpack = require('webpack'); -const MiniCssExtractPlugin = require('mini-css-extract-plugin'); -const { CleanWebpackPlugin } = require('clean-webpack-plugin'); - -const rootPath = path.resolve(__dirname, 'dist'); - -function getEntryPoints() { - return [ - ...glob.sync('./Scripts/**/*.js', { nosort: true }), - ...glob.sync('./Content/**/*.css', { nosort: true }), - ]; -} - -module.exports = (env, argv) => { - const isProduction = argv.mode === 'production'; - - return { - entry: getEntryPoints(), - devtool: false, - output: { - path: rootPath, - filename: 'app.js', - }, - module: { - rules: [ - { - test: /\.css$/, - use: [MiniCssExtractPlugin.loader, 'css-loader'], - } - ] - }, - plugins: [ - new CleanWebpackPlugin(), - isProduction ? - new webpack.SourceMapDevToolPlugin({ - namespace: namespace, - filename: '[file].map[query]' - }) : - new webpack.SourceMapDevToolPlugin({ - namespace: namespace - }), - new MiniCssExtractPlugin({ - filename: 'style.css', - }), - ], - }; -}; From c751b592901364fb070f9ff0021031e7d67e6dbf Mon Sep 17 00:00:00 2001 From: Basil Kotov Date: Tue, 14 Oct 2025 16:01:12 +0100 Subject: [PATCH 07/29] remove unused controllers --- .../Controllers/DatatransController.cs | 83 ------------------- .../Controllers/TestController.cs | 30 ------- src/VirtoCommerce.Datatrans.Web/Module.cs | 1 - 3 files changed, 114 deletions(-) delete mode 100644 src/VirtoCommerce.Datatrans.Web/Controllers/DatatransController.cs delete mode 100644 src/VirtoCommerce.Datatrans.Web/Controllers/TestController.cs diff --git a/src/VirtoCommerce.Datatrans.Web/Controllers/DatatransController.cs b/src/VirtoCommerce.Datatrans.Web/Controllers/DatatransController.cs deleted file mode 100644 index 4ff28ad..0000000 --- a/src/VirtoCommerce.Datatrans.Web/Controllers/DatatransController.cs +++ /dev/null @@ -1,83 +0,0 @@ -using System; -using System.Collections.Specialized; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Mvc; -using VirtoCommerce.Datatrans.Data.Providers; -using VirtoCommerce.OrdersModule.Core.Services; -using VirtoCommerce.PaymentModule.Core.Services; -using VirtoCommerce.PaymentModule.Model.Requests; -using VirtoCommerce.Platform.Core.Common; - -namespace VirtoCommerce.Datatrans.Web.Controllers; - -[Route("api/payments/datatrans")] -public class DatatransController(IPaymentMethodsService paymentMethods, - IPaymentService payments) : Controller -{ - [HttpPost("push")] - public async Task Push(CancellationToken cancellationToken = default) - { - // Datatrans шлёт form-urlencoded - var form = Request.HasFormContentType - ? Request.Form - : throw new InvalidOperationException("Expected form data"); - - var query = new NameValueCollection(); - foreach (var kvp in form) - { - query[kvp.Key] = kvp.Value; - } - - return await HandleCallback(query, cancellationToken); - } - - private async Task HandleCallback(NameValueCollection query, CancellationToken cancellationToken = default) - { - var method = await paymentMethods.GetByIdAsync(nameof(DatatransPaymentMethod)); - if (method == null) - { - return NotFound("Datatrans payment method not found"); - } - - var datatrans = method as DatatransPaymentMethod; - if (datatrans == null) - { - return BadRequest("Payment method type mismatch"); - } - - var validate = datatrans.ValidatePostProcessRequest(query); - if (!validate.IsSuccess) - { - return BadRequest("Invalid Datatrans callback"); - } - - var transactionId = validate.OuterId; - if (string.IsNullOrEmpty(transactionId)) - { - return BadRequest("TransactionId not found"); - } - - var payment = await payments.GetByOuterIdAsync(transactionId); - if (payment == null) - { - return NotFound($"Payment with transactionId={transactionId} not found"); - } - - var postReq = new PostProcessPaymentRequest - { - Payment = payment, - OuterId = transactionId, - Parameters = query - }; - - var result = datatrans.PostProcessPayment(postReq); - - if (result.IsSuccess) - { - await payments.SaveChangesAsync([payment]); - } - - return Ok(); - } -} diff --git a/src/VirtoCommerce.Datatrans.Web/Controllers/TestController.cs b/src/VirtoCommerce.Datatrans.Web/Controllers/TestController.cs deleted file mode 100644 index 95172d7..0000000 --- a/src/VirtoCommerce.Datatrans.Web/Controllers/TestController.cs +++ /dev/null @@ -1,30 +0,0 @@ -using Microsoft.AspNetCore.Mvc; -using VirtoCommerce.Datatrans.Data.Providers; -using VirtoCommerce.OrdersModule.Core.Model; -using VirtoCommerce.PaymentModule.Model.Requests; -using VirtoCommerce.StoreModule.Core.Model; - -namespace VirtoCommerce.Datatrans.Web.Controllers; - -[Route("api/datatrans")] -public class TestController(DatatransPaymentMethod paymentMethod) : Controller -{ - [HttpGet] - [Route("test")] - public IActionResult Test() - { - var processPaymentRequest = new ProcessPaymentRequest - { - OrderId = "order-id", - Order = new CustomerOrder(), - PaymentId = "payment-id", - Payment = new PaymentIn(), - StoreId = "store-id", - Store = new Store() - }; - - var processPaymentResult = paymentMethod.ProcessPayment(processPaymentRequest); - - return Ok(processPaymentResult); - } -} diff --git a/src/VirtoCommerce.Datatrans.Web/Module.cs b/src/VirtoCommerce.Datatrans.Web/Module.cs index 1949a03..229305a 100644 --- a/src/VirtoCommerce.Datatrans.Web/Module.cs +++ b/src/VirtoCommerce.Datatrans.Web/Module.cs @@ -26,7 +26,6 @@ public void Initialize(IServiceCollection serviceCollection) serviceCollection.AddOptions().Bind(Configuration.GetSection("Payments:Datatrans")).ValidateDataAnnotations(); serviceCollection.AddTransient(); - serviceCollection.AddTransient(); serviceCollection.AddHttpClient("Datatrans", (sp, http) => From d8a4eba02756b4865ca93692be1ee6ae43bda72c Mon Sep 17 00:00:00 2001 From: Basil Kotov Date: Tue, 14 Oct 2025 16:15:49 +0100 Subject: [PATCH 08/29] fix minor amount calculation --- .../Providers/DatatransPaymentMethod.cs | 36 +++++++++++-------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/src/VirtoCommerce.Datatrans.Data/Providers/DatatransPaymentMethod.cs b/src/VirtoCommerce.Datatrans.Data/Providers/DatatransPaymentMethod.cs index fd60f8c..634b94b 100644 --- a/src/VirtoCommerce.Datatrans.Data/Providers/DatatransPaymentMethod.cs +++ b/src/VirtoCommerce.Datatrans.Data/Providers/DatatransPaymentMethod.cs @@ -5,6 +5,7 @@ using System.Threading; using System.Threading.Tasks; using Newtonsoft.Json; +using VirtoCommerce.CoreModule.Core.Currency; using VirtoCommerce.Datatrans.Core.Models; using VirtoCommerce.Datatrans.Core.Services; using VirtoCommerce.OrdersModule.Core.Model; @@ -15,7 +16,7 @@ namespace VirtoCommerce.Datatrans.Data.Providers; -public class DatatransPaymentMethod(IDatatransClient datatransClient) : PaymentMethod(nameof(DatatransPaymentMethod)), ISupportCaptureFlow, ISupportRefundFlow +public class DatatransPaymentMethod(IDatatransClient datatransClient, ICurrencyService currencyService) : PaymentMethod(nameof(DatatransPaymentMethod)), ISupportCaptureFlow, ISupportRefundFlow { public override PaymentMethodType PaymentMethodType => PaymentMethodType.Standard; public override PaymentMethodGroupType PaymentMethodGroupType => PaymentMethodGroupType.BankCard; @@ -66,7 +67,7 @@ protected virtual async Task ProcessPaymentAsync(Pr { var payment = (PaymentIn)request.Payment; - var initRequest = CreateInitRequest(request); + var initRequest = await CreateInitRequest(request); var initResponse = await datatransClient.InitTransactionAsync(initRequest); var ok = initResponse.Error is null && !string.IsNullOrEmpty(initResponse.TransactionId); @@ -75,7 +76,7 @@ protected virtual async Task ProcessPaymentAsync(Pr payment.PaymentStatus = ok ? PaymentStatus.Pending : PaymentStatus.Voided; payment.Status = payment.PaymentStatus.ToString(); - return CreateInitRequestResult(initResponse, request); + return await CreateInitRequestResult(initResponse, request); } protected virtual async Task PostProcessPaymentAsync(PostProcessPaymentRequest request, CancellationToken cancellationToken = default) @@ -99,7 +100,7 @@ protected virtual async Task PostProcessPayment if (transaction.Status is "authenticated") { transaction.Refno = Guid.NewGuid().ToString().Replace("-", "").ToLower(); - var authReq = CreateAuthorizeRequest(request, transaction); + var authReq = await CreateAuthorizeRequest(request, transaction); var authResp = await datatransClient.AuthorizeAuthenticatedAsync(transactionId, authReq, cancellationToken); transaction = await datatransClient.GetTransactionAsync(transactionId, cancellationToken); @@ -173,7 +174,7 @@ protected virtual async Task CaptureProcessPaymentA } var transaction = await datatransClient.GetTransactionAsync(transactionId); - var amountMinor = ToMinorUnits(amountToCapture); + var amountMinor = await ToMinorUnits(payment.Currency, amountToCapture); var captureRequest = new DatatransCaptureRequest { @@ -210,7 +211,6 @@ protected virtual async Task CaptureProcessPaymentA protected virtual async Task RefundProcessPaymentAsync(RefundPaymentRequest context) { var payment = (PaymentIn)context.Payment; - var order = (CustomerOrder)context.Order; var transactionId = GetTransactionId(context); if (!payment.CapturedDate.HasValue) @@ -243,7 +243,7 @@ protected virtual async Task RefundProcessPaymentAsy } var transaction = await datatransClient.GetTransactionAsync(transactionId); - var amountMinor = ToMinorUnits(amountToRefund); + var amountMinor = await ToMinorUnits(payment.Currency, amountToRefund); var request = new DatatransRefundRequest { @@ -274,7 +274,7 @@ protected virtual async Task RefundProcessPaymentAsy #region extension points - protected virtual DatatransInitRequest CreateInitRequest(ProcessPaymentRequest request) + protected virtual async Task CreateInitRequest(ProcessPaymentRequest request) { var payment = (PaymentIn)request.Payment; var order = (CustomerOrder)request.Order; @@ -283,17 +283,17 @@ protected virtual DatatransInitRequest CreateInitRequest(ProcessPaymentRequest r var url = (store.SecureUrl.IsNullOrEmpty() ? store.Url : store.SecureUrl)?.TrimEnd('/'); var result = AbstractTypeFactory.TryCreateInstance(); - result.Amount = ToMinorUnits(payment.Sum); + result.Amount = await ToMinorUnits(payment.Currency, payment.Sum); result.Currency = payment.Currency ?? order.Currency; result.ReturnUrl = $"{url}/account/orders/{order.Id}/payment"; return result; } - protected virtual ProcessPaymentRequestResult CreateInitRequestResult(DatatransInitResponse initResponse, ProcessPaymentRequest request) + protected virtual Task CreateInitRequestResult(DatatransInitResponse initResponse, ProcessPaymentRequest request) { var payment = (PaymentIn)request.Payment; - return new ProcessPaymentRequestResult + var result = new ProcessPaymentRequestResult { IsSuccess = initResponse.Error != null, NewPaymentStatus = payment.PaymentStatus, @@ -305,16 +305,18 @@ protected virtual ProcessPaymentRequestResult CreateInitRequestResult(DatatransI ["startUrl"] = datatransClient.BuildStartPaymentUri(initResponse.TransactionId).ToString(), }, }; + + return Task.FromResult(result); } - protected virtual DatatransAuthorizeAuthenticatedRequest CreateAuthorizeRequest(PostProcessPaymentRequest request, DatatransTransaction transaction) + protected virtual Task CreateAuthorizeRequest(PostProcessPaymentRequest request, DatatransTransaction transaction) { var result = AbstractTypeFactory.TryCreateInstance(); result.Amount = transaction.Detail.Authorize.Amount; result.Refno = transaction.Refno; - return result; + return Task.FromResult(result); } #endregion @@ -333,9 +335,13 @@ private string GetTransactionId(PaymentRequestBase context) return transactionId; } - private static long ToMinorUnits(decimal amount) + private async Task ToMinorUnits(string currencyCode, decimal amount) { - return (long)Math.Round(amount * 100m, MidpointRounding.AwayFromZero); + const int @base = 10; + var currency = (await currencyService.GetAllCurrenciesAsync()).First(x => x.Code == currencyCode); + var multiplier = (decimal)Math.Pow(@base, currency.DecimalDigits); // 1, 100, or 1000 + + return (long)Math.Round(amount * multiplier, MidpointRounding.AwayFromZero); } #endregion From 0f9473cda065ca616be8dcf990bfe9fb7d8edf7b Mon Sep 17 00:00:00 2001 From: Basil Kotov Date: Tue, 14 Oct 2025 16:52:57 +0100 Subject: [PATCH 09/29] fix isSuccess in responses --- .../Providers/DatatransPaymentMethod.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/VirtoCommerce.Datatrans.Data/Providers/DatatransPaymentMethod.cs b/src/VirtoCommerce.Datatrans.Data/Providers/DatatransPaymentMethod.cs index 634b94b..e5f027c 100644 --- a/src/VirtoCommerce.Datatrans.Data/Providers/DatatransPaymentMethod.cs +++ b/src/VirtoCommerce.Datatrans.Data/Providers/DatatransPaymentMethod.cs @@ -147,7 +147,7 @@ protected virtual async Task VoidProcessPaymentAsync(V return new VoidPaymentRequestResult { - IsSuccess = response.Error != null, + IsSuccess = response.Error == null, NewPaymentStatus = payment.PaymentStatus, ErrorMessage = response.Error?.Message, }; @@ -202,7 +202,7 @@ protected virtual async Task CaptureProcessPaymentA return new CapturePaymentRequestResult { - IsSuccess = response.Error != null, + IsSuccess = response.Error == null, NewPaymentStatus = payment.PaymentStatus, ErrorMessage = response.Error?.Message, }; @@ -264,7 +264,7 @@ protected virtual async Task RefundProcessPaymentAsy return new RefundPaymentRequestResult { - IsSuccess = response.Error != null, + IsSuccess = response.Error == null, NewPaymentStatus = payment.PaymentStatus, ErrorMessage = response.Error?.Message, }; @@ -295,7 +295,7 @@ protected virtual Task CreateInitRequestResult(Data var result = new ProcessPaymentRequestResult { - IsSuccess = initResponse.Error != null, + IsSuccess = initResponse.Error == null, NewPaymentStatus = payment.PaymentStatus, ErrorMessage = initResponse.Error?.Message, PublicParameters = new() From e68f467fe32183c3f6db349601eb0fe781ff0ab2 Mon Sep 17 00:00:00 2001 From: Basil Kotov Date: Tue, 14 Oct 2025 16:54:26 +0100 Subject: [PATCH 10/29] change author --- src/VirtoCommerce.Datatrans.Web/module.manifest | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/VirtoCommerce.Datatrans.Web/module.manifest b/src/VirtoCommerce.Datatrans.Web/module.manifest index ac4b0f9..9969899 100644 --- a/src/VirtoCommerce.Datatrans.Web/module.manifest +++ b/src/VirtoCommerce.Datatrans.Web/module.manifest @@ -15,7 +15,7 @@ VirtoCommerce Datatrans - basilkot + Basil Kotov VirtoCommerce From 1a162778ae5d1bf12dd522bc530e1197dfe9e6f6 Mon Sep 17 00:00:00 2001 From: Basil Kotov Date: Tue, 14 Oct 2025 17:07:40 +0100 Subject: [PATCH 11/29] make static methods --- .../Providers/DatatransPaymentMethod.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/VirtoCommerce.Datatrans.Data/Providers/DatatransPaymentMethod.cs b/src/VirtoCommerce.Datatrans.Data/Providers/DatatransPaymentMethod.cs index e5f027c..a4bff65 100644 --- a/src/VirtoCommerce.Datatrans.Data/Providers/DatatransPaymentMethod.cs +++ b/src/VirtoCommerce.Datatrans.Data/Providers/DatatransPaymentMethod.cs @@ -101,7 +101,7 @@ protected virtual async Task PostProcessPayment { transaction.Refno = Guid.NewGuid().ToString().Replace("-", "").ToLower(); var authReq = await CreateAuthorizeRequest(request, transaction); - var authResp = await datatransClient.AuthorizeAuthenticatedAsync(transactionId, authReq, cancellationToken); + await datatransClient.AuthorizeAuthenticatedAsync(transactionId, authReq, cancellationToken); transaction = await datatransClient.GetTransactionAsync(transactionId, cancellationToken); } @@ -323,7 +323,7 @@ protected virtual Task CreateAuthorizeRe #region Helpers - private string GetTransactionId(PaymentRequestBase context) + private static string GetTransactionId(PaymentRequestBase context) { var payment = (PaymentIn)context.Payment; @@ -364,7 +364,7 @@ CustomerOrder order }; } - private PostProcessPaymentRequestResult PaymentApproved(DatatransTransaction tx, PaymentStatus newStatus, PaymentIn payment, CustomerOrder order) + private static PostProcessPaymentRequestResult PaymentApproved(DatatransTransaction tx, PaymentStatus newStatus, PaymentIn payment, CustomerOrder order) { var result = new PostProcessPaymentRequestResult { @@ -416,7 +416,7 @@ private PostProcessPaymentRequestResult PaymentApproved(DatatransTransaction tx, return result; } - private PostProcessPaymentRequestResult PaymentDeclined(DatatransTransaction tx, PaymentIn payment) + private static PostProcessPaymentRequestResult PaymentDeclined(DatatransTransaction tx, PaymentIn payment) { var msg = tx.Error != null ? JsonConvert.SerializeObject(tx.Error) : "Invalid Datatrans response"; var errorMessage = $"Your transaction was declined: {msg}"; @@ -432,7 +432,7 @@ private PostProcessPaymentRequestResult PaymentDeclined(DatatransTransaction tx, }; } - private PostProcessPaymentRequestResult PaymentPending(DatatransTransaction tx, PaymentIn payment) + private static PostProcessPaymentRequestResult PaymentPending(DatatransTransaction tx, PaymentIn payment) { var msg = tx.Error != null ? JsonConvert.SerializeObject(tx.Error) : "Invalid Datatrans response"; var errorMessage = $"Your transaction is pending: {msg}"; @@ -449,7 +449,7 @@ private PostProcessPaymentRequestResult PaymentPending(DatatransTransaction tx, }; } - private PostProcessPaymentRequestResult PaymentInvalid(DatatransTransaction tx, PaymentIn payment) + private static PostProcessPaymentRequestResult PaymentInvalid(DatatransTransaction tx, PaymentIn payment) { var msg = tx.Error != null ? JsonConvert.SerializeObject(tx.Error) : "Invalid Datatrans response"; var errorMessage = $"There was an error processing your transaction: {msg}"; From 9d3c556dafd9e5e56fdb1e859aabf4830bd9614e Mon Sep 17 00:00:00 2001 From: Basil Kotov Date: Tue, 14 Oct 2025 17:16:20 +0100 Subject: [PATCH 12/29] mark method as static --- .../Providers/DatatransPaymentMethod.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/VirtoCommerce.Datatrans.Data/Providers/DatatransPaymentMethod.cs b/src/VirtoCommerce.Datatrans.Data/Providers/DatatransPaymentMethod.cs index a4bff65..65fe4bc 100644 --- a/src/VirtoCommerce.Datatrans.Data/Providers/DatatransPaymentMethod.cs +++ b/src/VirtoCommerce.Datatrans.Data/Providers/DatatransPaymentMethod.cs @@ -348,7 +348,7 @@ private async Task ToMinorUnits(string currencyCode, decimal amount) #region post process status mappers - private PostProcessPaymentRequestResult GetDatatransPostResult( + private static PostProcessPaymentRequestResult GetDatatransPostResult( DatatransTransaction transaction, PaymentIn payment, CustomerOrder order From ba6ffba3728ec7ce006cf649036d50ef95692328 Mon Sep 17 00:00:00 2001 From: Basil Kotov Date: Wed, 15 Oct 2025 07:12:32 +0100 Subject: [PATCH 13/29] fis modules names in manifest --- src/VirtoCommerce.Datatrans.Web/module.manifest | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/VirtoCommerce.Datatrans.Web/module.manifest b/src/VirtoCommerce.Datatrans.Web/module.manifest index 9969899..9b4719f 100644 --- a/src/VirtoCommerce.Datatrans.Web/module.manifest +++ b/src/VirtoCommerce.Datatrans.Web/module.manifest @@ -6,9 +6,9 @@ 3.904.0 - - - + + + VirtoCommerce Datatrans From 63ab47a3ed71d5266e131685056b2653fd1903e8 Mon Sep 17 00:00:00 2001 From: Andrew <56427313+AndrewEhlo@users.noreply.github.com> Date: Wed, 15 Oct 2025 18:30:00 +0500 Subject: [PATCH 14/29] Test Katalon cli v10.3.2 --- .github/workflows/module-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/module-ci.yml b/.github/workflows/module-ci.yml index 3537d12..6ce031b 100644 --- a/.github/workflows/module-ci.yml +++ b/.github/workflows/module-ci.yml @@ -241,7 +241,7 @@ jobs: if: ${{ ((github.ref == 'refs/heads/dev') && (github.event_name == 'push') && (needs.ci.outputs.run-e2e == 'true')) || (github.event_name == 'workflow_dispatch') || (github.base_ref == 'dev') && (github.event_name == 'pull_request') }} needs: 'ci' - uses: VirtoCommerce/.github/.github/workflows/e2e.yml@v3.800.12 + uses: VirtoCommerce/.github/.github/workflows/e2e.yml@VCST-4123 #v3.800.12 with: katalonRepo: 'VirtoCommerce/vc-quality-gate-katalon' From 840dee8c8f3567d1509ddac5309d61319bead060 Mon Sep 17 00:00:00 2001 From: Andrew <56427313+AndrewEhlo@users.noreply.github.com> Date: Thu, 16 Oct 2025 08:39:32 +0500 Subject: [PATCH 15/29] Update e2e workflow reference to v3.800.12 --- .github/workflows/module-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/module-ci.yml b/.github/workflows/module-ci.yml index 6ce031b..3537d12 100644 --- a/.github/workflows/module-ci.yml +++ b/.github/workflows/module-ci.yml @@ -241,7 +241,7 @@ jobs: if: ${{ ((github.ref == 'refs/heads/dev') && (github.event_name == 'push') && (needs.ci.outputs.run-e2e == 'true')) || (github.event_name == 'workflow_dispatch') || (github.base_ref == 'dev') && (github.event_name == 'pull_request') }} needs: 'ci' - uses: VirtoCommerce/.github/.github/workflows/e2e.yml@VCST-4123 #v3.800.12 + uses: VirtoCommerce/.github/.github/workflows/e2e.yml@v3.800.12 with: katalonRepo: 'VirtoCommerce/vc-quality-gate-katalon' From 30f2dbac27720b81b11850d6d11ac1d44405bb93 Mon Sep 17 00:00:00 2001 From: Artem Dudarev Date: Fri, 17 Oct 2025 18:19:03 +0200 Subject: [PATCH 16/29] Refactoring --- VirtoCommerce.Datatrans.sln.DotSettings | 5 +- src/VirtoCommerce.Datatrans.Core/Events/.keep | 0 .../Models/DatatransCaptureResponse.cs | 4 +- .../Models/DatatransOptions.cs | 2 +- .../Models/DatatransTransaction.cs | 8 +- .../Models/DatatransVoidResponse.cs | 4 +- .../Notifications/.keep | 0 .../Services/IDatatransClient.cs | 13 +- .../Providers/DatatransPaymentMethod.cs | 119 +++++++++--------- .../Services/DatatransClient.cs | 33 ++--- src/VirtoCommerce.Datatrans.Web/Module.cs | 9 +- 11 files changed, 97 insertions(+), 100 deletions(-) delete mode 100644 src/VirtoCommerce.Datatrans.Core/Events/.keep delete mode 100644 src/VirtoCommerce.Datatrans.Core/Notifications/.keep diff --git a/VirtoCommerce.Datatrans.sln.DotSettings b/VirtoCommerce.Datatrans.sln.DotSettings index e3902f5..6f30e24 100644 --- a/VirtoCommerce.Datatrans.sln.DotSettings +++ b/VirtoCommerce.Datatrans.sln.DotSettings @@ -1,5 +1,6 @@ - - True + + <Policy><Descriptor Staticness="Static" AccessRightKinds="Private" Description="Static readonly fields (private)"><ElementKinds><Kind Name="READONLY_FIELD" /></ElementKinds></Descriptor><Policy Inspect="True" WarnAboutPrefixesAndSuffixes="False" Prefix="_" Suffix="" Style="aaBb" /></Policy> + True True True True diff --git a/src/VirtoCommerce.Datatrans.Core/Events/.keep b/src/VirtoCommerce.Datatrans.Core/Events/.keep deleted file mode 100644 index e69de29..0000000 diff --git a/src/VirtoCommerce.Datatrans.Core/Models/DatatransCaptureResponse.cs b/src/VirtoCommerce.Datatrans.Core/Models/DatatransCaptureResponse.cs index ed5ae83..83c208a 100644 --- a/src/VirtoCommerce.Datatrans.Core/Models/DatatransCaptureResponse.cs +++ b/src/VirtoCommerce.Datatrans.Core/Models/DatatransCaptureResponse.cs @@ -1,5 +1,3 @@ namespace VirtoCommerce.Datatrans.Core.Models; -public class DatatransCaptureResponse : DatatransResponseBase -{ -} +public class DatatransCaptureResponse : DatatransResponseBase; diff --git a/src/VirtoCommerce.Datatrans.Core/Models/DatatransOptions.cs b/src/VirtoCommerce.Datatrans.Core/Models/DatatransOptions.cs index 7b9f936..bca3a8c 100644 --- a/src/VirtoCommerce.Datatrans.Core/Models/DatatransOptions.cs +++ b/src/VirtoCommerce.Datatrans.Core/Models/DatatransOptions.cs @@ -25,7 +25,7 @@ public class DatatransApiRoutes public string SecureFieldsPath { get; set; } = "/v1/transactions/secureFields"; // GET - public string TxnPath { get; set; } = "/v1/transactions/{transactionId}"; + public string TransactionPath { get; set; } = "/v1/transactions/{transactionId}"; // POST public string AuthorizeAuthenticatedPath { get; set; } = "/v1/transactions/{transactionId}/authorize"; diff --git a/src/VirtoCommerce.Datatrans.Core/Models/DatatransTransaction.cs b/src/VirtoCommerce.Datatrans.Core/Models/DatatransTransaction.cs index d8f0fa3..06e8808 100644 --- a/src/VirtoCommerce.Datatrans.Core/Models/DatatransTransaction.cs +++ b/src/VirtoCommerce.Datatrans.Core/Models/DatatransTransaction.cs @@ -16,14 +16,14 @@ public class DatatransTransaction : DatatransResponseBase public DatatransTransactionCard Card { get; set; } } -public class DatatransTransactionAmount +public class DatatransTransactionDetail { - public long Amount { get; set; } + public DatatransTransactionAmount Authorize { get; set; } } -public class DatatransTransactionDetail +public class DatatransTransactionAmount { - public DatatransTransactionAmount Authorize { get; set; } + public long Amount { get; set; } } public class DatatransTransactionCard diff --git a/src/VirtoCommerce.Datatrans.Core/Models/DatatransVoidResponse.cs b/src/VirtoCommerce.Datatrans.Core/Models/DatatransVoidResponse.cs index d2fee2c..89433dc 100644 --- a/src/VirtoCommerce.Datatrans.Core/Models/DatatransVoidResponse.cs +++ b/src/VirtoCommerce.Datatrans.Core/Models/DatatransVoidResponse.cs @@ -1,5 +1,3 @@ namespace VirtoCommerce.Datatrans.Core.Models; -public class DatatransVoidResponse : DatatransResponseBase -{ -} +public class DatatransVoidResponse : DatatransResponseBase; diff --git a/src/VirtoCommerce.Datatrans.Core/Notifications/.keep b/src/VirtoCommerce.Datatrans.Core/Notifications/.keep deleted file mode 100644 index e69de29..0000000 diff --git a/src/VirtoCommerce.Datatrans.Core/Services/IDatatransClient.cs b/src/VirtoCommerce.Datatrans.Core/Services/IDatatransClient.cs index 48b0f9e..5a1ba33 100644 --- a/src/VirtoCommerce.Datatrans.Core/Services/IDatatransClient.cs +++ b/src/VirtoCommerce.Datatrans.Core/Services/IDatatransClient.cs @@ -7,18 +7,17 @@ namespace VirtoCommerce.Datatrans.Core.Services; public interface IDatatransClient { - Task InitTransactionAsync(DatatransInitRequest request, CancellationToken ct = default); + Task InitTransactionAsync(DatatransInitRequest request, CancellationToken cancellationToken = default); - Task GetTransactionAsync(string transactionId, CancellationToken ct = default); + Task GetTransactionAsync(string transactionId, CancellationToken cancellationToken = default); - Task AuthorizeAuthenticatedAsync(string transactionId, DatatransAuthorizeAuthenticatedRequest request, - CancellationToken ct = default); + Task AuthorizeAuthenticatedAsync(string transactionId, DatatransAuthorizeAuthenticatedRequest request, CancellationToken cancellationToken = default); - Task CaptureAsync(string transactionId, DatatransCaptureRequest request, CancellationToken ct = default); + Task CaptureAsync(string transactionId, DatatransCaptureRequest request, CancellationToken cancellationToken = default); - Task VoidAsync(string transactionId, CancellationToken ct = default); + Task VoidAsync(string transactionId, CancellationToken cancellationToken = default); - Task RefundAsync(string transactionId, DatatransRefundRequest request, CancellationToken ct = default); + Task RefundAsync(string transactionId, DatatransRefundRequest request, CancellationToken cancellationToken = default); Uri BuildStartPaymentUri(string transactionId); diff --git a/src/VirtoCommerce.Datatrans.Data/Providers/DatatransPaymentMethod.cs b/src/VirtoCommerce.Datatrans.Data/Providers/DatatransPaymentMethod.cs index 65fe4bc..f9cefd8 100644 --- a/src/VirtoCommerce.Datatrans.Data/Providers/DatatransPaymentMethod.cs +++ b/src/VirtoCommerce.Datatrans.Data/Providers/DatatransPaymentMethod.cs @@ -21,7 +21,7 @@ public class DatatransPaymentMethod(IDatatransClient datatransClient, ICurrencyS public override PaymentMethodType PaymentMethodType => PaymentMethodType.Standard; public override PaymentMethodGroupType PaymentMethodGroupType => PaymentMethodGroupType.BankCard; - #region overrides + #region Overrides public override ProcessPaymentRequestResult ProcessPayment(ProcessPaymentRequest request) { @@ -50,18 +50,20 @@ public override RefundPaymentRequestResult RefundProcessPayment(RefundPaymentReq public override ValidatePostProcessRequestResult ValidatePostProcessRequest(NameValueCollection queryString) { - var tx = queryString["transactionId"]; + var transactionId = queryString["transactionId"]; + var result = new ValidatePostProcessRequestResult { - IsSuccess = !string.IsNullOrEmpty(tx), - OuterId = tx, + IsSuccess = !transactionId.IsNullOrEmpty(), + OuterId = transactionId, }; + return result; } #endregion - #region protected async methods + #region Protected async methods protected virtual async Task ProcessPaymentAsync(ProcessPaymentRequest request) { @@ -70,10 +72,10 @@ protected virtual async Task ProcessPaymentAsync(Pr var initRequest = await CreateInitRequest(request); var initResponse = await datatransClient.InitTransactionAsync(initRequest); - var ok = initResponse.Error is null && !string.IsNullOrEmpty(initResponse.TransactionId); + var success = initResponse.Error is null && !initResponse.TransactionId.IsNullOrEmpty(); payment.OuterId = initResponse.TransactionId; - payment.PaymentStatus = ok ? PaymentStatus.Pending : PaymentStatus.Voided; + payment.PaymentStatus = success ? PaymentStatus.Pending : PaymentStatus.Voided; payment.Status = payment.PaymentStatus.ToString(); return await CreateInitRequestResult(initResponse, request); @@ -81,17 +83,14 @@ protected virtual async Task ProcessPaymentAsync(Pr protected virtual async Task PostProcessPaymentAsync(PostProcessPaymentRequest request, CancellationToken cancellationToken = default) { - var payment = (PaymentIn)request.Payment; - var order = (CustomerOrder)request.Order; - var transactionId = request.Parameters?.Get("transactionId"); - if (string.IsNullOrEmpty(transactionId)) + if (transactionId.IsNullOrEmpty()) { return new PostProcessPaymentRequestResult { IsSuccess = false, - ErrorMessage = "transactionId not found" + ErrorMessage = "transactionId not found", }; } @@ -99,14 +98,16 @@ protected virtual async Task PostProcessPayment if (transaction.Status is "authenticated") { - transaction.Refno = Guid.NewGuid().ToString().Replace("-", "").ToLower(); - var authReq = await CreateAuthorizeRequest(request, transaction); - await datatransClient.AuthorizeAuthenticatedAsync(transactionId, authReq, cancellationToken); + transaction.Refno = Guid.NewGuid().ToString("N").ToLower(); + var authorizeRequest = await CreateAuthorizeRequest(transaction, request); + await datatransClient.AuthorizeAuthenticatedAsync(transactionId, authorizeRequest, cancellationToken); transaction = await datatransClient.GetTransactionAsync(transactionId, cancellationToken); } - var result = GetDatatransPostResult(transaction, payment, order); + var order = (CustomerOrder)request.Order; + var payment = (PaymentIn)request.Payment; + var result = GetDatatransPostResult(transaction, order, payment); return result; } @@ -114,14 +115,13 @@ protected virtual async Task PostProcessPayment protected virtual async Task VoidProcessPaymentAsync(VoidPaymentRequest request) { var payment = (PaymentIn)request.Payment; - var transactionId = GetTransactionId(request); if (payment.PaymentStatus == PaymentStatus.Voided) { return new VoidPaymentRequestResult { IsSuccess = true, - NewPaymentStatus = PaymentStatus.Voided + NewPaymentStatus = PaymentStatus.Voided, }; } @@ -130,10 +130,11 @@ protected virtual async Task VoidProcessPaymentAsync(V return new VoidPaymentRequestResult { IsSuccess = false, - ErrorMessage = "Cannot void a captured payment. Use refund instead." + ErrorMessage = "Cannot void a captured payment. Use refund instead.", }; } + var transactionId = GetTransactionId(request); var response = await datatransClient.VoidAsync(transactionId); if (response.Error != null) @@ -161,7 +162,7 @@ protected virtual async Task CaptureProcessPaymentA var alreadyCaptured = payment.Captures.Sum(x => x.Amount); var total = payment.Sum; - var amountToCapture = context.CaptureAmount ?? (total - alreadyCaptured); + var amountToCapture = context.CaptureAmount ?? total - alreadyCaptured; if (amountToCapture <= 0m) { @@ -169,7 +170,7 @@ protected virtual async Task CaptureProcessPaymentA { IsSuccess = true, NewPaymentStatus = payment.PaymentStatus, - ErrorMessage = null + ErrorMessage = null, }; } @@ -218,7 +219,7 @@ protected virtual async Task RefundProcessPaymentAsy return new RefundPaymentRequestResult { IsSuccess = false, - ErrorMessage = "No captured amount to refund." + ErrorMessage = "No captured amount to refund.", }; } @@ -227,7 +228,7 @@ protected virtual async Task RefundProcessPaymentAsy return new RefundPaymentRequestResult { IsSuccess = false, - ErrorMessage = "Refund amount exceeds captured amount." + ErrorMessage = "Refund amount exceeds captured amount.", }; } @@ -238,7 +239,7 @@ protected virtual async Task RefundProcessPaymentAsy return new RefundPaymentRequestResult { IsSuccess = false, - ErrorMessage = "Refund amount must be greater than zero." + ErrorMessage = "Refund amount must be greater than zero.", }; } @@ -272,13 +273,13 @@ protected virtual async Task RefundProcessPaymentAsy #endregion - #region extension points + #region Extension points protected virtual async Task CreateInitRequest(ProcessPaymentRequest request) { - var payment = (PaymentIn)request.Payment; - var order = (CustomerOrder)request.Order; var store = (Store)request.Store; + var order = (CustomerOrder)request.Order; + var payment = (PaymentIn)request.Payment; var url = (store.SecureUrl.IsNullOrEmpty() ? store.Url : store.SecureUrl)?.TrimEnd('/'); @@ -286,6 +287,7 @@ protected virtual async Task CreateInitRequest(ProcessPaym result.Amount = await ToMinorUnits(payment.Currency, payment.Sum); result.Currency = payment.Currency ?? order.Currency; result.ReturnUrl = $"{url}/account/orders/{order.Id}/payment"; + return result; } @@ -309,7 +311,7 @@ protected virtual Task CreateInitRequestResult(Data return Task.FromResult(result); } - protected virtual Task CreateAuthorizeRequest(PostProcessPaymentRequest request, DatatransTransaction transaction) + protected virtual Task CreateAuthorizeRequest(DatatransTransaction transaction, PostProcessPaymentRequest request) { var result = AbstractTypeFactory.TryCreateInstance(); @@ -346,82 +348,79 @@ private async Task ToMinorUnits(string currencyCode, decimal amount) #endregion - #region post process status mappers + #region Post process status mappers - private static PostProcessPaymentRequestResult GetDatatransPostResult( - DatatransTransaction transaction, - PaymentIn payment, - CustomerOrder order - ) + private static PostProcessPaymentRequestResult GetDatatransPostResult(DatatransTransaction transaction, CustomerOrder order, PaymentIn payment) { var newStatus = ConvertStatus(transaction.Status); + return newStatus switch { - PaymentStatus.Authorized or PaymentStatus.Paid => PaymentApproved(transaction, newStatus, payment, order), + PaymentStatus.Authorized or PaymentStatus.Paid => PaymentApproved(transaction, order, payment, newStatus), PaymentStatus.Declined => PaymentDeclined(transaction, payment), PaymentStatus.Pending => PaymentPending(transaction, payment), _ => PaymentInvalid(transaction, payment), }; } - private static PostProcessPaymentRequestResult PaymentApproved(DatatransTransaction tx, PaymentStatus newStatus, PaymentIn payment, CustomerOrder order) + private static PostProcessPaymentRequestResult PaymentApproved(DatatransTransaction transaction, CustomerOrder order, PaymentIn payment, PaymentStatus newStatus) { var result = new PostProcessPaymentRequestResult { NewPaymentStatus = newStatus, OrderId = order.Id, - OuterId = tx.TransactionId, + OuterId = transaction.TransactionId, IsSuccess = true, }; payment.PaymentStatus = newStatus; payment.Status = newStatus.ToString(); payment.IsApproved = true; - payment.OuterId = tx.TransactionId; + payment.OuterId = transaction.TransactionId; payment.AuthorizedDate ??= DateTime.UtcNow; payment.CapturedDate ??= DateTime.UtcNow; payment.Captures ??= new List(); payment.Captures.Add(new Capture { - TransactionId = tx.TransactionId, + TransactionId = transaction.TransactionId, Amount = payment.Sum, Currency = payment.Currency, CreatedDate = DateTime.UtcNow, - OuterId = tx.TransactionId, + OuterId = transaction.TransactionId, }); - var note = $"Transaction ID: {tx.TransactionId}"; - if (!string.IsNullOrEmpty(tx.MerchantId)) + var note = $"Transaction ID: {transaction.TransactionId}"; + if (!string.IsNullOrEmpty(transaction.MerchantId)) { - note += $", Merchant ID: {tx.MerchantId}"; + note += $", Merchant ID: {transaction.MerchantId}"; } payment.Comment = $"Paid successfully via Datatrans. {note}{Environment.NewLine}"; order.Status = "Processing"; - var transaction = new PaymentGatewayTransaction + var paymentGatewayTransaction = new PaymentGatewayTransaction { IsProcessed = true, ProcessedDate = DateTime.UtcNow, CurrencyCode = payment.Currency, Amount = payment.Sum, Note = note, - ResponseData = JsonConvert.SerializeObject(tx) + ResponseData = JsonConvert.SerializeObject(transaction), }; payment.Transactions ??= new List(); - payment.Transactions.Add(transaction); + payment.Transactions.Add(paymentGatewayTransaction); return result; } - private static PostProcessPaymentRequestResult PaymentDeclined(DatatransTransaction tx, PaymentIn payment) + private static PostProcessPaymentRequestResult PaymentDeclined(DatatransTransaction transaction, PaymentIn payment) { - var msg = tx.Error != null ? JsonConvert.SerializeObject(tx.Error) : "Invalid Datatrans response"; - var errorMessage = $"Your transaction was declined: {msg}"; + var error = transaction.Error != null ? JsonConvert.SerializeObject(transaction.Error) : "Invalid Datatrans response"; + var errorMessage = $"Your transaction was declined: {error}"; - payment.Status = PaymentStatus.Declined.ToString(); + payment.Status = nameof(PaymentStatus.Declined); payment.ProcessPaymentResult = new ProcessPaymentRequestResult { ErrorMessage = errorMessage }; payment.Comment = $"{errorMessage}{Environment.NewLine}"; @@ -432,29 +431,29 @@ private static PostProcessPaymentRequestResult PaymentDeclined(DatatransTransact }; } - private static PostProcessPaymentRequestResult PaymentPending(DatatransTransaction tx, PaymentIn payment) + private static PostProcessPaymentRequestResult PaymentPending(DatatransTransaction transaction, PaymentIn payment) { - var msg = tx.Error != null ? JsonConvert.SerializeObject(tx.Error) : "Invalid Datatrans response"; - var errorMessage = $"Your transaction is pending: {msg}"; + var error = transaction.Error != null ? JsonConvert.SerializeObject(transaction.Error) : "Invalid Datatrans response"; + var errorMessage = $"Your transaction is pending: {error}"; payment.ProcessPaymentResult = new ProcessPaymentRequestResult { ErrorMessage = errorMessage }; payment.Comment = $"{errorMessage}{Environment.NewLine}"; - payment.OuterId ??= tx.TransactionId; + payment.OuterId ??= transaction.TransactionId; return new PostProcessPaymentRequestResult { ErrorMessage = errorMessage, IsSuccess = true, - OuterId = tx.TransactionId + OuterId = transaction.TransactionId, }; } - private static PostProcessPaymentRequestResult PaymentInvalid(DatatransTransaction tx, PaymentIn payment) + private static PostProcessPaymentRequestResult PaymentInvalid(DatatransTransaction transaction, PaymentIn payment) { - var msg = tx.Error != null ? JsonConvert.SerializeObject(tx.Error) : "Invalid Datatrans response"; - var errorMessage = $"There was an error processing your transaction: {msg}"; + var error = transaction.Error != null ? JsonConvert.SerializeObject(transaction.Error) : "Invalid Datatrans response"; + var errorMessage = $"There was an error processing your transaction: {error}"; - payment.Status = PaymentStatus.Error.ToString(); + payment.Status = nameof(PaymentStatus.Error); payment.ProcessPaymentResult = new ProcessPaymentRequestResult { ErrorMessage = errorMessage }; payment.Comment = $"{errorMessage}{Environment.NewLine}"; @@ -472,7 +471,7 @@ private static PaymentStatus ConvertStatus(string status) "canceled" => PaymentStatus.Voided, "transmitted" => PaymentStatus.Pending, "failed" => PaymentStatus.Declined, - _ => PaymentStatus.Error + _ => PaymentStatus.Error, }; } diff --git a/src/VirtoCommerce.Datatrans.Data/Services/DatatransClient.cs b/src/VirtoCommerce.Datatrans.Data/Services/DatatransClient.cs index 8351f97..eb50806 100644 --- a/src/VirtoCommerce.Datatrans.Data/Services/DatatransClient.cs +++ b/src/VirtoCommerce.Datatrans.Data/Services/DatatransClient.cs @@ -2,6 +2,7 @@ using System.Net.Http; using System.Text; using System.Text.Json; +using System.Text.Json.Serialization; using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Options; @@ -20,7 +21,7 @@ public class DatatransClient(IHttpClientFactory httpClientFactory, IOptions _options.UseSandbox ? _options.SandboxStartUrlBase : _options.ProductionStartUrlBase; @@ -33,44 +34,44 @@ public Uri BuildStartPaymentUri(string transactionId) public string GetSecureFieldsScriptUrl() => SecureScriptUrl; - public async Task InitTransactionAsync(DatatransInitRequest request, CancellationToken ct = default) + public async Task InitTransactionAsync(DatatransInitRequest request, CancellationToken cancellationToken = default) { - var resp = await SendAsync(HttpMethod.Post, _options.Routes.SecureFieldsPath, request, ct); + var resp = await SendAsync(HttpMethod.Post, _options.Routes.SecureFieldsPath, request, cancellationToken); return ParseResponse(resp); } - public async Task GetTransactionAsync(string transactionId, CancellationToken ct = default) + public async Task GetTransactionAsync(string transactionId, CancellationToken cancellationToken = default) { - var path = _options.Routes.TxnPath.Replace("{transactionId}", Uri.EscapeDataString(transactionId)); - var resp = await SendAsync(HttpMethod.Get, path, null, ct); + var path = _options.Routes.TransactionPath.Replace("{transactionId}", Uri.EscapeDataString(transactionId)); + var resp = await SendAsync(HttpMethod.Get, path, null, cancellationToken); return ParseResponse(resp); } - public async Task AuthorizeAuthenticatedAsync(string transactionId, DatatransAuthorizeAuthenticatedRequest request, CancellationToken ct = default) + public async Task AuthorizeAuthenticatedAsync(string transactionId, DatatransAuthorizeAuthenticatedRequest request, CancellationToken cancellationToken = default) { var path = _options.Routes.AuthorizeAuthenticatedPath.Replace("{transactionId}", Uri.EscapeDataString(transactionId)); - var resp = await SendAsync(HttpMethod.Post, path, request, ct); + var resp = await SendAsync(HttpMethod.Post, path, request, cancellationToken); return ParseResponse(resp); } - public async Task CaptureAsync(string transactionId, DatatransCaptureRequest request, CancellationToken ct = default) + public async Task CaptureAsync(string transactionId, DatatransCaptureRequest request, CancellationToken cancellationToken = default) { var path = _options.Routes.CapturePath.Replace("{transactionId}", Uri.EscapeDataString(transactionId)); - var resp = await SendAsync(HttpMethod.Post, path, request, ct); + var resp = await SendAsync(HttpMethod.Post, path, request, cancellationToken); return ParseResponse(resp); } - public async Task VoidAsync(string transactionId, CancellationToken ct = default) + public async Task VoidAsync(string transactionId, CancellationToken cancellationToken = default) { var path = _options.Routes.VoidPath.Replace("{transactionId}", Uri.EscapeDataString(transactionId)); - var resp = await SendAsync(HttpMethod.Post, path, new { }, ct); + var resp = await SendAsync(HttpMethod.Post, path, new { }, cancellationToken); return ParseResponse(resp); } - public async Task RefundAsync(string transactionId, DatatransRefundRequest request, CancellationToken ct = default) + public async Task RefundAsync(string transactionId, DatatransRefundRequest request, CancellationToken cancellationToken = default) { var path = _options.Routes.RefundPath.Replace("{transactionId}", Uri.EscapeDataString(transactionId)); - var resp = await SendAsync(HttpMethod.Post, path, request, ct); + var resp = await SendAsync(HttpMethod.Post, path, request, cancellationToken); return ParseResponse(resp); } @@ -110,8 +111,8 @@ private async Task SendAsync(HttpMethod method, string path, object body Error = new DatatransError { Message = exception.Message, - Raw = json - } + Raw = json, + }, }; } } diff --git a/src/VirtoCommerce.Datatrans.Web/Module.cs b/src/VirtoCommerce.Datatrans.Web/Module.cs index 229305a..34bebf9 100644 --- a/src/VirtoCommerce.Datatrans.Web/Module.cs +++ b/src/VirtoCommerce.Datatrans.Web/Module.cs @@ -11,6 +11,7 @@ using VirtoCommerce.Datatrans.Data.Providers; using VirtoCommerce.Datatrans.Data.Services; using VirtoCommerce.PaymentModule.Core.Services; +using VirtoCommerce.Platform.Core.Common; using VirtoCommerce.Platform.Core.Modularity; using VirtoCommerce.Platform.Core.Settings; @@ -30,13 +31,13 @@ public void Initialize(IServiceCollection serviceCollection) serviceCollection.AddHttpClient("Datatrans", (sp, http) => { - var opt = sp.GetRequiredService>().Value; - http.BaseAddress = new Uri(opt.UseSandbox ? opt.SandboxBaseUrl : opt.ProductionBaseUrl); + var options = sp.GetRequiredService>().Value; + http.BaseAddress = new Uri(options.UseSandbox ? options.SandboxBaseUrl : options.ProductionBaseUrl); http.Timeout = TimeSpan.FromSeconds(30); - if (!string.IsNullOrEmpty(opt.MerchantId)) + if (!options.MerchantId.IsNullOrEmpty()) { - var bytes = Encoding.UTF8.GetBytes($"{opt.MerchantId}:{opt.Secret}"); + var bytes = Encoding.UTF8.GetBytes($"{options.MerchantId}:{options.Secret}"); http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(bytes)); } From 34f6b3a376f5494220601cc5fa0784dd58923040 Mon Sep 17 00:00:00 2001 From: Artem Dudarev Date: Fri, 17 Oct 2025 18:23:27 +0200 Subject: [PATCH 17/29] Cleanup --- .../VirtoCommerce.Datatrans.Data.csproj | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/VirtoCommerce.Datatrans.Data/VirtoCommerce.Datatrans.Data.csproj b/src/VirtoCommerce.Datatrans.Data/VirtoCommerce.Datatrans.Data.csproj index 8e7f75a..b844f65 100644 --- a/src/VirtoCommerce.Datatrans.Data/VirtoCommerce.Datatrans.Data.csproj +++ b/src/VirtoCommerce.Datatrans.Data/VirtoCommerce.Datatrans.Data.csproj @@ -13,7 +13,4 @@ - - - From 0496210ac00563efaa2c48597c7fb000d41e65a8 Mon Sep 17 00:00:00 2001 From: Basil Kotov Date: Mon, 20 Oct 2025 12:31:41 +0100 Subject: [PATCH 18/29] move external models to separate folder --- .../DatatransAuthorizeAuthenticatedRequest.cs | 2 +- .../{ => External}/DatatransAuthorizeResponse.cs | 2 +- .../Models/{ => External}/DatatransCaptureRequest.cs | 2 +- .../Models/{ => External}/DatatransCaptureResponse.cs | 2 +- .../Models/{ => External}/DatatransError.cs | 2 +- .../Models/{ => External}/DatatransInitRequest.cs | 2 +- .../Models/{ => External}/DatatransInitResponse.cs | 2 +- .../Models/{ => External}/DatatransRefundRequest.cs | 2 +- .../Models/{ => External}/DatatransRefundResponse.cs | 2 +- .../Models/{ => External}/DatatransResponseBase.cs | 2 +- .../Models/{ => External}/DatatransTransaction.cs | 2 +- .../Models/{ => External}/DatatransVoidResponse.cs | 2 +- .../Services/IDatatransClient.cs | 2 +- .../Providers/DatatransPaymentMethod.cs | 2 +- .../Services/DatatransClient.cs | 11 ++--------- 15 files changed, 16 insertions(+), 23 deletions(-) rename src/VirtoCommerce.Datatrans.Core/Models/{ => External}/DatatransAuthorizeAuthenticatedRequest.cs (70%) rename src/VirtoCommerce.Datatrans.Core/Models/{ => External}/DatatransAuthorizeResponse.cs (69%) rename src/VirtoCommerce.Datatrans.Core/Models/{ => External}/DatatransCaptureRequest.cs (73%) rename src/VirtoCommerce.Datatrans.Core/Models/{ => External}/DatatransCaptureResponse.cs (53%) rename src/VirtoCommerce.Datatrans.Core/Models/{ => External}/DatatransError.cs (72%) rename src/VirtoCommerce.Datatrans.Core/Models/{ => External}/DatatransInitRequest.cs (79%) rename src/VirtoCommerce.Datatrans.Core/Models/{ => External}/DatatransInitResponse.cs (66%) rename src/VirtoCommerce.Datatrans.Core/Models/{ => External}/DatatransRefundRequest.cs (73%) rename src/VirtoCommerce.Datatrans.Core/Models/{ => External}/DatatransRefundResponse.cs (75%) rename src/VirtoCommerce.Datatrans.Core/Models/{ => External}/DatatransResponseBase.cs (60%) rename src/VirtoCommerce.Datatrans.Core/Models/{ => External}/DatatransTransaction.cs (96%) rename src/VirtoCommerce.Datatrans.Core/Models/{ => External}/DatatransVoidResponse.cs (52%) diff --git a/src/VirtoCommerce.Datatrans.Core/Models/DatatransAuthorizeAuthenticatedRequest.cs b/src/VirtoCommerce.Datatrans.Core/Models/External/DatatransAuthorizeAuthenticatedRequest.cs similarity index 70% rename from src/VirtoCommerce.Datatrans.Core/Models/DatatransAuthorizeAuthenticatedRequest.cs rename to src/VirtoCommerce.Datatrans.Core/Models/External/DatatransAuthorizeAuthenticatedRequest.cs index db9c1b9..236d755 100644 --- a/src/VirtoCommerce.Datatrans.Core/Models/DatatransAuthorizeAuthenticatedRequest.cs +++ b/src/VirtoCommerce.Datatrans.Core/Models/External/DatatransAuthorizeAuthenticatedRequest.cs @@ -1,4 +1,4 @@ -namespace VirtoCommerce.Datatrans.Core.Models; +namespace VirtoCommerce.Datatrans.Core.Models.External; public class DatatransAuthorizeAuthenticatedRequest { diff --git a/src/VirtoCommerce.Datatrans.Core/Models/DatatransAuthorizeResponse.cs b/src/VirtoCommerce.Datatrans.Core/Models/External/DatatransAuthorizeResponse.cs similarity index 69% rename from src/VirtoCommerce.Datatrans.Core/Models/DatatransAuthorizeResponse.cs rename to src/VirtoCommerce.Datatrans.Core/Models/External/DatatransAuthorizeResponse.cs index 8b7b897..c1920fa 100644 --- a/src/VirtoCommerce.Datatrans.Core/Models/DatatransAuthorizeResponse.cs +++ b/src/VirtoCommerce.Datatrans.Core/Models/External/DatatransAuthorizeResponse.cs @@ -1,4 +1,4 @@ -namespace VirtoCommerce.Datatrans.Core.Models; +namespace VirtoCommerce.Datatrans.Core.Models.External; public class DatatransAuthorizeResponse : DatatransResponseBase { diff --git a/src/VirtoCommerce.Datatrans.Core/Models/DatatransCaptureRequest.cs b/src/VirtoCommerce.Datatrans.Core/Models/External/DatatransCaptureRequest.cs similarity index 73% rename from src/VirtoCommerce.Datatrans.Core/Models/DatatransCaptureRequest.cs rename to src/VirtoCommerce.Datatrans.Core/Models/External/DatatransCaptureRequest.cs index 5f56faa..a1bdd9c 100644 --- a/src/VirtoCommerce.Datatrans.Core/Models/DatatransCaptureRequest.cs +++ b/src/VirtoCommerce.Datatrans.Core/Models/External/DatatransCaptureRequest.cs @@ -1,4 +1,4 @@ -namespace VirtoCommerce.Datatrans.Core.Models; +namespace VirtoCommerce.Datatrans.Core.Models.External; public class DatatransCaptureRequest { diff --git a/src/VirtoCommerce.Datatrans.Core/Models/DatatransCaptureResponse.cs b/src/VirtoCommerce.Datatrans.Core/Models/External/DatatransCaptureResponse.cs similarity index 53% rename from src/VirtoCommerce.Datatrans.Core/Models/DatatransCaptureResponse.cs rename to src/VirtoCommerce.Datatrans.Core/Models/External/DatatransCaptureResponse.cs index 83c208a..066cf6d 100644 --- a/src/VirtoCommerce.Datatrans.Core/Models/DatatransCaptureResponse.cs +++ b/src/VirtoCommerce.Datatrans.Core/Models/External/DatatransCaptureResponse.cs @@ -1,3 +1,3 @@ -namespace VirtoCommerce.Datatrans.Core.Models; +namespace VirtoCommerce.Datatrans.Core.Models.External; public class DatatransCaptureResponse : DatatransResponseBase; diff --git a/src/VirtoCommerce.Datatrans.Core/Models/DatatransError.cs b/src/VirtoCommerce.Datatrans.Core/Models/External/DatatransError.cs similarity index 72% rename from src/VirtoCommerce.Datatrans.Core/Models/DatatransError.cs rename to src/VirtoCommerce.Datatrans.Core/Models/External/DatatransError.cs index b64af8b..039c9a3 100644 --- a/src/VirtoCommerce.Datatrans.Core/Models/DatatransError.cs +++ b/src/VirtoCommerce.Datatrans.Core/Models/External/DatatransError.cs @@ -1,4 +1,4 @@ -namespace VirtoCommerce.Datatrans.Core.Models; +namespace VirtoCommerce.Datatrans.Core.Models.External; public class DatatransError { diff --git a/src/VirtoCommerce.Datatrans.Core/Models/DatatransInitRequest.cs b/src/VirtoCommerce.Datatrans.Core/Models/External/DatatransInitRequest.cs similarity index 79% rename from src/VirtoCommerce.Datatrans.Core/Models/DatatransInitRequest.cs rename to src/VirtoCommerce.Datatrans.Core/Models/External/DatatransInitRequest.cs index a874835..830e645 100644 --- a/src/VirtoCommerce.Datatrans.Core/Models/DatatransInitRequest.cs +++ b/src/VirtoCommerce.Datatrans.Core/Models/External/DatatransInitRequest.cs @@ -1,4 +1,4 @@ -namespace VirtoCommerce.Datatrans.Core.Models; +namespace VirtoCommerce.Datatrans.Core.Models.External; public class DatatransInitRequest { diff --git a/src/VirtoCommerce.Datatrans.Core/Models/DatatransInitResponse.cs b/src/VirtoCommerce.Datatrans.Core/Models/External/DatatransInitResponse.cs similarity index 66% rename from src/VirtoCommerce.Datatrans.Core/Models/DatatransInitResponse.cs rename to src/VirtoCommerce.Datatrans.Core/Models/External/DatatransInitResponse.cs index 1074c8f..5224121 100644 --- a/src/VirtoCommerce.Datatrans.Core/Models/DatatransInitResponse.cs +++ b/src/VirtoCommerce.Datatrans.Core/Models/External/DatatransInitResponse.cs @@ -1,4 +1,4 @@ -namespace VirtoCommerce.Datatrans.Core.Models; +namespace VirtoCommerce.Datatrans.Core.Models.External; public class DatatransInitResponse : DatatransResponseBase { diff --git a/src/VirtoCommerce.Datatrans.Core/Models/DatatransRefundRequest.cs b/src/VirtoCommerce.Datatrans.Core/Models/External/DatatransRefundRequest.cs similarity index 73% rename from src/VirtoCommerce.Datatrans.Core/Models/DatatransRefundRequest.cs rename to src/VirtoCommerce.Datatrans.Core/Models/External/DatatransRefundRequest.cs index 373d94e..972cfad 100644 --- a/src/VirtoCommerce.Datatrans.Core/Models/DatatransRefundRequest.cs +++ b/src/VirtoCommerce.Datatrans.Core/Models/External/DatatransRefundRequest.cs @@ -1,4 +1,4 @@ -namespace VirtoCommerce.Datatrans.Core.Models; +namespace VirtoCommerce.Datatrans.Core.Models.External; public class DatatransRefundRequest { diff --git a/src/VirtoCommerce.Datatrans.Core/Models/DatatransRefundResponse.cs b/src/VirtoCommerce.Datatrans.Core/Models/External/DatatransRefundResponse.cs similarity index 75% rename from src/VirtoCommerce.Datatrans.Core/Models/DatatransRefundResponse.cs rename to src/VirtoCommerce.Datatrans.Core/Models/External/DatatransRefundResponse.cs index 826a6aa..3ae4f3e 100644 --- a/src/VirtoCommerce.Datatrans.Core/Models/DatatransRefundResponse.cs +++ b/src/VirtoCommerce.Datatrans.Core/Models/External/DatatransRefundResponse.cs @@ -1,4 +1,4 @@ -namespace VirtoCommerce.Datatrans.Core.Models; +namespace VirtoCommerce.Datatrans.Core.Models.External; public class DatatransRefundResponse : DatatransResponseBase { diff --git a/src/VirtoCommerce.Datatrans.Core/Models/DatatransResponseBase.cs b/src/VirtoCommerce.Datatrans.Core/Models/External/DatatransResponseBase.cs similarity index 60% rename from src/VirtoCommerce.Datatrans.Core/Models/DatatransResponseBase.cs rename to src/VirtoCommerce.Datatrans.Core/Models/External/DatatransResponseBase.cs index cac3adf..9c7164a 100644 --- a/src/VirtoCommerce.Datatrans.Core/Models/DatatransResponseBase.cs +++ b/src/VirtoCommerce.Datatrans.Core/Models/External/DatatransResponseBase.cs @@ -1,4 +1,4 @@ -namespace VirtoCommerce.Datatrans.Core.Models; +namespace VirtoCommerce.Datatrans.Core.Models.External; public class DatatransResponseBase { diff --git a/src/VirtoCommerce.Datatrans.Core/Models/DatatransTransaction.cs b/src/VirtoCommerce.Datatrans.Core/Models/External/DatatransTransaction.cs similarity index 96% rename from src/VirtoCommerce.Datatrans.Core/Models/DatatransTransaction.cs rename to src/VirtoCommerce.Datatrans.Core/Models/External/DatatransTransaction.cs index 06e8808..edb3038 100644 --- a/src/VirtoCommerce.Datatrans.Core/Models/DatatransTransaction.cs +++ b/src/VirtoCommerce.Datatrans.Core/Models/External/DatatransTransaction.cs @@ -1,6 +1,6 @@ using Newtonsoft.Json; -namespace VirtoCommerce.Datatrans.Core.Models; +namespace VirtoCommerce.Datatrans.Core.Models.External; public class DatatransTransaction : DatatransResponseBase { diff --git a/src/VirtoCommerce.Datatrans.Core/Models/DatatransVoidResponse.cs b/src/VirtoCommerce.Datatrans.Core/Models/External/DatatransVoidResponse.cs similarity index 52% rename from src/VirtoCommerce.Datatrans.Core/Models/DatatransVoidResponse.cs rename to src/VirtoCommerce.Datatrans.Core/Models/External/DatatransVoidResponse.cs index 89433dc..d70f6c2 100644 --- a/src/VirtoCommerce.Datatrans.Core/Models/DatatransVoidResponse.cs +++ b/src/VirtoCommerce.Datatrans.Core/Models/External/DatatransVoidResponse.cs @@ -1,3 +1,3 @@ -namespace VirtoCommerce.Datatrans.Core.Models; +namespace VirtoCommerce.Datatrans.Core.Models.External; public class DatatransVoidResponse : DatatransResponseBase; diff --git a/src/VirtoCommerce.Datatrans.Core/Services/IDatatransClient.cs b/src/VirtoCommerce.Datatrans.Core/Services/IDatatransClient.cs index 5a1ba33..a07867c 100644 --- a/src/VirtoCommerce.Datatrans.Core/Services/IDatatransClient.cs +++ b/src/VirtoCommerce.Datatrans.Core/Services/IDatatransClient.cs @@ -1,7 +1,7 @@ using System; using System.Threading; using System.Threading.Tasks; -using VirtoCommerce.Datatrans.Core.Models; +using VirtoCommerce.Datatrans.Core.Models.External; namespace VirtoCommerce.Datatrans.Core.Services; diff --git a/src/VirtoCommerce.Datatrans.Data/Providers/DatatransPaymentMethod.cs b/src/VirtoCommerce.Datatrans.Data/Providers/DatatransPaymentMethod.cs index f9cefd8..b3c26d3 100644 --- a/src/VirtoCommerce.Datatrans.Data/Providers/DatatransPaymentMethod.cs +++ b/src/VirtoCommerce.Datatrans.Data/Providers/DatatransPaymentMethod.cs @@ -6,7 +6,7 @@ using System.Threading.Tasks; using Newtonsoft.Json; using VirtoCommerce.CoreModule.Core.Currency; -using VirtoCommerce.Datatrans.Core.Models; +using VirtoCommerce.Datatrans.Core.Models.External; using VirtoCommerce.Datatrans.Core.Services; using VirtoCommerce.OrdersModule.Core.Model; using VirtoCommerce.PaymentModule.Core.Model; diff --git a/src/VirtoCommerce.Datatrans.Data/Services/DatatransClient.cs b/src/VirtoCommerce.Datatrans.Data/Services/DatatransClient.cs index eb50806..7b15211 100644 --- a/src/VirtoCommerce.Datatrans.Data/Services/DatatransClient.cs +++ b/src/VirtoCommerce.Datatrans.Data/Services/DatatransClient.cs @@ -1,16 +1,15 @@ using System; using System.Net.Http; using System.Text; -using System.Text.Json; using System.Text.Json.Serialization; using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Options; using Newtonsoft.Json; using VirtoCommerce.Datatrans.Core.Models; +using VirtoCommerce.Datatrans.Core.Models.External; using VirtoCommerce.Datatrans.Core.Services; using VirtoCommerce.Platform.Core.Common; -using JsonSerializer = System.Text.Json.JsonSerializer; namespace VirtoCommerce.Datatrans.Data.Services; @@ -18,12 +17,6 @@ public class DatatransClient(IHttpClientFactory httpClientFactory, IOptions _options.UseSandbox ? _options.SandboxStartUrlBase : _options.ProductionStartUrlBase; private string SecureScriptUrl => _options.UseSandbox ? _options.SandboxSecureFieldsScriptUrl : _options.ProductionSecureFieldsScriptUrl; @@ -81,7 +74,7 @@ private async Task SendAsync(HttpMethod method, string path, object body if (body is not null) { - var json = JsonSerializer.Serialize(body, _json); + var json = JsonConvert.SerializeObject(body); msg.Content = new StringContent(json, Encoding.UTF8, "application/json"); } From c58fcfdfe1001502900b4cc8e238e89cf4972ae5 Mon Sep 17 00:00:00 2001 From: Basil Kotov Date: Mon, 20 Oct 2025 12:31:54 +0100 Subject: [PATCH 19/29] update logo --- .../Content/logo.png | Bin 14153 -> 12302 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/src/VirtoCommerce.Datatrans.Web/Content/logo.png b/src/VirtoCommerce.Datatrans.Web/Content/logo.png index ca22993d6af972f18e48f7c2996f620c8cffb9f9..91c90893a511b63bbc796d90c408fae8baed3af6 100644 GIT binary patch literal 12302 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 tq2-Jl0F_DpXpfcf4V16`w{m4>!s#;{0VsuiVI! Date: Mon, 20 Oct 2025 14:40:37 +0100 Subject: [PATCH 20/29] refactoring --- .../Models/DatatransApiRoutes.cs | 22 +++++++++++++++++++ .../Models/DatatransOptions.cs | 21 ------------------ .../Services/DatatransClient.cs | 13 +++++------ 3 files changed, 28 insertions(+), 28 deletions(-) create mode 100644 src/VirtoCommerce.Datatrans.Core/Models/DatatransApiRoutes.cs diff --git a/src/VirtoCommerce.Datatrans.Core/Models/DatatransApiRoutes.cs b/src/VirtoCommerce.Datatrans.Core/Models/DatatransApiRoutes.cs new file mode 100644 index 0000000..1c5439e --- /dev/null +++ b/src/VirtoCommerce.Datatrans.Core/Models/DatatransApiRoutes.cs @@ -0,0 +1,22 @@ +namespace VirtoCommerce.Datatrans.Core.Models; + +public class DatatransApiRoutes +{ + // POST + public string GetSecureFieldsPath() => "/v1/transactions/secureFields"; + + // GET + public string GetTransactionPath(string transactionId) => $"/v1/transactions/{transactionId}"; + + // POST + public string GetAuthorizeAuthenticatedPath(string transactionId) => $"/v1/transactions/{transactionId}/authorize"; + + // POST + public string GetCapturePath(string transactionId) => $"/v1/transactions/{transactionId}/capture"; + + // POST + public string GetVoidPath(string transactionId) => $"/v1/transactions/{transactionId}/cancel"; + + // POST + public string GetRefundPath(string transactionId) => $"/v1/transactions/{transactionId}/credit"; +} diff --git a/src/VirtoCommerce.Datatrans.Core/Models/DatatransOptions.cs b/src/VirtoCommerce.Datatrans.Core/Models/DatatransOptions.cs index bca3a8c..6bb397d 100644 --- a/src/VirtoCommerce.Datatrans.Core/Models/DatatransOptions.cs +++ b/src/VirtoCommerce.Datatrans.Core/Models/DatatransOptions.cs @@ -18,24 +18,3 @@ public class DatatransOptions public DatatransApiRoutes Routes { get; set; } = new(); } - -public class DatatransApiRoutes -{ - // POST - public string SecureFieldsPath { get; set; } = "/v1/transactions/secureFields"; - - // GET - public string TransactionPath { get; set; } = "/v1/transactions/{transactionId}"; - - // POST - public string AuthorizeAuthenticatedPath { get; set; } = "/v1/transactions/{transactionId}/authorize"; - - // POST - public string CapturePath { get; set; } = "/v1/transactions/{transactionId}/capture"; - - // POST - public string VoidPath { get; set; } = "/v1/transactions/{transactionId}/cancel"; - - // POST - public string RefundPath { get; set; } = "/v1/transactions/{transactionId}/credit"; -} diff --git a/src/VirtoCommerce.Datatrans.Data/Services/DatatransClient.cs b/src/VirtoCommerce.Datatrans.Data/Services/DatatransClient.cs index 7b15211..c8c1af4 100644 --- a/src/VirtoCommerce.Datatrans.Data/Services/DatatransClient.cs +++ b/src/VirtoCommerce.Datatrans.Data/Services/DatatransClient.cs @@ -1,7 +1,6 @@ using System; using System.Net.Http; using System.Text; -using System.Text.Json.Serialization; using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Options; @@ -29,41 +28,41 @@ public Uri BuildStartPaymentUri(string transactionId) public async Task InitTransactionAsync(DatatransInitRequest request, CancellationToken cancellationToken = default) { - var resp = await SendAsync(HttpMethod.Post, _options.Routes.SecureFieldsPath, request, cancellationToken); + var resp = await SendAsync(HttpMethod.Post, _options.Routes.GetSecureFieldsPath(), request, cancellationToken); return ParseResponse(resp); } public async Task GetTransactionAsync(string transactionId, CancellationToken cancellationToken = default) { - var path = _options.Routes.TransactionPath.Replace("{transactionId}", Uri.EscapeDataString(transactionId)); + var path = _options.Routes.GetTransactionPath(transactionId); var resp = await SendAsync(HttpMethod.Get, path, null, cancellationToken); return ParseResponse(resp); } public async Task AuthorizeAuthenticatedAsync(string transactionId, DatatransAuthorizeAuthenticatedRequest request, CancellationToken cancellationToken = default) { - var path = _options.Routes.AuthorizeAuthenticatedPath.Replace("{transactionId}", Uri.EscapeDataString(transactionId)); + var path = _options.Routes.GetAuthorizeAuthenticatedPath(transactionId); var resp = await SendAsync(HttpMethod.Post, path, request, cancellationToken); return ParseResponse(resp); } public async Task CaptureAsync(string transactionId, DatatransCaptureRequest request, CancellationToken cancellationToken = default) { - var path = _options.Routes.CapturePath.Replace("{transactionId}", Uri.EscapeDataString(transactionId)); + var path = _options.Routes.GetCapturePath(transactionId); var resp = await SendAsync(HttpMethod.Post, path, request, cancellationToken); return ParseResponse(resp); } public async Task VoidAsync(string transactionId, CancellationToken cancellationToken = default) { - var path = _options.Routes.VoidPath.Replace("{transactionId}", Uri.EscapeDataString(transactionId)); + var path = _options.Routes.GetVoidPath(transactionId); var resp = await SendAsync(HttpMethod.Post, path, new { }, cancellationToken); return ParseResponse(resp); } public async Task RefundAsync(string transactionId, DatatransRefundRequest request, CancellationToken cancellationToken = default) { - var path = _options.Routes.RefundPath.Replace("{transactionId}", Uri.EscapeDataString(transactionId)); + var path = _options.Routes.GetRefundPath(transactionId); var resp = await SendAsync(HttpMethod.Post, path, request, cancellationToken); return ParseResponse(resp); } From 520f1261e303b1141f023b37de4ed4fc01c53243 Mon Sep 17 00:00:00 2001 From: Basil Kotov Date: Fri, 24 Oct 2025 10:08:28 +0100 Subject: [PATCH 21/29] move returnUrl to settings --- src/VirtoCommerce.Datatrans.Core/ModuleConstants.cs | 8 ++++++++ .../Providers/DatatransPaymentMethod.cs | 9 ++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/VirtoCommerce.Datatrans.Core/ModuleConstants.cs b/src/VirtoCommerce.Datatrans.Core/ModuleConstants.cs index 96e9545..61ac728 100644 --- a/src/VirtoCommerce.Datatrans.Core/ModuleConstants.cs +++ b/src/VirtoCommerce.Datatrans.Core/ModuleConstants.cs @@ -17,12 +17,20 @@ public static class General DefaultValue = true, }; + public static SettingDescriptor ReturnUrl { get; } = new() + { + Name = "VirtoCommerce.Payment.Datatrans.ReturnUrl", + GroupName = "Payment|Datatrans", + ValueType = SettingValueType.ShortText, + DefaultValue = "/account/orders/{orderId}/payment", + }; public static IEnumerable AllGeneralSettings { get { yield return Sandbox; + yield return ReturnUrl; } } } diff --git a/src/VirtoCommerce.Datatrans.Data/Providers/DatatransPaymentMethod.cs b/src/VirtoCommerce.Datatrans.Data/Providers/DatatransPaymentMethod.cs index b3c26d3..52892b0 100644 --- a/src/VirtoCommerce.Datatrans.Data/Providers/DatatransPaymentMethod.cs +++ b/src/VirtoCommerce.Datatrans.Data/Providers/DatatransPaymentMethod.cs @@ -6,12 +6,14 @@ using System.Threading.Tasks; using Newtonsoft.Json; using VirtoCommerce.CoreModule.Core.Currency; +using VirtoCommerce.Datatrans.Core; using VirtoCommerce.Datatrans.Core.Models.External; using VirtoCommerce.Datatrans.Core.Services; using VirtoCommerce.OrdersModule.Core.Model; using VirtoCommerce.PaymentModule.Core.Model; using VirtoCommerce.PaymentModule.Model.Requests; using VirtoCommerce.Platform.Core.Common; +using VirtoCommerce.Platform.Core.Settings; using VirtoCommerce.StoreModule.Core.Model; namespace VirtoCommerce.Datatrans.Data.Providers; @@ -286,7 +288,12 @@ protected virtual async Task CreateInitRequest(ProcessPaym var result = AbstractTypeFactory.TryCreateInstance(); result.Amount = await ToMinorUnits(payment.Currency, payment.Sum); result.Currency = payment.Currency ?? order.Currency; - result.ReturnUrl = $"{url}/account/orders/{order.Id}/payment"; + + var returnUrl = Settings.GetValue(ModuleConstants.Settings.General.ReturnUrl) + ?.Replace("{orderId}", order.Id) + ?.TrimStart('/'); + + result.ReturnUrl = $"{url}/{returnUrl}"; return result; } From cddf9fb91514937af8ee8ee23fd9c8347c55fbc1 Mon Sep 17 00:00:00 2001 From: Basil Kotov Date: Fri, 24 Oct 2025 11:58:01 +0100 Subject: [PATCH 22/29] small fix --- .../Providers/DatatransPaymentMethod.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/VirtoCommerce.Datatrans.Data/Providers/DatatransPaymentMethod.cs b/src/VirtoCommerce.Datatrans.Data/Providers/DatatransPaymentMethod.cs index 52892b0..afc4c67 100644 --- a/src/VirtoCommerce.Datatrans.Data/Providers/DatatransPaymentMethod.cs +++ b/src/VirtoCommerce.Datatrans.Data/Providers/DatatransPaymentMethod.cs @@ -290,8 +290,8 @@ protected virtual async Task CreateInitRequest(ProcessPaym result.Currency = payment.Currency ?? order.Currency; var returnUrl = Settings.GetValue(ModuleConstants.Settings.General.ReturnUrl) - ?.Replace("{orderId}", order.Id) - ?.TrimStart('/'); + .Replace("{orderId}", order.Id) + .TrimStart('/'); result.ReturnUrl = $"{url}/{returnUrl}"; From 08a1e631f37cb58dcf160adb6202eb95938e52c0 Mon Sep 17 00:00:00 2001 From: Basil Kotov Date: Mon, 27 Oct 2025 07:31:42 +0000 Subject: [PATCH 23/29] small fixes --- .../Providers/DatatransPaymentMethod.cs | 10 +++++++--- .../Services/DatatransClient.cs | 5 +++++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/VirtoCommerce.Datatrans.Data/Providers/DatatransPaymentMethod.cs b/src/VirtoCommerce.Datatrans.Data/Providers/DatatransPaymentMethod.cs index afc4c67..d7f49b3 100644 --- a/src/VirtoCommerce.Datatrans.Data/Providers/DatatransPaymentMethod.cs +++ b/src/VirtoCommerce.Datatrans.Data/Providers/DatatransPaymentMethod.cs @@ -307,13 +307,17 @@ protected virtual Task CreateInitRequestResult(Data IsSuccess = initResponse.Error == null, NewPaymentStatus = payment.PaymentStatus, ErrorMessage = initResponse.Error?.Message, - PublicParameters = new() + }; + + if (result.IsSuccess) + { + result.PublicParameters = new() { ["transactionId"] = initResponse.TransactionId, ["clientScript"] = datatransClient.GetSecureFieldsScriptUrl(), ["startUrl"] = datatransClient.BuildStartPaymentUri(initResponse.TransactionId).ToString(), - }, - }; + }; + } return Task.FromResult(result); } diff --git a/src/VirtoCommerce.Datatrans.Data/Services/DatatransClient.cs b/src/VirtoCommerce.Datatrans.Data/Services/DatatransClient.cs index c8c1af4..51eea44 100644 --- a/src/VirtoCommerce.Datatrans.Data/Services/DatatransClient.cs +++ b/src/VirtoCommerce.Datatrans.Data/Services/DatatransClient.cs @@ -21,6 +21,11 @@ public class DatatransClient(IHttpClientFactory httpClientFactory, IOptions Date: Mon, 27 Oct 2025 08:49:24 +0000 Subject: [PATCH 24/29] change json serialization settings --- .../Services/DatatransClient.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/VirtoCommerce.Datatrans.Data/Services/DatatransClient.cs b/src/VirtoCommerce.Datatrans.Data/Services/DatatransClient.cs index 51eea44..61e0233 100644 --- a/src/VirtoCommerce.Datatrans.Data/Services/DatatransClient.cs +++ b/src/VirtoCommerce.Datatrans.Data/Services/DatatransClient.cs @@ -5,6 +5,7 @@ using System.Threading.Tasks; using Microsoft.Extensions.Options; using Newtonsoft.Json; +using Newtonsoft.Json.Serialization; using VirtoCommerce.Datatrans.Core.Models; using VirtoCommerce.Datatrans.Core.Models.External; using VirtoCommerce.Datatrans.Core.Services; @@ -14,6 +15,12 @@ namespace VirtoCommerce.Datatrans.Data.Services; public class DatatransClient(IHttpClientFactory httpClientFactory, IOptions options) : IDatatransClient { + private static readonly JsonSerializerSettings _serializerSettings = new() + { + ContractResolver = new CamelCasePropertyNamesContractResolver(), + NullValueHandling = NullValueHandling.Ignore + }; + private readonly DatatransOptions _options = options.Value; private string BaseStartUrl => _options.UseSandbox ? _options.SandboxStartUrlBase : _options.ProductionStartUrlBase; @@ -78,7 +85,7 @@ private async Task SendAsync(HttpMethod method, string path, object body if (body is not null) { - var json = JsonConvert.SerializeObject(body); + var json = JsonConvert.SerializeObject(body, _serializerSettings); msg.Content = new StringContent(json, Encoding.UTF8, "application/json"); } From f2f8ae282c70801ec1bbd37ec7e92dabc77c26ad Mon Sep 17 00:00:00 2001 From: Basil Kotov Date: Wed, 29 Oct 2025 12:05:44 +0000 Subject: [PATCH 25/29] use fallback for minor currency units --- .../Providers/DatatransPaymentMethod.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/VirtoCommerce.Datatrans.Data/Providers/DatatransPaymentMethod.cs b/src/VirtoCommerce.Datatrans.Data/Providers/DatatransPaymentMethod.cs index d7f49b3..c8a3f23 100644 --- a/src/VirtoCommerce.Datatrans.Data/Providers/DatatransPaymentMethod.cs +++ b/src/VirtoCommerce.Datatrans.Data/Providers/DatatransPaymentMethod.cs @@ -351,8 +351,10 @@ private static string GetTransactionId(PaymentRequestBase context) private async Task ToMinorUnits(string currencyCode, decimal amount) { const int @base = 10; - var currency = (await currencyService.GetAllCurrenciesAsync()).First(x => x.Code == currencyCode); - var multiplier = (decimal)Math.Pow(@base, currency.DecimalDigits); // 1, 100, or 1000 + var currency = (await currencyService.GetAllCurrenciesAsync()).FirstOrDefault(x => x.Code.EqualsIgnoreCase(currencyCode)); + var multiplier = currency != null + ? (decimal)Math.Pow(@base, currency.DecimalDigits) // 1, 100, or 1000 + : 100m; return (long)Math.Round(amount * multiplier, MidpointRounding.AwayFromZero); } From 01c7cddf45462442d216f01363c3ef9debb64a67 Mon Sep 17 00:00:00 2001 From: Basil Kotov Date: Wed, 29 Oct 2025 12:08:46 +0000 Subject: [PATCH 26/29] fix currency --- .../Providers/DatatransPaymentMethod.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/VirtoCommerce.Datatrans.Data/Providers/DatatransPaymentMethod.cs b/src/VirtoCommerce.Datatrans.Data/Providers/DatatransPaymentMethod.cs index c8a3f23..313c28e 100644 --- a/src/VirtoCommerce.Datatrans.Data/Providers/DatatransPaymentMethod.cs +++ b/src/VirtoCommerce.Datatrans.Data/Providers/DatatransPaymentMethod.cs @@ -286,8 +286,11 @@ protected virtual async Task CreateInitRequest(ProcessPaym var url = (store.SecureUrl.IsNullOrEmpty() ? store.Url : store.SecureUrl)?.TrimEnd('/'); var result = AbstractTypeFactory.TryCreateInstance(); - result.Amount = await ToMinorUnits(payment.Currency, payment.Sum); - result.Currency = payment.Currency ?? order.Currency; + + var currency = payment.Currency.EmptyToNull() ?? order.Currency; + + result.Amount = await ToMinorUnits(currency, payment.Sum); + result.Currency = currency; var returnUrl = Settings.GetValue(ModuleConstants.Settings.General.ReturnUrl) .Replace("{orderId}", order.Id) From 8cb0132c05effd184788512e0f8b34f303321af9 Mon Sep 17 00:00:00 2001 From: Basil Kotov Date: Thu, 30 Oct 2025 07:16:52 +0000 Subject: [PATCH 27/29] decimal point --- .../Providers/DatatransPaymentMethod.cs | 30 +++++++++++++++---- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/src/VirtoCommerce.Datatrans.Data/Providers/DatatransPaymentMethod.cs b/src/VirtoCommerce.Datatrans.Data/Providers/DatatransPaymentMethod.cs index 313c28e..b32514a 100644 --- a/src/VirtoCommerce.Datatrans.Data/Providers/DatatransPaymentMethod.cs +++ b/src/VirtoCommerce.Datatrans.Data/Providers/DatatransPaymentMethod.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Collections.Specialized; +using System.Globalization; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -352,14 +353,33 @@ private static string GetTransactionId(PaymentRequestBase context) } private async Task ToMinorUnits(string currencyCode, decimal amount) + { + var multiplier = await GetMultiplier(currencyCode); + return (long)Math.Round(amount * multiplier, MidpointRounding.AwayFromZero); + } + + private async Task GetMultiplier(string currencyCode) { const int @base = 10; - var currency = (await currencyService.GetAllCurrenciesAsync()).FirstOrDefault(x => x.Code.EqualsIgnoreCase(currencyCode)); - var multiplier = currency != null - ? (decimal)Math.Pow(@base, currency.DecimalDigits) // 1, 100, or 1000 - : 100m; + int digits; - return (long)Math.Round(amount * multiplier, MidpointRounding.AwayFromZero); + var culture = CultureInfo + .GetCultures(CultureTypes.SpecificCultures) + .Select(c => new { c, Region = new RegionInfo(c.LCID) }) + .FirstOrDefault(x => x.Region.ISOCurrencySymbol == currencyCode); + + if (culture != null) + { + digits = culture.c.NumberFormat.CurrencyDecimalDigits; + } + else + { + var currency = (await currencyService.GetAllCurrenciesAsync()).FirstOrDefault(x => x.Code.EqualsIgnoreCase(currencyCode)); + digits = currency?.DecimalDigits ?? 2; + } + + var multiplier = (decimal)Math.Pow(@base, digits); // 1, 100, or 1000 + return multiplier; } #endregion From 0fba4d7aa26dc15b576204ffd5a33fcaa7ba6884 Mon Sep 17 00:00:00 2001 From: Basil Kotov Date: Thu, 30 Oct 2025 07:42:13 +0000 Subject: [PATCH 28/29] revert decimal point --- .../Providers/DatatransPaymentMethod.cs | 30 ++++--------------- 1 file changed, 5 insertions(+), 25 deletions(-) diff --git a/src/VirtoCommerce.Datatrans.Data/Providers/DatatransPaymentMethod.cs b/src/VirtoCommerce.Datatrans.Data/Providers/DatatransPaymentMethod.cs index b32514a..313c28e 100644 --- a/src/VirtoCommerce.Datatrans.Data/Providers/DatatransPaymentMethod.cs +++ b/src/VirtoCommerce.Datatrans.Data/Providers/DatatransPaymentMethod.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Collections.Specialized; -using System.Globalization; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -353,33 +352,14 @@ private static string GetTransactionId(PaymentRequestBase context) } private async Task ToMinorUnits(string currencyCode, decimal amount) - { - var multiplier = await GetMultiplier(currencyCode); - return (long)Math.Round(amount * multiplier, MidpointRounding.AwayFromZero); - } - - private async Task GetMultiplier(string currencyCode) { const int @base = 10; - int digits; - - var culture = CultureInfo - .GetCultures(CultureTypes.SpecificCultures) - .Select(c => new { c, Region = new RegionInfo(c.LCID) }) - .FirstOrDefault(x => x.Region.ISOCurrencySymbol == currencyCode); - - if (culture != null) - { - digits = culture.c.NumberFormat.CurrencyDecimalDigits; - } - else - { - var currency = (await currencyService.GetAllCurrenciesAsync()).FirstOrDefault(x => x.Code.EqualsIgnoreCase(currencyCode)); - digits = currency?.DecimalDigits ?? 2; - } + var currency = (await currencyService.GetAllCurrenciesAsync()).FirstOrDefault(x => x.Code.EqualsIgnoreCase(currencyCode)); + var multiplier = currency != null + ? (decimal)Math.Pow(@base, currency.DecimalDigits) // 1, 100, or 1000 + : 100m; - var multiplier = (decimal)Math.Pow(@base, digits); // 1, 100, or 1000 - return multiplier; + return (long)Math.Round(amount * multiplier, MidpointRounding.AwayFromZero); } #endregion From 60cdcd6ecea2c02ced89b629c163bba028a71617 Mon Sep 17 00:00:00 2001 From: Basil Kotov Date: Fri, 31 Oct 2025 07:18:55 +0000 Subject: [PATCH 29/29] fix error handling in refund and capture --- .../Providers/DatatransPaymentMethod.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/VirtoCommerce.Datatrans.Data/Providers/DatatransPaymentMethod.cs b/src/VirtoCommerce.Datatrans.Data/Providers/DatatransPaymentMethod.cs index 313c28e..e791a51 100644 --- a/src/VirtoCommerce.Datatrans.Data/Providers/DatatransPaymentMethod.cs +++ b/src/VirtoCommerce.Datatrans.Data/Providers/DatatransPaymentMethod.cs @@ -190,7 +190,7 @@ protected virtual async Task CaptureProcessPaymentA payment.OuterId = transactionId; - if (response.Error != null) + if (response.Error == null) { transaction = await datatransClient.GetTransactionAsync(transactionId); payment.PaymentStatus = ConvertStatus(transaction.Status); @@ -257,7 +257,7 @@ protected virtual async Task RefundProcessPaymentAsy var response = await datatransClient.RefundAsync(transactionId, request); - if (response.Error != null) + if (response.Error == null) { transaction = await datatransClient.GetTransactionAsync(transactionId); payment.PaymentStatus = ConvertStatus(transaction.Status);