Compare commits
101
Commits
97eec30f20
...
1.44.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
50a8a59d92 | ||
|
|
70c6e0bfbc | ||
|
|
b70d9559b0 | ||
|
|
032b9e1818 | ||
|
|
424c1c6f8c | ||
|
|
81d5e8f07c | ||
|
|
7d5e9a18d8 | ||
|
|
20a53942b5 | ||
|
|
3656223b5f | ||
|
|
9edb2aa4aa | ||
|
|
ccf30ac36b | ||
|
|
6ed023f2cf | ||
|
|
d6fdf1b9c8 | ||
|
|
2c9f5a846c | ||
|
|
89a343a85f | ||
|
|
41f7c05be3 | ||
|
|
52d204e286 | ||
|
|
1a03355e84 | ||
|
|
f245bc94e1 | ||
|
|
7743c3178e | ||
|
|
da141311ff | ||
|
|
ab3d8e6e9a | ||
|
|
97bde73777 | ||
|
|
db4c348288 | ||
|
|
a65e926a53 | ||
|
|
6683234642 | ||
|
|
1471d9e597 | ||
|
|
6ddbb9479a | ||
|
|
e978aa17f8 | ||
|
|
6c7349a0f8 | ||
|
|
a31f75c5ef | ||
|
|
e97fd6cd3f | ||
|
|
7f4246ac63 | ||
|
|
184c7c252a | ||
|
|
dfc62c8fe1 | ||
|
|
bfe8c458d6 | ||
|
|
0f91f102e5 | ||
|
|
e6e0475db1 | ||
|
|
be9c83c8a3 | ||
|
|
65687d231e | ||
|
|
5090c60797 | ||
|
|
4523ef6151 | ||
|
|
9432252e15 | ||
|
|
36b3656886 | ||
|
|
47111a1a3a | ||
|
|
f606b8fd3c | ||
|
|
2610275bef | ||
|
|
134d8429c0 | ||
|
|
42001998d6 | ||
|
|
a42c51d7b2 | ||
|
|
6eb3d50375 | ||
|
|
26075cd9a7 | ||
|
|
4deb732804 | ||
|
|
cecd9f90e9 | ||
|
|
73ba41beaf | ||
|
|
e8e9a85c57 | ||
|
|
394429677e | ||
|
|
20d9387d0b | ||
|
|
32d1019eb5 | ||
|
|
9f6d0ccaa0 | ||
|
|
275befc258 | ||
|
|
1acbc4d213 | ||
|
|
193496bbf9 | ||
|
|
8c99668fac | ||
|
|
a015801423 | ||
|
|
ad44f46204 | ||
|
|
9d64b5e76d | ||
|
|
49d999c1e3 | ||
|
|
fd6b8cd965 | ||
|
|
9ed4777a18 | ||
|
|
ff34326a53 | ||
|
|
0cf44f68cc | ||
|
|
6db6228bc9 | ||
|
|
41ed5a4288 | ||
|
|
61118c6223 | ||
|
|
bbcba5e06c | ||
|
|
bd852b30c3 | ||
|
|
502cc326dd | ||
|
|
37e2116aaf | ||
|
|
4675d4c5fc | ||
|
|
60980292a2 | ||
|
|
f80bb2fff9 | ||
|
|
df1e31cc86 | ||
|
|
6767906b0d | ||
|
|
8cb1943ac8 | ||
|
|
a344af4498 | ||
|
|
c95efd1faf | ||
|
|
3065d8e27a | ||
|
|
d998aac7c4 | ||
|
|
33633502e2 | ||
|
|
fe1d78342b | ||
|
|
acc0d44c7c | ||
|
|
c6ce9c85df | ||
|
|
6ca87413d6 | ||
|
|
4321b03735 | ||
|
|
83f51c6a23 | ||
|
|
4b822c63b2 | ||
|
|
f5c9557f59 | ||
|
|
33112dcf79 | ||
|
|
604d21162a | ||
|
|
47534ce671 |
+53
@@ -0,0 +1,53 @@
|
|||||||
|
---
|
||||||
|
kind: pipeline
|
||||||
|
type: docker
|
||||||
|
name: litecharms-nuget-libraries
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: build
|
||||||
|
image: mcr.microsoft.com/dotnet/sdk:10.0
|
||||||
|
commands:
|
||||||
|
- dotnet restore
|
||||||
|
- dotnet build -c Release --no-restore
|
||||||
|
|
||||||
|
- name: pack-and-publish
|
||||||
|
image: mcr.microsoft.com/dotnet/sdk:10.0
|
||||||
|
environment:
|
||||||
|
NEXUS_KEY: { from_secret: nexus_api_key }
|
||||||
|
NEXUS_URL: https://nexus.khongisa.co.za/repository/nuget-hosted/
|
||||||
|
VERSION: 1.${DRONE_BUILD_NUMBER}.0
|
||||||
|
commands:
|
||||||
|
- dotnet pack LiteCharms.Features/LiteCharms.Features.csproj -c Release -p:PackageVersion=$VERSION -o dist/
|
||||||
|
- dotnet nuget push dist/LiteCharms.Features.$VERSION.nupkg --api-key $NEXUS_KEY --source $NEXUS_URL
|
||||||
|
- dotnet pack LiteCharms.Features.TechShop/LiteCharms.Features.TechShop.csproj -c Release -p:PackageVersion=$VERSION -o dist/
|
||||||
|
- dotnet nuget push dist/LiteCharms.Features.TechShop.$VERSION.nupkg --api-key $NEXUS_KEY --source $NEXUS_URL
|
||||||
|
|
||||||
|
- name: gitea-tag-release
|
||||||
|
image: alpine/git
|
||||||
|
environment:
|
||||||
|
GITEA_TOKEN: { from_secret: git_token }
|
||||||
|
GITEA_USER: { from_secret: git_username }
|
||||||
|
GITEA_PASS: { from_secret: git_password }
|
||||||
|
VERSION: 1.${DRONE_BUILD_NUMBER}.0
|
||||||
|
commands:
|
||||||
|
- echo "169.255.58.144 gitea.khongisa.co.za" >> /etc/hosts
|
||||||
|
- apk add --no-cache curl
|
||||||
|
- git remote set-url origin https://$${GITEA_USER}:$${GITEA_PASS}@gitea.khongisa.co.za/litecharms/components.git
|
||||||
|
- git tag $VERSION
|
||||||
|
- git push origin $VERSION
|
||||||
|
- |
|
||||||
|
curl -X POST "https://gitea.khongisa.co.za/api/v1/repos/litecharms/components/releases" \
|
||||||
|
-H "Authorization: token $${GITEA_TOKEN}" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d "{
|
||||||
|
\"tag_name\": \"$VERSION\",
|
||||||
|
\"target_commitish\": \"${DRONE_COMMIT_SHA}\",
|
||||||
|
\"name\": \"Library Suite $VERSION\",
|
||||||
|
\"body\": \"### Published NuGet Packages\nAll packages versioned as **$VERSION**:\n* LiteCharms.Features\n* LiteCharms.Features.TechShop\n\n[View in Nexus](https://nexus.khongisa.co.za/repository/nuget-group/)\",
|
||||||
|
\"draft\": false,
|
||||||
|
\"prerelease\": false
|
||||||
|
}"
|
||||||
|
|
||||||
|
trigger:
|
||||||
|
event:
|
||||||
|
- pull_request
|
||||||
+248
@@ -0,0 +1,248 @@
|
|||||||
|
# Remove the line below if you want to inherit .editorconfig settings from higher directories
|
||||||
|
root = true
|
||||||
|
|
||||||
|
# C# files
|
||||||
|
[*.cs]
|
||||||
|
|
||||||
|
#### Core EditorConfig Options ####
|
||||||
|
|
||||||
|
# Indentation and spacing
|
||||||
|
indent_size = 4
|
||||||
|
indent_style = space
|
||||||
|
tab_width = 4
|
||||||
|
|
||||||
|
# New line preferences
|
||||||
|
end_of_line = crlf
|
||||||
|
insert_final_newline = false
|
||||||
|
|
||||||
|
#### .NET Code Actions ####
|
||||||
|
|
||||||
|
# Type members
|
||||||
|
dotnet_hide_advanced_members = false
|
||||||
|
dotnet_member_insertion_location = with_other_members_of_the_same_kind
|
||||||
|
dotnet_property_generation_behavior = prefer_throwing_properties
|
||||||
|
|
||||||
|
# Symbol search
|
||||||
|
dotnet_search_reference_assemblies = true
|
||||||
|
|
||||||
|
#### .NET Coding Conventions ####
|
||||||
|
|
||||||
|
# Organize usings
|
||||||
|
dotnet_separate_import_directive_groups = false
|
||||||
|
dotnet_sort_system_directives_first = false
|
||||||
|
file_header_template = unset
|
||||||
|
|
||||||
|
# this. and Me. preferences
|
||||||
|
dotnet_style_qualification_for_event = false
|
||||||
|
dotnet_style_qualification_for_field = false
|
||||||
|
dotnet_style_qualification_for_method = false
|
||||||
|
dotnet_style_qualification_for_property = false
|
||||||
|
|
||||||
|
# Language keywords vs BCL types preferences
|
||||||
|
dotnet_style_predefined_type_for_locals_parameters_members = true
|
||||||
|
dotnet_style_predefined_type_for_member_access = true
|
||||||
|
|
||||||
|
# Parentheses preferences
|
||||||
|
dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity
|
||||||
|
dotnet_style_parentheses_in_other_binary_operators = always_for_clarity
|
||||||
|
dotnet_style_parentheses_in_other_operators = never_if_unnecessary
|
||||||
|
dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity
|
||||||
|
|
||||||
|
# Modifier preferences
|
||||||
|
dotnet_style_require_accessibility_modifiers = for_non_interface_members
|
||||||
|
|
||||||
|
# Expression-level preferences
|
||||||
|
dotnet_prefer_system_hash_code = true
|
||||||
|
dotnet_style_coalesce_expression = true
|
||||||
|
dotnet_style_collection_initializer = true
|
||||||
|
dotnet_style_explicit_tuple_names = true
|
||||||
|
dotnet_style_namespace_match_folder = true
|
||||||
|
dotnet_style_null_propagation = true
|
||||||
|
dotnet_style_object_initializer = true
|
||||||
|
dotnet_style_operator_placement_when_wrapping = beginning_of_line
|
||||||
|
dotnet_style_prefer_auto_properties = true
|
||||||
|
dotnet_style_prefer_collection_expression = when_types_loosely_match
|
||||||
|
dotnet_style_prefer_compound_assignment = true
|
||||||
|
dotnet_style_prefer_conditional_expression_over_assignment = true
|
||||||
|
dotnet_style_prefer_conditional_expression_over_return = true
|
||||||
|
dotnet_style_prefer_foreach_explicit_cast_in_source = when_strongly_typed
|
||||||
|
dotnet_style_prefer_inferred_anonymous_type_member_names = true
|
||||||
|
dotnet_style_prefer_inferred_tuple_names = true
|
||||||
|
dotnet_style_prefer_is_null_check_over_reference_equality_method = true
|
||||||
|
dotnet_style_prefer_non_hidden_explicit_cast_in_source = true
|
||||||
|
dotnet_style_prefer_simplified_boolean_expressions = true
|
||||||
|
dotnet_style_prefer_simplified_interpolation = true
|
||||||
|
|
||||||
|
# Field preferences
|
||||||
|
dotnet_style_readonly_field = true
|
||||||
|
|
||||||
|
# Parameter preferences
|
||||||
|
dotnet_code_quality_unused_parameters = all
|
||||||
|
|
||||||
|
# Suppression preferences
|
||||||
|
dotnet_remove_unnecessary_suppression_exclusions = none
|
||||||
|
|
||||||
|
# New line preferences
|
||||||
|
dotnet_style_allow_multiple_blank_lines_experimental = true
|
||||||
|
dotnet_style_allow_statement_immediately_after_block_experimental = true
|
||||||
|
|
||||||
|
#### C# Coding Conventions ####
|
||||||
|
|
||||||
|
# var preferences
|
||||||
|
csharp_style_var_elsewhere = false
|
||||||
|
csharp_style_var_for_built_in_types = false
|
||||||
|
csharp_style_var_when_type_is_apparent = false
|
||||||
|
|
||||||
|
# Expression-bodied members
|
||||||
|
csharp_style_expression_bodied_accessors = true
|
||||||
|
csharp_style_expression_bodied_constructors = false
|
||||||
|
csharp_style_expression_bodied_indexers = true
|
||||||
|
csharp_style_expression_bodied_lambdas = true
|
||||||
|
csharp_style_expression_bodied_local_functions = true
|
||||||
|
csharp_style_expression_bodied_methods = false
|
||||||
|
csharp_style_expression_bodied_operators = false
|
||||||
|
csharp_style_expression_bodied_properties = true
|
||||||
|
|
||||||
|
# Pattern matching preferences
|
||||||
|
csharp_style_pattern_matching_over_as_with_null_check = true
|
||||||
|
csharp_style_pattern_matching_over_is_with_cast_check = true
|
||||||
|
csharp_style_prefer_extended_property_pattern = true
|
||||||
|
csharp_style_prefer_not_pattern = true
|
||||||
|
csharp_style_prefer_pattern_matching = true
|
||||||
|
csharp_style_prefer_switch_expression = true
|
||||||
|
|
||||||
|
# Null-checking preferences
|
||||||
|
csharp_style_conditional_delegate_call = true
|
||||||
|
|
||||||
|
# Modifier preferences
|
||||||
|
csharp_prefer_static_anonymous_function = true
|
||||||
|
csharp_prefer_static_local_function = true
|
||||||
|
csharp_preferred_modifier_order = public,private,protected,internal,file,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,required,volatile,async
|
||||||
|
csharp_style_prefer_readonly_struct = true
|
||||||
|
csharp_style_prefer_readonly_struct_member = true
|
||||||
|
|
||||||
|
# Code-block preferences
|
||||||
|
csharp_prefer_braces = true
|
||||||
|
csharp_prefer_simple_using_statement = true
|
||||||
|
csharp_prefer_system_threading_lock = true
|
||||||
|
csharp_style_namespace_declarations = block_scoped
|
||||||
|
csharp_style_prefer_method_group_conversion = true
|
||||||
|
csharp_style_prefer_primary_constructors = true
|
||||||
|
csharp_style_prefer_simple_property_accessors = true
|
||||||
|
csharp_style_prefer_top_level_statements = true
|
||||||
|
|
||||||
|
# Expression-level preferences
|
||||||
|
csharp_prefer_simple_default_expression = true
|
||||||
|
csharp_style_deconstructed_variable_declaration = true
|
||||||
|
csharp_style_implicit_object_creation_when_type_is_apparent = true
|
||||||
|
csharp_style_inlined_variable_declaration = true
|
||||||
|
csharp_style_prefer_implicitly_typed_lambda_expression = true
|
||||||
|
csharp_style_prefer_index_operator = true
|
||||||
|
csharp_style_prefer_local_over_anonymous_function = true
|
||||||
|
csharp_style_prefer_null_check_over_type_check = true
|
||||||
|
csharp_style_prefer_range_operator = true
|
||||||
|
csharp_style_prefer_tuple_swap = true
|
||||||
|
csharp_style_prefer_unbound_generic_type_in_nameof = true
|
||||||
|
csharp_style_prefer_utf8_string_literals = true
|
||||||
|
csharp_style_throw_expression = true
|
||||||
|
csharp_style_unused_value_assignment_preference = discard_variable
|
||||||
|
csharp_style_unused_value_expression_statement_preference = discard_variable
|
||||||
|
|
||||||
|
# 'using' directive preferences
|
||||||
|
csharp_using_directive_placement = outside_namespace
|
||||||
|
|
||||||
|
# New line preferences
|
||||||
|
csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = true
|
||||||
|
csharp_style_allow_blank_line_after_token_in_arrow_expression_clause_experimental = true
|
||||||
|
csharp_style_allow_blank_line_after_token_in_conditional_expression_experimental = true
|
||||||
|
csharp_style_allow_blank_lines_between_consecutive_braces_experimental = true
|
||||||
|
csharp_style_allow_embedded_statements_on_same_line_experimental = true
|
||||||
|
|
||||||
|
#### C# Formatting Rules ####
|
||||||
|
|
||||||
|
# New line preferences
|
||||||
|
csharp_new_line_before_catch = true
|
||||||
|
csharp_new_line_before_else = true
|
||||||
|
csharp_new_line_before_finally = true
|
||||||
|
csharp_new_line_before_members_in_anonymous_types = true
|
||||||
|
csharp_new_line_before_members_in_object_initializers = true
|
||||||
|
csharp_new_line_before_open_brace = all
|
||||||
|
csharp_new_line_between_query_expression_clauses = true
|
||||||
|
|
||||||
|
# Indentation preferences
|
||||||
|
csharp_indent_block_contents = true
|
||||||
|
csharp_indent_braces = false
|
||||||
|
csharp_indent_case_contents = true
|
||||||
|
csharp_indent_case_contents_when_block = true
|
||||||
|
csharp_indent_labels = one_less_than_current
|
||||||
|
csharp_indent_switch_labels = true
|
||||||
|
|
||||||
|
# Space preferences
|
||||||
|
csharp_space_after_cast = false
|
||||||
|
csharp_space_after_colon_in_inheritance_clause = true
|
||||||
|
csharp_space_after_comma = true
|
||||||
|
csharp_space_after_dot = false
|
||||||
|
csharp_space_after_keywords_in_control_flow_statements = true
|
||||||
|
csharp_space_after_semicolon_in_for_statement = true
|
||||||
|
csharp_space_around_binary_operators = before_and_after
|
||||||
|
csharp_space_around_declaration_statements = false
|
||||||
|
csharp_space_before_colon_in_inheritance_clause = true
|
||||||
|
csharp_space_before_comma = false
|
||||||
|
csharp_space_before_dot = false
|
||||||
|
csharp_space_before_open_square_brackets = false
|
||||||
|
csharp_space_before_semicolon_in_for_statement = false
|
||||||
|
csharp_space_between_empty_square_brackets = false
|
||||||
|
csharp_space_between_method_call_empty_parameter_list_parentheses = false
|
||||||
|
csharp_space_between_method_call_name_and_opening_parenthesis = false
|
||||||
|
csharp_space_between_method_call_parameter_list_parentheses = false
|
||||||
|
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
|
||||||
|
csharp_space_between_method_declaration_name_and_open_parenthesis = false
|
||||||
|
csharp_space_between_method_declaration_parameter_list_parentheses = false
|
||||||
|
csharp_space_between_parentheses = false
|
||||||
|
csharp_space_between_square_brackets = false
|
||||||
|
|
||||||
|
# Wrapping preferences
|
||||||
|
csharp_preserve_single_line_blocks = true
|
||||||
|
csharp_preserve_single_line_statements = true
|
||||||
|
|
||||||
|
#### Naming styles ####
|
||||||
|
|
||||||
|
# Naming rules
|
||||||
|
|
||||||
|
dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion
|
||||||
|
dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface
|
||||||
|
dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i
|
||||||
|
|
||||||
|
dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion
|
||||||
|
dotnet_naming_rule.types_should_be_pascal_case.symbols = types
|
||||||
|
dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case
|
||||||
|
|
||||||
|
dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion
|
||||||
|
dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members
|
||||||
|
dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case
|
||||||
|
|
||||||
|
# Symbol specifications
|
||||||
|
|
||||||
|
dotnet_naming_symbols.interface.applicable_kinds = interface
|
||||||
|
dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
|
||||||
|
dotnet_naming_symbols.interface.required_modifiers =
|
||||||
|
|
||||||
|
dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum
|
||||||
|
dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
|
||||||
|
dotnet_naming_symbols.types.required_modifiers =
|
||||||
|
|
||||||
|
dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method
|
||||||
|
dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
|
||||||
|
dotnet_naming_symbols.non_field_members.required_modifiers =
|
||||||
|
|
||||||
|
# Naming styles
|
||||||
|
|
||||||
|
dotnet_naming_style.pascal_case.required_prefix =
|
||||||
|
dotnet_naming_style.pascal_case.required_suffix =
|
||||||
|
dotnet_naming_style.pascal_case.word_separator =
|
||||||
|
dotnet_naming_style.pascal_case.capitalization = pascal_case
|
||||||
|
|
||||||
|
dotnet_naming_style.begins_with_i.required_prefix = I
|
||||||
|
dotnet_naming_style.begins_with_i.required_suffix =
|
||||||
|
dotnet_naming_style.begins_with_i.word_separator =
|
||||||
|
dotnet_naming_style.begins_with_i.capitalization = pascal_case
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
namespace LiteCharms.Entities.Configuration;
|
|
||||||
|
|
||||||
public class OrderConfiguration : IEntityTypeConfiguration<Order>
|
|
||||||
{
|
|
||||||
public void Configure(EntityTypeBuilder<Order> builder)
|
|
||||||
{
|
|
||||||
builder.ToTable(nameof(Order));
|
|
||||||
|
|
||||||
builder.HasKey(f => f.Id);
|
|
||||||
builder.Property(f => f.CreatedAt).ValueGeneratedOnAdd();
|
|
||||||
builder.Property(f => f.UpdatedAt).IsRequired(false).ValueGeneratedOnUpdate();
|
|
||||||
builder.Property(f => f.CustomerId).IsRequired();
|
|
||||||
builder.Property(f => f.RefundId).IsRequired(false);
|
|
||||||
builder.Property(f => f.ProductPriceId).IsRequired();
|
|
||||||
builder.Property(f => f.Status).HasConversion<int>().IsRequired();
|
|
||||||
builder.Property(f => f.Notes).HasColumnType("jsonb").IsRequired(false);
|
|
||||||
|
|
||||||
builder.HasOne(f => f.ProductPrice)
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey(f => f.ProductPriceId)
|
|
||||||
.OnDelete(DeleteBehavior.Restrict);
|
|
||||||
|
|
||||||
builder.HasOne(f => f.Customer)
|
|
||||||
.WithMany(f => f.Orders)
|
|
||||||
.HasForeignKey(f => f.CustomerId)
|
|
||||||
.OnDelete(DeleteBehavior.Restrict);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
namespace LiteCharms.Entities.Configuration;
|
|
||||||
|
|
||||||
public class ProductConfiguration : IEntityTypeConfiguration<Product>
|
|
||||||
{
|
|
||||||
public void Configure(EntityTypeBuilder<Product> builder)
|
|
||||||
{
|
|
||||||
builder.ToTable(nameof(Product));
|
|
||||||
|
|
||||||
builder.HasKey(f => f.Id);
|
|
||||||
builder.Property(f => f.Name).IsRequired();
|
|
||||||
builder.Property(f => f.Description).IsRequired();
|
|
||||||
builder.Property(f => f.Active).HasDefaultValue(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
using LiteCharms.Entities.Configuration;
|
|
||||||
|
|
||||||
namespace LiteCharms.Entities;
|
|
||||||
|
|
||||||
[EntityTypeConfiguration<CustomerConfiguration, Customer>]
|
|
||||||
public class Customer : Models.Customer
|
|
||||||
{
|
|
||||||
public virtual ICollection<Lead>? Leads { get; set; }
|
|
||||||
|
|
||||||
public virtual ICollection<Order>? Orders { get; set; }
|
|
||||||
}
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<TargetFramework>net10.0</TargetFramework>
|
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
|
||||||
<Nullable>enable</Nullable>
|
|
||||||
<SignAssembly>True</SignAssembly>
|
|
||||||
<AssemblyOriginatorKeyFile>..\LiteCharms.snk</AssemblyOriginatorKeyFile>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<!-- Nuget Package Details -->
|
|
||||||
<PropertyGroup>
|
|
||||||
<PackageId>LiteCharms.Entities</PackageId>
|
|
||||||
<Version>1.0.2</Version>
|
|
||||||
<Authors>Khwezi Mngoma</Authors>
|
|
||||||
<Company>Lite Charms (PTY) Ltd</Company>
|
|
||||||
<Description>Shared entities for Lite Charms applications.</Description>
|
|
||||||
<PackageProjectUrl>https://gitea.khongisa.co.za/litecharms/components</PackageProjectUrl>
|
|
||||||
<RepositoryUrl>https://gitea.khongisa.co.za/litecharms/components.git</RepositoryUrl>
|
|
||||||
<RepositoryType>git</RepositoryType>
|
|
||||||
<PackageLicenseFile>LICENSE</PackageLicenseFile>
|
|
||||||
<PackageTags>utility;dotnet</PackageTags>
|
|
||||||
<PackageIcon>icon.png</PackageIcon>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<None Include="..\LICENSE" Pack="true" PackagePath="\"/>
|
|
||||||
<None Include="..\icon.png" Pack="true" PackagePath="\" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<!-- Database -->
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="10.0.7" />
|
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="10.0.7" />
|
|
||||||
|
|
||||||
<!-- Global Usings -->
|
|
||||||
<Using Include="Microsoft.EntityFrameworkCore" />
|
|
||||||
<Using Include="Microsoft.EntityFrameworkCore.Metadata.Builders" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<ProjectReference Include="..\LiteCharms.Models\LiteCharms.Models.csproj" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
using LiteCharms.Entities.Configuration;
|
|
||||||
|
|
||||||
namespace LiteCharms.Entities;
|
|
||||||
|
|
||||||
[EntityTypeConfiguration<OrderConfiguration, Order>]
|
|
||||||
public class Order : Models.Order
|
|
||||||
{
|
|
||||||
public virtual OrderRefund? Refund { get; set; }
|
|
||||||
|
|
||||||
public virtual Customer? Customer { get; set; }
|
|
||||||
|
|
||||||
public virtual ProductPrice? ProductPrice { get; set; }
|
|
||||||
}
|
|
||||||
@@ -1,94 +0,0 @@
|
|||||||
using LiteCharms.Models;
|
|
||||||
|
|
||||||
namespace LiteCharms.Extensions;
|
|
||||||
|
|
||||||
public static class EntityModeMappers
|
|
||||||
{
|
|
||||||
public static Customer ToModel(this Entities.Customer entity) =>
|
|
||||||
new()
|
|
||||||
{
|
|
||||||
Id = entity.Id,
|
|
||||||
CreatedAt = entity.CreatedAt,
|
|
||||||
UpdatedAt = entity.UpdatedAt,
|
|
||||||
Active = entity.Active,
|
|
||||||
Address = entity.Address,
|
|
||||||
City = entity.City,
|
|
||||||
Company = entity.Company,
|
|
||||||
Country = entity.Country,
|
|
||||||
Discord = entity.Discord,
|
|
||||||
Email = entity.Email,
|
|
||||||
LastName = entity.LastName,
|
|
||||||
LinkedIn = entity.LinkedIn,
|
|
||||||
Name = entity.Name,
|
|
||||||
Phone = entity.Phone,
|
|
||||||
PostalCode = entity.PostalCode,
|
|
||||||
Region = entity.Region,
|
|
||||||
Slack = entity.Slack,
|
|
||||||
Tax = entity.Tax,
|
|
||||||
Website = entity.Website,
|
|
||||||
Whatsapp = entity.Whatsapp
|
|
||||||
};
|
|
||||||
|
|
||||||
public static Lead ToModel(this Entities.Lead entity) =>
|
|
||||||
new()
|
|
||||||
{
|
|
||||||
Id = entity.Id,
|
|
||||||
CreatedAt = entity.CreatedAt,
|
|
||||||
UpdatedAt = entity.UpdatedAt,
|
|
||||||
AdGroupId = entity.AdGroupId,
|
|
||||||
AdName = entity.AdName,
|
|
||||||
AppClickId = entity.AppClickId,
|
|
||||||
AttributionHash = entity.AttributionHash,
|
|
||||||
CampaignId = entity.CampaignId,
|
|
||||||
ClickLocation = entity.ClickLocation,
|
|
||||||
CustomerId = entity.CustomerId,
|
|
||||||
FeedItemId = entity.FeedItemId,
|
|
||||||
GoogleClickId = entity.GoogleClickId,
|
|
||||||
TargetId = entity.TargetId,
|
|
||||||
WebClickId = entity.WebClickId,
|
|
||||||
Status = entity.Status
|
|
||||||
};
|
|
||||||
|
|
||||||
public static Order ToModel(this Entities.Order entity) =>
|
|
||||||
new()
|
|
||||||
{
|
|
||||||
Id = entity.Id,
|
|
||||||
CreatedAt = entity.CreatedAt,
|
|
||||||
UpdatedAt = entity.UpdatedAt,
|
|
||||||
CustomerId = entity.CustomerId,
|
|
||||||
ProductPriceId = entity.ProductPriceId,
|
|
||||||
Notes = entity.Notes,
|
|
||||||
RefundId = entity.RefundId
|
|
||||||
};
|
|
||||||
|
|
||||||
public static OrderRefund ToModel(this Entities.OrderRefund entity) =>
|
|
||||||
new()
|
|
||||||
{
|
|
||||||
Id = entity.Id,
|
|
||||||
CreatedAt = entity.CreatedAt,
|
|
||||||
OrderId = entity.OrderId,
|
|
||||||
Reason = entity.Reason,
|
|
||||||
Amount = entity.Amount
|
|
||||||
};
|
|
||||||
|
|
||||||
public static Product ToModel(this Entities.Product entity) =>
|
|
||||||
new()
|
|
||||||
{
|
|
||||||
Id = entity.Id,
|
|
||||||
Name = entity.Name,
|
|
||||||
Description = entity.Description,
|
|
||||||
Active = entity.Active
|
|
||||||
};
|
|
||||||
|
|
||||||
public static ProductPrice ToModel(this Entities.ProductPrice entity) =>
|
|
||||||
new()
|
|
||||||
{
|
|
||||||
Id = entity.Id,
|
|
||||||
ProductId = entity.ProductId,
|
|
||||||
Price = entity.Price,
|
|
||||||
Active = entity.Active,
|
|
||||||
CreatedAt = entity.CreatedAt,
|
|
||||||
Discount = entity.Discount,
|
|
||||||
UpdatedAt = entity.UpdatedAt
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
using LiteCharms.Features.Extensions;
|
||||||
|
using LiteCharms.Features.TechShop.Extensions;
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.TechShop.Tests;
|
||||||
|
|
||||||
|
public class Fixture : IDisposable
|
||||||
|
{
|
||||||
|
public IConfiguration Configuration { get; set; }
|
||||||
|
|
||||||
|
public IServiceProvider Services { get; set; }
|
||||||
|
|
||||||
|
public IMediator Mediator { get; set; }
|
||||||
|
|
||||||
|
public Fixture()
|
||||||
|
{
|
||||||
|
Configuration = new ConfigurationBuilder()
|
||||||
|
.SetBasePath(Directory.GetCurrentDirectory())
|
||||||
|
.AddUserSecrets<Fixture>()
|
||||||
|
.AddJsonFile(Path.Combine(Directory.GetCurrentDirectory(), "appsettings.json"), optional: true, reloadOnChange: true)
|
||||||
|
.AddEnvironmentVariables()
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
Services = new ServiceCollection()
|
||||||
|
.AddMediator()
|
||||||
|
.AddLogging()
|
||||||
|
.AddTechShopServices()
|
||||||
|
.AddEmailServiceBus()
|
||||||
|
.AddGarageS3(Configuration)
|
||||||
|
.AddTechShopDatabase(Configuration)
|
||||||
|
.AddEmailServices(Configuration)
|
||||||
|
.AddSingleton(Configuration)
|
||||||
|
.BuildServiceProvider();
|
||||||
|
|
||||||
|
Mediator = Services.GetRequiredService<IMediator>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose() { }
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net10.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<IsPackable>false</IsPackable>
|
||||||
|
<UserSecretsId>fa06c1a6-2ba8-4c47-b19b-11e0f78e7b92</UserSecretsId>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="coverlet.collector" Version="10.0.1">
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
</PackageReference>
|
||||||
|
<PackageReference Include="Mediator.SourceGenerator" Version="3.0.2">
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
</PackageReference>
|
||||||
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.5.1" />
|
||||||
|
<PackageReference Include="xunit" Version="2.9.3" />
|
||||||
|
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5">
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
</PackageReference>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<!-- Global Usings -->
|
||||||
|
<ItemGroup>
|
||||||
|
<Using Include="Mediator" />
|
||||||
|
<Using Include="Xunit.Abstractions" />
|
||||||
|
<Using Include="Microsoft.Extensions.DependencyInjection" />
|
||||||
|
<Using Include="Microsoft.Extensions.Configuration" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\LiteCharms.Features.TechShop\LiteCharms.Features.TechShop.csproj" />
|
||||||
|
<ProjectReference Include="..\LiteCharms.Features\LiteCharms.Features.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Using Include="Xunit" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Update="appsettings.json">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Update="appsettings.json">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
using LiteCharms.Features.Models;
|
||||||
|
using LiteCharms.Features.TechShop.Notifications;
|
||||||
|
using LiteCharms.Features.TechShop.Notifications.Events;
|
||||||
|
using static LiteCharms.Features.Extensions.Email;
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.TechShop.Tests;
|
||||||
|
|
||||||
|
public class NotificationsFeatureTests(Fixture fixture, ITestOutputHelper output) : IClassFixture<Fixture>
|
||||||
|
{
|
||||||
|
private readonly NotificationService notificationService = fixture.Services.GetRequiredService<NotificationService>();
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task CreateNotificationCommand_ShouldSucceed()
|
||||||
|
{
|
||||||
|
Notifications.Models.CreateNotification request = new()
|
||||||
|
{
|
||||||
|
CorrelationId = Guid.CreateVersion7().ToString(),
|
||||||
|
CorrelationIdType = CorrelationIdTypes.None,
|
||||||
|
Direction = NotificationDirection.Outgoing,
|
||||||
|
Platform = NotificationPlatforms.Email,
|
||||||
|
Priority = Priorities.Medium,
|
||||||
|
Sender = "xUnit Test",
|
||||||
|
SenderAddress = "khwezi@mngoma.africa",
|
||||||
|
Recipient = $"{ShopEmailFromName} [Test]",
|
||||||
|
RecipientAddress = ShopEmailFromAddress,
|
||||||
|
Subject = "Test Message",
|
||||||
|
Message = "This is an automation test",
|
||||||
|
IsHtml = false,
|
||||||
|
IsInternal = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
var createResult = await notificationService.CreateNotificationAsync(request);
|
||||||
|
|
||||||
|
Assert.True(createResult.IsSuccess);
|
||||||
|
|
||||||
|
foreach (var error in createResult.Errors) output.WriteLine(error.Message);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task GetNotifications_ShouldReturn_AllNotifications()
|
||||||
|
{
|
||||||
|
DateRange range = new()
|
||||||
|
{
|
||||||
|
From = DateOnly.FromDateTime(new DateTime(2026, 04, 01, 0, 0, 0, DateTimeKind.Utc)),
|
||||||
|
To = DateOnly.FromDateTime(DateTime.UtcNow),
|
||||||
|
MaxRecords = 10
|
||||||
|
};
|
||||||
|
|
||||||
|
var getResult = await notificationService.GetNotificationsAsync(range);
|
||||||
|
|
||||||
|
Assert.True(getResult.IsSuccess);
|
||||||
|
|
||||||
|
foreach (var error in getResult.Errors) output.WriteLine(error.Message);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task ProcessEmailNotificationsEvent_ShouldSucceed()
|
||||||
|
{
|
||||||
|
var notification = ProcessEmailNotificationsEvent.Create();
|
||||||
|
|
||||||
|
await fixture.Mediator.Publish(notification);
|
||||||
|
|
||||||
|
Assert.True(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
using LiteCharms.Features.TechShop.Products;
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.TechShop.Tests;
|
||||||
|
|
||||||
|
public class ProductsFeatureTests(Fixture fixture, ITestOutputHelper output) : IClassFixture<Fixture>
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public async Task GetProductsAsync_ReturnsProducts()
|
||||||
|
{
|
||||||
|
var productService = fixture.Services.GetRequiredService<ProductService>();
|
||||||
|
|
||||||
|
var result = await productService.GetProductsAsync();
|
||||||
|
|
||||||
|
Assert.True(result.IsSuccess);
|
||||||
|
Assert.NotNull(result.Value);
|
||||||
|
|
||||||
|
output.WriteLine($"Retrieved {result.Value.Length} products.");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
{
|
||||||
|
"BookshopS3Settings": {
|
||||||
|
"ServiceUrl": "http://192.168.1.177:30900",
|
||||||
|
"Region": "garage",
|
||||||
|
"BucketName": "bookshop",
|
||||||
|
"CdnBaseUrl": "https://bookshop.cdn.khongisa.co.za"
|
||||||
|
},
|
||||||
|
"BookshopQuotesS3Settings": {
|
||||||
|
"ServiceUrl": "http://192.168.1.177:30900",
|
||||||
|
"Region": "garage",
|
||||||
|
"BucketName": "bookshop.quotes",
|
||||||
|
"CdnBaseUrl": "https://bookshop.quotes.cdn.khongisa.co.za"
|
||||||
|
},
|
||||||
|
"Email": {
|
||||||
|
"Credentials": {
|
||||||
|
"Username": "shop@litecharms.co.za"
|
||||||
|
},
|
||||||
|
"Port": 465,
|
||||||
|
"Host": "mail.litecharms.co.za",
|
||||||
|
"UseSsl": true
|
||||||
|
},
|
||||||
|
"Monitoring": {
|
||||||
|
"ApiKey": "",
|
||||||
|
"Address": "http://aspire-dashboard-service.aspire.svc.cluster.local:18889",
|
||||||
|
"ServiceName": "LiteCharms.LeadGenerator"
|
||||||
|
},
|
||||||
|
"Logging": {
|
||||||
|
"LogLevel": {
|
||||||
|
"Default": "Information",
|
||||||
|
"Microsoft.AspNetCore": "Warning"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"AllowedHosts": "*"
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
namespace LiteCharms.Features.TechShop.CartPackages.Entities;
|
||||||
|
|
||||||
|
[EntityTypeConfiguration<PackageConfirguration, Package>]
|
||||||
|
public class Package : Models.Package
|
||||||
|
{
|
||||||
|
public virtual ICollection<PackageItem>? PackageItems { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
namespace LiteCharms.Features.TechShop.CartPackages.Entities;
|
||||||
|
|
||||||
|
public class PackageConfirguration : IEntityTypeConfiguration<Package>
|
||||||
|
{
|
||||||
|
public void Configure(EntityTypeBuilder<Package> builder)
|
||||||
|
{
|
||||||
|
builder.ToTable(nameof(Package));
|
||||||
|
|
||||||
|
builder.HasKey(f => f.Id);
|
||||||
|
builder.Property(f => f.CreatedAt).IsRequired().ValueGeneratedOnAdd().HasDefaultValueSql("now()");
|
||||||
|
builder.Property(f => f.UpdatedAt).IsRequired(false).HasDefaultValueSql(null);
|
||||||
|
builder.Property(f => f.Name).IsRequired();
|
||||||
|
builder.Property(f => f.Summary).IsRequired().HasMaxLength(512);
|
||||||
|
builder.Property(f => f.Description).IsRequired().HasMaxLength(2048);
|
||||||
|
builder.Property(f => f.ImageUrl).IsRequired(false).HasMaxLength(2048);
|
||||||
|
builder.Property(f => f.Active);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
using LiteCharms.Features.TechShop.Products.Entities;
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.TechShop.CartPackages.Entities;
|
||||||
|
|
||||||
|
[EntityTypeConfiguration<PackageItemConfiguration, PackageItem>]
|
||||||
|
public class PackageItem : Models.PackageItem
|
||||||
|
{
|
||||||
|
public virtual Package? Package { get; set; }
|
||||||
|
|
||||||
|
public virtual ProductPrice? ProductPrice { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
namespace LiteCharms.Features.TechShop.CartPackages.Entities;
|
||||||
|
|
||||||
|
public class PackageItemConfiguration : IEntityTypeConfiguration<PackageItem>
|
||||||
|
{
|
||||||
|
public void Configure(EntityTypeBuilder<PackageItem> builder)
|
||||||
|
{
|
||||||
|
builder.ToTable(nameof(PackageItem));
|
||||||
|
|
||||||
|
builder.HasKey(f => f.Id);
|
||||||
|
builder.Property(f => f.CreatedAt).IsRequired().ValueGeneratedOnAdd().HasDefaultValueSql("now()");
|
||||||
|
builder.Property(f => f.PackageId).IsRequired();
|
||||||
|
builder.Property(f => f.ProductPriceId).IsRequired();
|
||||||
|
builder.Property(f => f.Active);
|
||||||
|
|
||||||
|
builder.HasOne(f => f.Package)
|
||||||
|
.WithMany(f => f.PackageItems)
|
||||||
|
.HasForeignKey(pi => pi.PackageId)
|
||||||
|
.IsRequired()
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
builder.HasOne(f => f.ProductPrice)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey(pi => pi.ProductPriceId)
|
||||||
|
.IsRequired()
|
||||||
|
.OnDelete(DeleteBehavior.Restrict);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
namespace LiteCharms.Features.TechShop.CartPackages.Models;
|
||||||
|
|
||||||
|
public class Package
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
|
||||||
|
public DateTime CreatedAt { get; set; }
|
||||||
|
|
||||||
|
public DateTime? UpdatedAt { get; set; }
|
||||||
|
|
||||||
|
public string? Name { get; set; }
|
||||||
|
|
||||||
|
public string? Summary { get; set; }
|
||||||
|
|
||||||
|
public string? Description { get; set; }
|
||||||
|
|
||||||
|
public string? ImageUrl { get; set; }
|
||||||
|
|
||||||
|
public bool Active { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
namespace LiteCharms.Features.TechShop.CartPackages.Models;
|
||||||
|
|
||||||
|
public class PackageItem
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
|
||||||
|
public Guid PackageId { get; set; }
|
||||||
|
|
||||||
|
public Guid ProductPriceId { get; set; }
|
||||||
|
|
||||||
|
public DateTimeOffset CreatedAt { get; set; }
|
||||||
|
|
||||||
|
public bool Active { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,242 @@
|
|||||||
|
using LiteCharms.Features.Extensions;
|
||||||
|
using LiteCharms.Features.Models;
|
||||||
|
using LiteCharms.Features.TechShop.CartPackages.Models;
|
||||||
|
using LiteCharms.Features.TechShop.Extensions;
|
||||||
|
using LiteCharms.Features.TechShop.Postgres;
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.TechShop.CartPackages;
|
||||||
|
|
||||||
|
public class PackageService(IDbContextFactory<ShopDbContext> contextFactory)
|
||||||
|
{
|
||||||
|
public async ValueTask<Result<Guid>> AddPackageItemAsync(Guid packageId, Guid productPriceId, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
|
if (!await context.Packages.AnyAsync(p => p.Id == packageId, cancellationToken))
|
||||||
|
return Result.Fail($"Could not find package by ID {packageId}");
|
||||||
|
|
||||||
|
if (!await context.ProductPrices.AnyAsync(p => p.Id == productPriceId && p.Active == true, cancellationToken))
|
||||||
|
return Result.Fail($"Could not find an active product price by ID {productPriceId}");
|
||||||
|
|
||||||
|
if (await context.PackageItems.AnyAsync(p => p.ProductPriceId == productPriceId && p.PackageId == packageId, cancellationToken))
|
||||||
|
return Result.Fail<Guid>($"Product price {productPriceId} is already added to this package {packageId}");
|
||||||
|
|
||||||
|
var newPackageItem = context.PackageItems.Add(new Entities.PackageItem
|
||||||
|
{
|
||||||
|
PackageId = packageId,
|
||||||
|
ProductPriceId = productPriceId,
|
||||||
|
Active = true
|
||||||
|
});
|
||||||
|
|
||||||
|
return await context.SaveChangesAsync(cancellationToken) > 0
|
||||||
|
? Result.Ok(newPackageItem.Entity.Id)
|
||||||
|
: Result.Fail<Guid>($"Failed to add new package item by ID {productPriceId}");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Result.Fail<Guid>(new Error(ex.Message).CausedBy(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async ValueTask<Result<Guid>> CreatePackageAsync(string? name, string? summary, string? description, string? ImageUrl, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
|
if (await context.Packages.AnyAsync(p => p.Name == name, cancellationToken))
|
||||||
|
return Result.Fail($"A package by the same name already exists: {name}");
|
||||||
|
|
||||||
|
var newPackage = context.Packages.Add(new Entities.Package
|
||||||
|
{
|
||||||
|
Name = name,
|
||||||
|
Summary = summary,
|
||||||
|
Description = description,
|
||||||
|
ImageUrl = ImageUrl,
|
||||||
|
Active = true
|
||||||
|
});
|
||||||
|
|
||||||
|
return await context.SaveChangesAsync(cancellationToken) > 0
|
||||||
|
? Result.Ok(newPackage.Entity.Id)
|
||||||
|
: Result.Fail($"Failed to create a new package by the name: {name}");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Result.Fail<Guid>(new Error(ex.Message).CausedBy(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async ValueTask<Result> DeletePackageItemAsync(Guid packageId, Guid packageItemId, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
|
if (!await context.Packages.AnyAsync(p => p.Id == packageId, cancellationToken))
|
||||||
|
return Result.Fail($"Could not find package by ID {packageId}");
|
||||||
|
|
||||||
|
var item = await context.PackageItems.FirstOrDefaultAsync(p => p.Id == packageItemId && p.PackageId == packageId, cancellationToken);
|
||||||
|
|
||||||
|
if (item is null)
|
||||||
|
return Result.Fail($"Product item {packageItemId} is already added to this package {packageId}");
|
||||||
|
|
||||||
|
context.PackageItems.Remove(item);
|
||||||
|
|
||||||
|
return await context.SaveChangesAsync(cancellationToken) > 0
|
||||||
|
? Result.Ok()
|
||||||
|
: Result.Fail($"Failed to delete package item by id {packageItemId}");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Result.Fail(new Error(ex.Message).CausedBy(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async ValueTask<Result> DeletePackageItemsAsync(Guid packageId, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
|
if (!await context.Packages.AnyAsync(p => p.Id == packageId, cancellationToken))
|
||||||
|
return Result.Fail($"Could not find package by ID {packageId}");
|
||||||
|
|
||||||
|
var items = await context.PackageItems.Where(i => i.PackageId == packageId).ToArrayAsync(cancellationToken);
|
||||||
|
|
||||||
|
context.PackageItems.RemoveRange(items);
|
||||||
|
|
||||||
|
return await context.SaveChangesAsync(cancellationToken) > 0
|
||||||
|
? Result.Ok()
|
||||||
|
: Result.Fail($"Failed to delete package {packageId} items");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Result.Fail(new Error(ex.Message).CausedBy(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async ValueTask<Result<Package>> GetPackageAsync(Guid packageId, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
|
var package = await context.Packages.FirstOrDefaultAsync(p => p.Id == packageId, cancellationToken);
|
||||||
|
|
||||||
|
return package is not null
|
||||||
|
? Result.Ok(package.ToModel())
|
||||||
|
: Result.Fail($"Failed to find package by ID {packageId}");
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Result.Fail<Package>(new Error(ex.Message).CausedBy(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async ValueTask<Result<PackageItem[]>> GetPackageItemsAsync(Guid packageId, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
|
if (!await context.Packages.AnyAsync(p => p.Id == packageId, cancellationToken))
|
||||||
|
return Result.Fail<PackageItem[]>($"Package could not be found with ID {packageId}");
|
||||||
|
|
||||||
|
var items = await context.PackageItems.AsNoTracking()
|
||||||
|
.OrderByDescending(o => o.CreatedAt)
|
||||||
|
.Where(p => p.PackageId == packageId)
|
||||||
|
.ToArrayAsync(cancellationToken);
|
||||||
|
|
||||||
|
return items?.Length > 0
|
||||||
|
? Result.Ok(items.Select(i => i.ToModel()).ToArray())
|
||||||
|
: Result.Fail<PackageItem[]>($"Could not find package items by package ID {packageId}");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Result.Fail<PackageItem[]>(new Error(ex.Message).CausedBy(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async ValueTask<Result<Package[]>> GetPackagesAsync(Guid packageId, DateRange range, bool active, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var fromDate = range.From.ToDateTime(TimeOnly.MinValue);
|
||||||
|
var toDate = range.To.ToDateTime(TimeOnly.MaxValue);
|
||||||
|
|
||||||
|
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
|
var packages = await context.Packages
|
||||||
|
.AsNoTracking()
|
||||||
|
.OrderByDescending(o => o.CreatedAt)
|
||||||
|
.Where(p => p.CreatedAt >= fromDate && p.CreatedAt <= toDate)
|
||||||
|
.Where(p => p.Active == active)
|
||||||
|
.Take(range.MaxRecords)
|
||||||
|
.ToArrayAsync(cancellationToken);
|
||||||
|
|
||||||
|
return packages?.Length > 0
|
||||||
|
? Result.Ok(packages.Select(o => o.ToModel()).ToArray())
|
||||||
|
: Result.Fail<Package[]>(new Error($"No packages found for the specified date range {range.From} - {range.To}."));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Result.Fail<Package[]>(new Error(ex.Message).CausedBy(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async ValueTask<Result<Guid>> UpdatePackageAsync(Guid packageId, string? name, string? summary, string? description, string? ImageUrl, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
|
if (await context.Packages.AnyAsync(p => p.Name == name, cancellationToken))
|
||||||
|
return Result.Fail($"A package by the same name already exists: {name}");
|
||||||
|
|
||||||
|
var package = await context.Packages.FirstOrDefaultAsync(p => p.Id == packageId, cancellationToken);
|
||||||
|
|
||||||
|
if (package is null)
|
||||||
|
return Result.Fail($"Could not find package by id {packageId}");
|
||||||
|
|
||||||
|
package.Name = name;
|
||||||
|
package.Summary = summary;
|
||||||
|
package.Description = description;
|
||||||
|
package.ImageUrl = ImageUrl;
|
||||||
|
package.UpdatedAt = DateTime.UtcNow;
|
||||||
|
|
||||||
|
return await context.SaveChangesAsync(cancellationToken) > 0
|
||||||
|
? Result.Ok()
|
||||||
|
: Result.Fail($"Failed to update package with id {packageId}");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Result.Fail(new Error(ex.Message).CausedBy(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async ValueTask<Result<Guid>> UpdatePackageStatusAsync(Guid packageId, bool active, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
|
var package = await context.Packages.FirstOrDefaultAsync(p => p.Id == packageId, cancellationToken);
|
||||||
|
|
||||||
|
if (package is null)
|
||||||
|
return Result.Fail($"Could not find package by id {packageId}");
|
||||||
|
|
||||||
|
package.Active = active;
|
||||||
|
|
||||||
|
return await context.SaveChangesAsync(cancellationToken) > 0
|
||||||
|
? Result.Ok()
|
||||||
|
: Result.Fail($"Failed to update package with id {packageId}");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Result.Fail(new Error(ex.Message).CausedBy(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,133 @@
|
|||||||
|
using LiteCharms.Features.Extensions;
|
||||||
|
using LiteCharms.Features.Models;
|
||||||
|
using LiteCharms.Features.TechShop.Customers.Models;
|
||||||
|
using LiteCharms.Features.TechShop.Extensions;
|
||||||
|
using LiteCharms.Features.TechShop.Postgres;
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.TechShop.Customers;
|
||||||
|
|
||||||
|
public class CustomerService(IDbContextFactory<ShopDbContext> contextFactory)
|
||||||
|
{
|
||||||
|
public async ValueTask<Result<Guid>> CreateCustomerAsync(CreateCustomer request, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
|
var customerEmail = request.Email.ToLower().Trim();
|
||||||
|
|
||||||
|
if (await context.Customers.AnyAsync(c => c.Email == customerEmail, cancellationToken))
|
||||||
|
return Result.Fail<Guid>(new Error($"A customer with the email {customerEmail} already exists"));
|
||||||
|
|
||||||
|
var newCustomer = context.Customers.Add(new Entities.Customer
|
||||||
|
{
|
||||||
|
Company = request.Company,
|
||||||
|
Name = request.Name,
|
||||||
|
LastName = request.LastName,
|
||||||
|
Tax = request.Tax,
|
||||||
|
Email = customerEmail,
|
||||||
|
Discord = request.Discord,
|
||||||
|
Slack = request.Slack,
|
||||||
|
LinkedIn = request.LinkedIn,
|
||||||
|
Whatsapp = request.Whatsapp,
|
||||||
|
Website = request.Website,
|
||||||
|
Phone = request.Phone,
|
||||||
|
Address = request.Address,
|
||||||
|
City = request.City,
|
||||||
|
Region = request.Region,
|
||||||
|
Country = request.Country,
|
||||||
|
PostalCode = request.PostalCode,
|
||||||
|
Active = true,
|
||||||
|
});
|
||||||
|
|
||||||
|
return await context.SaveChangesAsync(cancellationToken) > 0
|
||||||
|
? Result.Ok(newCustomer.Entity.Id)
|
||||||
|
: Result.Fail<Guid>(new Error($"Failed to create customer {customerEmail}"));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Result.Fail<Guid>(new Error(ex.Message).CausedBy(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async ValueTask<Result<Customer>> GetCustomerAsync(Guid customerId, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
|
var customer = await context.Customers.FirstOrDefaultAsync(c => c.Id == customerId, cancellationToken);
|
||||||
|
|
||||||
|
return customer is not null
|
||||||
|
? Result.Ok(customer.ToModel())
|
||||||
|
: Result.Fail<Customer>($"Customer not found with id {customerId}");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Result.Fail<Customer>(new Error(ex.Message).CausedBy(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async ValueTask<Result<Customer[]>> GetCustomersAsync(DateRange range, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var fromDate = range.From.ToDateTime(TimeOnly.MinValue);
|
||||||
|
var toDate = range.To.ToDateTime(TimeOnly.MaxValue);
|
||||||
|
|
||||||
|
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
|
var customers = await context.Customers.AsNoTracking()
|
||||||
|
.OrderByDescending(o => o.CreatedAt)
|
||||||
|
.Where(c => c.CreatedAt >= fromDate && c.CreatedAt <= toDate)
|
||||||
|
.Take(range.MaxRecords)
|
||||||
|
.ToArrayAsync(cancellationToken);
|
||||||
|
|
||||||
|
return customers?.Length > 0
|
||||||
|
? Result.Ok(customers.Select(c => c.ToModel()).ToArray())
|
||||||
|
: Result.Fail<Customer[]>(new Error("No customers found in the specified date range."));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Result.Fail<Customer[]>(new Error(ex.Message).CausedBy(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async ValueTask<Result> UpdateCustomerAsync(UpdateCustomer request, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
|
var customer = await context.Customers.FirstOrDefaultAsync(c => c.Id == request.CustomerId, cancellationToken);
|
||||||
|
|
||||||
|
if (customer is null)
|
||||||
|
return Result.Fail(new Error($"Customer with ID {request.CustomerId} not found."));
|
||||||
|
|
||||||
|
customer.Name = request.Name;
|
||||||
|
customer.LastName = request.LastName;
|
||||||
|
customer.Email = request.Email;
|
||||||
|
customer.Company = request.Company;
|
||||||
|
customer.Address = request.Address;
|
||||||
|
customer.City = request.City;
|
||||||
|
customer.Region = request.Region;
|
||||||
|
customer.Country = request.Country;
|
||||||
|
customer.PostalCode = request.PostalCode;
|
||||||
|
customer.Phone = request.Phone;
|
||||||
|
customer.Tax = request.Tax;
|
||||||
|
customer.City = request.City;
|
||||||
|
customer.Discord = request.Discord;
|
||||||
|
customer.Slack = request.Slack;
|
||||||
|
customer.LinkedIn = request.LinkedIn;
|
||||||
|
customer.Whatsapp = request.Whatsapp;
|
||||||
|
|
||||||
|
return await context.SaveChangesAsync(cancellationToken) > 0
|
||||||
|
? Result.Ok()
|
||||||
|
: Result.Fail(new Error($"Failed to update the customer {request.CustomerId}."));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Result.Fail(new Error(ex.Message).CausedBy(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
using LiteCharms.Features.TechShop.Leads.Entities;
|
||||||
|
using LiteCharms.Features.TechShop.Orders.Entities;
|
||||||
|
using LiteCharms.Features.TechShop.Quotes.Entities;
|
||||||
|
using LiteCharms.Features.TechShop.ShoppingCarts.Entities;
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.TechShop.Customers.Entities;
|
||||||
|
|
||||||
|
[EntityTypeConfiguration<CustomerConfiguration, Customer>]
|
||||||
|
public class Customer : Models.Customer
|
||||||
|
{
|
||||||
|
public virtual ICollection<Lead>? Leads { get; set; }
|
||||||
|
|
||||||
|
public virtual ICollection<Order>? Orders { get; set; }
|
||||||
|
|
||||||
|
public virtual ICollection<Quote>? Quotes { get; set; }
|
||||||
|
|
||||||
|
public virtual ICollection<ShoppingCart>? ShoppingCarts { get; set; }
|
||||||
|
}
|
||||||
+4
-9
@@ -1,14 +1,14 @@
|
|||||||
namespace LiteCharms.Entities.Configuration;
|
namespace LiteCharms.Features.TechShop.Customers.Entities;
|
||||||
|
|
||||||
public class CustomerConfiguration : IEntityTypeConfiguration<Customer>
|
public class CustomerConfiguration : IEntityTypeConfiguration<Customer>
|
||||||
{
|
{
|
||||||
public void Configure(EntityTypeBuilder<Customer> builder)
|
public void Configure(EntityTypeBuilder<Customer> builder)
|
||||||
{
|
{
|
||||||
builder.ToTable(nameof(Customer));
|
builder.ToTable("Customers");
|
||||||
|
|
||||||
builder.HasKey(f => f.Id);
|
builder.HasKey(f => f.Id);
|
||||||
builder.Property(f => f.CreatedAt).ValueGeneratedOnAdd();
|
builder.Property(f => f.CreatedAt).ValueGeneratedOnAdd().HasDefaultValueSql("now()");
|
||||||
builder.Property(f => f.UpdatedAt).IsRequired(false).ValueGeneratedOnUpdate();
|
builder.Property(f => f.UpdatedAt).IsRequired(false).HasDefaultValueSql(null);
|
||||||
builder.Property(f => f.Company);
|
builder.Property(f => f.Company);
|
||||||
builder.Property(f => f.Name).IsRequired();
|
builder.Property(f => f.Name).IsRequired();
|
||||||
builder.Property(f => f.LastName).IsRequired();
|
builder.Property(f => f.LastName).IsRequired();
|
||||||
@@ -26,10 +26,5 @@ public class CustomerConfiguration : IEntityTypeConfiguration<Customer>
|
|||||||
builder.Property(f => f.Country);
|
builder.Property(f => f.Country);
|
||||||
builder.Property(f => f.PostalCode);
|
builder.Property(f => f.PostalCode);
|
||||||
builder.Property(f => f.Active).HasDefaultValue(true);
|
builder.Property(f => f.Active).HasDefaultValue(true);
|
||||||
|
|
||||||
builder.HasMany(f => f.Leads)
|
|
||||||
.WithOne(f => f.Customer)
|
|
||||||
.HasForeignKey(f => f.CustomerId)
|
|
||||||
.OnDelete(DeleteBehavior.NoAction);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+3
-3
@@ -1,12 +1,12 @@
|
|||||||
namespace LiteCharms.Models;
|
namespace LiteCharms.Features.TechShop.Customers.Models;
|
||||||
|
|
||||||
public class Customer
|
public class Customer
|
||||||
{
|
{
|
||||||
public Guid Id { get; set; }
|
public Guid Id { get; set; }
|
||||||
|
|
||||||
public DateTimeOffset CreatedAt { get; set; }
|
public DateTime CreatedAt { get; set; }
|
||||||
|
|
||||||
public DateTimeOffset? UpdatedAt { get; set; }
|
public DateTime? UpdatedAt { get; set; }
|
||||||
|
|
||||||
public string? Company { get; set; }
|
public string? Company { get; set; }
|
||||||
|
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
namespace LiteCharms.Features.TechShop.Customers.Models;
|
||||||
|
|
||||||
|
public record CreateCustomer
|
||||||
|
{
|
||||||
|
public string? Company { get; set; }
|
||||||
|
|
||||||
|
public required string Name { get; set; }
|
||||||
|
|
||||||
|
public required string LastName { get; set; }
|
||||||
|
|
||||||
|
public string? Tax { get; set; }
|
||||||
|
|
||||||
|
public required string Email { get; set; }
|
||||||
|
|
||||||
|
public string? Discord { get; set; }
|
||||||
|
|
||||||
|
public string? Slack { get; set; }
|
||||||
|
|
||||||
|
public string? LinkedIn { get; set; }
|
||||||
|
|
||||||
|
public string? Whatsapp { get; set; }
|
||||||
|
|
||||||
|
public string? Website { get; set; }
|
||||||
|
|
||||||
|
public string? Phone { get; set; }
|
||||||
|
|
||||||
|
public string? Address { get; set; }
|
||||||
|
|
||||||
|
public string? City { get; set; }
|
||||||
|
|
||||||
|
public string? Region { get; set; }
|
||||||
|
|
||||||
|
public string? Country { get; set; }
|
||||||
|
|
||||||
|
public string? PostalCode { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public record UpdateCustomer
|
||||||
|
{
|
||||||
|
public required Guid CustomerId { get; set; }
|
||||||
|
|
||||||
|
public string? Company { get; set; }
|
||||||
|
|
||||||
|
public string? Name { get; set; }
|
||||||
|
|
||||||
|
public string? LastName { get; set; }
|
||||||
|
|
||||||
|
public string? Tax { get; set; }
|
||||||
|
|
||||||
|
public string? Email { get; set; }
|
||||||
|
|
||||||
|
public string? Discord { get; set; }
|
||||||
|
|
||||||
|
public string? Slack { get; set; }
|
||||||
|
|
||||||
|
public string? LinkedIn { get; set; }
|
||||||
|
|
||||||
|
public string? Whatsapp { get; set; }
|
||||||
|
|
||||||
|
public string? Website { get; set; }
|
||||||
|
|
||||||
|
public string? Phone { get; set; }
|
||||||
|
|
||||||
|
public string? Address { get; set; }
|
||||||
|
|
||||||
|
public string? City { get; set; }
|
||||||
|
|
||||||
|
public string? Region { get; set; }
|
||||||
|
|
||||||
|
public string? Country { get; set; }
|
||||||
|
|
||||||
|
public string? PostalCode { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
namespace LiteCharms.Features.TechShop;
|
||||||
|
|
||||||
|
public enum CorrelationIdTypes : int
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
Email = 1,
|
||||||
|
Discord = 2,
|
||||||
|
Slack = 3,
|
||||||
|
Whatsapp = 4,
|
||||||
|
Customer = 5,
|
||||||
|
Order = 6,
|
||||||
|
Refund = 7,
|
||||||
|
Lead = 8,
|
||||||
|
Quote = 9,
|
||||||
|
LinkedIn = 10
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum NotificationPlatforms : int
|
||||||
|
{
|
||||||
|
Email = 1,
|
||||||
|
Discord = 2,
|
||||||
|
Slack = 3,
|
||||||
|
WhatsApp = 4,
|
||||||
|
System = 5
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum QuoteStatus : int
|
||||||
|
{
|
||||||
|
Draft = 0,
|
||||||
|
Sent = 1,
|
||||||
|
Accepted = 2,
|
||||||
|
Rejected = 3,
|
||||||
|
Expired = 4
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum OrderStatus : int
|
||||||
|
{
|
||||||
|
Pending = 0,
|
||||||
|
Completed = 1,
|
||||||
|
Cancelled = 2,
|
||||||
|
Failed = 3,
|
||||||
|
Refunded = 4,
|
||||||
|
Error = 5
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum LeadStatus : int
|
||||||
|
{
|
||||||
|
New = 0,
|
||||||
|
Contacted = 1,
|
||||||
|
Qualified = 2,
|
||||||
|
Unqualified = 3,
|
||||||
|
Converted = 4,
|
||||||
|
Lost = 5
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum NotificationDirection : int
|
||||||
|
{
|
||||||
|
Incoming = 0,
|
||||||
|
Outgoing = 1,
|
||||||
|
Neutral = 2
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
using LiteCharms.Features.TechShop.HealthChecks;
|
||||||
|
using static LiteCharms.Features.TechShop.Extensions.Postgres;
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.TechShop.Extensions;
|
||||||
|
|
||||||
|
public static class HealthChecks
|
||||||
|
{
|
||||||
|
public static IServiceCollection AddShopQuartzHealthCheck(this IServiceCollection services)
|
||||||
|
{
|
||||||
|
services.AddHealthChecks().AddCheck<ShopQuartzHealthCheck>("ShopQuartz");
|
||||||
|
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static IServiceCollection AddShopPostgresHealthCheck(this IServiceCollection services)
|
||||||
|
{
|
||||||
|
services.AddHealthChecks().AddCheck<PostgresShopHealthCheck>(ShopDbConfigName);
|
||||||
|
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,202 @@
|
|||||||
|
using LiteCharms.Features.TechShop.CartPackages.Models;
|
||||||
|
using LiteCharms.Features.TechShop.Customers.Models;
|
||||||
|
using LiteCharms.Features.TechShop.Leads.Models;
|
||||||
|
using LiteCharms.Features.TechShop.Notifications.Models;
|
||||||
|
using LiteCharms.Features.TechShop.Orders.Models;
|
||||||
|
using LiteCharms.Features.TechShop.Products.Entities;
|
||||||
|
using LiteCharms.Features.TechShop.Products.Models;
|
||||||
|
using LiteCharms.Features.TechShop.Quotes.Models;
|
||||||
|
using LiteCharms.Features.TechShop.ShoppingCarts.Models;
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.TechShop.Extensions;
|
||||||
|
|
||||||
|
public static class Mappers
|
||||||
|
{
|
||||||
|
public static ShoppingCartPackage ToModel(this ShoppingCarts.Entities.ShoppingCartPackage entity) =>
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
Id = entity.Id,
|
||||||
|
CreatedAt = entity.CreatedAt,
|
||||||
|
PackageId = entity.PackageId,
|
||||||
|
ShoppingCartId = entity.ShoppingCartId
|
||||||
|
};
|
||||||
|
|
||||||
|
public static PackageItem ToModel(this CartPackages.Entities.PackageItem entity) =>
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
Id = entity.Id,
|
||||||
|
Active = entity.Active,
|
||||||
|
CreatedAt = entity.CreatedAt,
|
||||||
|
PackageId = entity.PackageId,
|
||||||
|
ProductPriceId = entity.ProductPriceId
|
||||||
|
};
|
||||||
|
|
||||||
|
public static Package ToModel(this CartPackages.Entities.Package entity) =>
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
Id = entity.Id,
|
||||||
|
CreatedAt = entity.CreatedAt,
|
||||||
|
Active = entity.Active,
|
||||||
|
Description = entity.Description,
|
||||||
|
Name = entity.Name,
|
||||||
|
UpdatedAt = entity.UpdatedAt,
|
||||||
|
ImageUrl = entity.ImageUrl,
|
||||||
|
Summary = entity.Summary
|
||||||
|
};
|
||||||
|
|
||||||
|
public static ShoppingCartItem ToModel(this ShoppingCarts.Entities.ShoppingCartItem entity) =>
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
Id = entity.Id,
|
||||||
|
CreatedAt = entity.CreatedAt,
|
||||||
|
UpdatedAt = entity.UpdatedAt,
|
||||||
|
ProductPriceId = entity.ProductPriceId,
|
||||||
|
Quantity = entity.Quantity,
|
||||||
|
ShoppingCartId = entity.ShoppingCartId
|
||||||
|
};
|
||||||
|
|
||||||
|
public static ShoppingCart ToModel(this ShoppingCarts.Entities.ShoppingCart entity) =>
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
Id = entity.Id,
|
||||||
|
CreatedAt = entity.CreatedAt,
|
||||||
|
UpdatedAt = entity.UpdatedAt,
|
||||||
|
CustomerId = entity.CustomerId,
|
||||||
|
OrderId = entity.OrderId
|
||||||
|
};
|
||||||
|
|
||||||
|
public static Quote ToModel(this Quotes.Entities.Quote entity) =>
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
Id = entity.Id,
|
||||||
|
CreatedAt = entity.CreatedAt,
|
||||||
|
UpdatedAt = entity.UpdatedAt,
|
||||||
|
CustomerId = entity.CustomerId,
|
||||||
|
ExpiredAt = entity.ExpiredAt,
|
||||||
|
Reason = entity.Reason,
|
||||||
|
ShoppingCartId = entity.ShoppingCartId,
|
||||||
|
Status = entity.Status,
|
||||||
|
InvoiceUrl = entity.InvoiceUrl,
|
||||||
|
OrderId = entity.OrderId
|
||||||
|
};
|
||||||
|
|
||||||
|
public static Notification ToModel(this Notifications.Entities.Notification entity) =>
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
Id = entity.Id,
|
||||||
|
CreatedAt = entity.CreatedAt,
|
||||||
|
Message = entity.Message,
|
||||||
|
Direction = entity.Direction,
|
||||||
|
CorrelationId = entity.CorrelationId,
|
||||||
|
CorrelationIdType = entity.CorrelationIdType,
|
||||||
|
IsInternal = entity.IsInternal,
|
||||||
|
SenderAddress = entity.SenderAddress,
|
||||||
|
Platform = entity.Platform,
|
||||||
|
RecipientName = entity.RecipientName,
|
||||||
|
Subject = entity.Subject,
|
||||||
|
Processed = entity.Processed,
|
||||||
|
SenderName = entity.SenderName,
|
||||||
|
RecipientAddress = entity.RecipientAddress,
|
||||||
|
Priority = entity.Priority,
|
||||||
|
UpdatedAt = entity?.UpdatedAt,
|
||||||
|
IsHtml = entity!.IsHtml,
|
||||||
|
HasError = entity.HasError,
|
||||||
|
Errors = entity.Errors
|
||||||
|
};
|
||||||
|
|
||||||
|
public static Customer ToModel(this Customers.Entities.Customer entity) =>
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
Id = entity.Id,
|
||||||
|
CreatedAt = entity.CreatedAt,
|
||||||
|
UpdatedAt = entity.UpdatedAt,
|
||||||
|
Active = entity.Active,
|
||||||
|
Address = entity.Address,
|
||||||
|
City = entity.City,
|
||||||
|
Company = entity.Company,
|
||||||
|
Country = entity.Country,
|
||||||
|
Discord = entity.Discord,
|
||||||
|
Email = entity.Email,
|
||||||
|
LastName = entity.LastName,
|
||||||
|
LinkedIn = entity.LinkedIn,
|
||||||
|
Name = entity.Name,
|
||||||
|
Phone = entity.Phone,
|
||||||
|
PostalCode = entity.PostalCode,
|
||||||
|
Region = entity.Region,
|
||||||
|
Slack = entity.Slack,
|
||||||
|
Tax = entity.Tax,
|
||||||
|
Website = entity.Website,
|
||||||
|
Whatsapp = entity.Whatsapp
|
||||||
|
};
|
||||||
|
|
||||||
|
public static Lead ToModel(this Leads.Entities.Lead entity) =>
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
Id = entity.Id,
|
||||||
|
CreatedAt = entity.CreatedAt,
|
||||||
|
UpdatedAt = entity.UpdatedAt,
|
||||||
|
AdGroupId = entity.AdGroupId,
|
||||||
|
AdName = entity.AdName,
|
||||||
|
AppClickId = entity.AppClickId,
|
||||||
|
AttributionHash = entity.AttributionHash,
|
||||||
|
CampaignId = entity.CampaignId,
|
||||||
|
ClickLocation = entity.ClickLocation,
|
||||||
|
CustomerId = entity.CustomerId,
|
||||||
|
FeedItemId = entity.FeedItemId,
|
||||||
|
Source = entity.Source,
|
||||||
|
ClickId = entity.ClickId,
|
||||||
|
TargetId = entity.TargetId,
|
||||||
|
WebClickId = entity.WebClickId,
|
||||||
|
Status = entity.Status
|
||||||
|
};
|
||||||
|
|
||||||
|
public static Order ToModel(this Orders.Entities.Order entity) =>
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
Id = entity.Id,
|
||||||
|
CreatedAt = entity.CreatedAt,
|
||||||
|
UpdatedAt = entity.UpdatedAt,
|
||||||
|
CustomerId = entity.CustomerId,
|
||||||
|
Notes = entity.Notes,
|
||||||
|
Status = entity.Status,
|
||||||
|
Requirements = entity.Requirements,
|
||||||
|
Terms = entity.Terms,
|
||||||
|
InvoiceUrl = entity.InvoiceUrl
|
||||||
|
};
|
||||||
|
|
||||||
|
public static OrderRefund ToModel(this Orders.Entities.OrderRefund entity) =>
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
Id = entity.Id,
|
||||||
|
CreatedAt = entity.CreatedAt,
|
||||||
|
OrderId = entity.OrderId,
|
||||||
|
Reason = entity.Reason,
|
||||||
|
Amount = entity.Amount
|
||||||
|
};
|
||||||
|
|
||||||
|
public static Products.Models.Product ToModel(this Products.Entities.Product entity) =>
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
Id = entity.Id,
|
||||||
|
CreatedAt = entity.CreatedAt,
|
||||||
|
Name = entity.Name,
|
||||||
|
Description = entity.Description,
|
||||||
|
Active = entity.Active,
|
||||||
|
Summary = entity.Summary,
|
||||||
|
ImageUrl = entity.ImageUrl,
|
||||||
|
Thumbnails = entity.Thumbnails,
|
||||||
|
Metadata = entity.Metadata,
|
||||||
|
};
|
||||||
|
|
||||||
|
public static Products.Models.ProductPrice ToModel(this Products.Entities.ProductPrice entity) =>
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
Id = entity.Id,
|
||||||
|
ProductId = entity.ProductId,
|
||||||
|
Price = entity.Price,
|
||||||
|
Active = entity.Active,
|
||||||
|
CreatedAt = entity.CreatedAt,
|
||||||
|
Discount = entity.Discount,
|
||||||
|
UpdatedAt = entity.UpdatedAt
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
using LiteCharms.Features.TechShop.Postgres;
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.TechShop.Extensions;
|
||||||
|
|
||||||
|
public static class Postgres
|
||||||
|
{
|
||||||
|
public const string ShopDbConfigName = "PostgresShop";
|
||||||
|
|
||||||
|
public static IServiceCollection AddTechShopDatabase(this IServiceCollection services, IConfiguration configuration)
|
||||||
|
{
|
||||||
|
services.AddPooledDbContextFactory<ShopDbContext>(options =>
|
||||||
|
options.UseNpgsql(configuration.GetConnectionString(ShopDbConfigName)));
|
||||||
|
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
using LiteCharms.Features.TechShop.CartPackages;
|
||||||
|
using LiteCharms.Features.TechShop.Customers;
|
||||||
|
using LiteCharms.Features.TechShop.Leads;
|
||||||
|
using LiteCharms.Features.TechShop.Notifications;
|
||||||
|
using LiteCharms.Features.TechShop.Orders;
|
||||||
|
using LiteCharms.Features.TechShop.Products;
|
||||||
|
using LiteCharms.Features.TechShop.Quotes;
|
||||||
|
using LiteCharms.Features.TechShop.ShoppingCarts;
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.TechShop.Extensions;
|
||||||
|
|
||||||
|
public static class Shop
|
||||||
|
{
|
||||||
|
public static IServiceCollection AddTechShopServices(this IServiceCollection services)
|
||||||
|
{
|
||||||
|
services.AddSingleton<PackageService>()
|
||||||
|
.AddSingleton<LeadService>()
|
||||||
|
.AddSingleton<NotificationService>()
|
||||||
|
.AddSingleton<OrderService>()
|
||||||
|
.AddSingleton<ProductService>()
|
||||||
|
.AddSingleton<QuoteService>()
|
||||||
|
.AddSingleton<ShoppingCartService>()
|
||||||
|
.AddSingleton<CustomerService>();
|
||||||
|
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
}
|
||||||
+7
-5
@@ -1,8 +1,10 @@
|
|||||||
namespace LiteCharms.Infrastructure.HealthChecks;
|
using static LiteCharms.Features.TechShop.Extensions.Postgres;
|
||||||
|
|
||||||
public class PostgresHealthCheck(IConfiguration configuration) : IHealthCheck
|
namespace LiteCharms.Features.TechShop.HealthChecks;
|
||||||
|
|
||||||
|
public class PostgresShopHealthCheck(IConfiguration configuration) : IHealthCheck
|
||||||
{
|
{
|
||||||
private readonly string connectionString = configuration.GetConnectionString("PostgresLeadGenerator")!;
|
private readonly string connectionString = configuration.GetConnectionString(ShopDbConfigName)!;
|
||||||
|
|
||||||
public async Task<HealthCheckResult> CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = default)
|
public async Task<HealthCheckResult> CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
@@ -16,11 +18,11 @@ public class PostgresHealthCheck(IConfiguration configuration) : IHealthCheck
|
|||||||
|
|
||||||
await command.ExecuteScalarAsync(cancellationToken);
|
await command.ExecuteScalarAsync(cancellationToken);
|
||||||
|
|
||||||
return HealthCheckResult.Healthy("PostgreSQL is responsive.");
|
return HealthCheckResult.Healthy($"{ShopDbConfigName} is responsive.");
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
return HealthCheckResult.Unhealthy("PostgreSQL is unreachable.", ex);
|
return HealthCheckResult.Unhealthy($"{ShopDbConfigName} is unreachable.", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
using static LiteCharms.Features.Extensions.Quartz;
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.TechShop.HealthChecks;
|
||||||
|
|
||||||
|
public class ShopQuartzHealthCheck(ISchedulerFactory schedulerFactory) : IHealthCheck
|
||||||
|
{
|
||||||
|
public async Task<HealthCheckResult> CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var scheduler = await schedulerFactory.GetScheduler(ShopSchedulerName, cancellationToken);
|
||||||
|
|
||||||
|
if(scheduler == null)
|
||||||
|
return HealthCheckResult.Unhealthy($"Scheduler with name '{ShopSchedulerName}' not found.");
|
||||||
|
|
||||||
|
if (!scheduler.IsStarted)
|
||||||
|
return HealthCheckResult.Unhealthy($"{ShopSchedulerName} Quartz scheduler is not running");
|
||||||
|
|
||||||
|
await scheduler.CheckExists(new JobKey(Guid.NewGuid().ToString()), cancellationToken);
|
||||||
|
|
||||||
|
return HealthCheckResult.Healthy($"{ShopSchedulerName} Quartz scheduler is ready");
|
||||||
|
}
|
||||||
|
catch (SchedulerException)
|
||||||
|
{
|
||||||
|
return HealthCheckResult.Unhealthy($"{ShopSchedulerName} Quartz scheduler cannot connect to the store");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using LiteCharms.Entities.Configuration;
|
using LiteCharms.Features.TechShop.Customers.Entities;
|
||||||
|
|
||||||
namespace LiteCharms.Entities;
|
namespace LiteCharms.Features.TechShop.Leads.Entities;
|
||||||
|
|
||||||
[EntityTypeConfiguration<LeadConfiguration, Lead>]
|
[EntityTypeConfiguration<LeadConfiguration, Lead>]
|
||||||
public class Lead : Models.Lead
|
public class Lead : Models.Lead
|
||||||
+12
-6
@@ -1,16 +1,17 @@
|
|||||||
namespace LiteCharms.Entities.Configuration;
|
namespace LiteCharms.Features.TechShop.Leads.Entities;
|
||||||
|
|
||||||
public class LeadConfiguration : IEntityTypeConfiguration<Lead>
|
public class LeadConfiguration : IEntityTypeConfiguration<Lead>
|
||||||
{
|
{
|
||||||
public void Configure(EntityTypeBuilder<Lead> builder)
|
public void Configure(EntityTypeBuilder<Lead> builder)
|
||||||
{
|
{
|
||||||
builder.ToTable(nameof(Lead));
|
builder.ToTable("Leads");
|
||||||
|
|
||||||
builder.HasKey(f => f.Id);
|
builder.HasKey(f => f.Id);
|
||||||
builder.Property(f => f.CreatedAt).ValueGeneratedOnAdd();
|
builder.Property(f => f.CreatedAt).ValueGeneratedOnAdd().HasDefaultValueSql("now()");
|
||||||
builder.Property(f => f.UpdatedAt).IsRequired(false).ValueGeneratedOnUpdate();
|
builder.Property(f => f.UpdatedAt).IsRequired(false).HasDefaultValueSql(null);
|
||||||
builder.Property(f => f.CustomerId).IsRequired(false);
|
builder.Property(f => f.CustomerId);
|
||||||
builder.Property(f => f.GoogleClickId);
|
builder.Property(f => f.Source);
|
||||||
|
builder.Property(f => f.ClickId);
|
||||||
builder.Property(f => f.WebClickId);
|
builder.Property(f => f.WebClickId);
|
||||||
builder.Property(f => f.AppClickId);
|
builder.Property(f => f.AppClickId);
|
||||||
builder.Property(f => f.CampaignId);
|
builder.Property(f => f.CampaignId);
|
||||||
@@ -21,5 +22,10 @@ public class LeadConfiguration : IEntityTypeConfiguration<Lead>
|
|||||||
builder.Property(f => f.ClickLocation);
|
builder.Property(f => f.ClickLocation);
|
||||||
builder.Property(f => f.Status).IsRequired();
|
builder.Property(f => f.Status).IsRequired();
|
||||||
builder.Property(f => f.AttributionHash).IsRequired(true);
|
builder.Property(f => f.AttributionHash).IsRequired(true);
|
||||||
|
|
||||||
|
builder.HasOne(f => f.Customer)
|
||||||
|
.WithMany(f => f.Leads)
|
||||||
|
.HasForeignKey(f => f.CustomerId)
|
||||||
|
.OnDelete(DeleteBehavior.Restrict);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,118 @@
|
|||||||
|
using LiteCharms.Features.Extensions;
|
||||||
|
using LiteCharms.Features.Models;
|
||||||
|
using LiteCharms.Features.TechShop.Extensions;
|
||||||
|
using LiteCharms.Features.TechShop.Leads.Models;
|
||||||
|
using LiteCharms.Features.TechShop.Postgres;
|
||||||
|
using static LiteCharms.Features.Extensions.Hash;
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.TechShop.Leads;
|
||||||
|
|
||||||
|
public class LeadService(IDbContextFactory<ShopDbContext> contextFactory)
|
||||||
|
{
|
||||||
|
public async ValueTask<Result<Guid>> CreateLeadAsync(CreateLead request, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
|
var newLead = context.Leads.Add(new Entities.Lead
|
||||||
|
{
|
||||||
|
WebClickId = request.WebClickId,
|
||||||
|
AppClickId = request.AppClickId,
|
||||||
|
Source = request.Source,
|
||||||
|
ClickId = request.ClickId,
|
||||||
|
AdGroupId = request.AdGroupId,
|
||||||
|
AdName = request.AdName,
|
||||||
|
CampaignId = request.CampaignId,
|
||||||
|
ClickLocation = request.ClickLocation,
|
||||||
|
CustomerId = request.CustomerId,
|
||||||
|
FeedItemId = request.FeedItemId,
|
||||||
|
Status = LeadStatus.New,
|
||||||
|
TargetId = request.TargetId,
|
||||||
|
AttributionHash = StringToSha256Hash.Invoke($"{request.ClickId}{request.AppClickId}{request.WebClickId}")
|
||||||
|
});
|
||||||
|
|
||||||
|
return await context.SaveChangesAsync(cancellationToken) > 0
|
||||||
|
? Result.Ok(newLead.Entity.Id)
|
||||||
|
: Result.Fail<Guid>(new Error($"Failed to create lead -> Google ClickId: {request.ClickId}, App ClickId: {request.AppClickId}, Web ClickId: {request.WebClickId}"));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Result.Fail<Guid>(new Error(ex.Message).CausedBy(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async ValueTask<Result<Lead[]>> GetCustomerLeadsAsync(Guid customerId, DateRange range, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var fromDate = range.From.ToDateTime(TimeOnly.MinValue);
|
||||||
|
var toDate = range.To.ToDateTime(TimeOnly.MaxValue);
|
||||||
|
|
||||||
|
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
|
var leads = await context.Leads.AsNoTracking()
|
||||||
|
.OrderByDescending(o => o.CreatedAt)
|
||||||
|
.Where(lead => lead.CustomerId == customerId)
|
||||||
|
.Where(lead => lead.CreatedAt.Date >= fromDate && lead.CreatedAt.Date <= toDate)
|
||||||
|
.ToArrayAsync(cancellationToken);
|
||||||
|
|
||||||
|
return leads?.Length > 0
|
||||||
|
? Result.Ok(leads.Select(l => l.ToModel()).ToArray())
|
||||||
|
: Result.Fail(new Error($"No customer {customerId} leads found for the specified date range {range.From} to {range.To}."));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Result.Fail<Lead[]>(new Error(ex.Message).CausedBy(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async ValueTask<Result<Lead[]>> GetLeadsAsync(DateRange range, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var fromDate = range.From.ToDateTime(TimeOnly.MinValue);
|
||||||
|
var toDate = range.To.ToDateTime(TimeOnly.MaxValue);
|
||||||
|
|
||||||
|
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
|
var leads = await context.Leads.AsNoTracking()
|
||||||
|
.OrderByDescending(o => o.CreatedAt)
|
||||||
|
.Where(l => l.CreatedAt.Date >= fromDate && l.CreatedAt.Date <= toDate)
|
||||||
|
.Take(range.MaxRecords)
|
||||||
|
.ToArrayAsync(cancellationToken);
|
||||||
|
|
||||||
|
return leads?.Length > 0
|
||||||
|
? Result.Ok(leads.Select(l => l.ToModel()).ToArray())
|
||||||
|
: Result.Fail(new Error($"No leads found for the specified date range {range.From} to {range.To}."));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Result.Fail(new Error(ex.Message).CausedBy(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async ValueTask<Result> UpdateLeadAsync(Guid leadId, LeadStatus status, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
|
var lead = await context.Leads.FirstOrDefaultAsync(l => l.Id == leadId, cancellationToken);
|
||||||
|
|
||||||
|
if (lead is null)
|
||||||
|
return Result.Fail(new Error($"Lead with ID {leadId} not found."));
|
||||||
|
|
||||||
|
lead.Status = status;
|
||||||
|
lead.UpdatedAt = DateTime.UtcNow;
|
||||||
|
|
||||||
|
return await context.SaveChangesAsync(cancellationToken) > 0
|
||||||
|
? Result.Ok()
|
||||||
|
: Result.Fail(new Error($"Failed to update the lead {leadId}."));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Result.Fail(new Error(ex.Message).CausedBy(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,16 +1,18 @@
|
|||||||
namespace LiteCharms.Models;
|
namespace LiteCharms.Features.TechShop.Leads.Models;
|
||||||
|
|
||||||
public class Lead
|
public class Lead
|
||||||
{
|
{
|
||||||
public Guid Id { get; set; }
|
public Guid Id { get; set; }
|
||||||
|
|
||||||
public DateTimeOffset CreatedAt { get; set; }
|
public DateTime CreatedAt { get; set; }
|
||||||
|
|
||||||
public DateTimeOffset? UpdatedAt { get; set; }
|
public DateTime? UpdatedAt { get; set; }
|
||||||
|
|
||||||
public Guid? CustomerId { get; set; }
|
public Guid? CustomerId { get; set; }
|
||||||
|
|
||||||
public string? GoogleClickId { get; set; }
|
public string? Source { get; set; }
|
||||||
|
|
||||||
|
public string? ClickId { get; set; }
|
||||||
|
|
||||||
public string? WebClickId { get; set; }
|
public string? WebClickId { get; set; }
|
||||||
|
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
namespace LiteCharms.Features.TechShop.Leads.Models;
|
||||||
|
|
||||||
|
public record CreateLead
|
||||||
|
{
|
||||||
|
public Guid? CustomerId { get; set; }
|
||||||
|
|
||||||
|
public required string Source { get; set; }
|
||||||
|
|
||||||
|
public required string ClickId { get; set; }
|
||||||
|
|
||||||
|
public required string WebClickId { get; set; }
|
||||||
|
|
||||||
|
public required string AppClickId { get; set; }
|
||||||
|
|
||||||
|
public long? CampaignId { get; set; }
|
||||||
|
|
||||||
|
public long? AdGroupId { get; set; }
|
||||||
|
|
||||||
|
public long? AdName { get; set; }
|
||||||
|
|
||||||
|
public long? TargetId { get; set; }
|
||||||
|
|
||||||
|
public long? FeedItemId { get; set; }
|
||||||
|
|
||||||
|
public string? ClickLocation { get; set; }
|
||||||
|
|
||||||
|
public string? AttribusionHash { get; set; }
|
||||||
|
}
|
||||||
+85
-16
@@ -6,15 +6,16 @@
|
|||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<SignAssembly>True</SignAssembly>
|
<SignAssembly>True</SignAssembly>
|
||||||
<AssemblyOriginatorKeyFile>..\LiteCharms.snk</AssemblyOriginatorKeyFile>
|
<AssemblyOriginatorKeyFile>..\LiteCharms.snk</AssemblyOriginatorKeyFile>
|
||||||
|
<UserSecretsId>fbd8f4a2-0420-44e2-baff-4678d9e7eee1</UserSecretsId>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<!-- Nuget Package Details -->
|
<!-- Nuget Package Details -->
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<PackageId>LiteCharms.Extensions</PackageId>
|
<PackageId>LiteCharms.Features.TechShop</PackageId>
|
||||||
<Version>1.0.7</Version>
|
<Version>1.0.20</Version>
|
||||||
<Authors>Khwezi Mngoma</Authors>
|
<Authors>Khwezi Mngoma</Authors>
|
||||||
<Company>Lite Charms (PTY) Ltd</Company>
|
<Company>Lite Charms (PTY) Ltd</Company>
|
||||||
<Description>Extension components for Lite Charms applications.</Description>
|
<Description>TechShop feature components for Lite Charms applications.</Description>
|
||||||
<PackageProjectUrl>https://gitea.khongisa.co.za/litecharms/components</PackageProjectUrl>
|
<PackageProjectUrl>https://gitea.khongisa.co.za/litecharms/components</PackageProjectUrl>
|
||||||
<RepositoryUrl>https://gitea.khongisa.co.za/litecharms/components.git</RepositoryUrl>
|
<RepositoryUrl>https://gitea.khongisa.co.za/litecharms/components.git</RepositoryUrl>
|
||||||
<RepositoryType>git</RepositoryType>
|
<RepositoryType>git</RepositoryType>
|
||||||
@@ -28,12 +29,30 @@
|
|||||||
<None Include="..\icon.png" Pack="true" PackagePath="\" />
|
<None Include="..\icon.png" Pack="true" PackagePath="\" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<!-- Shared Usings -->
|
<!-- Quartz Scheduler-->
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Using Include="Microsoft.AspNetCore.Builder" />
|
<PackageReference Include="OpenTelemetry" Version="1.15.3" />
|
||||||
|
<PackageReference Include="Quartz" Version="3.18.1" />
|
||||||
|
<PackageReference Include="Quartz.Plugins" Version="3.18.1" />
|
||||||
|
<PackageReference Include="Quartz.Plugins.TimeZoneConverter" Version="3.18.1" />
|
||||||
|
<PackageReference Include="Quartz.Serialization.SystemTextJson" Version="3.18.1" />
|
||||||
|
<PackageReference Include="Quartz.AspNetCore" Version="3.18.1" />
|
||||||
|
<PackageReference Include="Quartz.Extensions.DependencyInjection" Version="3.18.1" />
|
||||||
|
|
||||||
|
<!-- Global Usings -->
|
||||||
|
<Using Include="Quartz" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<!-- Configuration -->
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Configuration" Version="10.0.8" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="10.0.8" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="10.0.8" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="10.0.8" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="10.0.8" />
|
||||||
|
|
||||||
|
<!-- Global Usings -->
|
||||||
<Using Include="Microsoft.Extensions.Configuration" />
|
<Using Include="Microsoft.Extensions.Configuration" />
|
||||||
<Using Include="Microsoft.Extensions.DependencyInjection" />
|
|
||||||
<Using Include="Microsoft.Extensions.Logging" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<!-- Health Checks -->
|
<!-- Health Checks -->
|
||||||
@@ -43,8 +62,9 @@
|
|||||||
<PackageReference Include="AspNetCore.HealthChecks.UI.Core" Version="9.0.0" />
|
<PackageReference Include="AspNetCore.HealthChecks.UI.Core" Version="9.0.0" />
|
||||||
<PackageReference Include="AspNetCore.HealthChecks.UI.Data" Version="9.0.0" />
|
<PackageReference Include="AspNetCore.HealthChecks.UI.Data" Version="9.0.0" />
|
||||||
<PackageReference Include="AspNetCore.HealthChecks.UI.InMemory.Storage" Version="9.0.0" />
|
<PackageReference Include="AspNetCore.HealthChecks.UI.InMemory.Storage" Version="9.0.0" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="10.0.7" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="10.0.8" />
|
||||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="10.0.7" />
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="10.0.8" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks" Version="10.0.8" />
|
||||||
|
|
||||||
<!-- Global Usings -->
|
<!-- Global Usings -->
|
||||||
<Using Include="Microsoft.Extensions.Diagnostics.HealthChecks" />
|
<Using Include="Microsoft.Extensions.Diagnostics.HealthChecks" />
|
||||||
@@ -58,6 +78,7 @@
|
|||||||
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.15.2" />
|
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.15.2" />
|
||||||
<PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.15.1" />
|
<PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.15.1" />
|
||||||
<PackageReference Include="OpenTelemetry.Instrumentation.Runtime" Version="1.15.1" />
|
<PackageReference Include="OpenTelemetry.Instrumentation.Runtime" Version="1.15.1" />
|
||||||
|
<PackageReference Include="OpenTelemetry.Exporter.Console" Version="1.15.3" />
|
||||||
|
|
||||||
<!-- Global Usings -->
|
<!-- Global Usings -->
|
||||||
<Using Include="OpenTelemetry.Resources" />
|
<Using Include="OpenTelemetry.Resources" />
|
||||||
@@ -69,13 +90,13 @@
|
|||||||
|
|
||||||
<!-- Database -->
|
<!-- Database -->
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="10.0.7" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="10.0.8" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="10.0.7">
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="10.0.8">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="10.0.7" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="10.0.8" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="10.0.7">
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="10.0.8">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
@@ -88,10 +109,58 @@
|
|||||||
<Using Include="Microsoft.EntityFrameworkCore.Metadata.Builders" />
|
<Using Include="Microsoft.EntityFrameworkCore.Metadata.Builders" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<!-- Email -->
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\LiteCharms.Entities\LiteCharms.Entities.csproj" />
|
<PackageReference Include="MailKit" Version="4.16.0" />
|
||||||
<ProjectReference Include="..\LiteCharms.Infrastructure\LiteCharms.Infrastructure.csproj" />
|
<PackageReference Include="MimeKit" Version="4.16.0" />
|
||||||
<ProjectReference Include="..\LiteCharms.Models\LiteCharms.Models.csproj" />
|
|
||||||
|
<!-- Global Usings-->
|
||||||
|
<Using Include="MimeKit" />
|
||||||
|
<Using Include="MailKit.Net.Smtp" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<!-- CQRS -->
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="FluentResults" Version="4.0.0" />
|
||||||
|
<PackageReference Include="Mediator.Abstractions" Version="3.0.2" />
|
||||||
|
|
||||||
|
<!-- Global Usings -->
|
||||||
|
<Using Include="FluentResults" />
|
||||||
|
<Using Include="Mediator" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<!-- Amazon S3 SDK -->
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="AWSSDK.Extensions.NetCore.Setup" Version="4.0.4.1" />
|
||||||
|
<PackageReference Include="AWSSDK.S3" Version="4.0.23.4" />
|
||||||
|
<ProjectReference Include="..\LiteCharms.Features\LiteCharms.Features.csproj" />
|
||||||
|
|
||||||
|
<!-- global Usings -->
|
||||||
|
<Using Include="Amazon.S3" />
|
||||||
|
<Using Include="Amazon.S3.Model" />
|
||||||
|
<Using Include="Amazon.Runtime" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<!-- Shared Usings -->
|
||||||
|
<ItemGroup>
|
||||||
|
<Using Include="Microsoft.AspNetCore.Builder" />
|
||||||
|
<Using Include="Microsoft.Extensions.Hosting" />
|
||||||
|
<Using Include="System.Text" />
|
||||||
|
<Using Include="System.Text.Json" />
|
||||||
|
<Using Include="System.Threading.Channels" />
|
||||||
|
<Using Include="System.Collections.ObjectModel" />
|
||||||
|
<Using Include="System.Diagnostics" />
|
||||||
|
<Using Include="System.Diagnostics.Metrics" />
|
||||||
|
<Using Include="Microsoft.Extensions.DependencyInjection" />
|
||||||
|
<Using Include="System.Security.Cryptography" />
|
||||||
|
<Using Include="Microsoft.Extensions.Options" />
|
||||||
|
<Using Include="Microsoft.Extensions.Logging" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Update="appsettings.json">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
namespace LiteCharms.Features.TechShop.Notifications.Entities;
|
||||||
|
|
||||||
|
[EntityTypeConfiguration<NotificationConfiguration, Notification>]
|
||||||
|
public class Notification : Models.Notification;
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
namespace LiteCharms.Features.TechShop.Notifications.Entities;
|
||||||
|
|
||||||
|
public class NotificationConfiguration : IEntityTypeConfiguration<Notification>
|
||||||
|
{
|
||||||
|
public void Configure(EntityTypeBuilder<Notification> builder)
|
||||||
|
{
|
||||||
|
builder.ToTable("Notification");
|
||||||
|
|
||||||
|
builder.HasKey(f => f.Id);
|
||||||
|
builder.Property(f => f.CreatedAt).IsRequired().ValueGeneratedOnAdd().HasDefaultValueSql("now()");
|
||||||
|
builder.Property(f => f.UpdatedAt).IsRequired(false).HasDefaultValueSql(null);
|
||||||
|
builder.Property(f => f.Direction).IsRequired().HasConversion<int>();
|
||||||
|
builder.Property(f => f.Platform).IsRequired().HasConversion<int>();
|
||||||
|
builder.Property(f => f.Priority).IsRequired().HasConversion<int>();
|
||||||
|
builder.Property(f => f.CorrelationIdType).IsRequired().HasConversion<int>();
|
||||||
|
builder.Property(f => f.SenderAddress).IsRequired();
|
||||||
|
builder.Property(f => f.Subject).IsRequired();
|
||||||
|
builder.Property(f => f.Message).IsRequired();
|
||||||
|
builder.Property(f => f.RecipientName).IsRequired();
|
||||||
|
builder.Property(f => f.RecipientAddress).IsRequired();
|
||||||
|
builder.Property(f => f.CorrelationId).IsRequired();
|
||||||
|
builder.Property(f => f.IsHtml).HasDefaultValue(false);
|
||||||
|
builder.Property(f => f.IsInternal).HasDefaultValue(true);
|
||||||
|
builder.Property(f => f.Processed).HasDefaultValue(false);
|
||||||
|
builder.Property(f => f.HasError).HasDefaultValue(false);
|
||||||
|
builder.Property(f => f.Errors).HasColumnType("jsonb").IsRequired(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
+113
@@ -0,0 +1,113 @@
|
|||||||
|
using LiteCharms.Features.Email;
|
||||||
|
using LiteCharms.Features.TechShop.Notifications.Models;
|
||||||
|
using LiteCharms.Features.TechShop.Postgres;
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.TechShop.Notifications.Events.Handlers;
|
||||||
|
|
||||||
|
public class ProcessEmailNotificationsEventHandler(IDbContextFactory<ShopDbContext> contextFactory, ILogger<ProcessEmailNotificationsEvent> logger,
|
||||||
|
EmailService emailService) : INotificationHandler<ProcessEmailNotificationsEvent>
|
||||||
|
{
|
||||||
|
private bool dropBatch = false;
|
||||||
|
|
||||||
|
public async ValueTask Handle(ProcessEmailNotificationsEvent message, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
|
if (emailService.Status != EmailStatuses.Connected)
|
||||||
|
await emailService.ConnectAsync(cancellationToken);
|
||||||
|
|
||||||
|
var notifications = await context.Notifications
|
||||||
|
.OrderByDescending(o => o.CreatedAt)
|
||||||
|
.ThenBy(o => o.Priority)
|
||||||
|
.Where(n => n.Platform == NotificationPlatforms.Email &&
|
||||||
|
n.Direction == NotificationDirection.Outgoing && n.Processed == false)
|
||||||
|
.Take(message.MaxRecords)
|
||||||
|
.ToListAsync(cancellationToken);
|
||||||
|
|
||||||
|
foreach (var notification in notifications)
|
||||||
|
{
|
||||||
|
if (dropBatch) break;
|
||||||
|
|
||||||
|
var sendResult = await SendEmailAsync(notification,emailService, cancellationToken);
|
||||||
|
|
||||||
|
if(sendResult.IsFailed)
|
||||||
|
{
|
||||||
|
var errors = new List<string>(1000);
|
||||||
|
|
||||||
|
errors.AddRange(sendResult.Errors.Select(e => e.Message));
|
||||||
|
|
||||||
|
if (sendResult.Reasons?.Count > 0)
|
||||||
|
errors.AddRange(sendResult.Reasons.Select(e => e.Message));
|
||||||
|
|
||||||
|
notification.HasError = true;
|
||||||
|
notification.Errors = [.. errors];
|
||||||
|
}
|
||||||
|
|
||||||
|
notification.Processed = true;
|
||||||
|
notification.UpdatedAt = DateTime.UtcNow;
|
||||||
|
}
|
||||||
|
|
||||||
|
await context.SaveChangesAsync(cancellationToken);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
logger.LogError(ex, ex.Message);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
await emailService.DisconnectAsync(cancellationToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<Result> SendEmailAsync(Notification notification, EmailService service, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using Email.Models.Message message = CreateMessage(notification);
|
||||||
|
|
||||||
|
var sendResult = await service.SendEmailAsync(message, cancellationToken);
|
||||||
|
|
||||||
|
if (sendResult.IsFailed)
|
||||||
|
{
|
||||||
|
if (emailService.Status != EmailStatuses.Success && emailService.Status != EmailStatuses.Connected) dropBatch = true;
|
||||||
|
|
||||||
|
return Result.Fail(sendResult.Errors);
|
||||||
|
}
|
||||||
|
|
||||||
|
return sendResult.IsFailed
|
||||||
|
? Result.Fail(sendResult.Errors)
|
||||||
|
: Result.Ok();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Result.Fail(new Error(ex.Message).CausedBy(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Email.Models.Message CreateMessage(Notification notification) =>
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
Sender = new Email.Models.Party
|
||||||
|
{
|
||||||
|
Name = notification.SenderName,
|
||||||
|
Address = notification.SenderAddress
|
||||||
|
},
|
||||||
|
Recipient = new Email.Models.Party
|
||||||
|
{
|
||||||
|
Name = notification.RecipientName,
|
||||||
|
Address = notification.RecipientAddress
|
||||||
|
},
|
||||||
|
Subject = notification.Subject,
|
||||||
|
Body = new Email.Models.Body
|
||||||
|
{
|
||||||
|
Properties = new Email.Models.BodyProperties
|
||||||
|
{
|
||||||
|
HasAttachments = false,
|
||||||
|
IsHtml = notification.IsHtml
|
||||||
|
},
|
||||||
|
Message = notification.Message
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
+25
@@ -0,0 +1,25 @@
|
|||||||
|
using static LiteCharms.Features.Extensions.Email;
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.TechShop.Notifications.Events.Handlers;
|
||||||
|
|
||||||
|
public class SendShopEmailEnquiryEventHandler(NotificationService notificationService) :
|
||||||
|
INotificationHandler<SendShopEmailEnquiryEvent>
|
||||||
|
{
|
||||||
|
public async ValueTask Handle(SendShopEmailEnquiryEvent notification, CancellationToken cancellationToken) =>
|
||||||
|
await notificationService.CreateNotificationAsync(new Models.CreateNotification
|
||||||
|
{
|
||||||
|
CorrelationId = notification.CorrelationId,
|
||||||
|
CorrelationIdType = CorrelationIdTypes.None,
|
||||||
|
Direction = NotificationDirection.Outgoing,
|
||||||
|
IsHtml = false,
|
||||||
|
IsInternal = true,
|
||||||
|
Message = notification.Message,
|
||||||
|
Platform = NotificationPlatforms.Email,
|
||||||
|
Priority = notification.Priority,
|
||||||
|
Subject = notification.Subject!,
|
||||||
|
Sender = notification.SenderName!,
|
||||||
|
SenderAddress = notification.SenderAddress!,
|
||||||
|
Recipient = ShopEmailFromName,
|
||||||
|
RecipientAddress = ShopEmailFromAddress
|
||||||
|
}, cancellationToken);
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
using LiteCharms.Features.Abstractions;
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.TechShop.Notifications.Events;
|
||||||
|
|
||||||
|
public class ProcessEmailNotificationsEvent : EventBase, IEvent
|
||||||
|
{
|
||||||
|
public string Name { get; set; } = nameof(ProcessEmailNotificationsEvent);
|
||||||
|
|
||||||
|
public int MaxRecords { get; set; }
|
||||||
|
|
||||||
|
public ProcessEmailNotificationsEvent() { MaxRecords = 1000; }
|
||||||
|
|
||||||
|
private ProcessEmailNotificationsEvent(int maxRecords = 1000) => MaxRecords = maxRecords;
|
||||||
|
|
||||||
|
public static ProcessEmailNotificationsEvent Create(int maxRecords = 1000) => new(maxRecords);
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
using LiteCharms.Features.Abstractions;
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.TechShop.Notifications.Events;
|
||||||
|
|
||||||
|
public class SendShopEmailEnquiryEvent : EventBase, IEvent
|
||||||
|
{
|
||||||
|
public string Name { get; set; } = nameof(SendShopEmailEnquiryEvent);
|
||||||
|
|
||||||
|
public string? SenderName { get; set; }
|
||||||
|
|
||||||
|
public string? SenderAddress { get; set; }
|
||||||
|
|
||||||
|
public string? Subject { get; set; }
|
||||||
|
|
||||||
|
public string? Message { get; set; }
|
||||||
|
|
||||||
|
public Priorities Priority { get; set; }
|
||||||
|
|
||||||
|
public SendShopEmailEnquiryEvent() { }
|
||||||
|
|
||||||
|
private SendShopEmailEnquiryEvent(string senderName, string senderAddress, string subject, string message, Priorities priority = Priorities.Medium)
|
||||||
|
{
|
||||||
|
SenderName = senderName;
|
||||||
|
SenderAddress = senderAddress;
|
||||||
|
Subject = subject;
|
||||||
|
Message = message;
|
||||||
|
Priority = priority;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SendShopEmailEnquiryEvent Create(string senderName, string senderAddress, string subject, string message, Priorities priority = Priorities.Medium)
|
||||||
|
{
|
||||||
|
ArgumentNullException.ThrowIfNullOrWhiteSpace(senderName, nameof(senderName));
|
||||||
|
ArgumentNullException.ThrowIfNullOrWhiteSpace(senderAddress, nameof(senderAddress));
|
||||||
|
ArgumentNullException.ThrowIfNullOrWhiteSpace(subject, nameof(subject));
|
||||||
|
ArgumentNullException.ThrowIfNullOrWhiteSpace(message, nameof(message));
|
||||||
|
|
||||||
|
return new(senderName, senderAddress, subject, message, priority);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
using LiteCharms.Features.TechShop;
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.TechShop.Notifications.Models;
|
||||||
|
|
||||||
|
public class Notification
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
|
||||||
|
public DateTime CreatedAt { get; set; }
|
||||||
|
|
||||||
|
public DateTime? UpdatedAt { get; set; }
|
||||||
|
|
||||||
|
public NotificationDirection Direction { get; set; }
|
||||||
|
|
||||||
|
public NotificationPlatforms Platform { get; set; }
|
||||||
|
|
||||||
|
public Priorities Priority { get; set; }
|
||||||
|
|
||||||
|
public CorrelationIdTypes CorrelationIdType { get; set; }
|
||||||
|
|
||||||
|
public string? SenderAddress { get; set; }
|
||||||
|
|
||||||
|
public string? SenderName { get; set; }
|
||||||
|
|
||||||
|
public string? Subject { get; set; }
|
||||||
|
|
||||||
|
public string? Message { get; set; }
|
||||||
|
|
||||||
|
public string? RecipientName { get; set; }
|
||||||
|
|
||||||
|
public string? RecipientAddress { get; set; }
|
||||||
|
|
||||||
|
public string? CorrelationId { get; set; }
|
||||||
|
|
||||||
|
public bool IsHtml { get; set; }
|
||||||
|
|
||||||
|
public bool IsInternal { get; set; }
|
||||||
|
|
||||||
|
public bool Processed { get; set; }
|
||||||
|
|
||||||
|
public bool HasError { get; set; }
|
||||||
|
|
||||||
|
public string[]? Errors { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
namespace LiteCharms.Features.TechShop.Notifications.Models;
|
||||||
|
|
||||||
|
public record CreateNotification
|
||||||
|
{
|
||||||
|
public required NotificationDirection Direction { get; set; }
|
||||||
|
|
||||||
|
public required string Sender { get; set; }
|
||||||
|
|
||||||
|
public required string SenderAddress { get; set; }
|
||||||
|
|
||||||
|
public required string Subject { get; set; }
|
||||||
|
|
||||||
|
public string? Message { get; set; }
|
||||||
|
|
||||||
|
public required NotificationPlatforms Platform { get; set; }
|
||||||
|
|
||||||
|
public required Priorities Priority { get; set; }
|
||||||
|
|
||||||
|
public required string Recipient { get; set; }
|
||||||
|
|
||||||
|
public required string RecipientAddress { get; set; }
|
||||||
|
|
||||||
|
public string? CorrelationId { get; set; }
|
||||||
|
|
||||||
|
public CorrelationIdTypes CorrelationIdType { get; set; }
|
||||||
|
|
||||||
|
public bool IsInternal { get; set; }
|
||||||
|
|
||||||
|
public bool IsHtml { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class UpdateNotification
|
||||||
|
{
|
||||||
|
public required Guid NotificationId { get; set; }
|
||||||
|
|
||||||
|
public required bool Processed { get; set; }
|
||||||
|
|
||||||
|
public bool HasError { get; set; }
|
||||||
|
|
||||||
|
public string[]? Errors { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,113 @@
|
|||||||
|
using LiteCharms.Features.Extensions;
|
||||||
|
using LiteCharms.Features.Models;
|
||||||
|
using LiteCharms.Features.TechShop.Extensions;
|
||||||
|
using LiteCharms.Features.TechShop.Notifications.Models;
|
||||||
|
using LiteCharms.Features.TechShop.Postgres;
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.TechShop.Notifications;
|
||||||
|
|
||||||
|
public class NotificationService(IDbContextFactory<ShopDbContext> contextFactory)
|
||||||
|
{
|
||||||
|
public async ValueTask<Result<Guid>> CreateNotificationAsync(CreateNotification request, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
|
var newNotification = context.Notifications.Add(new Entities.Notification
|
||||||
|
{
|
||||||
|
Direction = request.Direction,
|
||||||
|
SenderName = request.Sender,
|
||||||
|
SenderAddress = request.SenderAddress,
|
||||||
|
RecipientName = request.Recipient,
|
||||||
|
RecipientAddress = request.RecipientAddress,
|
||||||
|
Subject = request.Subject,
|
||||||
|
Message = request.Message,
|
||||||
|
Platform = request.Platform,
|
||||||
|
Priority = request.Priority,
|
||||||
|
CorrelationId = request.CorrelationId,
|
||||||
|
CorrelationIdType = request.CorrelationIdType,
|
||||||
|
IsInternal = request.IsInternal,
|
||||||
|
IsHtml = request.IsHtml,
|
||||||
|
Processed = false
|
||||||
|
});
|
||||||
|
|
||||||
|
return await context.SaveChangesAsync(cancellationToken) > 0
|
||||||
|
? Result.Ok(newNotification.Entity.Id)
|
||||||
|
: Result.Fail(new Error("Failed to create notification"));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Result.Fail(new Error(ex.Message).CausedBy(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async ValueTask<Result<Notification>> GetNotificationAsync(Guid notificationId, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
|
var notification = await context.Notifications.FirstOrDefaultAsync(n => n.Id == notificationId, cancellationToken);
|
||||||
|
|
||||||
|
return notification is not null
|
||||||
|
? Result.Ok(notification.ToModel())
|
||||||
|
: Result.Fail<Notification>(new Error($"Notification with id {notificationId} not found"));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Result.Fail<Notification>(new Error(ex.Message).CausedBy(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async ValueTask<Result<Notification[]>> GetNotificationsAsync(DateRange range, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var fromDate = range.From.ToDateTime(TimeOnly.MinValue, DateTimeKind.Utc);
|
||||||
|
var toDate = range.To.ToDateTime(TimeOnly.MaxValue, DateTimeKind.Utc);
|
||||||
|
|
||||||
|
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
|
var notifications = await context.Notifications.AsNoTracking()
|
||||||
|
.Where(n => n.CreatedAt >= fromDate && n.CreatedAt <= toDate)
|
||||||
|
.OrderByDescending(n => n.CreatedAt)
|
||||||
|
.Take(range.MaxRecords)
|
||||||
|
.ToArrayAsync(cancellationToken);
|
||||||
|
|
||||||
|
return notifications?.Length > 0
|
||||||
|
? Result.Ok(notifications.Select(n => n.ToModel()).ToArray())
|
||||||
|
: Result.Fail(new Error($"No notifications found for the specified date range {range.From} to {range.To}."));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Result.Fail(new Error(ex.Message).CausedBy(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async ValueTask<Result> UpdateNotificationAsync(UpdateNotification request, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
|
var notification = await context.Notifications.FirstOrDefaultAsync(n => n.Id == request.NotificationId, cancellationToken);
|
||||||
|
|
||||||
|
if (notification is null)
|
||||||
|
return Result.Fail(new Error($"Notification with id {request.NotificationId} not found."));
|
||||||
|
|
||||||
|
notification.Processed = request.Processed;
|
||||||
|
notification.UpdatedAt = DateTime.UtcNow;
|
||||||
|
notification.HasError = request.HasError;
|
||||||
|
notification.Errors = request.Errors;
|
||||||
|
|
||||||
|
return await context.SaveChangesAsync(cancellationToken) > 0
|
||||||
|
? Result.Ok()
|
||||||
|
: Result.Fail(new Error($"Failed to update notification with id {request.NotificationId}."));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Result.Fail(new Error(ex.Message).CausedBy(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
using LiteCharms.Features.TechShop.Customers.Entities;
|
||||||
|
using LiteCharms.Features.TechShop.Quotes.Entities;
|
||||||
|
using LiteCharms.Features.TechShop.ShoppingCarts.Entities;
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.TechShop.Orders.Entities;
|
||||||
|
|
||||||
|
[EntityTypeConfiguration<OrderConfiguration, Order>]
|
||||||
|
public class Order : Models.Order
|
||||||
|
{
|
||||||
|
public virtual ICollection<OrderRefund>? Refunds { get; set; }
|
||||||
|
|
||||||
|
public virtual Customer? Customer { get; set; }
|
||||||
|
|
||||||
|
public virtual Quote? Quote { get; set; }
|
||||||
|
|
||||||
|
public virtual ShoppingCart? ShoppingCart { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
namespace LiteCharms.Features.TechShop.Orders.Entities;
|
||||||
|
|
||||||
|
public class OrderConfiguration : IEntityTypeConfiguration<Order>
|
||||||
|
{
|
||||||
|
public void Configure(EntityTypeBuilder<Order> builder)
|
||||||
|
{
|
||||||
|
builder.ToTable("Orders");
|
||||||
|
|
||||||
|
builder.HasKey(f => f.Id);
|
||||||
|
builder.Property(f => f.CreatedAt).ValueGeneratedOnAdd().HasDefaultValueSql("now()");
|
||||||
|
builder.Property(f => f.UpdatedAt).IsRequired(false).HasDefaultValueSql(null);
|
||||||
|
builder.Property(f => f.CustomerId).IsRequired();
|
||||||
|
builder.Property(f => f.Status).HasConversion<int>().IsRequired();
|
||||||
|
builder.Property(f => f.Requirements).HasColumnType("jsonb").IsRequired(false);
|
||||||
|
builder.Property(f => f.Notes).HasColumnType("jsonb").IsRequired(false);
|
||||||
|
builder.Property(f => f.Terms).HasColumnType("jsonb").IsRequired(false);
|
||||||
|
builder.Property(f => f.InvoiceUrl).IsRequired(false).HasMaxLength(2048);
|
||||||
|
|
||||||
|
builder.HasOne(o => o.Customer)
|
||||||
|
.WithMany(c => c.Orders)
|
||||||
|
.HasForeignKey(o => o.CustomerId)
|
||||||
|
.IsRequired()
|
||||||
|
.OnDelete(DeleteBehavior.Restrict);
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
-3
@@ -1,9 +1,8 @@
|
|||||||
using LiteCharms.Entities.Configuration;
|
namespace LiteCharms.Features.TechShop.Orders.Entities;
|
||||||
|
|
||||||
namespace LiteCharms.Entities;
|
|
||||||
|
|
||||||
[EntityTypeConfiguration<OrderRefundConfiguration, OrderRefund>]
|
[EntityTypeConfiguration<OrderRefundConfiguration, OrderRefund>]
|
||||||
public class OrderRefund : Models.OrderRefund
|
public class OrderRefund : Models.OrderRefund
|
||||||
{
|
{
|
||||||
|
|
||||||
public virtual Order? Order { get; set; }
|
public virtual Order? Order { get; set; }
|
||||||
}
|
}
|
||||||
+8
-6
@@ -1,19 +1,21 @@
|
|||||||
namespace LiteCharms.Entities.Configuration;
|
namespace LiteCharms.Features.TechShop.Orders.Entities;
|
||||||
|
|
||||||
public class OrderRefundConfiguration : IEntityTypeConfiguration<OrderRefund>
|
public class OrderRefundConfiguration : IEntityTypeConfiguration<OrderRefund>
|
||||||
{
|
{
|
||||||
public void Configure(EntityTypeBuilder<OrderRefund> builder)
|
public void Configure(EntityTypeBuilder<OrderRefund> builder)
|
||||||
{
|
{
|
||||||
builder.ToTable(nameof(OrderRefund));
|
builder.ToTable("OrderRefunds");
|
||||||
|
|
||||||
builder.HasKey(f => f.Id);
|
builder.HasKey(f => f.Id);
|
||||||
builder.Property(f => f.CreatedAt).ValueGeneratedOnAdd();
|
builder.Property(f => f.CreatedAt).ValueGeneratedOnAdd().HasDefaultValueSql("now()");
|
||||||
builder.Property(f => f.OrderId).IsRequired();
|
builder.Property(f => f.OrderId).IsRequired();
|
||||||
builder.Property(f => f.Reason).IsRequired();
|
builder.Property(f => f.Reason).IsRequired();
|
||||||
builder.Property(f => f.Amount).IsRequired().HasPrecision(18, 2);
|
builder.Property(f => f.Amount).IsRequired().HasPrecision(18, 2);
|
||||||
|
|
||||||
builder.HasOne(f => f.Order)
|
builder.HasOne(r => r.Order)
|
||||||
.WithOne(o => o.Refund)
|
.WithMany(o => o.Refunds)
|
||||||
.HasForeignKey<OrderRefund>(o => o.OrderId);
|
.HasForeignKey(r => r.OrderId)
|
||||||
|
.IsRequired()
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
using LiteCharms.Features.TechShop;
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.TechShop.Orders.Models;
|
||||||
|
|
||||||
|
public class Order
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
|
||||||
|
public DateTime CreatedAt { get; set; }
|
||||||
|
|
||||||
|
public DateTime? UpdatedAt { get; set; }
|
||||||
|
|
||||||
|
public Guid CustomerId { get; set; }
|
||||||
|
|
||||||
|
public OrderStatus Status { get; set; }
|
||||||
|
|
||||||
|
public string[]? Requirements { get; set; }
|
||||||
|
|
||||||
|
public string[]? Notes { get; set; }
|
||||||
|
|
||||||
|
public string[]? Terms { get; set; }
|
||||||
|
|
||||||
|
public string? InvoiceUrl { get; set; }
|
||||||
|
}
|
||||||
+2
-2
@@ -1,10 +1,10 @@
|
|||||||
namespace LiteCharms.Models;
|
namespace LiteCharms.Features.TechShop.Orders.Models;
|
||||||
|
|
||||||
public class OrderRefund
|
public class OrderRefund
|
||||||
{
|
{
|
||||||
public Guid Id { get; set; }
|
public Guid Id { get; set; }
|
||||||
|
|
||||||
public DateTimeOffset CreatedAt { get; set; }
|
public DateTime CreatedAt { get; set; }
|
||||||
|
|
||||||
public Guid OrderId { get; set; }
|
public Guid OrderId { get; set; }
|
||||||
|
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
using LiteCharms.Features.TechShop;
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.TechShop.Orders.Models;
|
||||||
|
|
||||||
|
public record CreateOrder
|
||||||
|
{
|
||||||
|
public required Guid CustomerId { get; set; }
|
||||||
|
|
||||||
|
public required Guid ShoppingCartId { get; set; }
|
||||||
|
|
||||||
|
public Guid? QuoteId { get; set; }
|
||||||
|
|
||||||
|
public string[]? Requirements { get; set; }
|
||||||
|
|
||||||
|
public string[]? Notes { get; set; }
|
||||||
|
|
||||||
|
public string[]? Terms { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public record UpdateOrder
|
||||||
|
{
|
||||||
|
public required Guid OrderId { get; set; }
|
||||||
|
|
||||||
|
public required OrderStatus Status { get; set; }
|
||||||
|
|
||||||
|
public string? InvoiceUrl { get; set; }
|
||||||
|
|
||||||
|
public string[]? Notes { get; set; }
|
||||||
|
|
||||||
|
public string[]? Requirements { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public record RefundCustomer
|
||||||
|
{
|
||||||
|
public required Guid OrderId { get; set; }
|
||||||
|
|
||||||
|
public required Guid CustomerId { get; set; }
|
||||||
|
|
||||||
|
public required string Reason { get; set; }
|
||||||
|
|
||||||
|
public required decimal Amount { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,260 @@
|
|||||||
|
using LiteCharms.Features.Extensions;
|
||||||
|
using LiteCharms.Features.Models;
|
||||||
|
using LiteCharms.Features.TechShop.Extensions;
|
||||||
|
using LiteCharms.Features.TechShop.Orders.Models;
|
||||||
|
using LiteCharms.Features.TechShop.Postgres;
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.TechShop.Orders;
|
||||||
|
|
||||||
|
public class OrderService(IDbContextFactory<ShopDbContext> contextFactory)
|
||||||
|
{
|
||||||
|
public async ValueTask<Result<Guid>> CreateOrderAsync(CreateOrder request, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
|
if (!await context.Customers.AnyAsync(c => c.Id == request.CustomerId, cancellationToken))
|
||||||
|
return Result.Fail<Guid>(new Error($"Customer {request.CustomerId} does not exist."));
|
||||||
|
|
||||||
|
if (!await context.ShoppingCarts.AnyAsync(sc => sc.Id == request.ShoppingCartId, cancellationToken))
|
||||||
|
return Result.Fail<Guid>(new Error($"Shopping cart {request.ShoppingCartId} does not exist."));
|
||||||
|
|
||||||
|
if (request.QuoteId.HasValue && !await context.Quotes.AnyAsync(q => q.Id == request.QuoteId.Value, cancellationToken))
|
||||||
|
return Result.Fail<Guid>(new Error($"Quote {request.QuoteId.Value} does not exist."));
|
||||||
|
|
||||||
|
var newOrder = context.Orders.Add(new Entities.Order
|
||||||
|
{
|
||||||
|
Status = OrderStatus.Pending,
|
||||||
|
CustomerId = request.CustomerId,
|
||||||
|
Requirements = request.Requirements,
|
||||||
|
Notes = request.Notes,
|
||||||
|
Terms = request.Terms
|
||||||
|
});
|
||||||
|
|
||||||
|
return await context.SaveChangesAsync(cancellationToken) > 0
|
||||||
|
? Result.Ok(newOrder.Entity.Id)
|
||||||
|
: Result.Fail<Guid>(new Error($"Failed to create customer {request.CustomerId} order using shopping cart {request.ShoppingCartId}."));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Result.Fail<Guid>(new Error(ex.Message).CausedBy(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async ValueTask<Result<OrderRefund[]>> GetCustomerOrderRefundsAsync(Guid customerId, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
|
if (!await context.Customers.AnyAsync(c => c.Id == customerId, cancellationToken))
|
||||||
|
return Result.Fail<OrderRefund[]>(new Error($"Customer with Id {customerId} does not exist."));
|
||||||
|
|
||||||
|
var refunds = await context.OrderRefunds.AsNoTracking().AsSplitQuery()
|
||||||
|
.OrderByDescending(o => o.CreatedAt)
|
||||||
|
.Where(r => r.Order!.CustomerId == customerId).ToArrayAsync(cancellationToken);
|
||||||
|
|
||||||
|
return refunds?.Length > 0
|
||||||
|
? Result.Ok(refunds.Select(r => r.ToModel()).ToArray())
|
||||||
|
: Result.Fail<OrderRefund[]>(new Error($"No refunds found for customer with Id {customerId}."));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Result.Fail<OrderRefund[]>(new Error(ex.Message).CausedBy(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async ValueTask<Result<Order[]>> GetCustomerOrdersAsync(Guid customerId, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
|
if (!await context.Customers.AsNoTracking().AnyAsync(c => c.Id == customerId, cancellationToken))
|
||||||
|
return Result.Fail<Order[]>(new Error($"Customer with Id {customerId} does not exist."));
|
||||||
|
|
||||||
|
var orders = await context.Orders.AsNoTracking()
|
||||||
|
.OrderByDescending(o => o.CreatedAt)
|
||||||
|
.Where(o => o.CustomerId == customerId)
|
||||||
|
.ToArrayAsync(cancellationToken);
|
||||||
|
|
||||||
|
return orders?.Length > 0
|
||||||
|
? Result.Ok(orders.Select(o => o.ToModel()).ToArray())
|
||||||
|
: Result.Fail<Order[]>(new Error($"No orders found for customer with Id {customerId}."));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Result.Fail<Order[]>(new Error(ex.Message).CausedBy(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async ValueTask<Result<OrderRefund>> GetOrderRefundAsync(Guid orderId, Guid orderRefundId, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
|
var refund = await context.OrderRefunds.AsNoTracking()
|
||||||
|
.FirstOrDefaultAsync(r => r.OrderId == orderId && r.Id == orderRefundId, cancellationToken);
|
||||||
|
|
||||||
|
return refund is not null
|
||||||
|
? Result.Ok(refund.ToModel())
|
||||||
|
: Result.Fail<OrderRefund>(new Error($"Refund {orderRefundId} not found for the given OrderId: {orderId}"));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Result.Fail<OrderRefund>(new Error(ex.Message).CausedBy(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async ValueTask<Result<OrderRefund>> GetOrderRefundAsync(Guid orderRefundId, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
|
var refund = await context.OrderRefunds.AsNoTracking().FirstOrDefaultAsync(r => r.Id == orderRefundId, cancellationToken);
|
||||||
|
|
||||||
|
return refund is not null
|
||||||
|
? Result.Ok(refund.ToModel())
|
||||||
|
: Result.Fail<OrderRefund>($"Order refund could not be found with id {orderRefundId}");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Result.Fail<OrderRefund>(new Error(ex.Message).CausedBy(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async ValueTask<Result<OrderRefund[]>> GetOrderRefundsAsync(Guid orderId, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
|
var refunds = await context.OrderRefunds.AsNoTracking()
|
||||||
|
.OrderByDescending(o => o.CreatedAt)
|
||||||
|
.Where(r => r.OrderId == orderId)
|
||||||
|
.ToArrayAsync(cancellationToken);
|
||||||
|
|
||||||
|
return refunds?.Length > 0
|
||||||
|
? Result.Ok(refunds.Select(r => r.ToModel()).ToArray())
|
||||||
|
: Result.Fail<OrderRefund[]>($"Order refunds could not be found with order id {orderId}");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Result.Fail<OrderRefund[]>(new Error(ex.Message).CausedBy(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async ValueTask<Result<Order[]>> GetOrdersAsync(DateRange range, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var fromDate = range.From.ToDateTime(TimeOnly.MinValue);
|
||||||
|
var toDate = range.To.ToDateTime(TimeOnly.MaxValue);
|
||||||
|
|
||||||
|
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
|
var orders = await context.Orders
|
||||||
|
.AsNoTracking()
|
||||||
|
.OrderByDescending(o => o.CreatedAt)
|
||||||
|
.Where(o => o.CreatedAt >= fromDate && o.CreatedAt <= toDate)
|
||||||
|
.Take(range.MaxRecords)
|
||||||
|
.ToArrayAsync(cancellationToken);
|
||||||
|
|
||||||
|
return orders?.Length > 0
|
||||||
|
? Result.Ok(orders.Select(o => o.ToModel()).ToArray())
|
||||||
|
: Result.Fail<Order[]>(new Error($"No orders found for the specified date range {range.From} - {range.To}."));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Result.Fail<Order[]>(new Error(ex.Message).CausedBy(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async ValueTask<Result<Guid>> RefundCustomerAsync(RefundCustomer request, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
|
if (!await context.Orders.AnyAsync(o => o.Id == request.OrderId, cancellationToken))
|
||||||
|
return Result.Fail<Guid>(new Error($"Order with Id: {request.OrderId} does not exist"));
|
||||||
|
|
||||||
|
if (!await context.Customers.AnyAsync(c => c.Id == request.CustomerId, cancellationToken))
|
||||||
|
return Result.Fail<Guid>(new Error($"Customer with Id: {request.CustomerId} does not exist"));
|
||||||
|
|
||||||
|
if (!await context.Orders.AnyAsync(o => o.Id == request.OrderId && o.CustomerId == request.CustomerId, cancellationToken))
|
||||||
|
return Result.Fail<Guid>(new Error($"Order with Id: {request.OrderId} does not belong to Customer with Id: {request.CustomerId}"));
|
||||||
|
|
||||||
|
var refund = context.OrderRefunds.Add(new Entities.OrderRefund
|
||||||
|
{
|
||||||
|
OrderId = request.OrderId,
|
||||||
|
Reason = request.Reason,
|
||||||
|
Amount = request.Amount
|
||||||
|
});
|
||||||
|
|
||||||
|
return await context.SaveChangesAsync(cancellationToken) > 0
|
||||||
|
? Result.Ok(refund.Entity.Id)
|
||||||
|
: Result.Fail<Guid>(new Error($"Failed to create refund for OrderId: {request.OrderId}"));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Result.Fail<Guid>(new Error(ex.Message).CausedBy(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async ValueTask<Result> UpdateOrderRefundAsync(Guid orderRefundId, string reason, decimal amount, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
|
var refund = await context.OrderRefunds.FirstOrDefaultAsync(r => r.Id == orderRefundId, cancellationToken);
|
||||||
|
|
||||||
|
if (refund is null)
|
||||||
|
return Result.Fail($"Order refund not found with id {orderRefundId}");
|
||||||
|
|
||||||
|
refund.Reason = reason;
|
||||||
|
refund.Amount = amount;
|
||||||
|
|
||||||
|
return await context.SaveChangesAsync(cancellationToken) > 0
|
||||||
|
? Result.Ok()
|
||||||
|
: Result.Fail($"Failed to update order refund {orderRefundId}");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Result.Fail(new Error(ex.Message).CausedBy(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async ValueTask<Result> UpdateOrderStatusAsync(UpdateOrder request, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
|
var order = await context.Orders.FirstOrDefaultAsync(o => o.Id == request.OrderId, cancellationToken);
|
||||||
|
|
||||||
|
if (order is null)
|
||||||
|
return Result.Fail(new Error($"Order {request.OrderId} not found"));
|
||||||
|
|
||||||
|
order.Status = request.Status;
|
||||||
|
order.UpdatedAt = DateTime.UtcNow;
|
||||||
|
|
||||||
|
if(!string.IsNullOrWhiteSpace(request.InvoiceUrl)) order.InvoiceUrl = request.InvoiceUrl;
|
||||||
|
|
||||||
|
if(request.Requirements?.Length > 0) order.Requirements = request.Requirements;
|
||||||
|
if(request.Notes?.Length > 0) order.Notes = request.Notes;
|
||||||
|
|
||||||
|
return await context.SaveChangesAsync(cancellationToken) > 0
|
||||||
|
? Result.Ok()
|
||||||
|
: Result.Fail(new Error($"Failed to update order {request.OrderId}"));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Result.Fail(new Error(ex.Message).CausedBy(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+771
@@ -0,0 +1,771 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using LiteCharms.Features.TechShop.Postgres;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.TechShop.Postgres.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(ShopDbContext))]
|
||||||
|
[Migration("20260512065421_Init")]
|
||||||
|
partial class Init
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder
|
||||||
|
.HasAnnotation("ProductVersion", "10.0.7")
|
||||||
|
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
||||||
|
|
||||||
|
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Entities.Customer", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<bool>("Active")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasDefaultValue(true);
|
||||||
|
|
||||||
|
b.Property<string>("Address")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("City")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Company")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Country")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasDefaultValueSql("now()");
|
||||||
|
|
||||||
|
b.Property<string>("Discord")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Email")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("LastName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("LinkedIn")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Phone")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("PostalCode")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Region")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Slack")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Tax")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset?>("UpdatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<string>("Website")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Whatsapp")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Customer", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Entities.Lead", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<long?>("AdGroupId")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<long?>("AdName")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<string>("AppClickId")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("AttributionHash")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<long?>("CampaignId")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<string>("ClickId")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("ClickLocation")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasDefaultValueSql("now()");
|
||||||
|
|
||||||
|
b.Property<Guid?>("CustomerId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<long?>("FeedItemId")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<string>("Source")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<int>("Status")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<long?>("TargetId")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset?>("UpdatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<string>("WebClickId")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("CustomerId");
|
||||||
|
|
||||||
|
b.ToTable("Lead", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Entities.Notification", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<string>("CorrelationId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<int>("CorrelationIdType")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasDefaultValueSql("now()");
|
||||||
|
|
||||||
|
b.Property<int>("Direction")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.PrimitiveCollection<string>("Errors")
|
||||||
|
.HasColumnType("jsonb");
|
||||||
|
|
||||||
|
b.Property<bool>("HasError")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasDefaultValue(false);
|
||||||
|
|
||||||
|
b.Property<bool>("IsHtml")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasDefaultValue(false);
|
||||||
|
|
||||||
|
b.Property<bool>("IsInternal")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasDefaultValue(true);
|
||||||
|
|
||||||
|
b.Property<string>("Message")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<int>("Platform")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<int>("Priority")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<bool>("Processed")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasDefaultValue(false);
|
||||||
|
|
||||||
|
b.Property<string>("Recipient")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("RecipientAddress")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Sender")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("SenderName")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Subject")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset?>("UpdatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Notification", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Entities.Order", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasDefaultValueSql("now()");
|
||||||
|
|
||||||
|
b.Property<Guid>("CustomerId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<string>("InvoiceUrl")
|
||||||
|
.HasMaxLength(2048)
|
||||||
|
.HasColumnType("character varying(2048)");
|
||||||
|
|
||||||
|
b.PrimitiveCollection<string>("Notes")
|
||||||
|
.HasColumnType("jsonb");
|
||||||
|
|
||||||
|
b.PrimitiveCollection<string>("Requirements")
|
||||||
|
.HasColumnType("jsonb");
|
||||||
|
|
||||||
|
b.Property<int>("Status")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.PrimitiveCollection<string>("Terms")
|
||||||
|
.HasColumnType("jsonb");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset?>("UpdatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("CustomerId");
|
||||||
|
|
||||||
|
b.ToTable("Order", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Entities.OrderRefund", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<decimal>("Amount")
|
||||||
|
.HasPrecision(18, 2)
|
||||||
|
.HasColumnType("numeric(18,2)");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasDefaultValueSql("now()");
|
||||||
|
|
||||||
|
b.Property<Guid>("OrderId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<string>("Reason")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("OrderId");
|
||||||
|
|
||||||
|
b.ToTable("OrderRefund", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Entities.Package", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<bool>("Active")
|
||||||
|
.HasColumnType("boolean");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasDefaultValueSql("now()");
|
||||||
|
|
||||||
|
b.Property<string>("Description")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(2048)
|
||||||
|
.HasColumnType("character varying(2048)");
|
||||||
|
|
||||||
|
b.Property<string>("ImageUrl")
|
||||||
|
.HasMaxLength(2048)
|
||||||
|
.HasColumnType("character varying(2048)");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Summary")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(512)
|
||||||
|
.HasColumnType("character varying(512)");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset?>("UpdatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Package", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Entities.PackageItem", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<bool>("Active")
|
||||||
|
.HasColumnType("boolean");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasDefaultValueSql("now()");
|
||||||
|
|
||||||
|
b.Property<Guid>("PackageId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<Guid>("ProductPriceId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("PackageId");
|
||||||
|
|
||||||
|
b.HasIndex("ProductPriceId");
|
||||||
|
|
||||||
|
b.ToTable("PackageItem", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Entities.Product", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<bool>("Active")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasDefaultValue(true);
|
||||||
|
|
||||||
|
b.Property<string>("Description")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(2048)
|
||||||
|
.HasColumnType("character varying(2048)");
|
||||||
|
|
||||||
|
b.Property<string>("ImageUrl")
|
||||||
|
.HasMaxLength(2048)
|
||||||
|
.HasColumnType("character varying(2048)");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Summary")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(512)
|
||||||
|
.HasColumnType("character varying(512)");
|
||||||
|
|
||||||
|
b.PrimitiveCollection<string>("Thumbnails")
|
||||||
|
.HasColumnType("jsonb");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Product", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Entities.ProductPrice", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<bool>("Active")
|
||||||
|
.HasColumnType("boolean");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasDefaultValueSql("now()");
|
||||||
|
|
||||||
|
b.Property<decimal>("Discount")
|
||||||
|
.HasPrecision(18, 2)
|
||||||
|
.HasColumnType("numeric(18,2)");
|
||||||
|
|
||||||
|
b.Property<decimal>("Price")
|
||||||
|
.HasPrecision(18, 2)
|
||||||
|
.HasColumnType("numeric(18,2)");
|
||||||
|
|
||||||
|
b.Property<Guid>("ProductId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset?>("UpdatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("ProductId");
|
||||||
|
|
||||||
|
b.ToTable("ProductPrice", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Entities.Quote", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasDefaultValueSql("now()");
|
||||||
|
|
||||||
|
b.Property<Guid>("CustomerId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset?>("ExpiredAt")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<string>("InvoiceUrl")
|
||||||
|
.HasMaxLength(2048)
|
||||||
|
.HasColumnType("character varying(2048)");
|
||||||
|
|
||||||
|
b.Property<Guid?>("OrderId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<string>("Reason")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<Guid?>("ShoppingCartId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<int>("Status")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset?>("UpdatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("CustomerId");
|
||||||
|
|
||||||
|
b.HasIndex("OrderId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.HasIndex("ShoppingCartId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("Quote", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Entities.ShoppingCart", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasDefaultValueSql("now()");
|
||||||
|
|
||||||
|
b.Property<Guid>("CustomerId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<Guid?>("OrderId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset?>("UpdatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("CustomerId");
|
||||||
|
|
||||||
|
b.HasIndex("OrderId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("ShoppingCart", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Entities.ShoppingCartItem", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("CreatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<Guid>("ProductPriceId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<int>("Quantity")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<Guid>("ShoppingCartId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("UpdatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("ProductPriceId");
|
||||||
|
|
||||||
|
b.HasIndex("ShoppingCartId");
|
||||||
|
|
||||||
|
b.ToTable("ShoppingCartItems");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Entities.ShoppingCartPackage", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasDefaultValueSql("now()");
|
||||||
|
|
||||||
|
b.Property<Guid>("PackageId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<Guid>("ShoppingCartId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("PackageId");
|
||||||
|
|
||||||
|
b.HasIndex("ShoppingCartId");
|
||||||
|
|
||||||
|
b.ToTable("ShoppingCartPackage", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Entities.Lead", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("LiteCharms.Entities.Customer", "Customer")
|
||||||
|
.WithMany("Leads")
|
||||||
|
.HasForeignKey("CustomerId");
|
||||||
|
|
||||||
|
b.Navigation("Customer");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Entities.Order", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("LiteCharms.Entities.Customer", "Customer")
|
||||||
|
.WithMany("Orders")
|
||||||
|
.HasForeignKey("CustomerId")
|
||||||
|
.OnDelete(DeleteBehavior.Restrict)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Customer");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Entities.OrderRefund", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("LiteCharms.Entities.Order", "Order")
|
||||||
|
.WithMany("Refunds")
|
||||||
|
.HasForeignKey("OrderId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Order");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Entities.PackageItem", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("LiteCharms.Entities.Package", "Package")
|
||||||
|
.WithMany("PackageItems")
|
||||||
|
.HasForeignKey("PackageId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("LiteCharms.Entities.ProductPrice", "ProductPrice")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ProductPriceId")
|
||||||
|
.OnDelete(DeleteBehavior.Restrict)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Package");
|
||||||
|
|
||||||
|
b.Navigation("ProductPrice");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Entities.ProductPrice", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("LiteCharms.Entities.Product", "Product")
|
||||||
|
.WithMany("ProductPrices")
|
||||||
|
.HasForeignKey("ProductId")
|
||||||
|
.OnDelete(DeleteBehavior.Restrict)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Product");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Entities.Quote", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("LiteCharms.Entities.Customer", "Customer")
|
||||||
|
.WithMany("Quotes")
|
||||||
|
.HasForeignKey("CustomerId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("LiteCharms.Entities.Order", "Order")
|
||||||
|
.WithOne("Quote")
|
||||||
|
.HasForeignKey("LiteCharms.Entities.Quote", "OrderId");
|
||||||
|
|
||||||
|
b.HasOne("LiteCharms.Entities.ShoppingCart", "ShoppingCart")
|
||||||
|
.WithOne("Quote")
|
||||||
|
.HasForeignKey("LiteCharms.Entities.Quote", "ShoppingCartId");
|
||||||
|
|
||||||
|
b.Navigation("Customer");
|
||||||
|
|
||||||
|
b.Navigation("Order");
|
||||||
|
|
||||||
|
b.Navigation("ShoppingCart");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Entities.ShoppingCart", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("LiteCharms.Entities.Customer", "Customer")
|
||||||
|
.WithMany("ShoppingCarts")
|
||||||
|
.HasForeignKey("CustomerId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("LiteCharms.Entities.Order", "Order")
|
||||||
|
.WithOne("ShoppingCart")
|
||||||
|
.HasForeignKey("LiteCharms.Entities.ShoppingCart", "OrderId")
|
||||||
|
.OnDelete(DeleteBehavior.SetNull);
|
||||||
|
|
||||||
|
b.Navigation("Customer");
|
||||||
|
|
||||||
|
b.Navigation("Order");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Entities.ShoppingCartItem", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("LiteCharms.Entities.ProductPrice", "ProductPrice")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ProductPriceId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("LiteCharms.Entities.ShoppingCart", "ShoppingCart")
|
||||||
|
.WithMany("ShoppingCartItems")
|
||||||
|
.HasForeignKey("ShoppingCartId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("ProductPrice");
|
||||||
|
|
||||||
|
b.Navigation("ShoppingCart");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Entities.ShoppingCartPackage", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("LiteCharms.Entities.Package", "Package")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("PackageId")
|
||||||
|
.OnDelete(DeleteBehavior.Restrict)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("LiteCharms.Entities.ShoppingCart", "ShoppingCart")
|
||||||
|
.WithMany("ShoppingCartPackages")
|
||||||
|
.HasForeignKey("ShoppingCartId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Package");
|
||||||
|
|
||||||
|
b.Navigation("ShoppingCart");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Entities.Customer", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Leads");
|
||||||
|
|
||||||
|
b.Navigation("Orders");
|
||||||
|
|
||||||
|
b.Navigation("Quotes");
|
||||||
|
|
||||||
|
b.Navigation("ShoppingCarts");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Entities.Order", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Quote");
|
||||||
|
|
||||||
|
b.Navigation("Refunds");
|
||||||
|
|
||||||
|
b.Navigation("ShoppingCart");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Entities.Package", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("PackageItems");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Entities.Product", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("ProductPrices");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Entities.ShoppingCart", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Quote");
|
||||||
|
|
||||||
|
b.Navigation("ShoppingCartItems");
|
||||||
|
|
||||||
|
b.Navigation("ShoppingCartPackages");
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,474 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.TechShop.Postgres.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class Init : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Customer",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
CreatedAt = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false, defaultValueSql: "now()"),
|
||||||
|
UpdatedAt = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: true),
|
||||||
|
Company = table.Column<string>(type: "text", nullable: true),
|
||||||
|
Name = table.Column<string>(type: "text", nullable: false),
|
||||||
|
LastName = table.Column<string>(type: "text", nullable: false),
|
||||||
|
Tax = table.Column<string>(type: "text", nullable: true),
|
||||||
|
Email = table.Column<string>(type: "text", nullable: false),
|
||||||
|
Discord = table.Column<string>(type: "text", nullable: true),
|
||||||
|
Slack = table.Column<string>(type: "text", nullable: true),
|
||||||
|
LinkedIn = table.Column<string>(type: "text", nullable: true),
|
||||||
|
Whatsapp = table.Column<string>(type: "text", nullable: true),
|
||||||
|
Website = table.Column<string>(type: "text", nullable: true),
|
||||||
|
Phone = table.Column<string>(type: "text", nullable: true),
|
||||||
|
Address = table.Column<string>(type: "text", nullable: true),
|
||||||
|
City = table.Column<string>(type: "text", nullable: true),
|
||||||
|
Region = table.Column<string>(type: "text", nullable: true),
|
||||||
|
Country = table.Column<string>(type: "text", nullable: true),
|
||||||
|
PostalCode = table.Column<string>(type: "text", nullable: true),
|
||||||
|
Active = table.Column<bool>(type: "boolean", nullable: false, defaultValue: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_Customer", x => x.Id);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Notification",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
CreatedAt = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false, defaultValueSql: "now()"),
|
||||||
|
UpdatedAt = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: true),
|
||||||
|
Direction = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
Platform = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
Priority = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
CorrelationIdType = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
Sender = table.Column<string>(type: "text", nullable: false),
|
||||||
|
SenderName = table.Column<string>(type: "text", nullable: true),
|
||||||
|
Subject = table.Column<string>(type: "text", nullable: false),
|
||||||
|
Message = table.Column<string>(type: "text", nullable: false),
|
||||||
|
Recipient = table.Column<string>(type: "text", nullable: false),
|
||||||
|
RecipientAddress = table.Column<string>(type: "text", nullable: false),
|
||||||
|
CorrelationId = table.Column<string>(type: "text", nullable: false),
|
||||||
|
IsHtml = table.Column<bool>(type: "boolean", nullable: false, defaultValue: false),
|
||||||
|
IsInternal = table.Column<bool>(type: "boolean", nullable: false, defaultValue: true),
|
||||||
|
Processed = table.Column<bool>(type: "boolean", nullable: false, defaultValue: false),
|
||||||
|
HasError = table.Column<bool>(type: "boolean", nullable: false, defaultValue: false),
|
||||||
|
Errors = table.Column<string>(type: "jsonb", nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_Notification", x => x.Id);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Package",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
CreatedAt = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false, defaultValueSql: "now()"),
|
||||||
|
UpdatedAt = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: true),
|
||||||
|
Name = table.Column<string>(type: "text", nullable: false),
|
||||||
|
Summary = table.Column<string>(type: "character varying(512)", maxLength: 512, nullable: false),
|
||||||
|
Description = table.Column<string>(type: "character varying(2048)", maxLength: 2048, nullable: false),
|
||||||
|
ImageUrl = table.Column<string>(type: "character varying(2048)", maxLength: 2048, nullable: true),
|
||||||
|
Active = table.Column<bool>(type: "boolean", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_Package", x => x.Id);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Product",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
Name = table.Column<string>(type: "text", nullable: false),
|
||||||
|
Summary = table.Column<string>(type: "character varying(512)", maxLength: 512, nullable: false),
|
||||||
|
Description = table.Column<string>(type: "character varying(2048)", maxLength: 2048, nullable: false),
|
||||||
|
ImageUrl = table.Column<string>(type: "character varying(2048)", maxLength: 2048, nullable: true),
|
||||||
|
Thumbnails = table.Column<string>(type: "jsonb", nullable: true),
|
||||||
|
Active = table.Column<bool>(type: "boolean", nullable: false, defaultValue: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_Product", x => x.Id);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Lead",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
CreatedAt = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false, defaultValueSql: "now()"),
|
||||||
|
UpdatedAt = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: true),
|
||||||
|
CustomerId = table.Column<Guid>(type: "uuid", nullable: true),
|
||||||
|
Source = table.Column<string>(type: "text", nullable: true),
|
||||||
|
ClickId = table.Column<string>(type: "text", nullable: true),
|
||||||
|
WebClickId = table.Column<string>(type: "text", nullable: true),
|
||||||
|
AppClickId = table.Column<string>(type: "text", nullable: true),
|
||||||
|
CampaignId = table.Column<long>(type: "bigint", nullable: true),
|
||||||
|
AdGroupId = table.Column<long>(type: "bigint", nullable: true),
|
||||||
|
AdName = table.Column<long>(type: "bigint", nullable: true),
|
||||||
|
TargetId = table.Column<long>(type: "bigint", nullable: true),
|
||||||
|
FeedItemId = table.Column<long>(type: "bigint", nullable: true),
|
||||||
|
ClickLocation = table.Column<string>(type: "text", nullable: true),
|
||||||
|
AttributionHash = table.Column<string>(type: "text", nullable: false),
|
||||||
|
Status = table.Column<int>(type: "integer", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_Lead", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_Lead_Customer_CustomerId",
|
||||||
|
column: x => x.CustomerId,
|
||||||
|
principalTable: "Customer",
|
||||||
|
principalColumn: "Id");
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Order",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
CreatedAt = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false, defaultValueSql: "now()"),
|
||||||
|
UpdatedAt = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: true),
|
||||||
|
CustomerId = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
Status = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
Requirements = table.Column<string>(type: "jsonb", nullable: true),
|
||||||
|
Notes = table.Column<string>(type: "jsonb", nullable: true),
|
||||||
|
Terms = table.Column<string>(type: "jsonb", nullable: true),
|
||||||
|
InvoiceUrl = table.Column<string>(type: "character varying(2048)", maxLength: 2048, nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_Order", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_Order_Customer_CustomerId",
|
||||||
|
column: x => x.CustomerId,
|
||||||
|
principalTable: "Customer",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Restrict);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "ProductPrice",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
CreatedAt = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false, defaultValueSql: "now()"),
|
||||||
|
UpdatedAt = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: true),
|
||||||
|
ProductId = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
Price = table.Column<decimal>(type: "numeric(18,2)", precision: 18, scale: 2, nullable: false),
|
||||||
|
Discount = table.Column<decimal>(type: "numeric(18,2)", precision: 18, scale: 2, nullable: false),
|
||||||
|
Active = table.Column<bool>(type: "boolean", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_ProductPrice", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_ProductPrice_Product_ProductId",
|
||||||
|
column: x => x.ProductId,
|
||||||
|
principalTable: "Product",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Restrict);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "OrderRefund",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
CreatedAt = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false, defaultValueSql: "now()"),
|
||||||
|
OrderId = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
Reason = table.Column<string>(type: "text", nullable: false),
|
||||||
|
Amount = table.Column<decimal>(type: "numeric(18,2)", precision: 18, scale: 2, nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_OrderRefund", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_OrderRefund_Order_OrderId",
|
||||||
|
column: x => x.OrderId,
|
||||||
|
principalTable: "Order",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "ShoppingCart",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
CreatedAt = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false, defaultValueSql: "now()"),
|
||||||
|
UpdatedAt = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: true),
|
||||||
|
CustomerId = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
OrderId = table.Column<Guid>(type: "uuid", nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_ShoppingCart", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_ShoppingCart_Customer_CustomerId",
|
||||||
|
column: x => x.CustomerId,
|
||||||
|
principalTable: "Customer",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_ShoppingCart_Order_OrderId",
|
||||||
|
column: x => x.OrderId,
|
||||||
|
principalTable: "Order",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.SetNull);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "PackageItem",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
PackageId = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
ProductPriceId = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
CreatedAt = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false, defaultValueSql: "now()"),
|
||||||
|
Active = table.Column<bool>(type: "boolean", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_PackageItem", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_PackageItem_Package_PackageId",
|
||||||
|
column: x => x.PackageId,
|
||||||
|
principalTable: "Package",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_PackageItem_ProductPrice_ProductPriceId",
|
||||||
|
column: x => x.ProductPriceId,
|
||||||
|
principalTable: "ProductPrice",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Restrict);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Quote",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
CreatedAt = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false, defaultValueSql: "now()"),
|
||||||
|
UpdatedAt = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: true),
|
||||||
|
ExpiredAt = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: true),
|
||||||
|
CustomerId = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
OrderId = table.Column<Guid>(type: "uuid", nullable: true),
|
||||||
|
ShoppingCartId = table.Column<Guid>(type: "uuid", nullable: true),
|
||||||
|
Status = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
InvoiceUrl = table.Column<string>(type: "character varying(2048)", maxLength: 2048, nullable: true),
|
||||||
|
Reason = table.Column<string>(type: "text", nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_Quote", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_Quote_Customer_CustomerId",
|
||||||
|
column: x => x.CustomerId,
|
||||||
|
principalTable: "Customer",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_Quote_Order_OrderId",
|
||||||
|
column: x => x.OrderId,
|
||||||
|
principalTable: "Order",
|
||||||
|
principalColumn: "Id");
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_Quote_ShoppingCart_ShoppingCartId",
|
||||||
|
column: x => x.ShoppingCartId,
|
||||||
|
principalTable: "ShoppingCart",
|
||||||
|
principalColumn: "Id");
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "ShoppingCartItems",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
ShoppingCartId = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
ProductPriceId = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
CreatedAt = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false),
|
||||||
|
UpdatedAt = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false),
|
||||||
|
Quantity = table.Column<int>(type: "integer", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_ShoppingCartItems", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_ShoppingCartItems_ProductPrice_ProductPriceId",
|
||||||
|
column: x => x.ProductPriceId,
|
||||||
|
principalTable: "ProductPrice",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_ShoppingCartItems_ShoppingCart_ShoppingCartId",
|
||||||
|
column: x => x.ShoppingCartId,
|
||||||
|
principalTable: "ShoppingCart",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "ShoppingCartPackage",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
CreatedAt = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false, defaultValueSql: "now()"),
|
||||||
|
ShoppingCartId = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
PackageId = table.Column<Guid>(type: "uuid", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_ShoppingCartPackage", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_ShoppingCartPackage_Package_PackageId",
|
||||||
|
column: x => x.PackageId,
|
||||||
|
principalTable: "Package",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Restrict);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_ShoppingCartPackage_ShoppingCart_ShoppingCartId",
|
||||||
|
column: x => x.ShoppingCartId,
|
||||||
|
principalTable: "ShoppingCart",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Lead_CustomerId",
|
||||||
|
table: "Lead",
|
||||||
|
column: "CustomerId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Order_CustomerId",
|
||||||
|
table: "Order",
|
||||||
|
column: "CustomerId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_OrderRefund_OrderId",
|
||||||
|
table: "OrderRefund",
|
||||||
|
column: "OrderId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_PackageItem_PackageId",
|
||||||
|
table: "PackageItem",
|
||||||
|
column: "PackageId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_PackageItem_ProductPriceId",
|
||||||
|
table: "PackageItem",
|
||||||
|
column: "ProductPriceId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_ProductPrice_ProductId",
|
||||||
|
table: "ProductPrice",
|
||||||
|
column: "ProductId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Quote_CustomerId",
|
||||||
|
table: "Quote",
|
||||||
|
column: "CustomerId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Quote_OrderId",
|
||||||
|
table: "Quote",
|
||||||
|
column: "OrderId",
|
||||||
|
unique: true);
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Quote_ShoppingCartId",
|
||||||
|
table: "Quote",
|
||||||
|
column: "ShoppingCartId",
|
||||||
|
unique: true);
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_ShoppingCart_CustomerId",
|
||||||
|
table: "ShoppingCart",
|
||||||
|
column: "CustomerId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_ShoppingCart_OrderId",
|
||||||
|
table: "ShoppingCart",
|
||||||
|
column: "OrderId",
|
||||||
|
unique: true);
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_ShoppingCartItems_ProductPriceId",
|
||||||
|
table: "ShoppingCartItems",
|
||||||
|
column: "ProductPriceId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_ShoppingCartItems_ShoppingCartId",
|
||||||
|
table: "ShoppingCartItems",
|
||||||
|
column: "ShoppingCartId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_ShoppingCartPackage_PackageId",
|
||||||
|
table: "ShoppingCartPackage",
|
||||||
|
column: "PackageId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_ShoppingCartPackage_ShoppingCartId",
|
||||||
|
table: "ShoppingCartPackage",
|
||||||
|
column: "ShoppingCartId");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Lead");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Notification");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "OrderRefund");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "PackageItem");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Quote");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "ShoppingCartItems");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "ShoppingCartPackage");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "ProductPrice");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Package");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "ShoppingCart");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Product");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Order");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Customer");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Generated
+871
@@ -0,0 +1,871 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using LiteCharms.Features.TechShop.Postgres;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.TechShop.Postgres.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(ShopDbContext))]
|
||||||
|
[Migration("20260514004002_UsedStringTableNames")]
|
||||||
|
partial class UsedStringTableNames
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder
|
||||||
|
.HasAnnotation("ProductVersion", "10.0.8")
|
||||||
|
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
||||||
|
|
||||||
|
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.CartPackages.Entities.Package", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<bool>("Active")
|
||||||
|
.HasColumnType("boolean");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasDefaultValueSql("now()");
|
||||||
|
|
||||||
|
b.Property<string>("Description")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(2048)
|
||||||
|
.HasColumnType("character varying(2048)");
|
||||||
|
|
||||||
|
b.Property<string>("ImageUrl")
|
||||||
|
.HasMaxLength(2048)
|
||||||
|
.HasColumnType("character varying(2048)");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Summary")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(512)
|
||||||
|
.HasColumnType("character varying(512)");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("UpdatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Package", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.CartPackages.Entities.PackageItem", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<bool>("Active")
|
||||||
|
.HasColumnType("boolean");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasDefaultValueSql("now()");
|
||||||
|
|
||||||
|
b.Property<Guid>("PackageId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<Guid>("ProductPriceId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("PackageId");
|
||||||
|
|
||||||
|
b.HasIndex("ProductPriceId");
|
||||||
|
|
||||||
|
b.ToTable("PackageItem", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.Customers.Entities.Customer", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<bool>("Active")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasDefaultValue(true);
|
||||||
|
|
||||||
|
b.Property<string>("Address")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("City")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Company")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Country")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasDefaultValueSql("now()");
|
||||||
|
|
||||||
|
b.Property<string>("Discord")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Email")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("LastName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("LinkedIn")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Phone")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("PostalCode")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Region")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Slack")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Tax")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("UpdatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<string>("Website")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Whatsapp")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Customers", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.Customers.Models.Customer", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<bool>("Active")
|
||||||
|
.HasColumnType("boolean");
|
||||||
|
|
||||||
|
b.Property<string>("Address")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("City")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Company")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Country")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<string>("Discord")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Email")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("LastName")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("LinkedIn")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Phone")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("PostalCode")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Region")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Slack")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Tax")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("UpdatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<string>("Website")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Whatsapp")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Customer");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.Leads.Entities.Lead", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<long?>("AdGroupId")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<long?>("AdName")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<string>("AppClickId")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("AttributionHash")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<long?>("CampaignId")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<string>("ClickId")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("ClickLocation")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasDefaultValueSql("now()");
|
||||||
|
|
||||||
|
b.Property<Guid?>("CustomerId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<Guid?>("CustomerId1")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<long?>("FeedItemId")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<string>("Source")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<int>("Status")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<long?>("TargetId")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("UpdatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<string>("WebClickId")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("CustomerId");
|
||||||
|
|
||||||
|
b.HasIndex("CustomerId1");
|
||||||
|
|
||||||
|
b.ToTable("Leads", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.Notifications.Entities.Notification", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<string>("CorrelationId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<int>("CorrelationIdType")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasDefaultValueSql("now()");
|
||||||
|
|
||||||
|
b.Property<int>("Direction")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.PrimitiveCollection<string>("Errors")
|
||||||
|
.HasColumnType("jsonb");
|
||||||
|
|
||||||
|
b.Property<bool>("HasError")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasDefaultValue(false);
|
||||||
|
|
||||||
|
b.Property<bool>("IsHtml")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasDefaultValue(false);
|
||||||
|
|
||||||
|
b.Property<bool>("IsInternal")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasDefaultValue(true);
|
||||||
|
|
||||||
|
b.Property<string>("Message")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<int>("Platform")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<int>("Priority")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<bool>("Processed")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasDefaultValue(false);
|
||||||
|
|
||||||
|
b.Property<string>("RecipientAddress")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("RecipientName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("SenderAddress")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("SenderName")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Subject")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("UpdatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Notification", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.Orders.Entities.Order", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasDefaultValueSql("now()");
|
||||||
|
|
||||||
|
b.Property<Guid>("CustomerId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<string>("InvoiceUrl")
|
||||||
|
.HasMaxLength(2048)
|
||||||
|
.HasColumnType("character varying(2048)");
|
||||||
|
|
||||||
|
b.PrimitiveCollection<string>("Notes")
|
||||||
|
.HasColumnType("jsonb");
|
||||||
|
|
||||||
|
b.PrimitiveCollection<string>("Requirements")
|
||||||
|
.HasColumnType("jsonb");
|
||||||
|
|
||||||
|
b.Property<int>("Status")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.PrimitiveCollection<string>("Terms")
|
||||||
|
.HasColumnType("jsonb");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("UpdatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("CustomerId");
|
||||||
|
|
||||||
|
b.ToTable("Orders", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.Orders.Entities.OrderRefund", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<decimal>("Amount")
|
||||||
|
.HasPrecision(18, 2)
|
||||||
|
.HasColumnType("numeric(18,2)");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasDefaultValueSql("now()");
|
||||||
|
|
||||||
|
b.Property<Guid>("OrderId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<string>("Reason")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("OrderId");
|
||||||
|
|
||||||
|
b.ToTable("OrderRefunds", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.Products.Entities.Product", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<bool>("Active")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasDefaultValue(true);
|
||||||
|
|
||||||
|
b.Property<string>("Description")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(2048)
|
||||||
|
.HasColumnType("character varying(2048)");
|
||||||
|
|
||||||
|
b.Property<string>("ImageUrl")
|
||||||
|
.HasMaxLength(2048)
|
||||||
|
.HasColumnType("character varying(2048)");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Summary")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(512)
|
||||||
|
.HasColumnType("character varying(512)");
|
||||||
|
|
||||||
|
b.PrimitiveCollection<string>("Thumbnails")
|
||||||
|
.HasColumnType("jsonb");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Products", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.Products.Entities.ProductPrice", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<bool>("Active")
|
||||||
|
.HasColumnType("boolean");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasDefaultValueSql("now()");
|
||||||
|
|
||||||
|
b.Property<decimal>("Discount")
|
||||||
|
.HasPrecision(18, 2)
|
||||||
|
.HasColumnType("numeric(18,2)");
|
||||||
|
|
||||||
|
b.Property<decimal>("Price")
|
||||||
|
.HasPrecision(18, 2)
|
||||||
|
.HasColumnType("numeric(18,2)");
|
||||||
|
|
||||||
|
b.Property<Guid>("ProductId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("UpdatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("ProductId");
|
||||||
|
|
||||||
|
b.ToTable("ProductPrices", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.Quotes.Entities.Quote", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasDefaultValueSql("now()");
|
||||||
|
|
||||||
|
b.Property<Guid>("CustomerId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("ExpiredAt")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<string>("InvoiceUrl")
|
||||||
|
.HasMaxLength(2048)
|
||||||
|
.HasColumnType("character varying(2048)");
|
||||||
|
|
||||||
|
b.Property<Guid?>("OrderId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<string>("Reason")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<Guid?>("ShoppingCartId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<int>("Status")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("UpdatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("CustomerId");
|
||||||
|
|
||||||
|
b.HasIndex("OrderId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.HasIndex("ShoppingCartId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("Quotes", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.ShoppingCarts.Entities.ShoppingCart", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasDefaultValueSql("now()");
|
||||||
|
|
||||||
|
b.Property<Guid>("CustomerId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<Guid?>("OrderId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("UpdatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("CustomerId");
|
||||||
|
|
||||||
|
b.HasIndex("OrderId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("ShoppingCarts", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.ShoppingCarts.Entities.ShoppingCartItem", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasDefaultValueSql("now()");
|
||||||
|
|
||||||
|
b.Property<Guid>("ProductPriceId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<Guid?>("ProductPriceId1")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<int>("Quantity")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasDefaultValue(1);
|
||||||
|
|
||||||
|
b.Property<Guid>("ShoppingCartId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<Guid?>("ShoppingCartId1")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("UpdatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("ProductPriceId");
|
||||||
|
|
||||||
|
b.HasIndex("ProductPriceId1");
|
||||||
|
|
||||||
|
b.HasIndex("ShoppingCartId");
|
||||||
|
|
||||||
|
b.HasIndex("ShoppingCartId1");
|
||||||
|
|
||||||
|
b.ToTable("ShoppingCartItems", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.ShoppingCarts.Entities.ShoppingCartPackage", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasDefaultValueSql("now()");
|
||||||
|
|
||||||
|
b.Property<Guid>("PackageId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<Guid>("ShoppingCartId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("PackageId");
|
||||||
|
|
||||||
|
b.HasIndex("ShoppingCartId");
|
||||||
|
|
||||||
|
b.ToTable("ShoppingCartPackages", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.CartPackages.Entities.PackageItem", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("LiteCharms.Features.Shop.CartPackages.Entities.Package", "Package")
|
||||||
|
.WithMany("PackageItems")
|
||||||
|
.HasForeignKey("PackageId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("LiteCharms.Features.Shop.Products.Entities.ProductPrice", "ProductPrice")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ProductPriceId")
|
||||||
|
.OnDelete(DeleteBehavior.Restrict)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Package");
|
||||||
|
|
||||||
|
b.Navigation("ProductPrice");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.Leads.Entities.Lead", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("LiteCharms.Features.Shop.Customers.Models.Customer", "Customer")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("CustomerId")
|
||||||
|
.OnDelete(DeleteBehavior.Restrict);
|
||||||
|
|
||||||
|
b.HasOne("LiteCharms.Features.Shop.Customers.Entities.Customer", null)
|
||||||
|
.WithMany("Leads")
|
||||||
|
.HasForeignKey("CustomerId1");
|
||||||
|
|
||||||
|
b.Navigation("Customer");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.Orders.Entities.Order", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("LiteCharms.Features.Shop.Customers.Entities.Customer", "Customer")
|
||||||
|
.WithMany("Orders")
|
||||||
|
.HasForeignKey("CustomerId")
|
||||||
|
.OnDelete(DeleteBehavior.Restrict)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Customer");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.Orders.Entities.OrderRefund", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("LiteCharms.Features.Shop.Orders.Entities.Order", "Order")
|
||||||
|
.WithMany("Refunds")
|
||||||
|
.HasForeignKey("OrderId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Order");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.Products.Entities.ProductPrice", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("LiteCharms.Features.Shop.Products.Entities.Product", "Product")
|
||||||
|
.WithMany("ProductPrices")
|
||||||
|
.HasForeignKey("ProductId")
|
||||||
|
.OnDelete(DeleteBehavior.Restrict)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Product");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.Quotes.Entities.Quote", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("LiteCharms.Features.Shop.Customers.Entities.Customer", "Customer")
|
||||||
|
.WithMany("Quotes")
|
||||||
|
.HasForeignKey("CustomerId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("LiteCharms.Features.Shop.Orders.Entities.Order", "Order")
|
||||||
|
.WithOne("Quote")
|
||||||
|
.HasForeignKey("LiteCharms.Features.Shop.Quotes.Entities.Quote", "OrderId");
|
||||||
|
|
||||||
|
b.HasOne("LiteCharms.Features.Shop.ShoppingCarts.Entities.ShoppingCart", "ShoppingCart")
|
||||||
|
.WithOne("Quote")
|
||||||
|
.HasForeignKey("LiteCharms.Features.Shop.Quotes.Entities.Quote", "ShoppingCartId");
|
||||||
|
|
||||||
|
b.Navigation("Customer");
|
||||||
|
|
||||||
|
b.Navigation("Order");
|
||||||
|
|
||||||
|
b.Navigation("ShoppingCart");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.ShoppingCarts.Entities.ShoppingCart", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("LiteCharms.Features.Shop.Customers.Entities.Customer", "Customer")
|
||||||
|
.WithMany("ShoppingCarts")
|
||||||
|
.HasForeignKey("CustomerId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("LiteCharms.Features.Shop.Orders.Entities.Order", "Order")
|
||||||
|
.WithOne("ShoppingCart")
|
||||||
|
.HasForeignKey("LiteCharms.Features.Shop.ShoppingCarts.Entities.ShoppingCart", "OrderId")
|
||||||
|
.OnDelete(DeleteBehavior.SetNull);
|
||||||
|
|
||||||
|
b.Navigation("Customer");
|
||||||
|
|
||||||
|
b.Navigation("Order");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.ShoppingCarts.Entities.ShoppingCartItem", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("LiteCharms.Features.Shop.Products.Entities.ProductPrice", null)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ProductPriceId")
|
||||||
|
.OnDelete(DeleteBehavior.Restrict)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("LiteCharms.Features.Shop.Products.Entities.ProductPrice", "ProductPrice")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ProductPriceId1");
|
||||||
|
|
||||||
|
b.HasOne("LiteCharms.Features.Shop.ShoppingCarts.Entities.ShoppingCart", null)
|
||||||
|
.WithMany("ShoppingCartItems")
|
||||||
|
.HasForeignKey("ShoppingCartId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("LiteCharms.Features.Shop.ShoppingCarts.Entities.ShoppingCart", "ShoppingCart")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ShoppingCartId1");
|
||||||
|
|
||||||
|
b.Navigation("ProductPrice");
|
||||||
|
|
||||||
|
b.Navigation("ShoppingCart");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.ShoppingCarts.Entities.ShoppingCartPackage", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("LiteCharms.Features.Shop.CartPackages.Entities.Package", "Package")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("PackageId")
|
||||||
|
.OnDelete(DeleteBehavior.Restrict)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("LiteCharms.Features.Shop.ShoppingCarts.Entities.ShoppingCart", "ShoppingCart")
|
||||||
|
.WithMany("ShoppingCartPackages")
|
||||||
|
.HasForeignKey("ShoppingCartId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Package");
|
||||||
|
|
||||||
|
b.Navigation("ShoppingCart");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.CartPackages.Entities.Package", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("PackageItems");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.Customers.Entities.Customer", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Leads");
|
||||||
|
|
||||||
|
b.Navigation("Orders");
|
||||||
|
|
||||||
|
b.Navigation("Quotes");
|
||||||
|
|
||||||
|
b.Navigation("ShoppingCarts");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.Orders.Entities.Order", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Quote");
|
||||||
|
|
||||||
|
b.Navigation("Refunds");
|
||||||
|
|
||||||
|
b.Navigation("ShoppingCart");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.Products.Entities.Product", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("ProductPrices");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.ShoppingCarts.Entities.ShoppingCart", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Quote");
|
||||||
|
|
||||||
|
b.Navigation("ShoppingCartItems");
|
||||||
|
|
||||||
|
b.Navigation("ShoppingCartPackages");
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+936
@@ -0,0 +1,936 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.TechShop.Postgres.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class UsedStringTableNames : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_PackageItem_ProductPrice_ProductPriceId",
|
||||||
|
table: "PackageItem");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_ShoppingCartItems_ProductPrice_ProductPriceId",
|
||||||
|
table: "ShoppingCartItems");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_ShoppingCartItems_ShoppingCart_ShoppingCartId",
|
||||||
|
table: "ShoppingCartItems");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Lead");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "OrderRefund");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "ProductPrice");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Quote");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "ShoppingCartPackage");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Product");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "ShoppingCart");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Order");
|
||||||
|
|
||||||
|
migrationBuilder.RenameColumn(
|
||||||
|
name: "Sender",
|
||||||
|
table: "Notification",
|
||||||
|
newName: "SenderAddress");
|
||||||
|
|
||||||
|
migrationBuilder.RenameColumn(
|
||||||
|
name: "Recipient",
|
||||||
|
table: "Notification",
|
||||||
|
newName: "RecipientName");
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<DateTime>(
|
||||||
|
name: "UpdatedAt",
|
||||||
|
table: "ShoppingCartItems",
|
||||||
|
type: "timestamp with time zone",
|
||||||
|
nullable: true,
|
||||||
|
oldClrType: typeof(DateTimeOffset),
|
||||||
|
oldType: "timestamp with time zone");
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<int>(
|
||||||
|
name: "Quantity",
|
||||||
|
table: "ShoppingCartItems",
|
||||||
|
type: "integer",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: 1,
|
||||||
|
oldClrType: typeof(int),
|
||||||
|
oldType: "integer");
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<DateTime>(
|
||||||
|
name: "CreatedAt",
|
||||||
|
table: "ShoppingCartItems",
|
||||||
|
type: "timestamp with time zone",
|
||||||
|
nullable: false,
|
||||||
|
defaultValueSql: "now()",
|
||||||
|
oldClrType: typeof(DateTimeOffset),
|
||||||
|
oldType: "timestamp with time zone");
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<Guid>(
|
||||||
|
name: "ProductPriceId1",
|
||||||
|
table: "ShoppingCartItems",
|
||||||
|
type: "uuid",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<Guid>(
|
||||||
|
name: "ShoppingCartId1",
|
||||||
|
table: "ShoppingCartItems",
|
||||||
|
type: "uuid",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<string>(
|
||||||
|
name: "Name",
|
||||||
|
table: "Customer",
|
||||||
|
type: "text",
|
||||||
|
nullable: true,
|
||||||
|
oldClrType: typeof(string),
|
||||||
|
oldType: "text");
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<string>(
|
||||||
|
name: "LastName",
|
||||||
|
table: "Customer",
|
||||||
|
type: "text",
|
||||||
|
nullable: true,
|
||||||
|
oldClrType: typeof(string),
|
||||||
|
oldType: "text");
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<string>(
|
||||||
|
name: "Email",
|
||||||
|
table: "Customer",
|
||||||
|
type: "text",
|
||||||
|
nullable: true,
|
||||||
|
oldClrType: typeof(string),
|
||||||
|
oldType: "text");
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<DateTime>(
|
||||||
|
name: "CreatedAt",
|
||||||
|
table: "Customer",
|
||||||
|
type: "timestamp with time zone",
|
||||||
|
nullable: false,
|
||||||
|
oldClrType: typeof(DateTimeOffset),
|
||||||
|
oldType: "timestamp with time zone",
|
||||||
|
oldDefaultValueSql: "now()");
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<bool>(
|
||||||
|
name: "Active",
|
||||||
|
table: "Customer",
|
||||||
|
type: "boolean",
|
||||||
|
nullable: false,
|
||||||
|
oldClrType: typeof(bool),
|
||||||
|
oldType: "boolean",
|
||||||
|
oldDefaultValue: true);
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Customers",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
CreatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: false, defaultValueSql: "now()"),
|
||||||
|
UpdatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
|
||||||
|
Company = table.Column<string>(type: "text", nullable: true),
|
||||||
|
Name = table.Column<string>(type: "text", nullable: false),
|
||||||
|
LastName = table.Column<string>(type: "text", nullable: false),
|
||||||
|
Tax = table.Column<string>(type: "text", nullable: true),
|
||||||
|
Email = table.Column<string>(type: "text", nullable: false),
|
||||||
|
Discord = table.Column<string>(type: "text", nullable: true),
|
||||||
|
Slack = table.Column<string>(type: "text", nullable: true),
|
||||||
|
LinkedIn = table.Column<string>(type: "text", nullable: true),
|
||||||
|
Whatsapp = table.Column<string>(type: "text", nullable: true),
|
||||||
|
Website = table.Column<string>(type: "text", nullable: true),
|
||||||
|
Phone = table.Column<string>(type: "text", nullable: true),
|
||||||
|
Address = table.Column<string>(type: "text", nullable: true),
|
||||||
|
City = table.Column<string>(type: "text", nullable: true),
|
||||||
|
Region = table.Column<string>(type: "text", nullable: true),
|
||||||
|
Country = table.Column<string>(type: "text", nullable: true),
|
||||||
|
PostalCode = table.Column<string>(type: "text", nullable: true),
|
||||||
|
Active = table.Column<bool>(type: "boolean", nullable: false, defaultValue: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_Customers", x => x.Id);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Products",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
Name = table.Column<string>(type: "text", nullable: false),
|
||||||
|
Summary = table.Column<string>(type: "character varying(512)", maxLength: 512, nullable: false),
|
||||||
|
Description = table.Column<string>(type: "character varying(2048)", maxLength: 2048, nullable: false),
|
||||||
|
ImageUrl = table.Column<string>(type: "character varying(2048)", maxLength: 2048, nullable: true),
|
||||||
|
Thumbnails = table.Column<string>(type: "jsonb", nullable: true),
|
||||||
|
Active = table.Column<bool>(type: "boolean", nullable: false, defaultValue: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_Products", x => x.Id);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Leads",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
CustomerId1 = table.Column<Guid>(type: "uuid", nullable: true),
|
||||||
|
CreatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: false, defaultValueSql: "now()"),
|
||||||
|
UpdatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
|
||||||
|
CustomerId = table.Column<Guid>(type: "uuid", nullable: true),
|
||||||
|
Source = table.Column<string>(type: "text", nullable: true),
|
||||||
|
ClickId = table.Column<string>(type: "text", nullable: true),
|
||||||
|
WebClickId = table.Column<string>(type: "text", nullable: true),
|
||||||
|
AppClickId = table.Column<string>(type: "text", nullable: true),
|
||||||
|
CampaignId = table.Column<long>(type: "bigint", nullable: true),
|
||||||
|
AdGroupId = table.Column<long>(type: "bigint", nullable: true),
|
||||||
|
AdName = table.Column<long>(type: "bigint", nullable: true),
|
||||||
|
TargetId = table.Column<long>(type: "bigint", nullable: true),
|
||||||
|
FeedItemId = table.Column<long>(type: "bigint", nullable: true),
|
||||||
|
ClickLocation = table.Column<string>(type: "text", nullable: true),
|
||||||
|
AttributionHash = table.Column<string>(type: "text", nullable: false),
|
||||||
|
Status = table.Column<int>(type: "integer", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_Leads", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_Leads_Customer_CustomerId",
|
||||||
|
column: x => x.CustomerId,
|
||||||
|
principalTable: "Customer",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Restrict);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_Leads_Customers_CustomerId1",
|
||||||
|
column: x => x.CustomerId1,
|
||||||
|
principalTable: "Customers",
|
||||||
|
principalColumn: "Id");
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Orders",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
CreatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: false, defaultValueSql: "now()"),
|
||||||
|
UpdatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
|
||||||
|
CustomerId = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
Status = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
Requirements = table.Column<string>(type: "jsonb", nullable: true),
|
||||||
|
Notes = table.Column<string>(type: "jsonb", nullable: true),
|
||||||
|
Terms = table.Column<string>(type: "jsonb", nullable: true),
|
||||||
|
InvoiceUrl = table.Column<string>(type: "character varying(2048)", maxLength: 2048, nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_Orders", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_Orders_Customers_CustomerId",
|
||||||
|
column: x => x.CustomerId,
|
||||||
|
principalTable: "Customers",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Restrict);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "ProductPrices",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
CreatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: false, defaultValueSql: "now()"),
|
||||||
|
UpdatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
|
||||||
|
ProductId = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
Price = table.Column<decimal>(type: "numeric(18,2)", precision: 18, scale: 2, nullable: false),
|
||||||
|
Discount = table.Column<decimal>(type: "numeric(18,2)", precision: 18, scale: 2, nullable: false),
|
||||||
|
Active = table.Column<bool>(type: "boolean", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_ProductPrices", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_ProductPrices_Products_ProductId",
|
||||||
|
column: x => x.ProductId,
|
||||||
|
principalTable: "Products",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Restrict);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "OrderRefunds",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
CreatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: false, defaultValueSql: "now()"),
|
||||||
|
OrderId = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
Reason = table.Column<string>(type: "text", nullable: false),
|
||||||
|
Amount = table.Column<decimal>(type: "numeric(18,2)", precision: 18, scale: 2, nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_OrderRefunds", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_OrderRefunds_Orders_OrderId",
|
||||||
|
column: x => x.OrderId,
|
||||||
|
principalTable: "Orders",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "ShoppingCarts",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
CreatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: false, defaultValueSql: "now()"),
|
||||||
|
UpdatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
|
||||||
|
CustomerId = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
OrderId = table.Column<Guid>(type: "uuid", nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_ShoppingCarts", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_ShoppingCarts_Customers_CustomerId",
|
||||||
|
column: x => x.CustomerId,
|
||||||
|
principalTable: "Customers",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_ShoppingCarts_Orders_OrderId",
|
||||||
|
column: x => x.OrderId,
|
||||||
|
principalTable: "Orders",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.SetNull);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Quotes",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
CreatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: false, defaultValueSql: "now()"),
|
||||||
|
UpdatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
|
||||||
|
ExpiredAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
|
||||||
|
CustomerId = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
OrderId = table.Column<Guid>(type: "uuid", nullable: true),
|
||||||
|
ShoppingCartId = table.Column<Guid>(type: "uuid", nullable: true),
|
||||||
|
Status = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
InvoiceUrl = table.Column<string>(type: "character varying(2048)", maxLength: 2048, nullable: true),
|
||||||
|
Reason = table.Column<string>(type: "text", nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_Quotes", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_Quotes_Customers_CustomerId",
|
||||||
|
column: x => x.CustomerId,
|
||||||
|
principalTable: "Customers",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_Quotes_Orders_OrderId",
|
||||||
|
column: x => x.OrderId,
|
||||||
|
principalTable: "Orders",
|
||||||
|
principalColumn: "Id");
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_Quotes_ShoppingCarts_ShoppingCartId",
|
||||||
|
column: x => x.ShoppingCartId,
|
||||||
|
principalTable: "ShoppingCarts",
|
||||||
|
principalColumn: "Id");
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "ShoppingCartPackages",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
CreatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: false, defaultValueSql: "now()"),
|
||||||
|
ShoppingCartId = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
PackageId = table.Column<Guid>(type: "uuid", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_ShoppingCartPackages", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_ShoppingCartPackages_Package_PackageId",
|
||||||
|
column: x => x.PackageId,
|
||||||
|
principalTable: "Package",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Restrict);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_ShoppingCartPackages_ShoppingCarts_ShoppingCartId",
|
||||||
|
column: x => x.ShoppingCartId,
|
||||||
|
principalTable: "ShoppingCarts",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_ShoppingCartItems_ProductPriceId1",
|
||||||
|
table: "ShoppingCartItems",
|
||||||
|
column: "ProductPriceId1");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_ShoppingCartItems_ShoppingCartId1",
|
||||||
|
table: "ShoppingCartItems",
|
||||||
|
column: "ShoppingCartId1");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Leads_CustomerId",
|
||||||
|
table: "Leads",
|
||||||
|
column: "CustomerId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Leads_CustomerId1",
|
||||||
|
table: "Leads",
|
||||||
|
column: "CustomerId1");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_OrderRefunds_OrderId",
|
||||||
|
table: "OrderRefunds",
|
||||||
|
column: "OrderId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Orders_CustomerId",
|
||||||
|
table: "Orders",
|
||||||
|
column: "CustomerId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_ProductPrices_ProductId",
|
||||||
|
table: "ProductPrices",
|
||||||
|
column: "ProductId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Quotes_CustomerId",
|
||||||
|
table: "Quotes",
|
||||||
|
column: "CustomerId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Quotes_OrderId",
|
||||||
|
table: "Quotes",
|
||||||
|
column: "OrderId",
|
||||||
|
unique: true);
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Quotes_ShoppingCartId",
|
||||||
|
table: "Quotes",
|
||||||
|
column: "ShoppingCartId",
|
||||||
|
unique: true);
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_ShoppingCartPackages_PackageId",
|
||||||
|
table: "ShoppingCartPackages",
|
||||||
|
column: "PackageId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_ShoppingCartPackages_ShoppingCartId",
|
||||||
|
table: "ShoppingCartPackages",
|
||||||
|
column: "ShoppingCartId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_ShoppingCarts_CustomerId",
|
||||||
|
table: "ShoppingCarts",
|
||||||
|
column: "CustomerId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_ShoppingCarts_OrderId",
|
||||||
|
table: "ShoppingCarts",
|
||||||
|
column: "OrderId",
|
||||||
|
unique: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_PackageItem_ProductPrices_ProductPriceId",
|
||||||
|
table: "PackageItem",
|
||||||
|
column: "ProductPriceId",
|
||||||
|
principalTable: "ProductPrices",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Restrict);
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_ShoppingCartItems_ProductPrices_ProductPriceId",
|
||||||
|
table: "ShoppingCartItems",
|
||||||
|
column: "ProductPriceId",
|
||||||
|
principalTable: "ProductPrices",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Restrict);
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_ShoppingCartItems_ProductPrices_ProductPriceId1",
|
||||||
|
table: "ShoppingCartItems",
|
||||||
|
column: "ProductPriceId1",
|
||||||
|
principalTable: "ProductPrices",
|
||||||
|
principalColumn: "Id");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_ShoppingCartItems_ShoppingCarts_ShoppingCartId",
|
||||||
|
table: "ShoppingCartItems",
|
||||||
|
column: "ShoppingCartId",
|
||||||
|
principalTable: "ShoppingCarts",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_ShoppingCartItems_ShoppingCarts_ShoppingCartId1",
|
||||||
|
table: "ShoppingCartItems",
|
||||||
|
column: "ShoppingCartId1",
|
||||||
|
principalTable: "ShoppingCarts",
|
||||||
|
principalColumn: "Id");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_PackageItem_ProductPrices_ProductPriceId",
|
||||||
|
table: "PackageItem");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_ShoppingCartItems_ProductPrices_ProductPriceId",
|
||||||
|
table: "ShoppingCartItems");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_ShoppingCartItems_ProductPrices_ProductPriceId1",
|
||||||
|
table: "ShoppingCartItems");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_ShoppingCartItems_ShoppingCarts_ShoppingCartId",
|
||||||
|
table: "ShoppingCartItems");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_ShoppingCartItems_ShoppingCarts_ShoppingCartId1",
|
||||||
|
table: "ShoppingCartItems");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Leads");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "OrderRefunds");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "ProductPrices");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Quotes");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "ShoppingCartPackages");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Products");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "ShoppingCarts");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Orders");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Customers");
|
||||||
|
|
||||||
|
migrationBuilder.DropIndex(
|
||||||
|
name: "IX_ShoppingCartItems_ProductPriceId1",
|
||||||
|
table: "ShoppingCartItems");
|
||||||
|
|
||||||
|
migrationBuilder.DropIndex(
|
||||||
|
name: "IX_ShoppingCartItems_ShoppingCartId1",
|
||||||
|
table: "ShoppingCartItems");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "ProductPriceId1",
|
||||||
|
table: "ShoppingCartItems");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "ShoppingCartId1",
|
||||||
|
table: "ShoppingCartItems");
|
||||||
|
|
||||||
|
migrationBuilder.RenameColumn(
|
||||||
|
name: "SenderAddress",
|
||||||
|
table: "Notification",
|
||||||
|
newName: "Sender");
|
||||||
|
|
||||||
|
migrationBuilder.RenameColumn(
|
||||||
|
name: "RecipientName",
|
||||||
|
table: "Notification",
|
||||||
|
newName: "Recipient");
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<DateTimeOffset>(
|
||||||
|
name: "UpdatedAt",
|
||||||
|
table: "ShoppingCartItems",
|
||||||
|
type: "timestamp with time zone",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)),
|
||||||
|
oldClrType: typeof(DateTime),
|
||||||
|
oldType: "timestamp with time zone",
|
||||||
|
oldNullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<int>(
|
||||||
|
name: "Quantity",
|
||||||
|
table: "ShoppingCartItems",
|
||||||
|
type: "integer",
|
||||||
|
nullable: false,
|
||||||
|
oldClrType: typeof(int),
|
||||||
|
oldType: "integer",
|
||||||
|
oldDefaultValue: 1);
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<DateTimeOffset>(
|
||||||
|
name: "CreatedAt",
|
||||||
|
table: "ShoppingCartItems",
|
||||||
|
type: "timestamp with time zone",
|
||||||
|
nullable: false,
|
||||||
|
oldClrType: typeof(DateTime),
|
||||||
|
oldType: "timestamp with time zone",
|
||||||
|
oldDefaultValueSql: "now()");
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<string>(
|
||||||
|
name: "Name",
|
||||||
|
table: "Customer",
|
||||||
|
type: "text",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: "",
|
||||||
|
oldClrType: typeof(string),
|
||||||
|
oldType: "text",
|
||||||
|
oldNullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<string>(
|
||||||
|
name: "LastName",
|
||||||
|
table: "Customer",
|
||||||
|
type: "text",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: "",
|
||||||
|
oldClrType: typeof(string),
|
||||||
|
oldType: "text",
|
||||||
|
oldNullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<string>(
|
||||||
|
name: "Email",
|
||||||
|
table: "Customer",
|
||||||
|
type: "text",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: "",
|
||||||
|
oldClrType: typeof(string),
|
||||||
|
oldType: "text",
|
||||||
|
oldNullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<DateTimeOffset>(
|
||||||
|
name: "CreatedAt",
|
||||||
|
table: "Customer",
|
||||||
|
type: "timestamp with time zone",
|
||||||
|
nullable: false,
|
||||||
|
defaultValueSql: "now()",
|
||||||
|
oldClrType: typeof(DateTime),
|
||||||
|
oldType: "timestamp with time zone");
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<bool>(
|
||||||
|
name: "Active",
|
||||||
|
table: "Customer",
|
||||||
|
type: "boolean",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: true,
|
||||||
|
oldClrType: typeof(bool),
|
||||||
|
oldType: "boolean");
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Lead",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
CustomerId = table.Column<Guid>(type: "uuid", nullable: true),
|
||||||
|
AdGroupId = table.Column<long>(type: "bigint", nullable: true),
|
||||||
|
AdName = table.Column<long>(type: "bigint", nullable: true),
|
||||||
|
AppClickId = table.Column<string>(type: "text", nullable: true),
|
||||||
|
AttributionHash = table.Column<string>(type: "text", nullable: false),
|
||||||
|
CampaignId = table.Column<long>(type: "bigint", nullable: true),
|
||||||
|
ClickId = table.Column<string>(type: "text", nullable: true),
|
||||||
|
ClickLocation = table.Column<string>(type: "text", nullable: true),
|
||||||
|
CreatedAt = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false, defaultValueSql: "now()"),
|
||||||
|
FeedItemId = table.Column<long>(type: "bigint", nullable: true),
|
||||||
|
Source = table.Column<string>(type: "text", nullable: true),
|
||||||
|
Status = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
TargetId = table.Column<long>(type: "bigint", nullable: true),
|
||||||
|
UpdatedAt = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: true),
|
||||||
|
WebClickId = table.Column<string>(type: "text", nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_Lead", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_Lead_Customer_CustomerId",
|
||||||
|
column: x => x.CustomerId,
|
||||||
|
principalTable: "Customer",
|
||||||
|
principalColumn: "Id");
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Order",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
CustomerId = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
CreatedAt = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false, defaultValueSql: "now()"),
|
||||||
|
InvoiceUrl = table.Column<string>(type: "character varying(2048)", maxLength: 2048, nullable: true),
|
||||||
|
Notes = table.Column<string>(type: "jsonb", nullable: true),
|
||||||
|
Requirements = table.Column<string>(type: "jsonb", nullable: true),
|
||||||
|
Status = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
Terms = table.Column<string>(type: "jsonb", nullable: true),
|
||||||
|
UpdatedAt = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_Order", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_Order_Customer_CustomerId",
|
||||||
|
column: x => x.CustomerId,
|
||||||
|
principalTable: "Customer",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Restrict);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Product",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
Active = table.Column<bool>(type: "boolean", nullable: false, defaultValue: true),
|
||||||
|
Description = table.Column<string>(type: "character varying(2048)", maxLength: 2048, nullable: false),
|
||||||
|
ImageUrl = table.Column<string>(type: "character varying(2048)", maxLength: 2048, nullable: true),
|
||||||
|
Name = table.Column<string>(type: "text", nullable: false),
|
||||||
|
Summary = table.Column<string>(type: "character varying(512)", maxLength: 512, nullable: false),
|
||||||
|
Thumbnails = table.Column<string>(type: "jsonb", nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_Product", x => x.Id);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "OrderRefund",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
OrderId = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
Amount = table.Column<decimal>(type: "numeric(18,2)", precision: 18, scale: 2, nullable: false),
|
||||||
|
CreatedAt = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false, defaultValueSql: "now()"),
|
||||||
|
Reason = table.Column<string>(type: "text", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_OrderRefund", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_OrderRefund_Order_OrderId",
|
||||||
|
column: x => x.OrderId,
|
||||||
|
principalTable: "Order",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "ShoppingCart",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
CustomerId = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
OrderId = table.Column<Guid>(type: "uuid", nullable: true),
|
||||||
|
CreatedAt = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false, defaultValueSql: "now()"),
|
||||||
|
UpdatedAt = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_ShoppingCart", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_ShoppingCart_Customer_CustomerId",
|
||||||
|
column: x => x.CustomerId,
|
||||||
|
principalTable: "Customer",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_ShoppingCart_Order_OrderId",
|
||||||
|
column: x => x.OrderId,
|
||||||
|
principalTable: "Order",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.SetNull);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "ProductPrice",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
ProductId = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
Active = table.Column<bool>(type: "boolean", nullable: false),
|
||||||
|
CreatedAt = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false, defaultValueSql: "now()"),
|
||||||
|
Discount = table.Column<decimal>(type: "numeric(18,2)", precision: 18, scale: 2, nullable: false),
|
||||||
|
Price = table.Column<decimal>(type: "numeric(18,2)", precision: 18, scale: 2, nullable: false),
|
||||||
|
UpdatedAt = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_ProductPrice", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_ProductPrice_Product_ProductId",
|
||||||
|
column: x => x.ProductId,
|
||||||
|
principalTable: "Product",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Restrict);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Quote",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
CustomerId = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
OrderId = table.Column<Guid>(type: "uuid", nullable: true),
|
||||||
|
ShoppingCartId = table.Column<Guid>(type: "uuid", nullable: true),
|
||||||
|
CreatedAt = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false, defaultValueSql: "now()"),
|
||||||
|
ExpiredAt = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: true),
|
||||||
|
InvoiceUrl = table.Column<string>(type: "character varying(2048)", maxLength: 2048, nullable: true),
|
||||||
|
Reason = table.Column<string>(type: "text", nullable: true),
|
||||||
|
Status = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
UpdatedAt = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_Quote", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_Quote_Customer_CustomerId",
|
||||||
|
column: x => x.CustomerId,
|
||||||
|
principalTable: "Customer",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_Quote_Order_OrderId",
|
||||||
|
column: x => x.OrderId,
|
||||||
|
principalTable: "Order",
|
||||||
|
principalColumn: "Id");
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_Quote_ShoppingCart_ShoppingCartId",
|
||||||
|
column: x => x.ShoppingCartId,
|
||||||
|
principalTable: "ShoppingCart",
|
||||||
|
principalColumn: "Id");
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "ShoppingCartPackage",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
PackageId = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
ShoppingCartId = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
CreatedAt = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false, defaultValueSql: "now()")
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_ShoppingCartPackage", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_ShoppingCartPackage_Package_PackageId",
|
||||||
|
column: x => x.PackageId,
|
||||||
|
principalTable: "Package",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Restrict);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_ShoppingCartPackage_ShoppingCart_ShoppingCartId",
|
||||||
|
column: x => x.ShoppingCartId,
|
||||||
|
principalTable: "ShoppingCart",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Lead_CustomerId",
|
||||||
|
table: "Lead",
|
||||||
|
column: "CustomerId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Order_CustomerId",
|
||||||
|
table: "Order",
|
||||||
|
column: "CustomerId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_OrderRefund_OrderId",
|
||||||
|
table: "OrderRefund",
|
||||||
|
column: "OrderId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_ProductPrice_ProductId",
|
||||||
|
table: "ProductPrice",
|
||||||
|
column: "ProductId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Quote_CustomerId",
|
||||||
|
table: "Quote",
|
||||||
|
column: "CustomerId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Quote_OrderId",
|
||||||
|
table: "Quote",
|
||||||
|
column: "OrderId",
|
||||||
|
unique: true);
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Quote_ShoppingCartId",
|
||||||
|
table: "Quote",
|
||||||
|
column: "ShoppingCartId",
|
||||||
|
unique: true);
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_ShoppingCart_CustomerId",
|
||||||
|
table: "ShoppingCart",
|
||||||
|
column: "CustomerId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_ShoppingCart_OrderId",
|
||||||
|
table: "ShoppingCart",
|
||||||
|
column: "OrderId",
|
||||||
|
unique: true);
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_ShoppingCartPackage_PackageId",
|
||||||
|
table: "ShoppingCartPackage",
|
||||||
|
column: "PackageId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_ShoppingCartPackage_ShoppingCartId",
|
||||||
|
table: "ShoppingCartPackage",
|
||||||
|
column: "ShoppingCartId");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_PackageItem_ProductPrice_ProductPriceId",
|
||||||
|
table: "PackageItem",
|
||||||
|
column: "ProductPriceId",
|
||||||
|
principalTable: "ProductPrice",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Restrict);
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_ShoppingCartItems_ProductPrice_ProductPriceId",
|
||||||
|
table: "ShoppingCartItems",
|
||||||
|
column: "ProductPriceId",
|
||||||
|
principalTable: "ProductPrice",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_ShoppingCartItems_ShoppingCart_ShoppingCartId",
|
||||||
|
table: "ShoppingCartItems",
|
||||||
|
column: "ShoppingCartId",
|
||||||
|
principalTable: "ShoppingCart",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+776
@@ -0,0 +1,776 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using LiteCharms.Features.TechShop.Postgres;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.TechShop.Postgres.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(ShopDbContext))]
|
||||||
|
[Migration("20260515055221_FixedLeadCustomerRelationship")]
|
||||||
|
partial class FixedLeadCustomerRelationship
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder
|
||||||
|
.HasAnnotation("ProductVersion", "10.0.8")
|
||||||
|
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
||||||
|
|
||||||
|
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.CartPackages.Entities.Package", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<bool>("Active")
|
||||||
|
.HasColumnType("boolean");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasDefaultValueSql("now()");
|
||||||
|
|
||||||
|
b.Property<string>("Description")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(2048)
|
||||||
|
.HasColumnType("character varying(2048)");
|
||||||
|
|
||||||
|
b.Property<string>("ImageUrl")
|
||||||
|
.HasMaxLength(2048)
|
||||||
|
.HasColumnType("character varying(2048)");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Summary")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(512)
|
||||||
|
.HasColumnType("character varying(512)");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("UpdatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Package", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.CartPackages.Entities.PackageItem", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<bool>("Active")
|
||||||
|
.HasColumnType("boolean");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasDefaultValueSql("now()");
|
||||||
|
|
||||||
|
b.Property<Guid>("PackageId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<Guid>("ProductPriceId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("PackageId");
|
||||||
|
|
||||||
|
b.HasIndex("ProductPriceId");
|
||||||
|
|
||||||
|
b.ToTable("PackageItem", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.Customers.Entities.Customer", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<bool>("Active")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasDefaultValue(true);
|
||||||
|
|
||||||
|
b.Property<string>("Address")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("City")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Company")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Country")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasDefaultValueSql("now()");
|
||||||
|
|
||||||
|
b.Property<string>("Discord")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Email")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("LastName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("LinkedIn")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Phone")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("PostalCode")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Region")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Slack")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Tax")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("UpdatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<string>("Website")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Whatsapp")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Customers", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.Leads.Entities.Lead", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<long?>("AdGroupId")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<long?>("AdName")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<string>("AppClickId")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("AttributionHash")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<long?>("CampaignId")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<string>("ClickId")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("ClickLocation")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasDefaultValueSql("now()");
|
||||||
|
|
||||||
|
b.Property<Guid?>("CustomerId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<long?>("FeedItemId")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<string>("Source")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<int>("Status")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<long?>("TargetId")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("UpdatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<string>("WebClickId")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("CustomerId");
|
||||||
|
|
||||||
|
b.ToTable("Leads", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.Notifications.Entities.Notification", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<string>("CorrelationId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<int>("CorrelationIdType")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasDefaultValueSql("now()");
|
||||||
|
|
||||||
|
b.Property<int>("Direction")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.PrimitiveCollection<string>("Errors")
|
||||||
|
.HasColumnType("jsonb");
|
||||||
|
|
||||||
|
b.Property<bool>("HasError")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasDefaultValue(false);
|
||||||
|
|
||||||
|
b.Property<bool>("IsHtml")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasDefaultValue(false);
|
||||||
|
|
||||||
|
b.Property<bool>("IsInternal")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasDefaultValue(true);
|
||||||
|
|
||||||
|
b.Property<string>("Message")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<int>("Platform")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<int>("Priority")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<bool>("Processed")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasDefaultValue(false);
|
||||||
|
|
||||||
|
b.Property<string>("RecipientAddress")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("RecipientName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("SenderAddress")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("SenderName")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Subject")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("UpdatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Notification", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.Orders.Entities.Order", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasDefaultValueSql("now()");
|
||||||
|
|
||||||
|
b.Property<Guid>("CustomerId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<string>("InvoiceUrl")
|
||||||
|
.HasMaxLength(2048)
|
||||||
|
.HasColumnType("character varying(2048)");
|
||||||
|
|
||||||
|
b.PrimitiveCollection<string>("Notes")
|
||||||
|
.HasColumnType("jsonb");
|
||||||
|
|
||||||
|
b.PrimitiveCollection<string>("Requirements")
|
||||||
|
.HasColumnType("jsonb");
|
||||||
|
|
||||||
|
b.Property<int>("Status")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.PrimitiveCollection<string>("Terms")
|
||||||
|
.HasColumnType("jsonb");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("UpdatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("CustomerId");
|
||||||
|
|
||||||
|
b.ToTable("Orders", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.Orders.Entities.OrderRefund", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<decimal>("Amount")
|
||||||
|
.HasPrecision(18, 2)
|
||||||
|
.HasColumnType("numeric(18,2)");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasDefaultValueSql("now()");
|
||||||
|
|
||||||
|
b.Property<Guid>("OrderId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<string>("Reason")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("OrderId");
|
||||||
|
|
||||||
|
b.ToTable("OrderRefunds", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.Products.Entities.Product", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<bool>("Active")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasDefaultValue(true);
|
||||||
|
|
||||||
|
b.Property<string>("Description")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(2048)
|
||||||
|
.HasColumnType("character varying(2048)");
|
||||||
|
|
||||||
|
b.Property<string>("ImageUrl")
|
||||||
|
.HasMaxLength(2048)
|
||||||
|
.HasColumnType("character varying(2048)");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Summary")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(512)
|
||||||
|
.HasColumnType("character varying(512)");
|
||||||
|
|
||||||
|
b.PrimitiveCollection<string>("Thumbnails")
|
||||||
|
.HasColumnType("jsonb");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Products", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.Products.Entities.ProductPrice", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<bool>("Active")
|
||||||
|
.HasColumnType("boolean");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasDefaultValueSql("now()");
|
||||||
|
|
||||||
|
b.Property<decimal>("Discount")
|
||||||
|
.HasPrecision(18, 2)
|
||||||
|
.HasColumnType("numeric(18,2)");
|
||||||
|
|
||||||
|
b.Property<decimal>("Price")
|
||||||
|
.HasPrecision(18, 2)
|
||||||
|
.HasColumnType("numeric(18,2)");
|
||||||
|
|
||||||
|
b.Property<Guid>("ProductId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("UpdatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("ProductId");
|
||||||
|
|
||||||
|
b.ToTable("ProductPrices", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.Quotes.Entities.Quote", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasDefaultValueSql("now()");
|
||||||
|
|
||||||
|
b.Property<Guid>("CustomerId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("ExpiredAt")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<string>("InvoiceUrl")
|
||||||
|
.HasMaxLength(2048)
|
||||||
|
.HasColumnType("character varying(2048)");
|
||||||
|
|
||||||
|
b.Property<Guid?>("OrderId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<string>("Reason")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<Guid?>("ShoppingCartId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<int>("Status")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("UpdatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("CustomerId");
|
||||||
|
|
||||||
|
b.HasIndex("OrderId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.HasIndex("ShoppingCartId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("Quotes", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.ShoppingCarts.Entities.ShoppingCart", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasDefaultValueSql("now()");
|
||||||
|
|
||||||
|
b.Property<Guid>("CustomerId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<Guid?>("OrderId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("UpdatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("CustomerId");
|
||||||
|
|
||||||
|
b.HasIndex("OrderId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("ShoppingCarts", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.ShoppingCarts.Entities.ShoppingCartItem", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasDefaultValueSql("now()");
|
||||||
|
|
||||||
|
b.Property<Guid>("ProductPriceId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<int>("Quantity")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasDefaultValue(1);
|
||||||
|
|
||||||
|
b.Property<Guid>("ShoppingCartId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("UpdatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("ProductPriceId");
|
||||||
|
|
||||||
|
b.HasIndex("ShoppingCartId");
|
||||||
|
|
||||||
|
b.ToTable("ShoppingCartItems", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.ShoppingCarts.Entities.ShoppingCartPackage", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasDefaultValueSql("now()");
|
||||||
|
|
||||||
|
b.Property<Guid>("PackageId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<Guid>("ShoppingCartId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("PackageId");
|
||||||
|
|
||||||
|
b.HasIndex("ShoppingCartId");
|
||||||
|
|
||||||
|
b.ToTable("ShoppingCartPackages", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.CartPackages.Entities.PackageItem", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("LiteCharms.Features.Shop.CartPackages.Entities.Package", "Package")
|
||||||
|
.WithMany("PackageItems")
|
||||||
|
.HasForeignKey("PackageId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("LiteCharms.Features.Shop.Products.Entities.ProductPrice", "ProductPrice")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ProductPriceId")
|
||||||
|
.OnDelete(DeleteBehavior.Restrict)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Package");
|
||||||
|
|
||||||
|
b.Navigation("ProductPrice");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.Leads.Entities.Lead", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("LiteCharms.Features.Shop.Customers.Entities.Customer", "Customer")
|
||||||
|
.WithMany("Leads")
|
||||||
|
.HasForeignKey("CustomerId")
|
||||||
|
.OnDelete(DeleteBehavior.Restrict);
|
||||||
|
|
||||||
|
b.Navigation("Customer");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.Orders.Entities.Order", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("LiteCharms.Features.Shop.Customers.Entities.Customer", "Customer")
|
||||||
|
.WithMany("Orders")
|
||||||
|
.HasForeignKey("CustomerId")
|
||||||
|
.OnDelete(DeleteBehavior.Restrict)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Customer");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.Orders.Entities.OrderRefund", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("LiteCharms.Features.Shop.Orders.Entities.Order", "Order")
|
||||||
|
.WithMany("Refunds")
|
||||||
|
.HasForeignKey("OrderId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Order");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.Products.Entities.ProductPrice", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("LiteCharms.Features.Shop.Products.Entities.Product", "Product")
|
||||||
|
.WithMany("ProductPrices")
|
||||||
|
.HasForeignKey("ProductId")
|
||||||
|
.OnDelete(DeleteBehavior.Restrict)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Product");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.Quotes.Entities.Quote", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("LiteCharms.Features.Shop.Customers.Entities.Customer", "Customer")
|
||||||
|
.WithMany("Quotes")
|
||||||
|
.HasForeignKey("CustomerId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("LiteCharms.Features.Shop.Orders.Entities.Order", "Order")
|
||||||
|
.WithOne("Quote")
|
||||||
|
.HasForeignKey("LiteCharms.Features.Shop.Quotes.Entities.Quote", "OrderId");
|
||||||
|
|
||||||
|
b.HasOne("LiteCharms.Features.Shop.ShoppingCarts.Entities.ShoppingCart", "ShoppingCart")
|
||||||
|
.WithOne("Quote")
|
||||||
|
.HasForeignKey("LiteCharms.Features.Shop.Quotes.Entities.Quote", "ShoppingCartId");
|
||||||
|
|
||||||
|
b.Navigation("Customer");
|
||||||
|
|
||||||
|
b.Navigation("Order");
|
||||||
|
|
||||||
|
b.Navigation("ShoppingCart");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.ShoppingCarts.Entities.ShoppingCart", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("LiteCharms.Features.Shop.Customers.Entities.Customer", "Customer")
|
||||||
|
.WithMany("ShoppingCarts")
|
||||||
|
.HasForeignKey("CustomerId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("LiteCharms.Features.Shop.Orders.Entities.Order", "Order")
|
||||||
|
.WithOne("ShoppingCart")
|
||||||
|
.HasForeignKey("LiteCharms.Features.Shop.ShoppingCarts.Entities.ShoppingCart", "OrderId")
|
||||||
|
.OnDelete(DeleteBehavior.SetNull);
|
||||||
|
|
||||||
|
b.Navigation("Customer");
|
||||||
|
|
||||||
|
b.Navigation("Order");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.ShoppingCarts.Entities.ShoppingCartItem", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("LiteCharms.Features.Shop.Products.Entities.ProductPrice", "ProductPrice")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ProductPriceId")
|
||||||
|
.OnDelete(DeleteBehavior.Restrict)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("LiteCharms.Features.Shop.ShoppingCarts.Entities.ShoppingCart", "ShoppingCart")
|
||||||
|
.WithMany("ShoppingCartItems")
|
||||||
|
.HasForeignKey("ShoppingCartId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("ProductPrice");
|
||||||
|
|
||||||
|
b.Navigation("ShoppingCart");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.ShoppingCarts.Entities.ShoppingCartPackage", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("LiteCharms.Features.Shop.CartPackages.Entities.Package", "Package")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("PackageId")
|
||||||
|
.OnDelete(DeleteBehavior.Restrict)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("LiteCharms.Features.Shop.ShoppingCarts.Entities.ShoppingCart", "ShoppingCart")
|
||||||
|
.WithMany("ShoppingCartPackages")
|
||||||
|
.HasForeignKey("ShoppingCartId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Package");
|
||||||
|
|
||||||
|
b.Navigation("ShoppingCart");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.CartPackages.Entities.Package", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("PackageItems");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.Customers.Entities.Customer", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Leads");
|
||||||
|
|
||||||
|
b.Navigation("Orders");
|
||||||
|
|
||||||
|
b.Navigation("Quotes");
|
||||||
|
|
||||||
|
b.Navigation("ShoppingCarts");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.Orders.Entities.Order", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Quote");
|
||||||
|
|
||||||
|
b.Navigation("Refunds");
|
||||||
|
|
||||||
|
b.Navigation("ShoppingCart");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.Products.Entities.Product", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("ProductPrices");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.ShoppingCarts.Entities.ShoppingCart", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Quote");
|
||||||
|
|
||||||
|
b.Navigation("ShoppingCartItems");
|
||||||
|
|
||||||
|
b.Navigation("ShoppingCartPackages");
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+166
@@ -0,0 +1,166 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.TechShop.Postgres.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class FixedLeadCustomerRelationship : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Leads_Customer_CustomerId",
|
||||||
|
table: "Leads");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Leads_Customers_CustomerId1",
|
||||||
|
table: "Leads");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_ShoppingCartItems_ProductPrices_ProductPriceId1",
|
||||||
|
table: "ShoppingCartItems");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_ShoppingCartItems_ShoppingCarts_ShoppingCartId1",
|
||||||
|
table: "ShoppingCartItems");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Customer");
|
||||||
|
|
||||||
|
migrationBuilder.DropIndex(
|
||||||
|
name: "IX_ShoppingCartItems_ProductPriceId1",
|
||||||
|
table: "ShoppingCartItems");
|
||||||
|
|
||||||
|
migrationBuilder.DropIndex(
|
||||||
|
name: "IX_ShoppingCartItems_ShoppingCartId1",
|
||||||
|
table: "ShoppingCartItems");
|
||||||
|
|
||||||
|
migrationBuilder.DropIndex(
|
||||||
|
name: "IX_Leads_CustomerId1",
|
||||||
|
table: "Leads");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "ProductPriceId1",
|
||||||
|
table: "ShoppingCartItems");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "ShoppingCartId1",
|
||||||
|
table: "ShoppingCartItems");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "CustomerId1",
|
||||||
|
table: "Leads");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Leads_Customers_CustomerId",
|
||||||
|
table: "Leads",
|
||||||
|
column: "CustomerId",
|
||||||
|
principalTable: "Customers",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Restrict);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Leads_Customers_CustomerId",
|
||||||
|
table: "Leads");
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<Guid>(
|
||||||
|
name: "ProductPriceId1",
|
||||||
|
table: "ShoppingCartItems",
|
||||||
|
type: "uuid",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<Guid>(
|
||||||
|
name: "ShoppingCartId1",
|
||||||
|
table: "ShoppingCartItems",
|
||||||
|
type: "uuid",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<Guid>(
|
||||||
|
name: "CustomerId1",
|
||||||
|
table: "Leads",
|
||||||
|
type: "uuid",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Customer",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
Active = table.Column<bool>(type: "boolean", nullable: false),
|
||||||
|
Address = table.Column<string>(type: "text", nullable: true),
|
||||||
|
City = table.Column<string>(type: "text", nullable: true),
|
||||||
|
Company = table.Column<string>(type: "text", nullable: true),
|
||||||
|
Country = table.Column<string>(type: "text", nullable: true),
|
||||||
|
CreatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
|
||||||
|
Discord = table.Column<string>(type: "text", nullable: true),
|
||||||
|
Email = table.Column<string>(type: "text", nullable: true),
|
||||||
|
LastName = table.Column<string>(type: "text", nullable: true),
|
||||||
|
LinkedIn = table.Column<string>(type: "text", nullable: true),
|
||||||
|
Name = table.Column<string>(type: "text", nullable: true),
|
||||||
|
Phone = table.Column<string>(type: "text", nullable: true),
|
||||||
|
PostalCode = table.Column<string>(type: "text", nullable: true),
|
||||||
|
Region = table.Column<string>(type: "text", nullable: true),
|
||||||
|
Slack = table.Column<string>(type: "text", nullable: true),
|
||||||
|
Tax = table.Column<string>(type: "text", nullable: true),
|
||||||
|
UpdatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
|
||||||
|
Website = table.Column<string>(type: "text", nullable: true),
|
||||||
|
Whatsapp = table.Column<string>(type: "text", nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_Customer", x => x.Id);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_ShoppingCartItems_ProductPriceId1",
|
||||||
|
table: "ShoppingCartItems",
|
||||||
|
column: "ProductPriceId1");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_ShoppingCartItems_ShoppingCartId1",
|
||||||
|
table: "ShoppingCartItems",
|
||||||
|
column: "ShoppingCartId1");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Leads_CustomerId1",
|
||||||
|
table: "Leads",
|
||||||
|
column: "CustomerId1");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Leads_Customer_CustomerId",
|
||||||
|
table: "Leads",
|
||||||
|
column: "CustomerId",
|
||||||
|
principalTable: "Customer",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Restrict);
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Leads_Customers_CustomerId1",
|
||||||
|
table: "Leads",
|
||||||
|
column: "CustomerId1",
|
||||||
|
principalTable: "Customers",
|
||||||
|
principalColumn: "Id");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_ShoppingCartItems_ProductPrices_ProductPriceId1",
|
||||||
|
table: "ShoppingCartItems",
|
||||||
|
column: "ProductPriceId1",
|
||||||
|
principalTable: "ProductPrices",
|
||||||
|
principalColumn: "Id");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_ShoppingCartItems_ShoppingCarts_ShoppingCartId1",
|
||||||
|
table: "ShoppingCartItems",
|
||||||
|
column: "ShoppingCartId1",
|
||||||
|
principalTable: "ShoppingCarts",
|
||||||
|
principalColumn: "Id");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Generated
+788
@@ -0,0 +1,788 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using LiteCharms.Features.TechShop.Postgres;
|
||||||
|
using LiteCharms.Features.TechShop.Products.Models;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.TechShop.Postgres.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(ShopDbContext))]
|
||||||
|
[Migration("20260520191059_AddedProductMetadata")]
|
||||||
|
partial class AddedProductMetadata
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder
|
||||||
|
.HasAnnotation("ProductVersion", "10.0.8")
|
||||||
|
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
||||||
|
|
||||||
|
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.CartPackages.Entities.Package", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<bool>("Active")
|
||||||
|
.HasColumnType("boolean");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasDefaultValueSql("now()");
|
||||||
|
|
||||||
|
b.Property<string>("Description")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(2048)
|
||||||
|
.HasColumnType("character varying(2048)");
|
||||||
|
|
||||||
|
b.Property<string>("ImageUrl")
|
||||||
|
.HasMaxLength(2048)
|
||||||
|
.HasColumnType("character varying(2048)");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Summary")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(512)
|
||||||
|
.HasColumnType("character varying(512)");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("UpdatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Package", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.CartPackages.Entities.PackageItem", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<bool>("Active")
|
||||||
|
.HasColumnType("boolean");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasDefaultValueSql("now()");
|
||||||
|
|
||||||
|
b.Property<Guid>("PackageId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<Guid>("ProductPriceId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("PackageId");
|
||||||
|
|
||||||
|
b.HasIndex("ProductPriceId");
|
||||||
|
|
||||||
|
b.ToTable("PackageItem", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.Customers.Entities.Customer", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<bool>("Active")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasDefaultValue(true);
|
||||||
|
|
||||||
|
b.Property<string>("Address")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("City")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Company")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Country")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasDefaultValueSql("now()");
|
||||||
|
|
||||||
|
b.Property<string>("Discord")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Email")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("LastName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("LinkedIn")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Phone")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("PostalCode")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Region")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Slack")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Tax")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("UpdatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<string>("Website")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Whatsapp")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Customers", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.Leads.Entities.Lead", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<long?>("AdGroupId")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<long?>("AdName")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<string>("AppClickId")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("AttributionHash")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<long?>("CampaignId")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<string>("ClickId")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("ClickLocation")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasDefaultValueSql("now()");
|
||||||
|
|
||||||
|
b.Property<Guid?>("CustomerId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<long?>("FeedItemId")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<string>("Source")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<int>("Status")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<long?>("TargetId")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("UpdatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<string>("WebClickId")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("CustomerId");
|
||||||
|
|
||||||
|
b.ToTable("Leads", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.Notifications.Entities.Notification", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<string>("CorrelationId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<int>("CorrelationIdType")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasDefaultValueSql("now()");
|
||||||
|
|
||||||
|
b.Property<int>("Direction")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.PrimitiveCollection<string>("Errors")
|
||||||
|
.HasColumnType("jsonb");
|
||||||
|
|
||||||
|
b.Property<bool>("HasError")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasDefaultValue(false);
|
||||||
|
|
||||||
|
b.Property<bool>("IsHtml")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasDefaultValue(false);
|
||||||
|
|
||||||
|
b.Property<bool>("IsInternal")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasDefaultValue(true);
|
||||||
|
|
||||||
|
b.Property<string>("Message")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<int>("Platform")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<int>("Priority")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<bool>("Processed")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasDefaultValue(false);
|
||||||
|
|
||||||
|
b.Property<string>("RecipientAddress")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("RecipientName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("SenderAddress")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("SenderName")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Subject")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("UpdatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Notification", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.Orders.Entities.Order", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasDefaultValueSql("now()");
|
||||||
|
|
||||||
|
b.Property<Guid>("CustomerId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<string>("InvoiceUrl")
|
||||||
|
.HasMaxLength(2048)
|
||||||
|
.HasColumnType("character varying(2048)");
|
||||||
|
|
||||||
|
b.PrimitiveCollection<string>("Notes")
|
||||||
|
.HasColumnType("jsonb");
|
||||||
|
|
||||||
|
b.PrimitiveCollection<string>("Requirements")
|
||||||
|
.HasColumnType("jsonb");
|
||||||
|
|
||||||
|
b.Property<int>("Status")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.PrimitiveCollection<string>("Terms")
|
||||||
|
.HasColumnType("jsonb");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("UpdatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("CustomerId");
|
||||||
|
|
||||||
|
b.ToTable("Orders", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.Orders.Entities.OrderRefund", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<decimal>("Amount")
|
||||||
|
.HasPrecision(18, 2)
|
||||||
|
.HasColumnType("numeric(18,2)");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasDefaultValueSql("now()");
|
||||||
|
|
||||||
|
b.Property<Guid>("OrderId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<string>("Reason")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("OrderId");
|
||||||
|
|
||||||
|
b.ToTable("OrderRefunds", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.Products.Entities.Product", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<bool>("Active")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasDefaultValue(false);
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasDefaultValueSql("now()");
|
||||||
|
|
||||||
|
b.Property<string>("Description")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(2048)
|
||||||
|
.HasColumnType("character varying(2048)");
|
||||||
|
|
||||||
|
b.Property<string>("ImageUrl")
|
||||||
|
.HasMaxLength(2048)
|
||||||
|
.HasColumnType("character varying(2048)");
|
||||||
|
|
||||||
|
b.Property<ProductMetadata>("Metadata")
|
||||||
|
.HasColumnType("jsonb");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Summary")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(512)
|
||||||
|
.HasColumnType("character varying(512)");
|
||||||
|
|
||||||
|
b.PrimitiveCollection<string>("Thumbnails")
|
||||||
|
.HasColumnType("jsonb");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("UpdatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Products", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.Products.Entities.ProductPrice", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<bool>("Active")
|
||||||
|
.HasColumnType("boolean");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasDefaultValueSql("now()");
|
||||||
|
|
||||||
|
b.Property<decimal>("Discount")
|
||||||
|
.HasPrecision(18, 2)
|
||||||
|
.HasColumnType("numeric(18,2)");
|
||||||
|
|
||||||
|
b.Property<decimal>("Price")
|
||||||
|
.HasPrecision(18, 2)
|
||||||
|
.HasColumnType("numeric(18,2)");
|
||||||
|
|
||||||
|
b.Property<Guid>("ProductId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("UpdatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("ProductId");
|
||||||
|
|
||||||
|
b.ToTable("ProductPrices", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.Quotes.Entities.Quote", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasDefaultValueSql("now()");
|
||||||
|
|
||||||
|
b.Property<Guid>("CustomerId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("ExpiredAt")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<string>("InvoiceUrl")
|
||||||
|
.HasMaxLength(2048)
|
||||||
|
.HasColumnType("character varying(2048)");
|
||||||
|
|
||||||
|
b.Property<Guid?>("OrderId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<string>("Reason")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<Guid?>("ShoppingCartId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<int>("Status")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("UpdatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("CustomerId");
|
||||||
|
|
||||||
|
b.HasIndex("OrderId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.HasIndex("ShoppingCartId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("Quotes", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.ShoppingCarts.Entities.ShoppingCart", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasDefaultValueSql("now()");
|
||||||
|
|
||||||
|
b.Property<Guid>("CustomerId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<Guid?>("OrderId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("UpdatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("CustomerId");
|
||||||
|
|
||||||
|
b.HasIndex("OrderId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("ShoppingCarts", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.ShoppingCarts.Entities.ShoppingCartItem", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasDefaultValueSql("now()");
|
||||||
|
|
||||||
|
b.Property<Guid>("ProductPriceId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<int>("Quantity")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasDefaultValue(1);
|
||||||
|
|
||||||
|
b.Property<Guid>("ShoppingCartId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("UpdatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("ProductPriceId");
|
||||||
|
|
||||||
|
b.HasIndex("ShoppingCartId");
|
||||||
|
|
||||||
|
b.ToTable("ShoppingCartItems", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.ShoppingCarts.Entities.ShoppingCartPackage", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasDefaultValueSql("now()");
|
||||||
|
|
||||||
|
b.Property<Guid>("PackageId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<Guid>("ShoppingCartId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("PackageId");
|
||||||
|
|
||||||
|
b.HasIndex("ShoppingCartId");
|
||||||
|
|
||||||
|
b.ToTable("ShoppingCartPackages", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.CartPackages.Entities.PackageItem", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("LiteCharms.Features.Shop.CartPackages.Entities.Package", "Package")
|
||||||
|
.WithMany("PackageItems")
|
||||||
|
.HasForeignKey("PackageId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("LiteCharms.Features.Shop.Products.Entities.ProductPrice", "ProductPrice")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ProductPriceId")
|
||||||
|
.OnDelete(DeleteBehavior.Restrict)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Package");
|
||||||
|
|
||||||
|
b.Navigation("ProductPrice");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.Leads.Entities.Lead", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("LiteCharms.Features.Shop.Customers.Entities.Customer", "Customer")
|
||||||
|
.WithMany("Leads")
|
||||||
|
.HasForeignKey("CustomerId")
|
||||||
|
.OnDelete(DeleteBehavior.Restrict);
|
||||||
|
|
||||||
|
b.Navigation("Customer");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.Orders.Entities.Order", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("LiteCharms.Features.Shop.Customers.Entities.Customer", "Customer")
|
||||||
|
.WithMany("Orders")
|
||||||
|
.HasForeignKey("CustomerId")
|
||||||
|
.OnDelete(DeleteBehavior.Restrict)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Customer");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.Orders.Entities.OrderRefund", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("LiteCharms.Features.Shop.Orders.Entities.Order", "Order")
|
||||||
|
.WithMany("Refunds")
|
||||||
|
.HasForeignKey("OrderId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Order");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.Products.Entities.ProductPrice", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("LiteCharms.Features.Shop.Products.Entities.Product", "Product")
|
||||||
|
.WithMany("ProductPrices")
|
||||||
|
.HasForeignKey("ProductId")
|
||||||
|
.OnDelete(DeleteBehavior.Restrict)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Product");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.Quotes.Entities.Quote", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("LiteCharms.Features.Shop.Customers.Entities.Customer", "Customer")
|
||||||
|
.WithMany("Quotes")
|
||||||
|
.HasForeignKey("CustomerId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("LiteCharms.Features.Shop.Orders.Entities.Order", "Order")
|
||||||
|
.WithOne("Quote")
|
||||||
|
.HasForeignKey("LiteCharms.Features.Shop.Quotes.Entities.Quote", "OrderId");
|
||||||
|
|
||||||
|
b.HasOne("LiteCharms.Features.Shop.ShoppingCarts.Entities.ShoppingCart", "ShoppingCart")
|
||||||
|
.WithOne("Quote")
|
||||||
|
.HasForeignKey("LiteCharms.Features.Shop.Quotes.Entities.Quote", "ShoppingCartId");
|
||||||
|
|
||||||
|
b.Navigation("Customer");
|
||||||
|
|
||||||
|
b.Navigation("Order");
|
||||||
|
|
||||||
|
b.Navigation("ShoppingCart");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.ShoppingCarts.Entities.ShoppingCart", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("LiteCharms.Features.Shop.Customers.Entities.Customer", "Customer")
|
||||||
|
.WithMany("ShoppingCarts")
|
||||||
|
.HasForeignKey("CustomerId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("LiteCharms.Features.Shop.Orders.Entities.Order", "Order")
|
||||||
|
.WithOne("ShoppingCart")
|
||||||
|
.HasForeignKey("LiteCharms.Features.Shop.ShoppingCarts.Entities.ShoppingCart", "OrderId")
|
||||||
|
.OnDelete(DeleteBehavior.SetNull);
|
||||||
|
|
||||||
|
b.Navigation("Customer");
|
||||||
|
|
||||||
|
b.Navigation("Order");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.ShoppingCarts.Entities.ShoppingCartItem", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("LiteCharms.Features.Shop.Products.Entities.ProductPrice", "ProductPrice")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ProductPriceId")
|
||||||
|
.OnDelete(DeleteBehavior.Restrict)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("LiteCharms.Features.Shop.ShoppingCarts.Entities.ShoppingCart", "ShoppingCart")
|
||||||
|
.WithMany("ShoppingCartItems")
|
||||||
|
.HasForeignKey("ShoppingCartId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("ProductPrice");
|
||||||
|
|
||||||
|
b.Navigation("ShoppingCart");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.ShoppingCarts.Entities.ShoppingCartPackage", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("LiteCharms.Features.Shop.CartPackages.Entities.Package", "Package")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("PackageId")
|
||||||
|
.OnDelete(DeleteBehavior.Restrict)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("LiteCharms.Features.Shop.ShoppingCarts.Entities.ShoppingCart", "ShoppingCart")
|
||||||
|
.WithMany("ShoppingCartPackages")
|
||||||
|
.HasForeignKey("ShoppingCartId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Package");
|
||||||
|
|
||||||
|
b.Navigation("ShoppingCart");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.CartPackages.Entities.Package", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("PackageItems");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.Customers.Entities.Customer", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Leads");
|
||||||
|
|
||||||
|
b.Navigation("Orders");
|
||||||
|
|
||||||
|
b.Navigation("Quotes");
|
||||||
|
|
||||||
|
b.Navigation("ShoppingCarts");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.Orders.Entities.Order", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Quote");
|
||||||
|
|
||||||
|
b.Navigation("Refunds");
|
||||||
|
|
||||||
|
b.Navigation("ShoppingCart");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.Products.Entities.Product", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("ProductPrices");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.ShoppingCarts.Entities.ShoppingCart", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Quote");
|
||||||
|
|
||||||
|
b.Navigation("ShoppingCartItems");
|
||||||
|
|
||||||
|
b.Navigation("ShoppingCartPackages");
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+71
@@ -0,0 +1,71 @@
|
|||||||
|
using System;
|
||||||
|
using LiteCharms.Features.TechShop.Products.Models;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.TechShop.Postgres.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class AddedProductMetadata : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AlterColumn<bool>(
|
||||||
|
name: "Active",
|
||||||
|
table: "Products",
|
||||||
|
type: "boolean",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: false,
|
||||||
|
oldClrType: typeof(bool),
|
||||||
|
oldType: "boolean",
|
||||||
|
oldDefaultValue: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "CreatedAt",
|
||||||
|
table: "Products",
|
||||||
|
type: "timestamp with time zone",
|
||||||
|
nullable: false,
|
||||||
|
defaultValueSql: "now()");
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<ProductMetadata>(
|
||||||
|
name: "Metadata",
|
||||||
|
table: "Products",
|
||||||
|
type: "jsonb",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "UpdatedAt",
|
||||||
|
table: "Products",
|
||||||
|
type: "timestamp with time zone",
|
||||||
|
nullable: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "CreatedAt",
|
||||||
|
table: "Products");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "Metadata",
|
||||||
|
table: "Products");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "UpdatedAt",
|
||||||
|
table: "Products");
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<bool>(
|
||||||
|
name: "Active",
|
||||||
|
table: "Products",
|
||||||
|
type: "boolean",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: true,
|
||||||
|
oldClrType: typeof(bool),
|
||||||
|
oldType: "boolean",
|
||||||
|
oldDefaultValue: false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,785 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using LiteCharms.Features.TechShop.Postgres;
|
||||||
|
using LiteCharms.Features.TechShop.Products.Models;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.TechShop.Postgres.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(ShopDbContext))]
|
||||||
|
partial class ShopDbContextModelSnapshot : ModelSnapshot
|
||||||
|
{
|
||||||
|
protected override void BuildModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder
|
||||||
|
.HasAnnotation("ProductVersion", "10.0.8")
|
||||||
|
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
||||||
|
|
||||||
|
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.CartPackages.Entities.Package", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<bool>("Active")
|
||||||
|
.HasColumnType("boolean");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasDefaultValueSql("now()");
|
||||||
|
|
||||||
|
b.Property<string>("Description")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(2048)
|
||||||
|
.HasColumnType("character varying(2048)");
|
||||||
|
|
||||||
|
b.Property<string>("ImageUrl")
|
||||||
|
.HasMaxLength(2048)
|
||||||
|
.HasColumnType("character varying(2048)");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Summary")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(512)
|
||||||
|
.HasColumnType("character varying(512)");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("UpdatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Package", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.CartPackages.Entities.PackageItem", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<bool>("Active")
|
||||||
|
.HasColumnType("boolean");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasDefaultValueSql("now()");
|
||||||
|
|
||||||
|
b.Property<Guid>("PackageId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<Guid>("ProductPriceId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("PackageId");
|
||||||
|
|
||||||
|
b.HasIndex("ProductPriceId");
|
||||||
|
|
||||||
|
b.ToTable("PackageItem", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.Customers.Entities.Customer", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<bool>("Active")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasDefaultValue(true);
|
||||||
|
|
||||||
|
b.Property<string>("Address")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("City")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Company")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Country")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasDefaultValueSql("now()");
|
||||||
|
|
||||||
|
b.Property<string>("Discord")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Email")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("LastName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("LinkedIn")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Phone")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("PostalCode")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Region")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Slack")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Tax")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("UpdatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<string>("Website")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Whatsapp")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Customers", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.Leads.Entities.Lead", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<long?>("AdGroupId")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<long?>("AdName")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<string>("AppClickId")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("AttributionHash")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<long?>("CampaignId")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<string>("ClickId")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("ClickLocation")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasDefaultValueSql("now()");
|
||||||
|
|
||||||
|
b.Property<Guid?>("CustomerId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<long?>("FeedItemId")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<string>("Source")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<int>("Status")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<long?>("TargetId")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("UpdatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<string>("WebClickId")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("CustomerId");
|
||||||
|
|
||||||
|
b.ToTable("Leads", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.Notifications.Entities.Notification", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<string>("CorrelationId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<int>("CorrelationIdType")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasDefaultValueSql("now()");
|
||||||
|
|
||||||
|
b.Property<int>("Direction")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.PrimitiveCollection<string>("Errors")
|
||||||
|
.HasColumnType("jsonb");
|
||||||
|
|
||||||
|
b.Property<bool>("HasError")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasDefaultValue(false);
|
||||||
|
|
||||||
|
b.Property<bool>("IsHtml")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasDefaultValue(false);
|
||||||
|
|
||||||
|
b.Property<bool>("IsInternal")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasDefaultValue(true);
|
||||||
|
|
||||||
|
b.Property<string>("Message")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<int>("Platform")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<int>("Priority")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<bool>("Processed")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasDefaultValue(false);
|
||||||
|
|
||||||
|
b.Property<string>("RecipientAddress")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("RecipientName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("SenderAddress")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("SenderName")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Subject")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("UpdatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Notification", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.Orders.Entities.Order", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasDefaultValueSql("now()");
|
||||||
|
|
||||||
|
b.Property<Guid>("CustomerId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<string>("InvoiceUrl")
|
||||||
|
.HasMaxLength(2048)
|
||||||
|
.HasColumnType("character varying(2048)");
|
||||||
|
|
||||||
|
b.PrimitiveCollection<string>("Notes")
|
||||||
|
.HasColumnType("jsonb");
|
||||||
|
|
||||||
|
b.PrimitiveCollection<string>("Requirements")
|
||||||
|
.HasColumnType("jsonb");
|
||||||
|
|
||||||
|
b.Property<int>("Status")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.PrimitiveCollection<string>("Terms")
|
||||||
|
.HasColumnType("jsonb");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("UpdatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("CustomerId");
|
||||||
|
|
||||||
|
b.ToTable("Orders", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.Orders.Entities.OrderRefund", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<decimal>("Amount")
|
||||||
|
.HasPrecision(18, 2)
|
||||||
|
.HasColumnType("numeric(18,2)");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasDefaultValueSql("now()");
|
||||||
|
|
||||||
|
b.Property<Guid>("OrderId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<string>("Reason")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("OrderId");
|
||||||
|
|
||||||
|
b.ToTable("OrderRefunds", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.Products.Entities.Product", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<bool>("Active")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasDefaultValue(false);
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasDefaultValueSql("now()");
|
||||||
|
|
||||||
|
b.Property<string>("Description")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(2048)
|
||||||
|
.HasColumnType("character varying(2048)");
|
||||||
|
|
||||||
|
b.Property<string>("ImageUrl")
|
||||||
|
.HasMaxLength(2048)
|
||||||
|
.HasColumnType("character varying(2048)");
|
||||||
|
|
||||||
|
b.Property<ProductMetadata>("Metadata")
|
||||||
|
.HasColumnType("jsonb");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Summary")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(512)
|
||||||
|
.HasColumnType("character varying(512)");
|
||||||
|
|
||||||
|
b.PrimitiveCollection<string>("Thumbnails")
|
||||||
|
.HasColumnType("jsonb");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("UpdatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Products", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.Products.Entities.ProductPrice", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<bool>("Active")
|
||||||
|
.HasColumnType("boolean");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasDefaultValueSql("now()");
|
||||||
|
|
||||||
|
b.Property<decimal>("Discount")
|
||||||
|
.HasPrecision(18, 2)
|
||||||
|
.HasColumnType("numeric(18,2)");
|
||||||
|
|
||||||
|
b.Property<decimal>("Price")
|
||||||
|
.HasPrecision(18, 2)
|
||||||
|
.HasColumnType("numeric(18,2)");
|
||||||
|
|
||||||
|
b.Property<Guid>("ProductId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("UpdatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("ProductId");
|
||||||
|
|
||||||
|
b.ToTable("ProductPrices", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.Quotes.Entities.Quote", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasDefaultValueSql("now()");
|
||||||
|
|
||||||
|
b.Property<Guid>("CustomerId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("ExpiredAt")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<string>("InvoiceUrl")
|
||||||
|
.HasMaxLength(2048)
|
||||||
|
.HasColumnType("character varying(2048)");
|
||||||
|
|
||||||
|
b.Property<Guid?>("OrderId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<string>("Reason")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<Guid?>("ShoppingCartId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<int>("Status")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("UpdatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("CustomerId");
|
||||||
|
|
||||||
|
b.HasIndex("OrderId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.HasIndex("ShoppingCartId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("Quotes", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.ShoppingCarts.Entities.ShoppingCart", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasDefaultValueSql("now()");
|
||||||
|
|
||||||
|
b.Property<Guid>("CustomerId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<Guid?>("OrderId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("UpdatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("CustomerId");
|
||||||
|
|
||||||
|
b.HasIndex("OrderId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("ShoppingCarts", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.ShoppingCarts.Entities.ShoppingCartItem", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasDefaultValueSql("now()");
|
||||||
|
|
||||||
|
b.Property<Guid>("ProductPriceId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<int>("Quantity")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasDefaultValue(1);
|
||||||
|
|
||||||
|
b.Property<Guid>("ShoppingCartId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("UpdatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("ProductPriceId");
|
||||||
|
|
||||||
|
b.HasIndex("ShoppingCartId");
|
||||||
|
|
||||||
|
b.ToTable("ShoppingCartItems", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.ShoppingCarts.Entities.ShoppingCartPackage", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasDefaultValueSql("now()");
|
||||||
|
|
||||||
|
b.Property<Guid>("PackageId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<Guid>("ShoppingCartId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("PackageId");
|
||||||
|
|
||||||
|
b.HasIndex("ShoppingCartId");
|
||||||
|
|
||||||
|
b.ToTable("ShoppingCartPackages", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.CartPackages.Entities.PackageItem", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("LiteCharms.Features.Shop.CartPackages.Entities.Package", "Package")
|
||||||
|
.WithMany("PackageItems")
|
||||||
|
.HasForeignKey("PackageId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("LiteCharms.Features.Shop.Products.Entities.ProductPrice", "ProductPrice")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ProductPriceId")
|
||||||
|
.OnDelete(DeleteBehavior.Restrict)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Package");
|
||||||
|
|
||||||
|
b.Navigation("ProductPrice");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.Leads.Entities.Lead", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("LiteCharms.Features.Shop.Customers.Entities.Customer", "Customer")
|
||||||
|
.WithMany("Leads")
|
||||||
|
.HasForeignKey("CustomerId")
|
||||||
|
.OnDelete(DeleteBehavior.Restrict);
|
||||||
|
|
||||||
|
b.Navigation("Customer");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.Orders.Entities.Order", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("LiteCharms.Features.Shop.Customers.Entities.Customer", "Customer")
|
||||||
|
.WithMany("Orders")
|
||||||
|
.HasForeignKey("CustomerId")
|
||||||
|
.OnDelete(DeleteBehavior.Restrict)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Customer");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.Orders.Entities.OrderRefund", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("LiteCharms.Features.Shop.Orders.Entities.Order", "Order")
|
||||||
|
.WithMany("Refunds")
|
||||||
|
.HasForeignKey("OrderId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Order");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.Products.Entities.ProductPrice", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("LiteCharms.Features.Shop.Products.Entities.Product", "Product")
|
||||||
|
.WithMany("ProductPrices")
|
||||||
|
.HasForeignKey("ProductId")
|
||||||
|
.OnDelete(DeleteBehavior.Restrict)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Product");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.Quotes.Entities.Quote", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("LiteCharms.Features.Shop.Customers.Entities.Customer", "Customer")
|
||||||
|
.WithMany("Quotes")
|
||||||
|
.HasForeignKey("CustomerId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("LiteCharms.Features.Shop.Orders.Entities.Order", "Order")
|
||||||
|
.WithOne("Quote")
|
||||||
|
.HasForeignKey("LiteCharms.Features.Shop.Quotes.Entities.Quote", "OrderId");
|
||||||
|
|
||||||
|
b.HasOne("LiteCharms.Features.Shop.ShoppingCarts.Entities.ShoppingCart", "ShoppingCart")
|
||||||
|
.WithOne("Quote")
|
||||||
|
.HasForeignKey("LiteCharms.Features.Shop.Quotes.Entities.Quote", "ShoppingCartId");
|
||||||
|
|
||||||
|
b.Navigation("Customer");
|
||||||
|
|
||||||
|
b.Navigation("Order");
|
||||||
|
|
||||||
|
b.Navigation("ShoppingCart");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.ShoppingCarts.Entities.ShoppingCart", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("LiteCharms.Features.Shop.Customers.Entities.Customer", "Customer")
|
||||||
|
.WithMany("ShoppingCarts")
|
||||||
|
.HasForeignKey("CustomerId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("LiteCharms.Features.Shop.Orders.Entities.Order", "Order")
|
||||||
|
.WithOne("ShoppingCart")
|
||||||
|
.HasForeignKey("LiteCharms.Features.Shop.ShoppingCarts.Entities.ShoppingCart", "OrderId")
|
||||||
|
.OnDelete(DeleteBehavior.SetNull);
|
||||||
|
|
||||||
|
b.Navigation("Customer");
|
||||||
|
|
||||||
|
b.Navigation("Order");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.ShoppingCarts.Entities.ShoppingCartItem", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("LiteCharms.Features.Shop.Products.Entities.ProductPrice", "ProductPrice")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ProductPriceId")
|
||||||
|
.OnDelete(DeleteBehavior.Restrict)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("LiteCharms.Features.Shop.ShoppingCarts.Entities.ShoppingCart", "ShoppingCart")
|
||||||
|
.WithMany("ShoppingCartItems")
|
||||||
|
.HasForeignKey("ShoppingCartId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("ProductPrice");
|
||||||
|
|
||||||
|
b.Navigation("ShoppingCart");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.ShoppingCarts.Entities.ShoppingCartPackage", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("LiteCharms.Features.Shop.CartPackages.Entities.Package", "Package")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("PackageId")
|
||||||
|
.OnDelete(DeleteBehavior.Restrict)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("LiteCharms.Features.Shop.ShoppingCarts.Entities.ShoppingCart", "ShoppingCart")
|
||||||
|
.WithMany("ShoppingCartPackages")
|
||||||
|
.HasForeignKey("ShoppingCartId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Package");
|
||||||
|
|
||||||
|
b.Navigation("ShoppingCart");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.CartPackages.Entities.Package", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("PackageItems");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.Customers.Entities.Customer", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Leads");
|
||||||
|
|
||||||
|
b.Navigation("Orders");
|
||||||
|
|
||||||
|
b.Navigation("Quotes");
|
||||||
|
|
||||||
|
b.Navigation("ShoppingCarts");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.Orders.Entities.Order", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Quote");
|
||||||
|
|
||||||
|
b.Navigation("Refunds");
|
||||||
|
|
||||||
|
b.Navigation("ShoppingCart");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.Products.Entities.Product", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("ProductPrices");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Features.Shop.ShoppingCarts.Entities.ShoppingCart", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Quote");
|
||||||
|
|
||||||
|
b.Navigation("ShoppingCartItems");
|
||||||
|
|
||||||
|
b.Navigation("ShoppingCartPackages");
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
using LiteCharms.Features.TechShop.CartPackages.Entities;
|
||||||
|
using LiteCharms.Features.TechShop.Customers.Entities;
|
||||||
|
using LiteCharms.Features.TechShop.Leads.Entities;
|
||||||
|
using LiteCharms.Features.TechShop.Notifications.Entities;
|
||||||
|
using LiteCharms.Features.TechShop.Orders.Entities;
|
||||||
|
using LiteCharms.Features.TechShop.Products.Entities;
|
||||||
|
using LiteCharms.Features.TechShop.Quotes.Entities;
|
||||||
|
using LiteCharms.Features.TechShop.ShoppingCarts.Entities;
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.TechShop.Postgres;
|
||||||
|
|
||||||
|
public class ShopDbContext(DbContextOptions<ShopDbContext> options) : DbContext(options)
|
||||||
|
{
|
||||||
|
public DbSet<Customer> Customers { get; set; }
|
||||||
|
|
||||||
|
public DbSet<Lead> Leads { get; set; }
|
||||||
|
|
||||||
|
public DbSet<Order> Orders { get; set; }
|
||||||
|
|
||||||
|
public DbSet<OrderRefund> OrderRefunds { get; set; }
|
||||||
|
|
||||||
|
public DbSet<Product> Products { get; set; }
|
||||||
|
|
||||||
|
public DbSet<ProductPrice> ProductPrices { get; set; }
|
||||||
|
|
||||||
|
public DbSet<Notification> Notifications { get; set; }
|
||||||
|
|
||||||
|
public DbSet<Quote> Quotes { get; set; }
|
||||||
|
|
||||||
|
public DbSet<ShoppingCart> ShoppingCarts { get; set; }
|
||||||
|
|
||||||
|
public DbSet<ShoppingCartItem> ShoppingCartItems { get; set; }
|
||||||
|
|
||||||
|
public DbSet<Package> Packages { get; set; }
|
||||||
|
|
||||||
|
public DbSet<PackageItem> PackageItems { get; set; }
|
||||||
|
|
||||||
|
public DbSet<ShoppingCartPackage> ShoppingCartPackages { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
using static LiteCharms.Features.TechShop.Extensions.Postgres;
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.TechShop.Postgres;
|
||||||
|
|
||||||
|
public class ShopDbContextFactory : IDesignTimeDbContextFactory<ShopDbContext>
|
||||||
|
{
|
||||||
|
public ShopDbContext CreateDbContext(string[] args)
|
||||||
|
{
|
||||||
|
var configuration = new ConfigurationBuilder()
|
||||||
|
.SetBasePath(Directory.GetCurrentDirectory())
|
||||||
|
.AddUserSecrets(typeof(ShopDbContext).Assembly)
|
||||||
|
.AddJsonFile("appsettings.json")
|
||||||
|
.AddEnvironmentVariables()
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
var optionsBuilder = new DbContextOptionsBuilder<ShopDbContext>();
|
||||||
|
optionsBuilder.UseNpgsql(configuration.GetConnectionString(ShopDbConfigName));
|
||||||
|
|
||||||
|
return new ShopDbContext(optionsBuilder.Options);
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
-3
@@ -1,9 +1,8 @@
|
|||||||
using LiteCharms.Entities.Configuration;
|
namespace LiteCharms.Features.TechShop.Products.Entities;
|
||||||
|
|
||||||
namespace LiteCharms.Entities;
|
|
||||||
|
|
||||||
[EntityTypeConfiguration<ProductConfiguration, Product>]
|
[EntityTypeConfiguration<ProductConfiguration, Product>]
|
||||||
public class Product : Models.Product
|
public class Product : Models.Product
|
||||||
{
|
{
|
||||||
|
|
||||||
public virtual ICollection<ProductPrice>? ProductPrices { get; set; }
|
public virtual ICollection<ProductPrice>? ProductPrices { get; set; }
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
namespace LiteCharms.Features.TechShop.Products.Entities;
|
||||||
|
|
||||||
|
public class ProductConfiguration : IEntityTypeConfiguration<Product>
|
||||||
|
{
|
||||||
|
public void Configure(EntityTypeBuilder<Product> builder)
|
||||||
|
{
|
||||||
|
builder.ToTable("Products");
|
||||||
|
|
||||||
|
builder.HasKey(f => f.Id);
|
||||||
|
builder.Property(f => f.Name).IsRequired();
|
||||||
|
builder.Property(f => f.CreatedAt).IsRequired().ValueGeneratedOnAdd().HasDefaultValueSql("now()");
|
||||||
|
builder.Property(f => f.UpdatedAt).IsRequired(false);
|
||||||
|
builder.Property(f => f.Summary).IsRequired().HasMaxLength(512);
|
||||||
|
builder.Property(f => f.Description).IsRequired().HasMaxLength(2048);
|
||||||
|
builder.Property(f => f.ImageUrl).IsRequired(false).HasMaxLength(2048);
|
||||||
|
builder.Property(f => f.Thumbnails).HasColumnType("jsonb").IsRequired(false);
|
||||||
|
builder.Property(f => f.Active).HasDefaultValue(false);
|
||||||
|
builder.Property(f => f.Metadata).HasColumnType("jsonb").IsRequired(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-3
@@ -1,6 +1,4 @@
|
|||||||
using LiteCharms.Entities.Configuration;
|
namespace LiteCharms.Features.TechShop.Products.Entities;
|
||||||
|
|
||||||
namespace LiteCharms.Entities;
|
|
||||||
|
|
||||||
[EntityTypeConfiguration<ProductPriceConfiguration, ProductPrice>]
|
[EntityTypeConfiguration<ProductPriceConfiguration, ProductPrice>]
|
||||||
public class ProductPrice : Models.ProductPrice
|
public class ProductPrice : Models.ProductPrice
|
||||||
+7
-6
@@ -1,22 +1,23 @@
|
|||||||
namespace LiteCharms.Entities.Configuration;
|
namespace LiteCharms.Features.TechShop.Products.Entities;
|
||||||
|
|
||||||
public class ProductPriceConfiguration : IEntityTypeConfiguration<ProductPrice>
|
public class ProductPriceConfiguration : IEntityTypeConfiguration<ProductPrice>
|
||||||
{
|
{
|
||||||
public void Configure(EntityTypeBuilder<ProductPrice> builder)
|
public void Configure(EntityTypeBuilder<ProductPrice> builder)
|
||||||
{
|
{
|
||||||
builder.ToTable(nameof(ProductPrice));
|
builder.ToTable("ProductPrices");
|
||||||
|
|
||||||
builder.HasKey(f => f.Id);
|
builder.HasKey(f => f.Id);
|
||||||
builder.Property(f => f.CreatedAt).ValueGeneratedOnAdd();
|
builder.Property(f => f.CreatedAt).IsRequired().ValueGeneratedOnAdd().HasDefaultValueSql("now()");
|
||||||
builder.Property(f => f.UpdatedAt).IsRequired(false).ValueGeneratedOnUpdate();
|
builder.Property(f => f.UpdatedAt).IsRequired(false);
|
||||||
builder.Property(f => f.ProductId).IsRequired();
|
builder.Property(f => f.ProductId).IsRequired();
|
||||||
builder.Property(f => f.Price).IsRequired().HasPrecision(18, 2);
|
builder.Property(f => f.Price).IsRequired().HasPrecision(18, 2);
|
||||||
builder.Property(f => f.Discount).HasPrecision(18, 2);
|
builder.Property(f => f.Discount).HasPrecision(18, 2);
|
||||||
builder.Property(f => f.Active);
|
builder.Property(f => f.Active);
|
||||||
|
|
||||||
builder.HasOne(f => f.Product)
|
builder.HasOne(f => f.Product)
|
||||||
.WithMany(p => p.ProductPrices)
|
.WithMany(f => f.ProductPrices)
|
||||||
.HasForeignKey(f => f.ProductId)
|
.HasForeignKey(pp => pp.ProductId)
|
||||||
|
.IsRequired()
|
||||||
.OnDelete(DeleteBehavior.Restrict);
|
.OnDelete(DeleteBehavior.Restrict);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.TechShop.Products.Models;
|
||||||
|
|
||||||
|
public class CreateProductModel
|
||||||
|
{
|
||||||
|
[MaxLength(128)]
|
||||||
|
[Required(ErrorMessage = "Product name is required.")]
|
||||||
|
public string? Name { get; set; }
|
||||||
|
|
||||||
|
[MaxLength(512)]
|
||||||
|
[Required(ErrorMessage = "Summary is required.")]
|
||||||
|
public string? Summary { get; set; }
|
||||||
|
|
||||||
|
[MaxLength(2048)]
|
||||||
|
[Required(ErrorMessage = "Description is required.")]
|
||||||
|
public string? Description { get; set; }
|
||||||
|
|
||||||
|
[Range(0.01, double.MaxValue, ErrorMessage = "Price must be greater than zero.")]
|
||||||
|
public decimal Price { get; set; }
|
||||||
|
|
||||||
|
[MaxLength(128)]
|
||||||
|
[Required(ErrorMessage = "Author metadata is required.")]
|
||||||
|
public string? Author { get; set; }
|
||||||
|
|
||||||
|
[Required(ErrorMessage = "Publication Date is required.")]
|
||||||
|
public DateTime PublishDate { get; set; } = DateTime.Today;
|
||||||
|
|
||||||
|
[MaxLength(255)]
|
||||||
|
[Required(ErrorMessage = "Copyright Information field is required.")]
|
||||||
|
public string? CopyrightInfo { get; set; }
|
||||||
|
|
||||||
|
[MaxLength(128)]
|
||||||
|
[Required(ErrorMessage = "ISBN code is required.")]
|
||||||
|
[RegularExpression(@"^(?=(?:\D*\d){10}(?:(?:\D*\d){3})?$)[\d-]+$", ErrorMessage = "Please enter a valid ISBN-10 or ISBN-13 string.")]
|
||||||
|
public string? Isbn { get; set; }
|
||||||
|
|
||||||
|
[Required(ErrorMessage = "Primary image is required.")]
|
||||||
|
public string? ImageUrl { get; set; }
|
||||||
|
|
||||||
|
public List<string> Thumbnails { get; set; } = [];
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
namespace LiteCharms.Features.TechShop.Products.Models;
|
||||||
|
|
||||||
|
public class Product
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
|
||||||
|
public DateTime CreatedAt { get; set; }
|
||||||
|
|
||||||
|
public DateTime? UpdatedAt { get; set; }
|
||||||
|
|
||||||
|
public string? Name { get; set; }
|
||||||
|
|
||||||
|
public string? Summary { get; set; }
|
||||||
|
|
||||||
|
public string? Description { get; set; }
|
||||||
|
|
||||||
|
public string? ImageUrl { get; set; }
|
||||||
|
|
||||||
|
public string[]? Thumbnails { get; set; }
|
||||||
|
|
||||||
|
public bool Active { get; set; }
|
||||||
|
|
||||||
|
public ProductMetadata? Metadata { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
namespace LiteCharms.Features.TechShop.Products.Models;
|
||||||
|
|
||||||
|
public class ProductMetadata
|
||||||
|
{
|
||||||
|
public string? Manufacturer { get; set; }
|
||||||
|
|
||||||
|
public string? ManufactureDate { get; set; }
|
||||||
|
|
||||||
|
public string? CopyrightInfo { get; set; }
|
||||||
|
|
||||||
|
public string? SerialNumber { get; set; }
|
||||||
|
}
|
||||||
+3
-3
@@ -1,12 +1,12 @@
|
|||||||
namespace LiteCharms.Models;
|
namespace LiteCharms.Features.TechShop.Products.Models;
|
||||||
|
|
||||||
public class ProductPrice
|
public class ProductPrice
|
||||||
{
|
{
|
||||||
public Guid Id { get; set; }
|
public Guid Id { get; set; }
|
||||||
|
|
||||||
public DateTimeOffset CreatedAt { get; set; }
|
public DateTime CreatedAt { get; set; }
|
||||||
|
|
||||||
public DateTimeOffset? UpdatedAt { get; set; }
|
public DateTime? UpdatedAt { get; set; }
|
||||||
|
|
||||||
public Guid ProductId { get; set; }
|
public Guid ProductId { get; set; }
|
||||||
|
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
namespace LiteCharms.Features.TechShop.Products.Models;
|
||||||
|
|
||||||
|
public record CreateProduct
|
||||||
|
{
|
||||||
|
public required string Name { get; set; }
|
||||||
|
|
||||||
|
public required string Summary { get; set; }
|
||||||
|
|
||||||
|
public required string Description { get; set; }
|
||||||
|
|
||||||
|
public required string ImageUrl { get; set; }
|
||||||
|
|
||||||
|
public string[]? Thumbnails { get; set; }
|
||||||
|
|
||||||
|
public ProductMetadata? Metadata { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,277 @@
|
|||||||
|
using LiteCharms.Features.TechShop.Extensions;
|
||||||
|
using LiteCharms.Features.TechShop.Postgres;
|
||||||
|
using LiteCharms.Features.TechShop.Products.Models;
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.TechShop.Products;
|
||||||
|
|
||||||
|
public class ProductService(IDbContextFactory<ShopDbContext> contextFactory)
|
||||||
|
{
|
||||||
|
public async ValueTask<Result> ChangeProductPriceStatusAsync(Guid productPriceId, bool active, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
|
var price = await context.ProductPrices.FirstOrDefaultAsync(p => p.Id == productPriceId, cancellationToken);
|
||||||
|
|
||||||
|
if (price is null)
|
||||||
|
return Result.Fail($"Could not find product price with ID {productPriceId}");
|
||||||
|
|
||||||
|
price.Active = active;
|
||||||
|
price.UpdatedAt = DateTime.UtcNow;
|
||||||
|
|
||||||
|
return await context.SaveChangesAsync(cancellationToken) > 0
|
||||||
|
? Result.Ok()
|
||||||
|
: Result.Fail($"Failed to change product price by ID {productPriceId}");
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Result.Fail(new Error(ex.Message).CausedBy(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async ValueTask<Result> ChangeProductStatusAsync(Guid productId, bool active, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
|
var product = await context.Products.FirstOrDefaultAsync(p => p.Id == productId, cancellationToken);
|
||||||
|
|
||||||
|
if (product is null)
|
||||||
|
return Result.Fail($"Could not find product with ID {productId}");
|
||||||
|
|
||||||
|
product.Active = active;
|
||||||
|
|
||||||
|
return await context.SaveChangesAsync(cancellationToken) > 0
|
||||||
|
? Result.Ok()
|
||||||
|
: Result.Fail($"Failed to change product status by ID {productId}");
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Result.Fail(new Error(ex.Message).CausedBy(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async ValueTask<Result<Guid>> CreateProductAsync(CreateProduct request, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
|
if (!await context.Products.AnyAsync(p => p.Name == request.Name, cancellationToken))
|
||||||
|
return Result.Fail<Guid>($"A product by the same name '{request.Name}' already exists");
|
||||||
|
|
||||||
|
var newProduct = context.Products.Add(new Entities.Product
|
||||||
|
{
|
||||||
|
Name = request.Name,
|
||||||
|
Summary = request.Summary,
|
||||||
|
Description = request.Description,
|
||||||
|
ImageUrl = request.ImageUrl,
|
||||||
|
Thumbnails = request.Thumbnails,
|
||||||
|
Metadata = request.Metadata
|
||||||
|
});
|
||||||
|
|
||||||
|
return await context.SaveChangesAsync(cancellationToken) > 0
|
||||||
|
? Result.Ok(newProduct.Entity.Id)
|
||||||
|
: Result.Fail($"Failed to create new product '{request.Name}'");
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Result.Fail(new Error(ex.Message).CausedBy(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async ValueTask<Result<Guid>> CreateProductPriceAsync(Guid productId, decimal price, decimal discount = 0, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
|
var newProductPrice = context.ProductPrices.Add(new Entities.ProductPrice
|
||||||
|
{
|
||||||
|
Price = price,
|
||||||
|
Discount = discount,
|
||||||
|
ProductId = productId
|
||||||
|
});
|
||||||
|
|
||||||
|
return await context.SaveChangesAsync(cancellationToken) > 0
|
||||||
|
? Result.Ok(newProductPrice.Entity.Id)
|
||||||
|
: Result.Fail($"Failed to create new product price for product id {productId}");
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Result.Fail(new Error(ex.Message).CausedBy(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async ValueTask<Result<Product>> GetProductAsync(Guid productId, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
|
var product = await context.Products.FirstOrDefaultAsync(p => p.Id == productId, cancellationToken);
|
||||||
|
|
||||||
|
return product is not null
|
||||||
|
? Result.Ok(product.ToModel())
|
||||||
|
: Result.Fail<Product>(new Error($"Product with ID {productId} not found."));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Result.Fail<Product>(new Error(ex.Message).CausedBy(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async ValueTask<Result<ProductPrice>> GetProductPriceAsync(Guid productPriceId, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
|
if (!await context.Products.AnyAsync(p => p.Id == productPriceId, cancellationToken))
|
||||||
|
return Result.Fail<ProductPrice>(new Error($"Product {productPriceId} not found."));
|
||||||
|
|
||||||
|
var productPrice = await context.ProductPrices.AsNoTracking()
|
||||||
|
.OrderByDescending(pp => pp.CreatedAt)
|
||||||
|
.FirstOrDefaultAsync(pp => pp.Id == productPriceId, cancellationToken);
|
||||||
|
|
||||||
|
return productPrice is not null
|
||||||
|
? Result.Ok(productPrice.ToModel())
|
||||||
|
: Result.Fail<ProductPrice>(new Error($"Product price {productPriceId} not found."));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Result.Fail<ProductPrice>(new Error(ex.Message).CausedBy(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async ValueTask<Result<ProductPrice[]>> GetProductPricesAsync(int maxRecords = 1000, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
|
var products = await context.ProductPrices.AsNoTracking()
|
||||||
|
.OrderByDescending(o => o.Id)
|
||||||
|
.Take(maxRecords)
|
||||||
|
.ToArrayAsync(cancellationToken);
|
||||||
|
|
||||||
|
return Result.Ok(products.Select(p => p.ToModel()).ToArray());
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Result.Fail<ProductPrice[]>(new Error(ex.Message).CausedBy(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async ValueTask<Result<Product[]>> GetProductsAsync(int maxRecords = 1000, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
|
var products = await context.Products.AsNoTracking()
|
||||||
|
.OrderByDescending(o => o.Id)
|
||||||
|
.Take(maxRecords)
|
||||||
|
.ToArrayAsync(cancellationToken);
|
||||||
|
|
||||||
|
return Result.Ok(products.Select(p => p.ToModel()).ToArray());
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Result.Fail<Product[]>(new Error(ex.Message).CausedBy(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async ValueTask<Result<Guid>> ReplaceProductPriceAsync(Guid productPriceId, decimal price, decimal discount = 0, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
|
var existingPrice = await context.ProductPrices.FirstOrDefaultAsync(p => p.Id == productPriceId, cancellationToken);
|
||||||
|
|
||||||
|
if (existingPrice is null)
|
||||||
|
return Result.Fail($"Could not find product price with ID {productPriceId}");
|
||||||
|
|
||||||
|
existingPrice.Active = false;
|
||||||
|
existingPrice.UpdatedAt = DateTime.UtcNow;
|
||||||
|
|
||||||
|
if (!(await context.SaveChangesAsync(cancellationToken) > 0))
|
||||||
|
return Result.Fail<Guid>($"Failed to deactivate existing price of ID {productPriceId}, try again later");
|
||||||
|
|
||||||
|
var result = await CreateProductPriceAsync(existingPrice.ProductId, price, discount, cancellationToken);
|
||||||
|
|
||||||
|
if (result.IsFailed)
|
||||||
|
{
|
||||||
|
var deactivatedPrice = await context.ProductPrices.FirstOrDefaultAsync(p => p.Id == productPriceId, cancellationToken);
|
||||||
|
|
||||||
|
existingPrice.Active = true;
|
||||||
|
existingPrice.UpdatedAt = DateTime.UtcNow;
|
||||||
|
|
||||||
|
return await context.SaveChangesAsync(cancellationToken) > 0
|
||||||
|
? Result.Fail<Guid>("Reverted to old price, creation of new price failed")
|
||||||
|
: Result.Fail<Guid>($"Failed to reactivate price of ID {productPriceId} after new price creation failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result.Ok(result.Value);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Result.Fail(new Error(ex.Message).CausedBy(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async ValueTask<Result> SetProductPriceStatusAsync(Guid productPriceId, bool active, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
|
var productPrice = await context.ProductPrices.FirstOrDefaultAsync(p => p.Id == productPriceId, cancellationToken);
|
||||||
|
|
||||||
|
if (productPrice is null)
|
||||||
|
return Result.Fail($"Could not find product price with ID {productPriceId}");
|
||||||
|
|
||||||
|
productPrice.Active = active;
|
||||||
|
productPrice.UpdatedAt = DateTime.UtcNow;
|
||||||
|
|
||||||
|
return await context.SaveChangesAsync(cancellationToken) > 0
|
||||||
|
? Result.Ok()
|
||||||
|
: Result.Fail($"Failed to change product price status by ID {productPriceId}");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Result.Fail(new Error(ex.Message).CausedBy(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async ValueTask<Result> UpdateProductMetadataAsync(Guid productId, ProductMetadata metadata, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
|
var product = await context.Products.FirstOrDefaultAsync(p => p.Id == productId, cancellationToken);
|
||||||
|
|
||||||
|
if (product is null)
|
||||||
|
return Result.Fail($"Could not find product with ID {productId}");
|
||||||
|
|
||||||
|
product.Metadata = metadata;
|
||||||
|
product.UpdatedAt = DateTime.UtcNow;
|
||||||
|
|
||||||
|
return await context.SaveChangesAsync(cancellationToken) > 0
|
||||||
|
? Result.Ok()
|
||||||
|
: Result.Fail($"Failed to update product metadata by ID {productId}");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Result.Fail(new Error(ex.Message).CausedBy(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
using LiteCharms.Features.TechShop.Customers.Entities;
|
||||||
|
using LiteCharms.Features.TechShop.Orders.Entities;
|
||||||
|
using LiteCharms.Features.TechShop.ShoppingCarts.Entities;
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.TechShop.Quotes.Entities;
|
||||||
|
|
||||||
|
[EntityTypeConfiguration<QuoteConfiguration, Quote>]
|
||||||
|
public class Quote : Models.Quote
|
||||||
|
{
|
||||||
|
public virtual Customer? Customer { get; set; }
|
||||||
|
|
||||||
|
public virtual Order? Order { get; set; }
|
||||||
|
|
||||||
|
public virtual ShoppingCart? ShoppingCart { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
namespace LiteCharms.Features.TechShop.Quotes.Entities;
|
||||||
|
|
||||||
|
public class QuoteConfiguration : IEntityTypeConfiguration<Quote>
|
||||||
|
{
|
||||||
|
public void Configure(EntityTypeBuilder<Quote> builder)
|
||||||
|
{
|
||||||
|
builder.ToTable("Quotes");
|
||||||
|
|
||||||
|
builder.HasKey(f => f.Id);
|
||||||
|
builder.Property(f => f.CreatedAt).IsRequired().ValueGeneratedOnAdd().HasDefaultValueSql("now()");
|
||||||
|
builder.Property(f => f.UpdatedAt).IsRequired(false).HasDefaultValueSql(null);
|
||||||
|
builder.Property(f => f.ExpiredAt).IsRequired(false).HasDefaultValueSql(null);
|
||||||
|
builder.Property(f => f.CustomerId).IsRequired();
|
||||||
|
builder.Property(f => f.OrderId);
|
||||||
|
builder.Property(f => f.ShoppingCartId);
|
||||||
|
builder.Property(f => f.Status).IsRequired().HasConversion<int>();
|
||||||
|
builder.Property(f => f.InvoiceUrl).IsRequired(false).HasMaxLength(2048);
|
||||||
|
builder.Property(f => f.Reason).IsRequired(false);
|
||||||
|
|
||||||
|
builder.HasOne(q => q.Customer)
|
||||||
|
.WithMany(c => c.Quotes)
|
||||||
|
.HasForeignKey(q => q.CustomerId)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
builder.HasOne(q => q.Order)
|
||||||
|
.WithOne(o => o.Quote)
|
||||||
|
.HasForeignKey<Quote>(q => q.OrderId);
|
||||||
|
|
||||||
|
builder.HasOne(q => q.ShoppingCart)
|
||||||
|
.WithOne(o => o.Quote)
|
||||||
|
.HasForeignKey<Quote>(q => q.ShoppingCartId);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
namespace LiteCharms.Features.TechShop.Quotes.Models;
|
||||||
|
|
||||||
|
public class Quote
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
|
||||||
|
public DateTime CreatedAt { get; set; }
|
||||||
|
|
||||||
|
public DateTime? UpdatedAt { get; set; }
|
||||||
|
|
||||||
|
public DateTime? ExpiredAt { get; set; }
|
||||||
|
|
||||||
|
public Guid CustomerId { get; set; }
|
||||||
|
|
||||||
|
public Guid? OrderId { get; set; }
|
||||||
|
|
||||||
|
public Guid? ShoppingCartId { get; set; }
|
||||||
|
|
||||||
|
public QuoteStatus Status { get; set; }
|
||||||
|
|
||||||
|
public string? InvoiceUrl { get; set; }
|
||||||
|
|
||||||
|
public string? Reason { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,156 @@
|
|||||||
|
using LiteCharms.Features.Extensions;
|
||||||
|
using LiteCharms.Features.Models;
|
||||||
|
using LiteCharms.Features.TechShop.Extensions;
|
||||||
|
using LiteCharms.Features.TechShop.Postgres;
|
||||||
|
using LiteCharms.Features.TechShop.Quotes.Models;
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.TechShop.Quotes;
|
||||||
|
|
||||||
|
public class QuoteService(IDbContextFactory<ShopDbContext> contextFactory)
|
||||||
|
{
|
||||||
|
public async ValueTask<Result> AssignQuoteToOrderAsync(Guid quoteId, Guid orderId, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
|
var quote = await context.Quotes.FirstOrDefaultAsync(o => o.Id == quoteId, cancellationToken);
|
||||||
|
|
||||||
|
if (quote is null)
|
||||||
|
return Result.Fail(new Error($"Quote with id {orderId} not found"));
|
||||||
|
|
||||||
|
if (!await context.Orders.AnyAsync(q => q.Id == orderId, cancellationToken))
|
||||||
|
return Result.Fail(new Error($"Order with id {quoteId} not found"));
|
||||||
|
|
||||||
|
if (quote.OrderId == orderId)
|
||||||
|
return Result.Fail(new Error($"Quote with id {quoteId} is already assigned to order with id {orderId}"));
|
||||||
|
|
||||||
|
quote.OrderId = orderId;
|
||||||
|
quote.UpdatedAt = DateTime.UtcNow;
|
||||||
|
|
||||||
|
return await context.SaveChangesAsync(cancellationToken) > 0
|
||||||
|
? Result.Ok()
|
||||||
|
: Result.Fail(new Error($"Failed to assign quote with id {quoteId} to order with id {orderId}"));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Result.Fail(new Error(ex.Message).CausedBy(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async ValueTask<Result> AssignQuoteToShoppingCartAsync(Guid quoteId, Guid shoppingCartId, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
|
var quote = await context.Quotes.FirstOrDefaultAsync(o => o.Id == quoteId, cancellationToken);
|
||||||
|
|
||||||
|
if (quote is null)
|
||||||
|
return Result.Fail(new Error($"Quote with id {quoteId} not found"));
|
||||||
|
|
||||||
|
if (!await context.ShoppingCarts.AnyAsync(q => q.Id == shoppingCartId, cancellationToken))
|
||||||
|
return Result.Fail(new Error($"Shopping Cart with id {shoppingCartId} not found"));
|
||||||
|
|
||||||
|
quote.ShoppingCartId = shoppingCartId;
|
||||||
|
quote.UpdatedAt = DateTime.UtcNow;
|
||||||
|
|
||||||
|
return await context.SaveChangesAsync(cancellationToken) > 0
|
||||||
|
? Result.Ok()
|
||||||
|
: Result.Fail(new Error("Failed to assign quote to shopping cart"));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Result.Fail(new Error(ex.Message).CausedBy(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async ValueTask<Result<Quote[]>> GetCustomerQuotesAsync(Guid customerId, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
|
if (!await context.Customers.AnyAsync(c => c.Id == customerId, cancellationToken))
|
||||||
|
return Result.Fail<Quote[]>(new Error($"Customer with Id {customerId} does not exist."));
|
||||||
|
|
||||||
|
var quotes = await context.Quotes.AsNoTracking()
|
||||||
|
.Where(q => q.CustomerId == customerId).ToArrayAsync(cancellationToken);
|
||||||
|
|
||||||
|
return quotes?.Length > 0
|
||||||
|
? Result.Ok(quotes.Select(q => q.ToModel()).ToArray())
|
||||||
|
: Result.Fail<Quote[]>(new Error($"No quotes found for customer with Id {customerId}."));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Result.Fail<Quote[]>(new Error(ex.Message).CausedBy(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async ValueTask<Result<Quote>> GetQuoteAsync(Guid quoteId, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
|
var quote = await context.Quotes.AsNoTracking().FirstOrDefaultAsync(q => q.Id == quoteId, cancellationToken);
|
||||||
|
|
||||||
|
return quote is not null
|
||||||
|
? Result.Ok(quote.ToModel())
|
||||||
|
: Result.Fail<Quote>(new Error($"Quote with ID {quoteId} not found."));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Result.Fail<Quote>(new Error(ex.Message).CausedBy(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async ValueTask<Result<Quote[]>> GetQuotesAsync(DateRange range, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var fromDate = range.From.ToDateTime(TimeOnly.MinValue);
|
||||||
|
var toDate = range.To.ToDateTime(TimeOnly.MaxValue);
|
||||||
|
|
||||||
|
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
|
var quotes = await context.Quotes.AsNoTracking()
|
||||||
|
.OrderByDescending(o => o.CreatedAt)
|
||||||
|
.Where(o => o.CreatedAt >= fromDate && o.CreatedAt <= toDate)
|
||||||
|
.Take(range.MaxRecords)
|
||||||
|
.ToArrayAsync(cancellationToken);
|
||||||
|
|
||||||
|
return quotes?.Length > 0
|
||||||
|
? Result.Ok(quotes.Select(o => o.ToModel()).ToArray())
|
||||||
|
: Result.Fail<Quote[]>(new Error($"No quotes found for the specified date range {range.From} - {range.To}."));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Result.Fail<Quote[]>(new Error(ex.Message).CausedBy(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async ValueTask<Result> UpdateQuoteStatusAsync(Guid quoteId, QuoteStatus status, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
|
var quote = await context.Quotes.FirstOrDefaultAsync(q => q.Id == quoteId, cancellationToken);
|
||||||
|
|
||||||
|
if (quote is null)
|
||||||
|
return Result.Fail(new Error("Quote not found."));
|
||||||
|
|
||||||
|
quote.Status = status;
|
||||||
|
quote.UpdatedAt = DateTime.UtcNow;
|
||||||
|
|
||||||
|
return await context.SaveChangesAsync(cancellationToken) > 0
|
||||||
|
? Result.Ok()
|
||||||
|
: Result.Fail(new Error("Failed to update quote status."));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Result.Fail(new Error(ex.Message).CausedBy(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
using LiteCharms.Features.TechShop.Customers.Entities;
|
||||||
|
using LiteCharms.Features.TechShop.Orders.Entities;
|
||||||
|
using LiteCharms.Features.TechShop.Quotes.Entities;
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.TechShop.ShoppingCarts.Entities;
|
||||||
|
|
||||||
|
[EntityTypeConfiguration<ShoppingCartConfiguration, ShoppingCart>]
|
||||||
|
public class ShoppingCart : Models.ShoppingCart
|
||||||
|
{
|
||||||
|
public virtual Customer? Customer { get; set; }
|
||||||
|
|
||||||
|
public virtual Order? Order { get; set; }
|
||||||
|
|
||||||
|
public virtual Quote? Quote { get; set; }
|
||||||
|
|
||||||
|
public virtual ICollection<ShoppingCartItem>? ShoppingCartItems { get; set; }
|
||||||
|
|
||||||
|
public virtual ICollection<ShoppingCartPackage>? ShoppingCartPackages { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
namespace LiteCharms.Features.TechShop.ShoppingCarts.Entities;
|
||||||
|
|
||||||
|
public class ShoppingCartConfiguration : IEntityTypeConfiguration<ShoppingCart>
|
||||||
|
{
|
||||||
|
public void Configure(EntityTypeBuilder<ShoppingCart> builder)
|
||||||
|
{
|
||||||
|
builder.ToTable("ShoppingCarts");
|
||||||
|
|
||||||
|
builder.HasKey(f => f.Id);
|
||||||
|
builder.Property(f => f.CreatedAt).IsRequired().ValueGeneratedOnAdd().HasDefaultValueSql("now()");
|
||||||
|
builder.Property(f => f.UpdatedAt).IsRequired(false).HasDefaultValueSql(null);
|
||||||
|
builder.Property(f => f.CustomerId).IsRequired();
|
||||||
|
builder.Property(f => f.OrderId);
|
||||||
|
|
||||||
|
builder.HasOne(s => s.Customer)
|
||||||
|
.WithMany(c => c.ShoppingCarts)
|
||||||
|
.HasForeignKey(s => s.CustomerId)
|
||||||
|
.IsRequired()
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
builder.HasOne(s => s.Order)
|
||||||
|
.WithOne(o => o.ShoppingCart)
|
||||||
|
.HasForeignKey<ShoppingCart>(s => s.OrderId)
|
||||||
|
.OnDelete(DeleteBehavior.SetNull);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
using LiteCharms.Features.TechShop.Products.Entities;
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.TechShop.ShoppingCarts.Entities;
|
||||||
|
|
||||||
|
[EntityTypeConfiguration<ShoppingCartItemConfiguration, ShoppingCartItem>]
|
||||||
|
public class ShoppingCartItem : Models.ShoppingCartItem
|
||||||
|
{
|
||||||
|
public virtual ShoppingCart? ShoppingCart { get; set; }
|
||||||
|
|
||||||
|
public virtual ProductPrice? ProductPrice { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
namespace LiteCharms.Features.TechShop.ShoppingCarts.Entities;
|
||||||
|
|
||||||
|
public class ShoppingCartItemConfiguration : IEntityTypeConfiguration<ShoppingCartItem>
|
||||||
|
{
|
||||||
|
public void Configure(EntityTypeBuilder<ShoppingCartItem> builder)
|
||||||
|
{
|
||||||
|
builder.ToTable("ShoppingCartItems");
|
||||||
|
|
||||||
|
builder.HasKey(f => f.Id);
|
||||||
|
builder.Property(f => f.CreatedAt).IsRequired().ValueGeneratedOnAdd().HasDefaultValueSql("now()");
|
||||||
|
builder.Property(f => f.UpdatedAt).IsRequired(false).HasDefaultValueSql(null);
|
||||||
|
builder.Property(f => f.Quantity).IsRequired().HasDefaultValue(1);
|
||||||
|
builder.Property(f => f.ShoppingCartId).IsRequired();
|
||||||
|
builder.Property(f => f.ProductPriceId).IsRequired();
|
||||||
|
|
||||||
|
builder.HasOne(f => f.ShoppingCart)
|
||||||
|
.WithMany(s => s.ShoppingCartItems)
|
||||||
|
.HasForeignKey(f => f.ShoppingCartId)
|
||||||
|
.IsRequired()
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
builder.HasOne(f => f.ProductPrice)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey(f => f.ProductPriceId)
|
||||||
|
.IsRequired()
|
||||||
|
.OnDelete(DeleteBehavior.Restrict);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
using LiteCharms.Features.TechShop.CartPackages.Entities;
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.TechShop.ShoppingCarts.Entities;
|
||||||
|
|
||||||
|
[EntityTypeConfiguration<ShoppingCartPackageConfiguration, ShoppingCartPackage>]
|
||||||
|
public class ShoppingCartPackage : Models.ShoppingCartPackage
|
||||||
|
{
|
||||||
|
public virtual ShoppingCart? ShoppingCart { get; set; }
|
||||||
|
|
||||||
|
public virtual Package? Package { get; set; }
|
||||||
|
}
|
||||||
+26
@@ -0,0 +1,26 @@
|
|||||||
|
namespace LiteCharms.Features.TechShop.ShoppingCarts.Entities;
|
||||||
|
|
||||||
|
public class ShoppingCartPackageConfiguration : IEntityTypeConfiguration<ShoppingCartPackage>
|
||||||
|
{
|
||||||
|
public void Configure(EntityTypeBuilder<ShoppingCartPackage> builder)
|
||||||
|
{
|
||||||
|
builder.ToTable("ShoppingCartPackages");
|
||||||
|
|
||||||
|
builder.HasKey(f => f.Id);
|
||||||
|
builder.Property(f => f.CreatedAt).IsRequired().ValueGeneratedOnAdd().HasDefaultValueSql("now()");
|
||||||
|
builder.Property(f => f.ShoppingCartId).IsRequired();
|
||||||
|
builder.Property(f => f.PackageId).IsRequired();
|
||||||
|
|
||||||
|
builder.HasOne(f => f.ShoppingCart)
|
||||||
|
.WithMany(s => s.ShoppingCartPackages)
|
||||||
|
.HasForeignKey(scp => scp.ShoppingCartId)
|
||||||
|
.IsRequired()
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
builder.HasOne(f => f.Package)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey(scp => scp.PackageId)
|
||||||
|
.IsRequired()
|
||||||
|
.OnDelete(DeleteBehavior.Restrict);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
namespace LiteCharms.Features.TechShop.ShoppingCarts.Models;
|
||||||
|
|
||||||
|
public class ShoppingCart
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
|
||||||
|
public DateTime CreatedAt { get; set; }
|
||||||
|
|
||||||
|
public DateTime? UpdatedAt { get; set; }
|
||||||
|
|
||||||
|
public Guid CustomerId { get; set; }
|
||||||
|
|
||||||
|
public Guid? OrderId { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
namespace LiteCharms.Features.TechShop.ShoppingCarts.Models;
|
||||||
|
|
||||||
|
public class ShoppingCartItem
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
|
||||||
|
public Guid ShoppingCartId { get; set; }
|
||||||
|
|
||||||
|
public Guid ProductPriceId { get; set; }
|
||||||
|
|
||||||
|
public DateTime CreatedAt { get; set; }
|
||||||
|
|
||||||
|
public DateTime? UpdatedAt { get; set; }
|
||||||
|
|
||||||
|
public int Quantity { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
namespace LiteCharms.Features.TechShop.ShoppingCarts.Models;
|
||||||
|
|
||||||
|
public class ShoppingCartPackage
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
|
||||||
|
public DateTime CreatedAt { get; set; }
|
||||||
|
|
||||||
|
public Guid ShoppingCartId { get; set; }
|
||||||
|
|
||||||
|
public Guid PackageId { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,297 @@
|
|||||||
|
using LiteCharms.Features.TechShop.Extensions;
|
||||||
|
using LiteCharms.Features.TechShop.Postgres;
|
||||||
|
using LiteCharms.Features.TechShop.ShoppingCarts.Models;
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.TechShop.ShoppingCarts;
|
||||||
|
|
||||||
|
public class ShoppingCartService(IDbContextFactory<ShopDbContext> contextFactory)
|
||||||
|
{
|
||||||
|
public async ValueTask<Result> AddItemToShoppingCartAsync(Guid shoppingCartId, Guid productPriceId, int quantity, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
|
if (!await context.ProductPrices.AnyAsync(c => c.Id == productPriceId, cancellationToken))
|
||||||
|
return Result.Fail($"Product item could not be found with id {productPriceId}");
|
||||||
|
|
||||||
|
var cart = await context.ShoppingCarts.FirstOrDefaultAsync(c => c.Id == shoppingCartId, cancellationToken);
|
||||||
|
|
||||||
|
if (cart is null)
|
||||||
|
return Result.Fail($"Shopping cart could not be found with id {shoppingCartId}");
|
||||||
|
|
||||||
|
if (cart.ShoppingCartItems?.Any(i => i.ProductPriceId == productPriceId) == true)
|
||||||
|
return Result.Fail($"Item already in shopping cart with id {shoppingCartId}");
|
||||||
|
|
||||||
|
context.ShoppingCartItems.Add(new Entities.ShoppingCartItem
|
||||||
|
{
|
||||||
|
ShoppingCartId = shoppingCartId,
|
||||||
|
ProductPriceId = productPriceId,
|
||||||
|
Quantity = quantity
|
||||||
|
});
|
||||||
|
|
||||||
|
return await context.SaveChangesAsync(cancellationToken) > 0
|
||||||
|
? Result.Ok()
|
||||||
|
: Result.Fail($"Failed to add cart item with id {productPriceId}");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Result.Fail(new Error(ex.Message).CausedBy(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async ValueTask<Result> AddPackageToShoppingCartAsync(Guid shoppingCartId, Guid packageId, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
|
if (!await context.Packages.AnyAsync(p => p.Id == packageId, cancellationToken))
|
||||||
|
return Result.Fail($"Package cold not be found by ID {packageId}");
|
||||||
|
|
||||||
|
var shoppingCart = await context.ShoppingCarts.FirstOrDefaultAsync(c => c.Id == shoppingCartId, cancellationToken);
|
||||||
|
|
||||||
|
if (shoppingCart is null)
|
||||||
|
return Result.Fail($"Shopping cart could not be found by ID {shoppingCartId}");
|
||||||
|
|
||||||
|
if (!await context.ShoppingCartPackages.AnyAsync(cp => cp.ShoppingCartId == shoppingCartId, cancellationToken))
|
||||||
|
return Result.Fail($"Package {packageId} is already in the cart");
|
||||||
|
|
||||||
|
var newShoppingCartPackage = context.ShoppingCartPackages.Add(new Entities.ShoppingCartPackage
|
||||||
|
{
|
||||||
|
ShoppingCartId = shoppingCartId,
|
||||||
|
PackageId = packageId
|
||||||
|
});
|
||||||
|
|
||||||
|
return await context.SaveChangesAsync(cancellationToken) > 0
|
||||||
|
? Result.Ok()
|
||||||
|
: Result.Fail($"Could not add package of id {packageId} to shopping cart {shoppingCartId}");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Result.Fail(new Error(ex.Message).CausedBy(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async ValueTask<Result<Guid>> CreateShoppingCartAsync(Guid customerId, Guid orderId, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
|
if (!await context.Customers.AnyAsync(c => c.Id == customerId, cancellationToken))
|
||||||
|
return Result.Fail<Guid>($"Customer could not be found with id {customerId}");
|
||||||
|
|
||||||
|
var cart = context.ShoppingCarts.Add(new Entities.ShoppingCart
|
||||||
|
{
|
||||||
|
CustomerId = customerId,
|
||||||
|
OrderId = orderId
|
||||||
|
});
|
||||||
|
|
||||||
|
return await context.SaveChangesAsync(cancellationToken) > 0
|
||||||
|
? Result.Ok(cart.Entity.Id)
|
||||||
|
: Result.Fail<Guid>($"Failed to create shopping cart for customer id {customerId}");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Result.Fail<Guid>(new Error(ex.Message).CausedBy(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async ValueTask<Result> EmptyShoppingCartAsync(Guid shoppingCartId, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
|
if (!await context.ShoppingCarts.AnyAsync(c => c.Id == shoppingCartId, cancellationToken))
|
||||||
|
return Result.Fail($"Shopping could not be found with id {shoppingCartId}");
|
||||||
|
|
||||||
|
if (await context.ShoppingCartItems.CountAsync(i => i.ShoppingCartId == shoppingCartId, cancellationToken) == 0)
|
||||||
|
return Result.Ok();
|
||||||
|
|
||||||
|
var cartItems = await context.ShoppingCartItems.Where(i => i.ShoppingCartId == shoppingCartId).ToListAsync(cancellationToken);
|
||||||
|
|
||||||
|
context.RemoveRange(cartItems);
|
||||||
|
|
||||||
|
return await context.SaveChangesAsync(cancellationToken) > 0
|
||||||
|
? Result.Ok()
|
||||||
|
: Result.Fail($"Could not empty cart with id {shoppingCartId}");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Result.Fail(new Error(ex.Message).CausedBy(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async ValueTask<Result<ShoppingCart[]>> GetCustomerShoppingCartsAsync(Guid customerId, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
|
if (!await context.Customers.AnyAsync(c => c.Id == customerId, cancellationToken))
|
||||||
|
return Result.Fail<ShoppingCart[]>(new Error($"Customer with Id {customerId} does not exist."));
|
||||||
|
|
||||||
|
var shoppingCarts = await context.ShoppingCarts.Where(sc => sc.CustomerId == customerId).ToArrayAsync(cancellationToken);
|
||||||
|
|
||||||
|
return shoppingCarts?.Length > 0
|
||||||
|
? Result.Ok(shoppingCarts.Select(c => c.ToModel()).ToArray())
|
||||||
|
: Result.Fail<ShoppingCart[]>(new Error($"No shopping carts found for customer with Id {customerId}."));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Result.Fail<ShoppingCart[]>(new Error(ex.Message).CausedBy(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async ValueTask<Result<ShoppingCart>> GetShoppingCartAsync(Guid shoppingCartId, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
|
var cart = await context.ShoppingCarts.AsNoTracking().FirstOrDefaultAsync(c => c.Id == shoppingCartId, cancellationToken);
|
||||||
|
|
||||||
|
return cart is not null
|
||||||
|
? Result.Ok(cart.ToModel())
|
||||||
|
: Result.Fail<ShoppingCart>($"Failed to find shopping cart with id {shoppingCartId}");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Result.Fail<ShoppingCart>(new Error(ex.Message).CausedBy(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async ValueTask<Result<ShoppingCartItem[]>> GetShoppingCartItemsAsync(Guid shoppingCartId, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
|
if (!await context.ShoppingCarts.AnyAsync(i => i.Id == shoppingCartId, cancellationToken))
|
||||||
|
return Result.Fail($"Shopping cart could not be found with id {shoppingCartId}");
|
||||||
|
|
||||||
|
var items = await context.ShoppingCartItems.AsNoTracking()
|
||||||
|
.Where(i => i.ShoppingCartId == shoppingCartId).ToArrayAsync(cancellationToken);
|
||||||
|
|
||||||
|
return items?.Length > 0
|
||||||
|
? Result.Ok(items.Select(i => i.ToModel()).ToArray())
|
||||||
|
: Result.Fail<ShoppingCartItem[]>($"Failed to retrieve shopping cart items with id {shoppingCartId}");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Result.Fail<ShoppingCartItem[]>(new Error(ex.Message).CausedBy(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async ValueTask<Result<ShoppingCartPackage[]>> GetShoppingCartPackagesAsync(Guid shoppingCartId, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
|
if (!await context.ShoppingCarts.AnyAsync(c => c.Id == shoppingCartId, cancellationToken))
|
||||||
|
return Result.Fail($"Shopping cart could not be found by ID {shoppingCartId}");
|
||||||
|
|
||||||
|
var packages = await context.ShoppingCartPackages.AsNoTracking()
|
||||||
|
.OrderByDescending(o => o.CreatedAt)
|
||||||
|
.Where(cp => cp.ShoppingCartId == shoppingCartId)
|
||||||
|
.ToArrayAsync(cancellationToken);
|
||||||
|
|
||||||
|
return packages?.Length > 0
|
||||||
|
? Result.Ok(packages.Select(p => p.ToModel()).ToArray())
|
||||||
|
: Result.Fail($"Could not find packaged in shopping cart by ID {shoppingCartId}");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Result.Fail<ShoppingCartPackage[]>(new Error(ex.Message).CausedBy(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async ValueTask<Result> RemovePackageFromShoppingCartAsync(Guid shoppingCartId, Guid shoppingCartPackageId, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
|
if (!await context.ShoppingCarts.AnyAsync(c => c.Id == shoppingCartId, cancellationToken))
|
||||||
|
return Result.Fail($"Shopping cart could not be found by ID {shoppingCartId}");
|
||||||
|
|
||||||
|
if (!await context.ShoppingCartPackages.AnyAsync(p => p.Id == shoppingCartPackageId, cancellationToken))
|
||||||
|
return Result.Fail($"Shopping cart package {shoppingCartPackageId} is not in the shopping cart {shoppingCartId}");
|
||||||
|
|
||||||
|
var shoppingCartPackage = await context.ShoppingCartPackages.FirstOrDefaultAsync(cp => cp.Id == shoppingCartPackageId, cancellationToken);
|
||||||
|
|
||||||
|
if (shoppingCartPackage is null)
|
||||||
|
return Result.Ok();
|
||||||
|
|
||||||
|
context.ShoppingCartPackages.Remove(shoppingCartPackage!);
|
||||||
|
|
||||||
|
return await context.SaveChangesAsync(cancellationToken) > 0
|
||||||
|
? Result.Ok()
|
||||||
|
: Result.Fail($"Could remove package of id {shoppingCartPackageId} from shopping cart {shoppingCartId}");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Result.Fail(new Error(ex.Message).CausedBy(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async ValueTask<Result> RemoveShoppingCartItemAsync(Guid shoppingCartId, Guid shoppingCartItemId, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
|
if (!await context.ProductPrices.AnyAsync(c => c.Id == shoppingCartItemId, cancellationToken))
|
||||||
|
return Result.Fail($"Product item could not be found with id {shoppingCartItemId}");
|
||||||
|
|
||||||
|
var cart = await context.ShoppingCarts.FirstOrDefaultAsync(c => c.Id == shoppingCartId, cancellationToken);
|
||||||
|
|
||||||
|
if (cart is null)
|
||||||
|
return Result.Fail($"Shopping cart item could not be found with id {shoppingCartId}");
|
||||||
|
|
||||||
|
var item = await context.ShoppingCartItems.FirstOrDefaultAsync(i => i.Id == shoppingCartItemId, cancellationToken);
|
||||||
|
|
||||||
|
if (item is null) return Result.Ok();
|
||||||
|
|
||||||
|
context.ShoppingCartItems.Remove(item);
|
||||||
|
|
||||||
|
return await context.SaveChangesAsync(cancellationToken) > 0
|
||||||
|
? Result.Ok()
|
||||||
|
: Result.Fail($"Failed to remove shopping cart item with id {shoppingCartItemId}");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Result.Fail(new Error(ex.Message).CausedBy(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async ValueTask<Result> UpdateShoppingCartItemAsync(Guid shoppingCartId, Guid shoppingCartItemId, int quantity, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
|
if (!await context.ShoppingCarts.AnyAsync(c => c.Id == shoppingCartId, cancellationToken))
|
||||||
|
return Result.Fail($"Shopping could not be found with id {shoppingCartId}");
|
||||||
|
|
||||||
|
var item = await context.ShoppingCartItems.FirstOrDefaultAsync(i => i.ShoppingCartId == shoppingCartId, cancellationToken);
|
||||||
|
|
||||||
|
if (item is null)
|
||||||
|
return Result.Fail($"Shopping cart item could not be found with id {shoppingCartItemId}");
|
||||||
|
|
||||||
|
item.Quantity = quantity;
|
||||||
|
item.UpdatedAt = DateTime.UtcNow;
|
||||||
|
|
||||||
|
return await context.SaveChangesAsync(cancellationToken) > 0
|
||||||
|
? Result.Ok()
|
||||||
|
: Result.Fail($"Failed to update cart item quntity");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Result.Fail(new Error(ex.Message).CausedBy(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"Email": {
|
||||||
|
"Credentials": {
|
||||||
|
"Username": "shop@litecharms.co.za"
|
||||||
|
},
|
||||||
|
"Port": 465,
|
||||||
|
"Host": "mail.litecharms.co.za",
|
||||||
|
"UseSsl": true
|
||||||
|
},
|
||||||
|
"Monitoring": {
|
||||||
|
"ApiKey": "",
|
||||||
|
"Address": "http://aspire-dashboard-service.aspire.svc.cluster.local:18889",
|
||||||
|
"ServiceName": "LiteCharms.LeadGenerator"
|
||||||
|
},
|
||||||
|
"Logging": {
|
||||||
|
"LogLevel": {
|
||||||
|
"Default": "Information",
|
||||||
|
"Microsoft.AspNetCore": "Warning"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"AllowedHosts": "*"
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
using LiteCharms.Features.Extensions;
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.Tests;
|
||||||
|
|
||||||
|
public class Fixture : IDisposable
|
||||||
|
{
|
||||||
|
public IConfiguration Configuration { get; set; }
|
||||||
|
|
||||||
|
public IServiceProvider Services { get; set; }
|
||||||
|
|
||||||
|
public IMediator Mediator { get; set; }
|
||||||
|
|
||||||
|
public Fixture()
|
||||||
|
{
|
||||||
|
Configuration = new ConfigurationBuilder()
|
||||||
|
.SetBasePath(Directory.GetCurrentDirectory())
|
||||||
|
.AddUserSecrets<Fixture>()
|
||||||
|
.AddJsonFile(Path.Combine(Directory.GetCurrentDirectory(), "appsettings.json"), optional: true, reloadOnChange: true)
|
||||||
|
.AddEnvironmentVariables()
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
Services = new ServiceCollection()
|
||||||
|
.AddMediator()
|
||||||
|
.AddLogging()
|
||||||
|
.AddEmailServiceBus()
|
||||||
|
.AddGarageS3(Configuration)
|
||||||
|
.AddEmailServices(Configuration)
|
||||||
|
.AddSingleton(Configuration)
|
||||||
|
.BuildServiceProvider();
|
||||||
|
|
||||||
|
Mediator = Services.GetRequiredService<IMediator>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose() { }
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net10.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<IsPackable>false</IsPackable>
|
||||||
|
<UserSecretsId>62fa604a-1340-4edb-9ddd-3305fcf46fca</UserSecretsId>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="coverlet.collector" Version="10.0.1">
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
</PackageReference>
|
||||||
|
<PackageReference Include="Mediator.SourceGenerator" Version="3.0.2">
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
</PackageReference>
|
||||||
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.5.1" />
|
||||||
|
<PackageReference Include="xunit" Version="2.9.3" />
|
||||||
|
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5">
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
</PackageReference>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<!-- Global Usings -->
|
||||||
|
<ItemGroup>
|
||||||
|
<Using Include="Mediator" />
|
||||||
|
<Using Include="Xunit.Abstractions" />
|
||||||
|
<Using Include="Microsoft.Extensions.DependencyInjection" />
|
||||||
|
<Using Include="Microsoft.Extensions.Configuration" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\LiteCharms.Features\LiteCharms.Features.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Using Include="Xunit" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Update="appsettings.json">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
using LiteCharms.Features.S3.Abstractions;
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.Tests;
|
||||||
|
|
||||||
|
public class S3ServiceFeatureTests(Fixture fixture, ITestOutputHelper output) : IClassFixture<Fixture>
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public async Task BookshopS3Service_MustReturnUrl()
|
||||||
|
{
|
||||||
|
var service = fixture.Services.GetKeyedService<IS3Service>(S3.Constants.BookshopBucketName);
|
||||||
|
|
||||||
|
var fileName = "appsettings.json";
|
||||||
|
|
||||||
|
string path = Path.Combine(Directory.GetCurrentDirectory(), fileName);
|
||||||
|
|
||||||
|
Assert.True(File.Exists(path));
|
||||||
|
|
||||||
|
var stream = File.OpenRead(path);
|
||||||
|
|
||||||
|
var result = await service!.UploadFileAsync(fileName, stream, MimeKit.MimeTypes.GetMimeType(fileName));
|
||||||
|
|
||||||
|
Assert.True(result.IsSuccess);
|
||||||
|
Assert.NotNull(result.Value);
|
||||||
|
Assert.NotEmpty(result.Value);
|
||||||
|
|
||||||
|
output.WriteLine(result.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task BookshopS3Service_MustDeleteFile()
|
||||||
|
{
|
||||||
|
var service = fixture.Services.GetKeyedService<IS3Service>(S3.Constants.BookshopBucketName);
|
||||||
|
|
||||||
|
var fileName = "appsettings.json";
|
||||||
|
|
||||||
|
string path = Path.Combine(Directory.GetCurrentDirectory(), fileName);
|
||||||
|
|
||||||
|
Assert.True(File.Exists(path));
|
||||||
|
|
||||||
|
var stream = File.OpenRead(path);
|
||||||
|
|
||||||
|
var uploadResult = await service!.UploadFileAsync(fileName, stream, MimeKit.MimeTypes.GetMimeType(fileName));
|
||||||
|
|
||||||
|
Assert.True(uploadResult.IsSuccess);
|
||||||
|
Assert.NotNull(uploadResult.Value);
|
||||||
|
Assert.NotEmpty(uploadResult.Value);
|
||||||
|
|
||||||
|
var fileKey = uploadResult.Value.Split('/').Last();
|
||||||
|
|
||||||
|
var deleteResult = await service!.DeleteFileAsync(fileKey);
|
||||||
|
|
||||||
|
Assert.True(deleteResult.IsSuccess);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
{
|
||||||
|
"BookshopS3Settings": {
|
||||||
|
"ServiceUrl": "http://192.168.1.177:30900",
|
||||||
|
"Region": "garage",
|
||||||
|
"BucketName": "bookshop",
|
||||||
|
"CdnBaseUrl": "https://bookshop.cdn.khongisa.co.za"
|
||||||
|
},
|
||||||
|
"BookshopQuotesS3Settings": {
|
||||||
|
"ServiceUrl": "http://192.168.1.177:30900",
|
||||||
|
"Region": "garage",
|
||||||
|
"BucketName": "bookshop.quotes",
|
||||||
|
"CdnBaseUrl": "https://bookshop.quotes.cdn.khongisa.co.za"
|
||||||
|
},
|
||||||
|
"Email": {
|
||||||
|
"Credentials": {
|
||||||
|
"Username": "shop@litecharms.co.za"
|
||||||
|
},
|
||||||
|
"Port": 465,
|
||||||
|
"Host": "mail.litecharms.co.za",
|
||||||
|
"UseSsl": true
|
||||||
|
},
|
||||||
|
"Monitoring": {
|
||||||
|
"ApiKey": "",
|
||||||
|
"Address": "http://aspire-dashboard-service.aspire.svc.cluster.local:18889",
|
||||||
|
"ServiceName": "LiteCharms.LeadGenerator"
|
||||||
|
},
|
||||||
|
"Logging": {
|
||||||
|
"LogLevel": {
|
||||||
|
"Default": "Information",
|
||||||
|
"Microsoft.AspNetCore": "Warning"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"AllowedHosts": "*"
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
using LiteCharms.Features.Extensions;
|
||||||
|
using static LiteCharms.Features.Extensions.Timezones;
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.Abstractions;
|
||||||
|
|
||||||
|
public abstract class EventBase
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; } = Guid.CreateVersion7();
|
||||||
|
|
||||||
|
public DateTimeOffset EnqueueAt { get; set; } = SouthAfricanTimeZone.UtcNow();
|
||||||
|
|
||||||
|
public string CorrelationId { get; set; } = Guid.CreateVersion7().ToString();
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
namespace LiteCharms.Features.Abstractions;
|
||||||
|
|
||||||
|
public interface IEvent : INotification
|
||||||
|
{
|
||||||
|
Guid Id { get; set; }
|
||||||
|
|
||||||
|
string Name { get; set; }
|
||||||
|
|
||||||
|
DateTimeOffset EnqueueAt { get; set; }
|
||||||
|
|
||||||
|
string CorrelationId { get; set; }
|
||||||
|
}
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
namespace LiteCharms.Features.Customers.Commands;
|
|
||||||
|
|
||||||
public class CreateCustomerCommand : IRequest<Result<Guid>>
|
|
||||||
{
|
|
||||||
public string? Company { get; set; }
|
|
||||||
|
|
||||||
public string Name { get; set; }
|
|
||||||
|
|
||||||
public string LastName { get; set; }
|
|
||||||
|
|
||||||
public string? Tax { get; set; }
|
|
||||||
|
|
||||||
public string Email { get; set; }
|
|
||||||
|
|
||||||
public string? Discord { get; set; }
|
|
||||||
|
|
||||||
public string? Slack { get; set; }
|
|
||||||
|
|
||||||
public string? LinkedIn { get; set; }
|
|
||||||
|
|
||||||
public string? Whatsapp { get; set; }
|
|
||||||
|
|
||||||
public string? Website { get; set; }
|
|
||||||
|
|
||||||
public string? Phone { get; set; }
|
|
||||||
|
|
||||||
public string? Address { get; set; }
|
|
||||||
|
|
||||||
public string? City { get; set; }
|
|
||||||
|
|
||||||
public string? Region { get; set; }
|
|
||||||
|
|
||||||
public string? Country { get; set; }
|
|
||||||
|
|
||||||
public string? PostalCode { get; set; }
|
|
||||||
|
|
||||||
private CreateCustomerCommand(string name, string lastName, string? company, string? tax, string email, string? discord, string? slack, string? linkedIn, string? whatsapp, string? website, string? phone, string? address, string? city, string? region, string? country, string? postalCode)
|
|
||||||
{
|
|
||||||
Name = name;
|
|
||||||
LastName = lastName;
|
|
||||||
Company = company;
|
|
||||||
Tax = tax;
|
|
||||||
Email = email;
|
|
||||||
Discord = discord;
|
|
||||||
Slack = slack;
|
|
||||||
LinkedIn = linkedIn;
|
|
||||||
Whatsapp = whatsapp;
|
|
||||||
Website = website;
|
|
||||||
Phone = phone;
|
|
||||||
Address = address;
|
|
||||||
City = city;
|
|
||||||
Region = region;
|
|
||||||
Country = country;
|
|
||||||
PostalCode = postalCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static CreateCustomerCommand Create(string name, string lastName, string? company, string? tax, string email, string? discord, string? slack, string? linkedIn, string? whatsapp, string? website, string? phone, string? address, string? city, string? region, string? country, string? postalCode)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrWhiteSpace(name) && string.IsNullOrWhiteSpace(lastName) && string.IsNullOrWhiteSpace(email))
|
|
||||||
throw new ArgumentException("At the following fields must be provided: Name, LastName, Email");
|
|
||||||
|
|
||||||
return new(name, lastName, company, tax, email, discord, slack, linkedIn, whatsapp, website, phone, address, city, region, country, postalCode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
using LiteCharms.Infrastructure.Database;
|
|
||||||
|
|
||||||
namespace LiteCharms.Features.Customers.Commands.Handlers;
|
|
||||||
|
|
||||||
public class CreateCustomerCommandHandler(IDbContextFactory<LeadGeneratorDbContext> contextFactory) : IRequestHandler<CreateCustomerCommand, Result<Guid>>
|
|
||||||
{
|
|
||||||
public async ValueTask<Result<Guid>> Handle(CreateCustomerCommand request, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
|
||||||
|
|
||||||
var customerEmail = request.Email.ToLower().Trim();
|
|
||||||
|
|
||||||
if (await context.Customers.AnyAsync(c => c.Email == customerEmail, cancellationToken))
|
|
||||||
return Result.Fail<Guid>(new Error($"A customer with the email {customerEmail} already exists"));
|
|
||||||
|
|
||||||
var newCustomer = context.Customers.Add(new Entities.Customer
|
|
||||||
{
|
|
||||||
Company = request.Company,
|
|
||||||
Name = request.Name,
|
|
||||||
LastName = request.LastName,
|
|
||||||
Tax = request.Tax,
|
|
||||||
Email = customerEmail,
|
|
||||||
Discord = request.Discord,
|
|
||||||
Slack = request.Slack,
|
|
||||||
LinkedIn = request.LinkedIn,
|
|
||||||
Whatsapp = request.Whatsapp,
|
|
||||||
Website = request.Website,
|
|
||||||
Phone = request.Phone,
|
|
||||||
Address = request.Address,
|
|
||||||
City = request.City,
|
|
||||||
Region = request.Region,
|
|
||||||
Country = request.Country,
|
|
||||||
PostalCode = request.PostalCode,
|
|
||||||
Active = true,
|
|
||||||
});
|
|
||||||
|
|
||||||
return await context.SaveChangesAsync(cancellationToken) > 0
|
|
||||||
? Result.Ok(newCustomer.Entity.Id)
|
|
||||||
: Result.Fail<Guid>(new Error($"Failed to create customer {customerEmail}"));
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
return Result.Fail<Guid>(new Error(ex.Message).CausedBy(ex));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
using LiteCharms.Infrastructure.Database;
|
|
||||||
|
|
||||||
namespace LiteCharms.Features.Customers.Commands.Handlers;
|
|
||||||
|
|
||||||
public class RefundCustomerCommandHandler(IDbContextFactory<LeadGeneratorDbContext> contextFactory) : IRequestHandler<RefundCustomerCommand, Result<Guid>>
|
|
||||||
{
|
|
||||||
public async ValueTask<Result<Guid>> Handle(RefundCustomerCommand request, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
|
||||||
|
|
||||||
if(!await context.Orders.AnyAsync(o => o.Id == request.OrderId, cancellationToken))
|
|
||||||
return Result.Fail<Guid>(new Error($"Order with Id: {request.OrderId} does not exist"));
|
|
||||||
|
|
||||||
if (!await context.Customers.AnyAsync(c => c.Id == request.CustomerId, cancellationToken))
|
|
||||||
return Result.Fail<Guid>(new Error($"Customer with Id: {request.CustomerId} does not exist"));
|
|
||||||
|
|
||||||
if(!await context.Orders.AnyAsync(o => o.Id == request.OrderId && o.CustomerId == request.CustomerId, cancellationToken))
|
|
||||||
return Result.Fail<Guid>(new Error($"Order with Id: {request.OrderId} does not belong to Customer with Id: {request.CustomerId}"));
|
|
||||||
|
|
||||||
var refund = context.OrderRefunds.Add(new Entities.OrderRefund
|
|
||||||
{
|
|
||||||
OrderId = request.OrderId,
|
|
||||||
Reason = request.Reason,
|
|
||||||
Amount = request.Amount
|
|
||||||
});
|
|
||||||
|
|
||||||
return await context.SaveChangesAsync(cancellationToken) > 0
|
|
||||||
? Result.Ok(refund.Entity.Id)
|
|
||||||
: Result.Fail<Guid>(new Error($"Failed to create refund for OrderId: {request.OrderId}"));
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
return Result.Fail<Guid>(new Error(ex.Message).CausedBy(ex));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user