diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json
deleted file mode 100644
index 45434e736..000000000
--- a/.devcontainer/devcontainer.json
+++ /dev/null
@@ -1,38 +0,0 @@
-// For format details, see https://aka.ms/devcontainer.json. For config options, see the
-// README at: https://github.com/devcontainers/templates/tree/main/src/dotnet
-{
- "name": "AccountGo (.NET)",
- // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
- "image": "mcr.microsoft.com/devcontainers/dotnet:0-7.0-bullseye",
- "features": {
- "ghcr.io/devcontainers/features/azure-cli:1": {},
- "ghcr.io/devcontainers/features/git:1": {},
- "ghcr.io/dhoeric/features/google-cloud-cli:1": {},
- "ghcr.io/warrenbuckley/codespace-features/sqlite:1": {},
- "ghcr.io/devcontainers/features/docker-in-docker:1": {
- "version": "latest",
- "moby": true
- },
- "ghcr.io/devcontainers/features/node:1": {}
- }
-
- // Features to add to the dev container. More info: https://containers.dev/features.
- // "features": {},
-
- // Use 'forwardPorts' to make a list of ports inside the container available locally.
- // "forwardPorts": [5000, 5001],
- // "portsAttributes": {
- // "5001": {
- // "protocol": "https"
- // }
- // }
-
- // Use 'postCreateCommand' to run commands after the container is created.
- // "postCreateCommand": "dotnet restore",
-
- // Configure tool-specific properties.
- // "customizations": {},
-
- // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
- // "remoteUser": "root"
-}
diff --git a/.github/workflows/build-deploy-azure.yml b/.github/workflows/build-deploy-azure.yml
deleted file mode 100644
index eb332b2cd..000000000
--- a/.github/workflows/build-deploy-azure.yml
+++ /dev/null
@@ -1,19 +0,0 @@
-name: Docker Image CI
-
-on:
- push:
- branches: [ "main" ]
- pull_request:
- branches: [ "main" ]
- workflow_dispatch:
-
-jobs:
-
- build:
-
- runs-on: ubuntu-latest
-
- steps:
- - uses: actions/checkout@v3
- - name: Build the Docker image
- run: docker-compose build
diff --git a/.github/workflows/gdbapi.yml b/.github/workflows/gdbapi.yml
new file mode 100644
index 000000000..03822235b
--- /dev/null
+++ b/.github/workflows/gdbapi.yml
@@ -0,0 +1,91 @@
+# Docs for the Azure Web Apps Deploy action: https://github.com/Azure/webapps-deploy
+# More GitHub Actions for Azure: https://github.com/Azure/actions
+
+name: Build and deploy Good Deed Books API to Azure Web App - gdbapi
+
+on:
+ push:
+ branches:
+ - main
+ workflow_dispatch:
+
+jobs:
+ build:
+ runs-on: windows-latest
+
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Set up .NET Core
+ uses: actions/setup-dotnet@v4
+ with:
+ dotnet-version: '9.x'
+
+ - name: Install dotnet-ef tool
+ run: |
+ dotnet tool install --global dotnet-ef
+ echo "++++ dotnet-ef version"
+ dotnet ef --version
+
+ - name: Install dotnet aspire workload
+ run: |
+ dotnet workload install aspire
+
+ - name: Build with dotnet
+ run: |
+ echo "++++ dotnet build"
+ dotnet build --configuration Release
+
+ - name: Add migrations
+ run: |
+ echo "++++ current directory"
+ pwd
+ echo "++++ add ApplicationIdentityDbContext migration IdentityMig"
+ dotnet ef migrations add IdentityMig --project ./src/Api/ --startup-project ./src/Api/Api.csproj --msbuildprojectextensionspath .build/obj/Api/ --context ApplicationIdentityDbContext --output-dir Data/Migrations/IdentityDb
+ echo "++++ add ApiDbContext migration ApiMig"
+ dotnet ef migrations add ApiMig --project ./src/Api/ --startup-project ./src/Api/Api.csproj --msbuildprojectextensionspath .build/obj/Api/ --context ApiDbContext --output-dir Data/Migrations/ApiDb
+ echo "++++ contents of ./src/Api/Data/Migrations/IdentityDb"
+ ls ./src/Api/Data/Migrations/IdentityDb
+ echo "++++ contents of ./src/Api/Data/Migrations/ApiDb"
+ ls ./src/Api/Data/Migrations/ApiDb
+
+ - name: dotnet publish
+ run: |
+ echo "++++ contents of dotnet publish ./src/Api/Api.csproj"
+ dotnet publish ./src/Api/Api.csproj -f net9.0 -c Release -o "${{runner.temp}}/myapp"
+
+ - name: Upload artifact for deployment job
+ uses: actions/upload-artifact@v4
+ with:
+ name: .net-app
+ path: ${{runner.temp}}/myapp
+
+ deploy:
+ runs-on: windows-latest
+ needs: build
+ environment:
+ name: 'Production'
+ url: ${{ steps.deploy-to-webapp.outputs.webapp-url }}
+ permissions:
+ id-token: write #This is required for requesting the JWT
+
+ steps:
+ - name: Download artifact from build job
+ uses: actions/download-artifact@v4
+ with:
+ name: .net-app
+
+ - name: Login to Azure
+ uses: azure/login@v2
+ with:
+ client-id: ${{ secrets.AZUREAPPSERVICE_CLIENTID_A17E281C175C4E629A76134AA823BAC5 }}
+ tenant-id: ${{ secrets.AZUREAPPSERVICE_TENANTID_258CF23452C24D9795BD94B25EF50B73 }}
+ subscription-id: ${{ secrets.AZUREAPPSERVICE_SUBSCRIPTIONID_9375B274C69740D39F4770D5D433E8B1 }}
+
+ - name: Deploy to Azure Web App
+ id: deploy-to-webapp
+ uses: azure/webapps-deploy@v3
+ with:
+ app-name: 'gdbapi'
+ slot-name: 'Production'
+ package: .
diff --git a/.github/workflows/gdbmvc_tar.yml b/.github/workflows/gdbmvc_tar.yml
new file mode 100644
index 000000000..a45c04e82
--- /dev/null
+++ b/.github/workflows/gdbmvc_tar.yml
@@ -0,0 +1,96 @@
+# Docs for the Azure Web Apps Deploy action: https://github.com/Azure/webapps-deploy
+# More GitHub Actions for Azure: https://github.com/Azure/actions
+name: Build and deploy Good Deed Books MVC project to Azure
+on:
+ push:
+ branches:
+ - main
+ workflow_dispatch:
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Set up .NET Core
+ uses: actions/setup-dotnet@v4
+ with:
+ dotnet-version: '9.x'
+ include-prerelease: true
+
+ - name: Install dotnet aspire workload
+ run: |
+ dotnet workload install aspire
+
+ - name: Build with dotnet
+ run: dotnet build --configuration Release
+
+ - name: dotnet publish
+ run: dotnet publish ./src/AccountGoWeb/AccountGoWeb.csproj -c Release -o ${{runner.temp}}/myapp
+
+ - name: Archive production artifacts
+ run: |
+ echo "+++++++++++++++++++++++++ where am I? ++++++++++++++++++++++++"
+ pwd
+ echo "+++++++++++++++++++++++++ save current directory into a variable dir ++++"
+ dir=$(pwd)
+ echo "+++++++++ what is in variable dir ++++++++++++++"
+ echo $dir
+ echo "++++++++++++++++++++++++ what's in current directory? ++++++++"
+ ls -al
+ echo "+++++ what's in the ${{runner.temp}}/myapp directory? ++++"
+ ls -al ${{runner.temp}}/myapp
+ echo "+++++ change directory to ${{runner.temp}}/myapp ++++"
+ cd ${{runner.temp}}/myapp
+ echo "+++++++++++++++++++++++++ where am I? ++++++++++++++++++++++++"
+ pwd
+ echo "+++++++++++++++++++++++++ compress current directory and save in $dir/my_artifact.tar.gz ++++"
+ tar -czvf $dir/my_artifact.tar.gz .
+ echo "+++++++++++++++++++++++++ change back to $dir directory ++++"
+ cd $dir
+ echo "++++++++++++++++++++++++ what's in $dir directory? ++++++++"
+ ls -al
+
+ - name: Upload artifact for deployment job
+ uses: actions/upload-artifact@v4
+ with:
+ name: .net-app
+ path: my_artifact.tar.gz
+
+ deploy:
+ runs-on: ubuntu-latest
+ needs: build
+ environment:
+ name: 'Production'
+ url: ${{ steps.deploy-to-webapp.outputs.webapp-url }}
+ permissions:
+ id-token: write #This is required for requesting the JWT
+
+ steps:
+ - name: Download artifact from build job
+ uses: actions/download-artifact@v4
+ with:
+ name: .net-app
+
+ - name: Login to Azure
+ uses: azure/login@v2
+ with:
+ client-id: ${{ secrets.AZUREAPPSERVICE_CLIENTID_8B6389BB3F37413FB2483AC2574C3BCB }}
+ tenant-id: ${{ secrets.AZUREAPPSERVICE_TENANTID_FD62C59DE5DC42C2A07DB8191A522348 }}
+ subscription-id: ${{ secrets.AZUREAPPSERVICE_SUBSCRIPTIONID_7076EF307FDA4C11BC99A0A7A0943794 }}
+
+ - name: Extract artifacts
+ run: |
+ tar -xzvf my_artifact.tar.gz -C .
+
+ - name: Set startup command
+ run: |
+ az webapp config set --resource-group goodbooks-RG --name gdbmvc --startup-file "dotnet /home/site/wwwroot/GoodBooks.dll"
+
+ - name: Deploy to Azure Web App
+ id: deploy-to-webapp
+ uses: azure/webapps-deploy@v3
+ with:
+ app-name: 'gdbmvc'
+ slot-name: 'Production'
+ package: .
diff --git a/.gitignore b/.gitignore
index fbb3738a8..6272404dc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,9 @@
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
+# custom 2024/04/29
+.idea
+
# User-specific files
*.suo
*.user
@@ -18,6 +21,7 @@ build/
bld/
[Bb]in/
[Oo]bj/
+node_modules/
# Roslyn cache directories
*.ide/
@@ -186,6 +190,10 @@ FakesAssemblies/
# Lib folder generated by gulpfile.js
**/src/[Ww]eb[Aa]ngular/wwwroot/[Ll]ib/*
+
+
+**/src/[Rr]eact[Ff]ront[Ee]nd/wwwroot/*
+
**/src/[Ww]eb[Aa]pp/wwwroot/app/scripts/*
**/src/[Ww]eb[Aa]pp/wwwroot/app/compiledscripts/*
**/src/[Ww]eb[Aa]pp/wwwroot/app/typescripts/compiledscripts/*
@@ -215,7 +223,8 @@ FakesAssemblies/
/src/Api/Plugins/*
/src/AccountGoWeb/Modules/*
/src/AccountGoWeb/Plugins/*
-/src/Api/Data/Migrations
+# /src/Api/Data/Migrations
.vscode
-exclude
\ No newline at end of file
+exclude
+/src/Api/appsettings.Development.json
diff --git a/accountgo.sln b/accountgo.sln
index 4eaa3f47d..becf77c72 100644
--- a/accountgo.sln
+++ b/accountgo.sln
@@ -1,7 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 15
-VisualStudioVersion = 15.0.26228.4
+# Visual Studio Version 17
+VisualStudioVersion = 17.8.34322.80
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Presentation", "Presentation", "{0295DFAC-BF6E-46C0-A63D-FBE9AF3C04E5}"
EndProject
@@ -19,19 +19,33 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AccountGoWeb", "src\Account
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dto", "src\Dto\Dto.csproj", "{1E610F55-2D74-4856-818B-0D0B47601B75}"
EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{E1B45442-3F2D-491A-9D8A-0DDA50309A1A}"
-EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Infrastructure", "src\Infrastructure\Infrastructure.csproj", "{EBFAFB5B-494F-48D5-A70D-AF1490B9260A}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{0EAC5155-A5EA-49C1-8E0C-19DD36D2C21C}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Module.Tests", "test\Module.Tests\Module.Tests.csproj", "{54631590-2A41-45F4-B057-92C840ED08C1}"
EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Modules", "Modules", "{E0861852-0F5B-4810-8586-A59038BC4034}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SampleNetStandard20", "test\SampleModules\SampleNetStandard20\SampleNetStandard20.csproj", "{B0AB6EA7-7D53-4457-9482-F0613F99E3BB}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SampleModule", "src\Modules\SampleModule\SampleModule.csproj", "{B296277A-C822-444E-8CFA-4CC4C1C1F737}"
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{EF0BD6F1-00D6-41E5-91AB-8B606D35D448}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SampleNetStandard20", "test\SampleModules\SampleNetStandard20\SampleNetStandard20.csproj", "{B0AB6EA7-7D53-4457-9482-F0613F99E3BB}"
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Modules", "Modules", "{EFF13E33-1D79-4221-87D7-4FCC8EA88943}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SampleModule", "src\Modules\SampleModule\SampleModule.csproj", "{ABD1EE97-DD84-4C6A-8F3F-28E7D3D898B4}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BlazorGDB", "src\BlazorGDB\BlazorGDB\BlazorGDB.csproj", "{AB5F238F-AB78-4A85-8D8D-17E211015FD3}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BlazorGDB.Client", "src\BlazorGDB\BlazorGDB.Client\BlazorGDB.Client.csproj", "{12BE663C-C0DD-4343-93DF-6B2D853B6B79}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LibraryGDB", "src\LibraryGDB\LibraryGDB.csproj", "{F64790E0-86AD-4562-9AC5-F4DD3F4881BA}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Aspire", "Aspire", "{64880D93-BAB4-FF83-898C-B934B68C31A9}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "src.ServiceDefaults", "src\src.ServiceDefaults\src.ServiceDefaults.csproj", "{949C95E9-4261-416E-8D2A-F05E3D4640CA}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "src.AppHost", "src\src.AppHost\src.AppHost.csproj", "{ADDBCE30-FE7F-4198-8A37-772EF6BF3676}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MigrationService", "src\MigrationService\MigrationService.csproj", "{DF084D96-707B-47C2-9493-85FA84631ACE}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -67,14 +81,38 @@ Global
{54631590-2A41-45F4-B057-92C840ED08C1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{54631590-2A41-45F4-B057-92C840ED08C1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{54631590-2A41-45F4-B057-92C840ED08C1}.Release|Any CPU.Build.0 = Release|Any CPU
- {B296277A-C822-444E-8CFA-4CC4C1C1F737}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {B296277A-C822-444E-8CFA-4CC4C1C1F737}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {B296277A-C822-444E-8CFA-4CC4C1C1F737}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {B296277A-C822-444E-8CFA-4CC4C1C1F737}.Release|Any CPU.Build.0 = Release|Any CPU
{B0AB6EA7-7D53-4457-9482-F0613F99E3BB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B0AB6EA7-7D53-4457-9482-F0613F99E3BB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B0AB6EA7-7D53-4457-9482-F0613F99E3BB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B0AB6EA7-7D53-4457-9482-F0613F99E3BB}.Release|Any CPU.Build.0 = Release|Any CPU
+ {ABD1EE97-DD84-4C6A-8F3F-28E7D3D898B4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {ABD1EE97-DD84-4C6A-8F3F-28E7D3D898B4}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {ABD1EE97-DD84-4C6A-8F3F-28E7D3D898B4}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {ABD1EE97-DD84-4C6A-8F3F-28E7D3D898B4}.Release|Any CPU.Build.0 = Release|Any CPU
+ {AB5F238F-AB78-4A85-8D8D-17E211015FD3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {AB5F238F-AB78-4A85-8D8D-17E211015FD3}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {AB5F238F-AB78-4A85-8D8D-17E211015FD3}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {AB5F238F-AB78-4A85-8D8D-17E211015FD3}.Release|Any CPU.Build.0 = Release|Any CPU
+ {12BE663C-C0DD-4343-93DF-6B2D853B6B79}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {12BE663C-C0DD-4343-93DF-6B2D853B6B79}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {12BE663C-C0DD-4343-93DF-6B2D853B6B79}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {12BE663C-C0DD-4343-93DF-6B2D853B6B79}.Release|Any CPU.Build.0 = Release|Any CPU
+ {F64790E0-86AD-4562-9AC5-F4DD3F4881BA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {F64790E0-86AD-4562-9AC5-F4DD3F4881BA}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {F64790E0-86AD-4562-9AC5-F4DD3F4881BA}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {F64790E0-86AD-4562-9AC5-F4DD3F4881BA}.Release|Any CPU.Build.0 = Release|Any CPU
+ {949C95E9-4261-416E-8D2A-F05E3D4640CA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {949C95E9-4261-416E-8D2A-F05E3D4640CA}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {949C95E9-4261-416E-8D2A-F05E3D4640CA}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {949C95E9-4261-416E-8D2A-F05E3D4640CA}.Release|Any CPU.Build.0 = Release|Any CPU
+ {ADDBCE30-FE7F-4198-8A37-772EF6BF3676}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {ADDBCE30-FE7F-4198-8A37-772EF6BF3676}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {ADDBCE30-FE7F-4198-8A37-772EF6BF3676}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {ADDBCE30-FE7F-4198-8A37-772EF6BF3676}.Release|Any CPU.Build.0 = Release|Any CPU
+ {DF084D96-707B-47C2-9493-85FA84631ACE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {DF084D96-707B-47C2-9493-85FA84631ACE}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {DF084D96-707B-47C2-9493-85FA84631ACE}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {DF084D96-707B-47C2-9493-85FA84631ACE}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -84,11 +122,18 @@ Global
{C02DECC9-2A82-42C0-8F26-D0AE6559AC5E} = {B4CE3CD4-74AA-4A22-B514-BC9B380AAFD7}
{09096FEC-DA29-4914-B046-CD280220C52A} = {0295DFAC-BF6E-46C0-A63D-FBE9AF3C04E5}
{9CA13D2D-D6E2-4201-946C-81D1E6093404} = {0295DFAC-BF6E-46C0-A63D-FBE9AF3C04E5}
- {1E610F55-2D74-4856-818B-0D0B47601B75} = {0295DFAC-BF6E-46C0-A63D-FBE9AF3C04E5}
+ {1E610F55-2D74-4856-818B-0D0B47601B75} = {EF0BD6F1-00D6-41E5-91AB-8B606D35D448}
{EBFAFB5B-494F-48D5-A70D-AF1490B9260A} = {B5D35D0C-387C-44FA-9A70-6FE24DAE5728}
{54631590-2A41-45F4-B057-92C840ED08C1} = {0EAC5155-A5EA-49C1-8E0C-19DD36D2C21C}
- {B296277A-C822-444E-8CFA-4CC4C1C1F737} = {E0861852-0F5B-4810-8586-A59038BC4034}
{B0AB6EA7-7D53-4457-9482-F0613F99E3BB} = {0EAC5155-A5EA-49C1-8E0C-19DD36D2C21C}
+ {EFF13E33-1D79-4221-87D7-4FCC8EA88943} = {EF0BD6F1-00D6-41E5-91AB-8B606D35D448}
+ {ABD1EE97-DD84-4C6A-8F3F-28E7D3D898B4} = {EFF13E33-1D79-4221-87D7-4FCC8EA88943}
+ {AB5F238F-AB78-4A85-8D8D-17E211015FD3} = {0295DFAC-BF6E-46C0-A63D-FBE9AF3C04E5}
+ {12BE663C-C0DD-4343-93DF-6B2D853B6B79} = {0295DFAC-BF6E-46C0-A63D-FBE9AF3C04E5}
+ {F64790E0-86AD-4562-9AC5-F4DD3F4881BA} = {B5D35D0C-387C-44FA-9A70-6FE24DAE5728}
+ {949C95E9-4261-416E-8D2A-F05E3D4640CA} = {64880D93-BAB4-FF83-898C-B934B68C31A9}
+ {ADDBCE30-FE7F-4198-8A37-772EF6BF3676} = {64880D93-BAB4-FF83-898C-B934B68C31A9}
+ {DF084D96-707B-47C2-9493-85FA84631ACE} = {B4CE3CD4-74AA-4A22-B514-BC9B380AAFD7}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {AD284F35-E81F-4678-B737-A5DC8CB883CB}
diff --git a/actions/endpoint_sahil_gdbapi.yml.20241204 b/actions/endpoint_sahil_gdbapi.yml.20241204
new file mode 100644
index 000000000..94f4b0fbd
--- /dev/null
+++ b/actions/endpoint_sahil_gdbapi.yml.20241204
@@ -0,0 +1,87 @@
+# Docs for the Azure Web Apps Deploy action: https://github.com/Azure/webapps-deploy
+# More GitHub Actions for Azure: https://github.com/Azure/actions
+
+name: Build and deploy Good Deed Books API to Azure Web App - gdbapi
+
+on:
+ push:
+ branches:
+ - endpoint_sahil
+ workflow_dispatch:
+
+jobs:
+ build:
+ runs-on: windows-latest
+
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Set up .NET Core
+ uses: actions/setup-dotnet@v4
+ with:
+ dotnet-version: '8.x'
+
+ - name: Install dotnet-ef tool
+ run: |
+ dotnet tool install --global dotnet-ef
+ echo "++++ dotnet-ef version"
+ dotnet ef --version
+
+ - name: Build with dotnet
+ run: |
+ echo "++++ dotnet build"
+ dotnet build --configuration Release
+
+ - name: Add migrations
+ run: |
+ echo "++++ current directory"
+ pwd
+ echo "++++ add ApplicationIdentityDbContext migration M1"
+ dotnet ef migrations add M1 --project ./src/Api/ --startup-project ./src/Api/Api.csproj --msbuildprojectextensionspath .build/obj/Api/ --context ApplicationIdentityDbContext --output-dir Data/Migrations/IdentityDb
+ echo "++++ add ApiDbContext migration M2"
+ dotnet ef migrations add M2 --project ./src/Api/ --startup-project ./src/Api/Api.csproj --msbuildprojectextensionspath .build/obj/Api/ --context ApiDbContext --output-dir Data/Migrations/ApiDb
+ echo "++++ contents of ./src/Api/Data/Migrations/IdentityDb"
+ ls ./src/Api/Data/Migrations/IdentityDb
+ echo "++++ contents of ./src/Api/Data/Migrations/ApiDb"
+ ls ./src/Api/Data/Migrations/ApiDb
+
+ - name: dotnet publish
+ run: |
+ echo "++++ contents of dotnet publish ./src/Api/Api.csproj"
+ dotnet publish ./src/Api/Api.csproj -f net8.0 -c Release -o "${{runner.temp}}/myapp"
+
+ - name: Upload artifact for deployment job
+ uses: actions/upload-artifact@v4
+ with:
+ name: .net-app
+ path: ${{runner.temp}}/myapp
+
+ deploy:
+ runs-on: windows-latest
+ needs: build
+ environment:
+ name: 'Production'
+ url: ${{ steps.deploy-to-webapp.outputs.webapp-url }}
+ permissions:
+ id-token: write #This is required for requesting the JWT
+
+ steps:
+ - name: Download artifact from build job
+ uses: actions/download-artifact@v4
+ with:
+ name: .net-app
+
+ - name: Login to Azure
+ uses: azure/login@v2
+ with:
+ client-id: ${{ secrets.AZUREAPPSERVICE_CLIENTID_A17E281C175C4E629A76134AA823BAC5 }}
+ tenant-id: ${{ secrets.AZUREAPPSERVICE_TENANTID_258CF23452C24D9795BD94B25EF50B73 }}
+ subscription-id: ${{ secrets.AZUREAPPSERVICE_SUBSCRIPTIONID_9375B274C69740D39F4770D5D433E8B1 }}
+
+ - name: Deploy to Azure Web App
+ id: deploy-to-webapp
+ uses: azure/webapps-deploy@v3
+ with:
+ app-name: 'gdbapi'
+ slot-name: 'Production'
+ package: .
diff --git a/actions/endpoint_sahil_gdbmvc.yml.20241204 b/actions/endpoint_sahil_gdbmvc.yml.20241204
new file mode 100644
index 000000000..330b665ab
--- /dev/null
+++ b/actions/endpoint_sahil_gdbmvc.yml.20241204
@@ -0,0 +1,101 @@
+# Docs for the Azure Web Apps Deploy action: https://github.com/Azure/webapps-deploy
+# More GitHub Actions for Azure: https://github.com/Azure/actions
+
+name: Build and deploy Good Deed Books MVC project to Azure
+
+on:
+ push:
+ branches:
+ - endpoint_sahil
+ workflow_dispatch:
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Set up .NET Core
+ uses: actions/setup-dotnet@v4
+ with:
+ dotnet-version: '8.x'
+ include-prerelease: true
+
+ - name: Build with dotnet
+ run: dotnet build --configuration Release
+
+ - name: dotnet publish
+ run: dotnet publish ./src/AccountGoWeb/AccountGoWeb.csproj -c Release -o ${{env.DOTNET_ROOT}}/myapp
+
+ - name: Archive production artifacts
+ run: |
+ echo "+++++++++++++++++++++++++ where am I? ++++++++++++++++++++++++"
+ pwd
+ echo "+++++++++++++++++++++++++ save current directory into a variable dir ++++"
+ dir=$(pwd)
+ echo "+++++++++ what is in variable dir ++++++++++++++"
+ echo $dir
+ echo "++++++++++++++++++++++++ what's in current directory? ++++++++"
+ ls -al
+ echo "+++++ what's in the ${{env.DOTNET_ROOT}}/myapp directory? ++++"
+ ls -al ${{env.DOTNET_ROOT}}/myapp
+ echo "+++++ change directoiry to ${{env.DOTNET_ROOT}}/myapp ++++"
+ cd ${{env.DOTNET_ROOT}}/myapp
+ echo "+++++++++++++++++++++++++ where am I? ++++++++++++++++++++++++"
+ pwd
+ echo "+++++++++++++++++++++++++ compress current directory and save in $dir/my_artifact.tar.gz ++++"
+ tar -czvf $dir/my_artifact.tar.gz .
+ echo "+++++++++++++++++++++++++ change dir to to $dir directory ++++"
+ cd $dir
+ echo "+++++++++++++++++++++++++ where am I? ++++++++++++++++++++++++"
+ pwd
+ echo "++++++++++++++++++++++++ what's in $dir directory? ++++++++"
+ ls -al
+
+ - name: Upload artifact for deployment job
+ uses: actions/upload-artifact@v4
+ with:
+ name: .net-app
+ path: my_artifact.tar.gz
+
+ deploy:
+ runs-on: ubuntu-latest
+ needs: build
+ environment:
+ name: 'Production'
+ url: ${{ steps.deploy-to-webapp.outputs.webapp-url }}
+ permissions:
+ id-token: write #This is required for requesting the JWT
+
+ steps:
+ - name: Download artifact from build job
+ uses: actions/download-artifact@v4
+ with:
+ name: .net-app
+
+ - name: Login to Azure
+ uses: azure/login@v2
+ with:
+ client-id: ${{ secrets.AZUREAPPSERVICE_CLIENTID_8B6389BB3F37413FB2483AC2574C3BCB }}
+ tenant-id: ${{ secrets.AZUREAPPSERVICE_TENANTID_FD62C59DE5DC42C2A07DB8191A522348 }}
+ subscription-id: ${{ secrets.AZUREAPPSERVICE_SUBSCRIPTIONID_7076EF307FDA4C11BC99A0A7A0943794 }}
+
+ - name: Extract artifacts
+ run: |
+ tar -xzvf my_artifact.tar.gz -C .
+
+ - name: Print working directory
+ run: pwd
+
+ - name: List directory contents
+ run: ls -l /home/runner/.dotnet/
+
+ - name: Deploy to Azure Web App
+ id: deploy-to-webapp
+ uses: azure/webapps-deploy@v3
+ with:
+ app-name: 'gdbmvc'
+ slot-name: 'Production'
+ package: .
+
\ No newline at end of file
diff --git a/actions/gdb-blazor.yml.gold b/actions/gdb-blazor.yml.gold
new file mode 100644
index 000000000..7691040f1
--- /dev/null
+++ b/actions/gdb-blazor.yml.gold
@@ -0,0 +1,76 @@
+# Docs for the Azure Web Apps Deploy action: https://github.com/Azure/webapps-deploy
+# More GitHub Actions for Azure: https://github.com/Azure/actions
+
+name: Build and deploy Good Deed Books BLAZOR project to Azure
+
+on:
+ push:
+ branches:
+ - endpoint_sahil
+ workflow_dispatch:
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Set up .NET Core
+ uses: actions/setup-dotnet@v4
+ with:
+ dotnet-version: '8.x'
+
+ - name: Build with dotnet
+ working-directory: ./src/BlazorGDB/BlazorGDB
+ run: dotnet build --configuration Release
+
+ - name: dotnet publish
+ working-directory: ./src/BlazorGDB/BlazorGDB
+ run: dotnet publish BlazorGDB.csproj -c Release -o ${{env.DOTNET_ROOT}}/myapp
+
+ - name: sanity check
+ run: |
+ echo "+++++++++++++++++++++++++ where am I? ++++++++++++++++++++++++"
+ pwd
+ echo "++++++++++++++++++++++++ what's in current directory? ++++++++"
+ ls -al
+ echo "+++++ what's in the ${{env.DOTNET_ROOT}}/myapp directory? ++++"
+ ls -al ${{env.DOTNET_ROOT}}/myapp
+
+ - name: Upload artifact for deployment job
+ uses: actions/upload-artifact@v4
+ with:
+ name: .net-app
+ path: ${{env.DOTNET_ROOT}}/myapp
+
+ deploy:
+ runs-on: ubuntu-latest
+ needs: build
+ environment:
+ name: 'Production'
+ url: ${{ steps.deploy-to-webapp.outputs.webapp-url }}
+ permissions:
+ id-token: write #This is required for requesting the JWT
+
+ steps:
+ - name: Download artifact from build job
+ uses: actions/download-artifact@v4
+ with:
+ name: .net-app
+
+ - name: Login to Azure
+ uses: azure/login@v2
+ with:
+ client-id: ${{ secrets.AZUREAPPSERVICE_CLIENTID_6A854C1CD0C74473AD2E3B9F843CC396 }}
+ tenant-id: ${{ secrets.AZUREAPPSERVICE_TENANTID_224A065E650B4D5F9EB2329B6B2F1716 }}
+ subscription-id: ${{ secrets.AZUREAPPSERVICE_SUBSCRIPTIONID_570B031F0942445C8E479905EE706F43 }}
+
+ - name: Deploy to Azure Web App
+ id: deploy-to-webapp
+ uses: azure/webapps-deploy@v3
+ with:
+ app-name: 'gdb-blazor'
+ slot-name: 'Production'
+ package: .
+
\ No newline at end of file
diff --git a/actions/gdb_api.yml.flat b/actions/gdb_api.yml.flat
new file mode 100644
index 000000000..9218db27d
--- /dev/null
+++ b/actions/gdb_api.yml.flat
@@ -0,0 +1,91 @@
+# Docs for the Azure Web Apps Deploy action: https://github.com/Azure/webapps-deploy
+# More GitHub Actions for Azure: https://github.com/Azure/actions
+
+name: Build and deploy Good Deed Books API project to Azure
+
+on:
+ push:
+ branches:
+ - endpoint_sahil
+ workflow_dispatch:
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Set up .NET Core
+ uses: actions/setup-dotnet@v1
+ with:
+ dotnet-version: '8.x'
+ include-prerelease: true
+
+ - name: Install dotnet-ef tool
+ run: |
+ dotnet tool install --global dotnet-ef
+ echo "++++ dotnet-ef version"
+ dotnet ef --version
+
+ - name: Build with dotnet
+ run: |
+ echo "++++ dotnet restore"
+ dotnet restore
+ echo "++++ dotnet build"
+ dotnet build --configuration Release
+
+ - name: Add migrations
+ run: |
+ echo "++++ current directory"
+ pwd
+ echo "++++ add ApplicationIdentityDbContext migration M1"
+ dotnet ef migrations add M1 --project ./src/Api/ --startup-project ./src/Api/Api.csproj --msbuildprojectextensionspath .build/obj/Api/ --context ApplicationIdentityDbContext --output-dir Data/Migrations/IdentityDb
+ echo "++++ add ApiDbContext migration M2"
+ dotnet ef migrations add M2 --project ./src/Api/ --startup-project ./src/Api/Api.csproj --msbuildprojectextensionspath .build/obj/Api/ --context ApiDbContext --output-dir Data/Migrations/ApiDb
+ echo "++++ contents of ./src/Api/Data/Migrations/IdentityDb"
+ ls ./src/Api/Data/Migrations/IdentityDb
+ echo "++++ contents of ./src/Api/Data/Migrations/ApiDb"
+ ls ./src/Api/Data/Migrations/ApiDb
+
+ - name: dotnet publish
+ run: |
+ echo "++++ contents of dotnet publish ./src/Api/Api.csproj"
+ dotnet publish ./src/Api/Api.csproj -c Release -o ${{env.DOTNET_ROOT}}/myapp
+
+ - name: Upload artifact for deployment job
+ uses: actions/upload-artifact@v3
+ with:
+ name: .net-app
+ path: ${{env.DOTNET_ROOT}}/myapp
+
+ deploy:
+ runs-on: ubuntu-latest
+ needs: build
+ environment:
+ name: 'Production'
+ url: ${{ steps.deploy-to-webapp.outputs.webapp-url }}
+ permissions:
+ id-token: write #This is required for requesting the JWT
+
+ steps:
+ - name: Download artifact from build job
+ uses: actions/download-artifact@v3
+ with:
+ name: .net-app
+
+ - name: Login to Azure
+ uses: azure/login@v1
+ with:
+ client-id: ${{ secrets.AZUREAPPSERVICE_CLIENTID_543326D87AEF459D91E15D756166A5AC }}
+ tenant-id: ${{ secrets.AZUREAPPSERVICE_TENANTID_D57EB2BACAA54EE2AB97F696E8E99A4B }}
+ subscription-id: ${{ secrets.AZUREAPPSERVICE_SUBSCRIPTIONID_3C797712E9A047958FF5C9BB540F0543 }}
+
+ - name: Deploy to Azure Web App
+ id: deploy-to-webapp
+ uses: azure/webapps-deploy@v2
+ with:
+ app-name: 'goodbooksapi'
+ slot-name: 'Production'
+ package: .
+
diff --git a/actions/gdb_mvc_tar.yml.flat b/actions/gdb_mvc_tar.yml.flat
new file mode 100644
index 000000000..0b749010a
--- /dev/null
+++ b/actions/gdb_mvc_tar.yml.flat
@@ -0,0 +1,101 @@
+# Docs for the Azure Web Apps Deploy action: https://github.com/Azure/webapps-deploy
+# More GitHub Actions for Azure: https://github.com/Azure/actions
+
+name: Build and deploy Good Deed Books MVC project to Azure
+
+on:
+ push:
+ branches:
+ - endpoint_sahil
+ workflow_dispatch:
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Set up .NET Core
+ uses: actions/setup-dotnet@v4
+ with:
+ dotnet-version: '8.x'
+ include-prerelease: true
+
+ - name: Build with dotnet
+ run: dotnet build --configuration Release
+
+ - name: dotnet publish
+ run: dotnet publish ./src/AccountGoWeb/AccountGoWeb.csproj -c Release -o ${{env.DOTNET_ROOT}}/myapp
+
+ - name: Archive production artifacts
+ run: |
+ echo "+++++++++++++++++++++++++ where am I? ++++++++++++++++++++++++"
+ pwd
+ echo "+++++++++++++++++++++++++ save current directory into a variable dir ++++"
+ dir=$(pwd)
+ echo "+++++++++ what is in variable dir ++++++++++++++"
+ echo $dir
+ echo "++++++++++++++++++++++++ what's in current directory? ++++++++"
+ ls -al
+ echo "+++++ what's in the ${{env.DOTNET_ROOT}}/myapp directory? ++++"
+ ls -al ${{env.DOTNET_ROOT}}/myapp
+ echo "+++++ change directoiry to ${{env.DOTNET_ROOT}}/myapp ++++"
+ cd ${{env.DOTNET_ROOT}}/myapp
+ echo "+++++++++++++++++++++++++ where am I? ++++++++++++++++++++++++"
+ pwd
+ echo "+++++++++++++++++++++++++ compress current directory and save in $dir/my_artifact.tar.gz ++++"
+ tar -czvf $dir/my_artifact.tar.gz .
+ echo "+++++++++++++++++++++++++ change dir to to $dir directory ++++"
+ cd $dir
+ echo "+++++++++++++++++++++++++ where am I? ++++++++++++++++++++++++"
+ pwd
+ echo "++++++++++++++++++++++++ what's in $dir directory? ++++++++"
+ ls -al
+
+ - name: Upload artifact for deployment job
+ uses: actions/upload-artifact@v4
+ with:
+ name: .net-app
+ path: my_artifact.tar.gz
+
+ deploy:
+ runs-on: ubuntu-latest
+ needs: build
+ environment:
+ name: 'Production'
+ url: ${{ steps.deploy-to-webapp.outputs.webapp-url }}
+ permissions:
+ id-token: write #This is required for requesting the JWT
+
+ steps:
+ - name: Download artifact from build job
+ uses: actions/download-artifact@v4
+ with:
+ name: .net-app
+
+ - name: Login to Azure
+ uses: azure/login@v2
+ with:
+ client-id: ${{ secrets.AZUREAPPSERVICE_CLIENTID_28108B2CCE81480BB0295B2554B37231 }}
+ tenant-id: ${{ secrets.AZUREAPPSERVICE_TENANTID_9ED1B649A03F45E7B34C3BE1217B6BDE }}
+ subscription-id: ${{ secrets.AZUREAPPSERVICE_SUBSCRIPTIONID_A41842A963384E4BAB26580EEFE65E92 }}
+
+ - name: Extract artifacts
+ run: |
+ tar -xzvf my_artifact.tar.gz -C .
+
+ - name: Print working directory
+ run: pwd
+
+ - name: List directory contents
+ run: ls -l /home/runner/.dotnet/
+
+ - name: Deploy to Azure Web App
+ id: deploy-to-webapp
+ uses: azure/webapps-deploy@v3
+ with:
+ app-name: 'good-books'
+ slot-name: 'Production'
+ package: .
+
diff --git a/actions/gdbblazor.yml b/actions/gdbblazor.yml
new file mode 100644
index 000000000..a372a08c3
--- /dev/null
+++ b/actions/gdbblazor.yml
@@ -0,0 +1,67 @@
+# Docs for the Azure Web Apps Deploy action: https://github.com/Azure/webapps-deploy
+# More GitHub Actions for Azure: https://github.com/Azure/actions
+
+name: Build and deploy Good Deed Books BLAZOR project to Azure
+
+on:
+ push:
+ branches:
+ - endpoint_sahil
+
+jobs:
+ build:
+ runs-on: windows-latest
+
+ steps:
+ - uses: actions/checkout@v2
+
+ - name: Set up .NET Core
+ uses: actions/setup-dotnet@v2
+ with:
+ dotnet-version: '8.0.x'
+
+ - name: Restore dependencies
+ run: dotnet restore ./src/BlazorGDB/BlazorGDB/BlazorGDB.csproj
+
+ - name: Build
+ run: dotnet build ./src/BlazorGDB/BlazorGDB/BlazorGDB.csproj --configuration Release
+
+ - name: Publish
+ run: dotnet publish ./src/BlazorGDB/BlazorGDB/BlazorGDB.csproj --configuration Release --output ${{ github.workspace }}/myapp
+
+ - name: Upload artifact for deployment job
+ uses: actions/upload-artifact@v3
+ with:
+ name: .net-app
+ path: ${{ github.workspace }}/myapp
+
+ deploy:
+ runs-on: windows-latest
+ needs: build
+ environment:
+ name: 'Production'
+ url: ${{ steps.deploy-to-webapp.outputs.webapp-url }}
+ permissions:
+ id-token: write #This is required for requesting the JWT
+
+ steps:
+ - name: Download artifact from build job
+ uses: actions/download-artifact@v3
+ with:
+ name: .net-app
+
+ - name: Login to Azure
+ uses: azure/login@v2
+ with:
+ client-id: ${{ secrets.AZUREAPPSERVICE_CLIENTID_C7C01847F7FC4BBFB72DEAC64242E5A4 }}
+ tenant-id: ${{ secrets.AZUREAPPSERVICE_TENANTID_21069DC407434A3591399953BE45ED78 }}
+ subscription-id: ${{ secrets.AZUREAPPSERVICE_SUBSCRIPTIONID_CC5D4E473B8345BA854EA230A48D8D20 }}
+
+ - name: Deploy to Azure Web App
+ id: deploy-to-webapp
+ uses: azure/webapps-deploy@v3
+ with:
+ app-name: 'gdbblazor'
+ slot-name: 'Production'
+ package: .
+
diff --git a/actions/good-books_mvc.yml.disable b/actions/good-books_mvc.yml.disable
new file mode 100644
index 000000000..659083c9a
--- /dev/null
+++ b/actions/good-books_mvc.yml.disable
@@ -0,0 +1,75 @@
+# Docs for the Azure Web Apps Deploy action: https://github.com/Azure/webapps-deploy
+# More GitHub Actions for Azure: https://github.com/Azure/actions
+
+name: Build and deploy GoodBooks MVC project to Azure
+
+on:
+ push:
+ branches:
+ - endpoint_sahil
+ workflow_dispatch:
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Set up .NET Core
+ uses: actions/setup-dotnet@v1
+ with:
+ dotnet-version: '8.x'
+ include-prerelease: true
+
+ - name: Build with dotnet
+ run: dotnet build --configuration Release
+
+ - name: dotnet publish
+ run: dotnet publish ./src/AccountGoWeb/AccountGoWeb.csproj -c Release -o ${{env.DOTNET_ROOT}}/myapp
+
+ # - name: Archive production artifacts
+ # run: |
+ # tar -czvf my_artifact.tar.gz ${{env.DOTNET_ROOT}}/myapp
+
+ - name: Upload artifact for deployment job
+ uses: actions/upload-artifact@v3
+ with:
+ name: .net-app
+ # path: my_artifact.tar.gz
+ path: ${{env.DOTNET_ROOT}}/myapp
+
+ deploy:
+ runs-on: ubuntu-latest
+ needs: build
+ environment:
+ name: 'Production'
+ url: ${{ steps.deploy-to-webapp.outputs.webapp-url }}
+ permissions:
+ id-token: write #This is required for requesting the JWT
+
+ steps:
+ - name: Download artifact from build job
+ uses: actions/download-artifact@v3
+ with:
+ name: .net-app
+
+ - name: Login to Azure
+ uses: azure/login@v1
+ with:
+ client-id: ${{ secrets.AZUREAPPSERVICE_CLIENTID_28108B2CCE81480BB0295B2554B37231 }}
+ tenant-id: ${{ secrets.AZUREAPPSERVICE_TENANTID_9ED1B649A03F45E7B34C3BE1217B6BDE }}
+ subscription-id: ${{ secrets.AZUREAPPSERVICE_SUBSCRIPTIONID_A41842A963384E4BAB26580EEFE65E92 }}
+
+ # - name: Extract artifacts
+ # run: |
+ # tar -xzvf my_artifact.tar.gz -C .
+
+ - name: Deploy to Azure Web App
+ id: deploy-to-webapp
+ uses: azure/webapps-deploy@v2
+ with:
+ app-name: 'good-books'
+ slot-name: 'Production'
+ package: .
+
diff --git a/actions/good-books_react.yml.disable b/actions/good-books_react.yml.disable
new file mode 100644
index 000000000..99103e5e5
--- /dev/null
+++ b/actions/good-books_react.yml.disable
@@ -0,0 +1,54 @@
+name: Azure Static Web Apps CI/CD
+
+on:
+ push:
+ branches:
+ - endpoint_sahil
+ pull_request:
+ types: [opened, synchronize, reopened, closed]
+ branches:
+ - endpoint_sahil
+
+jobs:
+ build_and_deploy_job:
+ if: github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.action != 'closed')
+ runs-on: ubuntu-latest
+ name: Build and Deploy Job
+ steps:
+ - uses: actions/checkout@v3
+ with:
+ submodules: true
+ lfs: false
+
+ - name: Replace API URL
+ run: |
+ echo "++++ search & replace API URL from http://localhost:8001 to https://goodbooksapi.azurewebsites.net"
+ sed -i 's|http://localhost:8001|https://goodbooksapi.azurewebsites.net|g' ./src/GoodBooksReact/src/components/Shared/Config/index.tsx
+ echo "++++ display contents of index.tsx after search & replace"
+ cat ./src/GoodBooksReact/src/components/Shared/Config/index.tsx
+
+ - name: Build And Deploy
+ id: builddeploy
+ uses: Azure/static-web-apps-deploy@v1
+ with:
+ azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_MANGO_GLACIER_0EDFEC41E }}
+ repo_token: ${{ secrets.GITHUB_TOKEN }} # Used for Github integrations (i.e. PR comments)
+ action: "upload"
+ ###### Repository/Build Configurations - These values can be configured to match your app requirements. ######
+ # For more information regarding Static Web App workflow configurations, please visit: https://aka.ms/swaworkflowconfig
+ app_location: "/src/GoodBooksReact/" # App source code path
+ api_location: "" # Api source code path - optional
+ output_location: "/dist" # Built app content directory - optional
+ ###### End of Repository/Build Configurations ######
+
+ close_pull_request_job:
+ if: github.event_name == 'pull_request' && github.event.action == 'closed'
+ runs-on: ubuntu-latest
+ name: Close Pull Request Job
+ steps:
+ - name: Close Pull Request
+ id: closepullrequest
+ uses: Azure/static-web-apps-deploy@v1
+ with:
+ azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_MANGO_GLACIER_0EDFEC41E }}
+ action: "close"
diff --git a/actions/mvc_tar.yml.works b/actions/mvc_tar.yml.works
new file mode 100644
index 000000000..0e57f5cfc
--- /dev/null
+++ b/actions/mvc_tar.yml.works
@@ -0,0 +1,92 @@
+# Docs for the Azure Web Apps Deploy action: https://github.com/Azure/webapps-deploy
+# More GitHub Actions for Azure: https://github.com/Azure/actions
+name: Build and deploy Good Deed Books MVC project to Azure
+on:
+ push:
+ branches:
+ - endpoint_sahil
+ workflow_dispatch:
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Set up .NET Core
+ uses: actions/setup-dotnet@v4
+ with:
+ dotnet-version: '8.x'
+ include-prerelease: true
+
+ - name: Build with dotnet
+ run: dotnet build --configuration Release
+
+ - name: dotnet publish
+ run: dotnet publish ./src/AccountGoWeb/AccountGoWeb.csproj -c Release -o ${{runner.temp}}/myapp
+
+ - name: Archive production artifacts
+ run: |
+ echo "+++++++++++++++++++++++++ where am I? ++++++++++++++++++++++++"
+ pwd
+ echo "+++++++++++++++++++++++++ save current directory into a variable dir ++++"
+ dir=$(pwd)
+ echo "+++++++++ what is in variable dir ++++++++++++++"
+ echo $dir
+ echo "++++++++++++++++++++++++ what's in current directory? ++++++++"
+ ls -al
+ echo "+++++ what's in the ${{runner.temp}}/myapp directory? ++++"
+ ls -al ${{runner.temp}}/myapp
+ echo "+++++ change directory to ${{runner.temp}}/myapp ++++"
+ cd ${{runner.temp}}/myapp
+ echo "+++++++++++++++++++++++++ where am I? ++++++++++++++++++++++++"
+ pwd
+ echo "+++++++++++++++++++++++++ compress current directory and save in $dir/my_artifact.tar.gz ++++"
+ tar -czvf $dir/my_artifact.tar.gz .
+ echo "+++++++++++++++++++++++++ change back to $dir directory ++++"
+ cd $dir
+ echo "++++++++++++++++++++++++ what's in $dir directory? ++++++++"
+ ls -al
+
+ - name: Upload artifact for deployment job
+ uses: actions/upload-artifact@v4
+ with:
+ name: .net-app
+ path: my_artifact.tar.gz
+
+ deploy:
+ runs-on: ubuntu-latest
+ needs: build
+ environment:
+ name: 'Production'
+ url: ${{ steps.deploy-to-webapp.outputs.webapp-url }}
+ permissions:
+ id-token: write #This is required for requesting the JWT
+
+ steps:
+ - name: Download artifact from build job
+ uses: actions/download-artifact@v4
+ with:
+ name: .net-app
+
+ - name: Login to Azure
+ uses: azure/login@v2
+ with:
+ client-id: ${{ secrets.AZUREAPPSERVICE_CLIENTID_8B6389BB3F37413FB2483AC2574C3BCB }}
+ tenant-id: ${{ secrets.AZUREAPPSERVICE_TENANTID_FD62C59DE5DC42C2A07DB8191A522348 }}
+ subscription-id: ${{ secrets.AZUREAPPSERVICE_SUBSCRIPTIONID_7076EF307FDA4C11BC99A0A7A0943794 }}
+
+ - name: Extract artifacts
+ run: |
+ tar -xzvf my_artifact.tar.gz -C .
+
+ - name: Set startup command
+ run: |
+ az webapp config set --resource-group goodbooks-RG --name gdbmvc --startup-file "dotnet /home/site/wwwroot/GoodBooks.dll"
+
+ - name: Deploy to Azure Web App
+ id: deploy-to-webapp
+ uses: azure/webapps-deploy@v2
+ with:
+ app-name: 'gdbmvc'
+ slot-name: 'Production'
+ package: .
diff --git a/db/scripts/initial_data/3_InitialData-0001-Audit.sql b/db/scripts/initial_data/3_InitialData-0001-Audit.sql
new file mode 100644
index 000000000..b16be7c0d
--- /dev/null
+++ b/db/scripts/initial_data/3_InitialData-0001-Audit.sql
@@ -0,0 +1,13 @@
+-- Add audit data for the Company table
+INSERT INTO [dbo].[AuditableEntity] ([EntityName], [EnableAudit]) VALUES ('Company', 1);
+
+DECLARE @auditableEntityId INT;
+SELECT @auditableEntityId = [Id] FROM [dbo].[AuditableEntity] WHERE [EntityName] = 'Company';
+
+-- Add attributes for the Company table
+INSERT INTO [dbo].[AuditableAttribute] ([AuditableEntityId], [AttributeName], [EnableAudit])
+VALUES
+ (@auditableEntityId, 'CompanyCode', 1),
+ (@auditableEntityId, 'Name', 1),
+ (@auditableEntityId, 'ShortName', 1),
+ (@auditableEntityId, 'CRA', 1);
\ No newline at end of file
diff --git a/docker-compose.yml b/docker-compose.yml
index c7fef8216..8901497e3 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -1,5 +1,5 @@
version: "3"
-services:
+services:
api:
image: accountgo/accountgoapi
build:
@@ -8,14 +8,7 @@ services:
ports:
- "8001:8001"
environment:
- # - ASPNETCORE_ENVIRONMENT=Production
- ASPNETCORE_URLS=http://+:8001
- # - DBSERVER=localhost
- # - DBUSERID=dbuser
- # - DBPASSWORD=Str0ngPassword
- # - DBNAME=accountgodb
- # depends_on:
- # - db
web:
image: accountgo/accountgoweb
build:
@@ -24,13 +17,5 @@ services:
ports:
- "8000:8000"
environment:
- # - ASPNETCORE_ENVIRONMENT=Production
- ASPNETCORE_URLS=http://+:8000
- APIHOST=api
- # db:
- # image: microsoft/mssql-server-linux
- # ports:
- # - "1433:1433"
- # environment:
- # SA_PASSWORD: "Str0ngPassword"
- # ACCEPT_EULA: "Y"
\ No newline at end of file
diff --git a/docs/Bootstrap Blazor.txt b/docs/Bootstrap Blazor.txt
new file mode 100644
index 000000000..97341be99
--- /dev/null
+++ b/docs/Bootstrap Blazor.txt
@@ -0,0 +1,93 @@
+https://github.com/vikramlearning/blazorbootstrap-starter-templates/tree/master
+
+
+dotnet add package Blazor.Bootstrap -v 3.0.0-preview.2
+
+Program.cs
+
+ builder.Services.AddBlazorBootstrap(); // Add this line
+
+_Imports.razor
+
+ @using BlazorBootstrap;
+
+Delete wwwroot/bootstrap folder
+
+Replace MainLayout.razor with:
+
+ @inherits LayoutComponentBase
+
+
+
+
+
+
+
+
+
+ @Body
+
+
+
+
+
+ @code {
+ Sidebar sidebar;
+ IEnumerable navItems;
+
+ private async Task SidebarDataProvider(SidebarDataProviderRequest request)
+ {
+ if (navItems is null)
+ navItems = GetNavItems();
+
+ return await Task.FromResult(request.ApplyTo(navItems));
+ }
+
+ private IEnumerable GetNavItems()
+ {
+ navItems = new List
+ {
+ new NavItem { Id = "1", Href = "/", IconName = IconName.HouseDoorFill, Text = "Home", Match=NavLinkMatch.All},
+ new NavItem { Id = "2", Href = "/counter", IconName = IconName.PlusSquareFill, Text = "Counter"},
+ new NavItem { Id = "3", Href = "/weather", IconName = IconName.Table, Text = "Fetch Data"},
+ };
+
+ return navItems;
+ }
+ }
+
+
+
+ An unhandled error has occurred.
+
Reload
+
🗙
+
+
+App.razor
+
+ 1) Delete >>
+ 2) Add these lines at top of file under
+
+
+
+
+
+ 3) Add these lines at bottom of file under
+
+
+
+
+
+
+
+
+ 4) Change to:
+
+
+
+
\ No newline at end of file
diff --git a/docs/GoodDeedBooks.docx b/docs/GoodDeedBooks.docx
new file mode 100644
index 000000000..30ae3bee2
Binary files /dev/null and b/docs/GoodDeedBooks.docx differ
diff --git a/docs/README.md b/docs/README.md
index 74552fce9..c4965d29f 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -128,7 +128,7 @@ At this point, your database has no data on it. But there is already an initial
- Items
- Banks
-To initialize a company, call the api endpoint directly http://localhost:8001/api/administration/initializedcompany from the browser or by using curl e.g. `curl http://localhost:8001/api/administration/initializedcompany`. If you encounter some issues, the easy way for now is recreate your database and repeat the `Publish Database` section.
+To initialize a company, call the api endpoint directly http://localhost:8001/api/administration/setup from the browser or by using curl e.g. `curl http://localhost:8001/api/administration/setup`. If you encounter some issues, the easy way for now is recreate your database and repeat the `Publish Database` section.
## Build and Run "Api" (Back-end)
1. Navigate directory to `src/Api` project
@@ -181,7 +181,7 @@ To run everything (database, api, web) in docker container you can use docker-co
1. Database instance running in docker container and you can connect to it
1. You should have a running "Api" and can test it by getting the list of customers e.g. http://localhost:8001/api/sales customers
1. You can browse the UI from http://localhost:8000 and able to login to the system using initial username/password: admin@accountgo.ph/P@ssword1
-1. Initialize data by calling a special api endpoint directly. http://localhost:8001/api/administration/initializedcompany
+1. Initialize data by calling a special api endpoint directly: http://localhost:8001/api/administration/setup
# Technology Stack
- ASP.NET Core 3.1
@@ -207,4 +207,4 @@ If you are a developer and wanted to take part as contributor/collaborator we ar
So go ahead, add your code and make your first pull request.
# Contact Support
-Feel free to email mvpsolution@gmail.com of any questions.
\ No newline at end of file
+Feel free to email mvpsolution@gmail.com of any questions.
diff --git a/docs/azure.txt b/docs/azure.txt
new file mode 100644
index 000000000..1e437cd3d
--- /dev/null
+++ b/docs/azure.txt
@@ -0,0 +1,8 @@
+API:
+https://goodbooksapi.azurewebsites.net
+
+MVC:
+https://good-books.azurewebsites.net
+
+React:
+https://mango-glacier-0edfec41e.5.azurestaticapps.net
diff --git a/docs/background.txt b/docs/background.txt
new file mode 100644
index 000000000..dfd5d92f3
--- /dev/null
+++ b/docs/background.txt
@@ -0,0 +1,41 @@
+I was asked by a non-profit organization to help them find a cheap accounting system instead of paying high subscription fees from a current vendor. I stumbled upon this open source project on GitHub:
+
+https://github.com/AccountGo/accountgo
+
+It is based on the following technologies:
+
+Backend: ASP.NET WebAPI and MVC
+Frontend: React with TypeScript
+Database: SQL Server
+
+It seems that development on this app stopped about seven years ago. When I looked at it, I figured that it has most of what is needed and could be brought up to snuff by upgrading the application to the latest state of .NET and React. Therefore, I forked it and updated it to the latest versions of .NET, React, and TypeScript.
+
+The forked app is at https://github.com/medhatelmasry/GoodBooks
+
+You can run it by following these steps:
+
+Clone the repo
+Start SQL Server in a docker container with:
+
+ docker run --cap-add SYS_PTRACE -e ACCEPT_EULA=1 -e MSSQL_SA_PASSWORD=SqlPassword! -p 1444:1433 --name azsql -d mcr.microsoft.com/azure-sql-edge
+
+In root directory of the code, run the following commands:
+
+ dotnet ef migrations add M1 --project ./src/Api/ --startup-project ./src/Api/Api.csproj --msbuildprojectextensionspath .build/obj/Api/ --context ApplicationIdentityDbContext --output-dir Data/Migrations/IdentityDb
+
+ dotnet ef migrations add M2 --project ./src/Api/ --startup-project ./src/Api/Api.csproj --msbuildprojectextensionspath .build/obj/Api/ --context ApiDbContext --output-dir Data/Migrations/ApiDb
+
+ dotnet ef database update --project ./src/Api/ --msbuildprojectextensionspath .build/obj/Api/ --context ApplicationIdentityDbContext
+
+ dotnet ef database update --project ./src/Api/ --msbuildprojectextensionspath .build/obj/Api/ --context ApiDbContext
+
+Update to the latest versions of Node & Npm
+Go to the src/Api folder and start the WebAPI app with: dotnet watch
+Hit this endpoint in order to populate the database with some sample data: http://localhost:8001/api/administration/setup
+In a separate terminal window, go to the src/GoodBooksReact folder run these commands:
+
+ npm install
+ npm run dev
+
+The React app will run. It is a rudimentary frontend menu system and is a work in progress.
+
diff --git a/docs/expand-chart-of-accounts.docx b/docs/expand-chart-of-accounts.docx
new file mode 100644
index 000000000..0ebf39cf4
Binary files /dev/null and b/docs/expand-chart-of-accounts.docx differ
diff --git a/docs/medhat.txt b/docs/medhat.txt
new file mode 100644
index 000000000..b66e10c56
--- /dev/null
+++ b/docs/medhat.txt
@@ -0,0 +1,28 @@
+docker run --cap-add SYS_PTRACE -e ACCEPT_EULA=1 -e MSSQL_SA_PASSWORD=SqlPassword! -p 1444:1433 --name azsql -d mcr.microsoft.com/azure-sql-edge
+
+Data Source=localhost,1444;Database=Northwind;Persist Security Info=True;User ID=sa;Password=SqlPassword!;TrustServerCertificate=True;
+
+====================
+
+dotnet ef migrations add M1 --project ./src/Api/ --startup-project ./src/Api/Api.csproj --msbuildprojectextensionspath .build/obj/Api/ --context ApplicationIdentityDbContext --output-dir Data/Migrations/IdentityDb
+
+dotnet ef migrations add M2 --project ./src/Api/ --startup-project ./src/Api/Api.csproj --msbuildprojectextensionspath .build/obj/Api/ --context ApiDbContext --output-dir Data/Migrations/ApiDb
+
+====================
+
+dotnet ef database update --project ./src/Api/ --msbuildprojectextensionspath .build/obj/Api/ --context ApplicationIdentityDbContext
+
+dotnet ef database update --project ./src/Api/ --msbuildprojectextensionspath .build/obj/Api/ --context ApiDbContext
+
+====================
+
+Update to the latest versions of node & npm
+
+====================
+
+Start the API .NET application then hit this endpoint in a browser to create seed data:
+http://localhost:8001/api/administration/setup
+
+
+
+
diff --git a/docs/open-source.txt b/docs/open-source.txt
new file mode 100644
index 000000000..38db29dbc
--- /dev/null
+++ b/docs/open-source.txt
@@ -0,0 +1,3 @@
+Open Source Accounting System
+
+https://github.com/AccountGo/accountgo
diff --git a/docs/pr.txt b/docs/pr.txt
new file mode 100644
index 000000000..b5b7b5215
--- /dev/null
+++ b/docs/pr.txt
@@ -0,0 +1,19 @@
+git checkout -b dotnet_9 origin/dotnet_9
+
+docker run --cap-add SYS_PTRACE -e ACCEPT_EULA=1 -e MSSQL_SA_PASSWORD=SqlPassword! -p 1444:1433 --name sql -d mcr.microsoft.com/mssql/server:2022-latest
+
+---------
+
+dotnet ef migrations add M1 --project ./src/Api/ --startup-project ./src/Api/Api.csproj --msbuildprojectextensionspath .build/obj/Api/ --context ApplicationIdentityDbContext --output-dir Data/Migrations/IdentityDb
+
+dotnet ef migrations add M2 --project ./src/Api/ --startup-project ./src/Api/Api.csproj --msbuildprojectextensionspath .build/obj/Api/ --context ApiDbContext --output-dir Data/Migrations/ApiDb
+
+dotnet ef database update --project ./src/Api/ --msbuildprojectextensionspath .build/obj/Api/ --context ApplicationIdentityDbContext
+
+dotnet ef database update --project ./src/Api/ --msbuildprojectextensionspath .build/obj/Api/ --context ApiDbContext
+
+==========
+
+Apply Entity Framework Core migrations in .NET Aspire
+ https://learn.microsoft.com/en-us/dotnet/aspire/database/ef-core-migrations
+
diff --git a/docs/react.txt b/docs/react.txt
new file mode 100644
index 000000000..2e56c21d6
--- /dev/null
+++ b/docs/react.txt
@@ -0,0 +1,4 @@
+https://www.youtube.com/watch?v=ElgfQdq-Htk
+
+https://www.youtube.com/watch?v=oN9W0Tkn8hg
+
diff --git a/move-to-blazor.txt b/move-to-blazor.txt
new file mode 100644
index 000000000..e388316b6
--- /dev/null
+++ b/move-to-blazor.txt
@@ -0,0 +1,9 @@
+Recreate starter Blazor app with database authentication
+- we will use JWT for client-side authentication
+
+Get chart of account to work
+
+CI/CD GiHul >> Azure
+
+Meet and decide on moving the current application into the Blazor template
+
diff --git a/src/AccountGoWeb/.vscode/launch.json b/src/AccountGoWeb/.vscode/launch.json
index 5825c3616..ddd8758f9 100644
--- a/src/AccountGoWeb/.vscode/launch.json
+++ b/src/AccountGoWeb/.vscode/launch.json
@@ -4,6 +4,11 @@
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
+ {
+ "name": ".NET Core Attach",
+ "type": "coreclr",
+ "request": "attach"
+ },
{
"name": ".NET Core Launch (web)",
"type": "coreclr",
diff --git a/src/AccountGoWeb/AccountGoWeb.csproj b/src/AccountGoWeb/AccountGoWeb.csproj
index 0175223c6..cea3034a4 100644
--- a/src/AccountGoWeb/AccountGoWeb.csproj
+++ b/src/AccountGoWeb/AccountGoWeb.csproj
@@ -1,46 +1,34 @@
-
-
+
- net7.0
- true
- AccountGoWeb
- AccountGoWeb
- latest
- 0.0.1-alpha
- Latest
+ net9.0
+ GoodBooks
+ GoodBooks
+ 1.0.0
+ enable
+ enable
+ true
+ aspnet-GoodBooks-21ac3a7f-d42e-4136-9340-b4f6254706df
+ NU1701
-
PreserveNewest
-
+
+
-
+
-
-
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
\ No newline at end of file
diff --git a/src/AccountGoWeb/Components/App.razor b/src/AccountGoWeb/Components/App.razor
new file mode 100644
index 000000000..a99d041ea
--- /dev/null
+++ b/src/AccountGoWeb/Components/App.razor
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/AccountGoWeb/Components/Pages/Counter.razor b/src/AccountGoWeb/Components/Pages/Counter.razor
new file mode 100644
index 000000000..0d9d43ad4
--- /dev/null
+++ b/src/AccountGoWeb/Components/Pages/Counter.razor
@@ -0,0 +1,19 @@
+@page "/counter"
+@rendermode InteractiveServer
+
+Counter
+
+Counter
+
+Current count: @currentCount
+
+Click me
+
+@code {
+ private int currentCount = 0;
+
+ private void IncrementCount()
+ {
+ currentCount++;
+ }
+}
diff --git a/src/AccountGoWeb/Components/Pages/Financial/ChartOfAccounts.razor b/src/AccountGoWeb/Components/Pages/Financial/ChartOfAccounts.razor
new file mode 100644
index 000000000..21557a326
--- /dev/null
+++ b/src/AccountGoWeb/Components/Pages/Financial/ChartOfAccounts.razor
@@ -0,0 +1,369 @@
+@page "/financials/chart-of-accounts"
+@using System.Text.Json
+@using System.Text.Json.Serialization
+@using LibraryGDB.Models.Financial
+@using Microsoft.JSInterop
+@using Microsoft.Net.Http.Headers
+@inject IHttpClientFactory ClientFactory
+@inject Microsoft.JSInterop.IJSRuntime JSRuntime
+
+Chart of Accounts
+
+Chart Of Accounts
+
+@if (getError || accounts is null)
+{
+ Unable to get data. Please try again later.
+}
+else if (isLoading)
+{
+ Loading accounts...
+}
+else
+{
+ @*
+ @foreach (var item in accounts)
+ {
+ @item.AccountName
+ }
+ *@
+
+
+
Add Account
+
+
+
+
+ Code
+ Name
+ Balance
+ Debit
+ Credit
+ Actions
+
+
+
+ @for (int accountIdx = 0; accountIdx < accounts.Count(); ++accountIdx)
+ {
+ var account = accounts.ToList()[accountIdx];
+ var accountTargetId = $"asset-{accountIdx}";
+
+
+ @account.AccountCode
+ @account.AccountName
+ @account.TotalBalance
+ @account.TotalDebitBalance
+ @account.TotalCreditBalance
+
+ OpenEditModal(account)">Edit
+ OpenDeleteModal(account)">Delete
+
+
+
+
+
+
+
+
+ @for (int childAccountIdx = 0; childAccountIdx < account.ChildAccounts!.Count; ++childAccountIdx)
+ {
+ var childAccount = account.ChildAccounts.ToList()[childAccountIdx];
+ var childAccountTargetId = $"asset-{accountIdx}-{childAccountIdx}";
+
+
+ @childAccount.AccountCode
+ @childAccount.AccountName
+ @childAccount.TotalBalance
+ @childAccount.TotalDebitBalance
+ @childAccount.TotalCreditBalance
+
+
+
+
+
+
+
+ @for (int grandChildAccountIdx = 0; grandChildAccountIdx < childAccount.ChildAccounts!.Count; ++grandChildAccountIdx)
+ {
+ var grandChildAccount = childAccount.ChildAccounts.ToList()[grandChildAccountIdx];
+ var grandChildAccountTargetId = $"asset-{accountIdx}-{childAccountIdx}-{grandChildAccountIdx}";
+
+
+ @grandChildAccount.AccountCode
+ @grandChildAccount.AccountName
+ @grandChildAccount.TotalBalance
+ @grandChildAccount.TotalDebitBalance
+ @grandChildAccount.TotalCreditBalance
+
+
+
+
+
+
+
+ @foreach (var greatGrandChildAccount in grandChildAccount.ChildAccounts!)
+ {
+
+ @greatGrandChildAccount.AccountCode
+ @greatGrandChildAccount.AccountName
+ @greatGrandChildAccount.TotalBalance
+ @greatGrandChildAccount.TotalDebitBalance
+ @greatGrandChildAccount.TotalCreditBalance
+
+ }
+
+
+
+
+
+ }
+
+
+
+
+
+ }
+
+
+
+
+
+ }
+
+
+
+
+}
+@if (isAddModalVisible || isEditModalVisible)
+{
+
+}
+
+@if (isDeleteModalVisible)
+{
+
+
+
+
+
+
+ Are you sure you want to delete the account
+ @selectedAccount?.AccountName
+ with code @selectedAccount?.AccountCode ?
+
+
+
+
+
+
+}
+
+@code {
+ private List accounts = new();
+ private AccountViewModel? selectedAccount = null;
+ private bool isAddModalVisible = false;
+ private bool isEditModalVisible = false;
+ private bool isDeleteModalVisible = false;
+ private string errorMessage = string.Empty;
+ private bool isLoading = true;
+ private bool getError = false;
+
+ // Fetch accounts from API on initialization
+ protected override async Task OnInitializedAsync()
+ {
+ await LoadAccountsFromApi();
+ isLoading = false;
+ }
+
+ // Load accounts from API
+ private async Task LoadAccountsFromApi()
+ {
+ try
+ {
+ string apiUrl = Environment.GetEnvironmentVariable("APIURL") ?? "http://localhost:8001/api/";
+ var client = ClientFactory.CreateClient();
+
+ var response = await client.GetAsync($"{apiUrl}financials/accounts");
+
+ if (response.IsSuccessStatusCode)
+ {
+ var jsonString = await response.Content.ReadAsStringAsync();
+ accounts = JsonSerializer.Deserialize>(jsonString, new JsonSerializerOptions
+ {
+ PropertyNameCaseInsensitive = true
+ }) ?? new List();
+ }
+ else
+ {
+ getError = true;
+ }
+ }
+ catch
+ {
+ getError = true;
+ }
+ }
+
+
+ // Open Add Modal
+ private void OpenAddModal()
+ {
+ selectedAccount = new AccountViewModel();
+ errorMessage = string.Empty;
+ isAddModalVisible = true;
+ }
+
+ // Open Edit Modal
+ private void OpenEditModal(AccountViewModel account)
+ {
+ selectedAccount = new AccountViewModel
+ {
+ AccountCode = account.AccountCode,
+ AccountName = account.AccountName,
+ TotalBalance = account.TotalBalance,
+ TotalDebitBalance = account.TotalDebitBalance,
+ TotalCreditBalance = account.TotalCreditBalance,
+ ChildAccounts = account.ChildAccounts
+ };
+ errorMessage = string.Empty;
+ isEditModalVisible = true;
+ }
+
+ // Close Add or Edit Modal
+ private void CloseModal()
+ {
+ isAddModalVisible = false;
+ isEditModalVisible = false;
+ selectedAccount = null;
+ }
+
+ // Open Delete Modal
+ private void OpenDeleteModal(AccountViewModel account)
+ {
+ selectedAccount = account;
+ isDeleteModalVisible = true;
+ }
+
+ // Close Delete Modal
+ private void CloseDeleteModal()
+ {
+ isDeleteModalVisible = false;
+ selectedAccount = null;
+ }
+
+ // Add or Update Account
+ private void SaveAccount()
+ {
+ if (selectedAccount == null)
+ {
+ errorMessage = "No account selected.";
+ return;
+ }
+
+ if (string.IsNullOrWhiteSpace(selectedAccount.AccountCode) || string.IsNullOrWhiteSpace(selectedAccount.AccountName))
+ {
+ errorMessage = "Both Account Code and Account Name are required.";
+ return;
+ }
+
+ if (isEditModalVisible)
+ {
+ // Edit existing account locally
+ var account = accounts.FirstOrDefault(a => a.AccountCode == selectedAccount.AccountCode);
+ if (account != null)
+ {
+ account.AccountName = selectedAccount.AccountName;
+ account.TotalBalance = selectedAccount.TotalBalance;
+ account.TotalDebitBalance = selectedAccount.TotalDebitBalance;
+ account.TotalCreditBalance = selectedAccount.TotalCreditBalance;
+ }
+ else
+ {
+ errorMessage = "Account not found.";
+ }
+ }
+ else
+ {
+ // Add new account locally
+ if (accounts.Any(a => a.AccountCode == selectedAccount.AccountCode))
+ {
+ errorMessage = "An account with this Account Code already exists.";
+ return;
+ }
+
+ accounts.Add(new AccountViewModel
+ {
+ AccountCode = selectedAccount.AccountCode,
+ AccountName = selectedAccount.AccountName,
+ TotalBalance = selectedAccount.TotalBalance,
+ TotalDebitBalance = selectedAccount.TotalDebitBalance,
+ TotalCreditBalance = selectedAccount.TotalCreditBalance,
+ ChildAccounts = new List()
+ });
+ }
+
+ CloseModal();
+ }
+
+ // Delete Account
+ private void ConfirmDeleteAccount()
+ {
+ if (selectedAccount == null)
+ {
+ errorMessage = "No account selected.";
+ return;
+ }
+
+ accounts.Remove(selectedAccount);
+ CloseDeleteModal();
+ }
+
+ // ViewModel for Accounts
+ public class AccountViewModel
+ {
+ public string AccountCode { get; set; } = string.Empty;
+ public string AccountName { get; set; } = string.Empty;
+ public decimal TotalBalance { get; set; }
+ public decimal TotalDebitBalance { get; set; }
+ public decimal TotalCreditBalance { get; set; }
+ public List ChildAccounts { get; set; } = new();
+ }
+}
diff --git a/src/AccountGoWeb/Components/Pages/Students.razor b/src/AccountGoWeb/Components/Pages/Students.razor
new file mode 100644
index 000000000..443d791b0
--- /dev/null
+++ b/src/AccountGoWeb/Components/Pages/Students.razor
@@ -0,0 +1,23 @@
+@page "/students"
+@rendermode InteractiveServer
+Students
+Students
+
+
+
+
+
+ @context.FirstName @context.LastName
+
+
+
+
+
+
+
+@code {
+ IQueryable students = Student.GetStudents();
+ PaginationState pagination = new PaginationState { ItemsPerPage = 10 };
+ GridSort sortByName = GridSort
+ .ByAscending(_ => _.FirstName).ThenAscending(_ => _.LastName);
+}
\ No newline at end of file
diff --git a/src/AccountGoWeb/Components/Routes.razor b/src/AccountGoWeb/Components/Routes.razor
new file mode 100644
index 000000000..da8815572
--- /dev/null
+++ b/src/AccountGoWeb/Components/Routes.razor
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/src/AccountGoWeb/Components/_Imports.razor b/src/AccountGoWeb/Components/_Imports.razor
new file mode 100644
index 000000000..8eccd6b2e
--- /dev/null
+++ b/src/AccountGoWeb/Components/_Imports.razor
@@ -0,0 +1,18 @@
+@using System.Net.Http
+@using System.Net.Http.Json
+@using Microsoft.AspNetCore.Components.Forms
+@using Microsoft.AspNetCore.Components.Routing
+@using Microsoft.AspNetCore.Components.Web
+@using static Microsoft.AspNetCore.Components.Web.RenderMode
+@using Microsoft.AspNetCore.Components.Web.Virtualization
+@using Microsoft.JSInterop
+@using Microsoft.AspNetCore.Components.QuickGrid
+@using AccountGoWeb
+@using AccountGoWeb.Components
+@using AccountGoWeb.Models
+@using AccountGoWeb.Models.Account
+@using AccountGoWeb.Models.Bogus
+@using AccountGoWeb.Models.Financial
+@using AccountGoWeb.Models.Purchasing
+@using AccountGoWeb.Models.Sales
+@using AccountGoWeb.Models.TaxSystem
diff --git a/src/AccountGoWeb/Controllers/AccountController.cs b/src/AccountGoWeb/Controllers/AccountController.cs
index 0eba93c37..9d558d04e 100644
--- a/src/AccountGoWeb/Controllers/AccountController.cs
+++ b/src/AccountGoWeb/Controllers/AccountController.cs
@@ -3,25 +3,20 @@
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
-using Microsoft.Extensions.Configuration;
-using System;
-using System.Collections.Generic;
-using System.Net.Http;
using System.Security.Claims;
-using System.Threading.Tasks;
namespace AccountGoWeb.Controllers
{
- public class AccountController : BaseController
+ public class AccountController : GoodController
{
public AccountController(IConfiguration config)
{
- _baseConfig = config;
+ _configuration = config;
}
[HttpGet]
[AllowAnonymous]
- public IActionResult SignIn(string returnUrl = null)
+ public IActionResult SignIn(string? returnUrl = null)
{
ViewData["ReturnUrl"] = returnUrl;
return View(new LoginViewModel() { Email = "admin@accountgo.ph", Password = "P@ssword1" });
@@ -29,7 +24,7 @@ public IActionResult SignIn(string returnUrl = null)
[HttpPost]
[AllowAnonymous]
- public async Task SignIn(LoginViewModel model, string returnUrl = null)
+ public async Task SignIn(LoginViewModel model, string? returnUrl = null)
{
ViewData["ReturnUrl"] = returnUrl;
@@ -47,8 +42,8 @@ public async Task SignIn(LoginViewModel model, string returnUrl =
var claims = new List();
claims.Add(new Claim(ClaimTypes.IsPersistent, model.RememberMe.ToString()));
- claims.Add(new Claim(ClaimTypes.NameIdentifier, user.Email));
- claims.Add(new Claim(ClaimTypes.Email, user.Email));
+ claims.Add(new Claim(ClaimTypes.NameIdentifier, user.Email!));
+ claims.Add(new Claim(ClaimTypes.Email, user.Email!));
string firstName = user.FirstName != null ? user.FirstName : "";
string lastName = user.LastName != null ? user.LastName : "";
@@ -58,7 +53,7 @@ public async Task SignIn(LoginViewModel model, string returnUrl =
claims.Add(new Claim(ClaimTypes.Name, firstName + " " + lastName));
foreach(var role in user.Roles)
- claims.Add(new Claim(ClaimTypes.Role, role.Name));
+ claims.Add(new Claim(ClaimTypes.Role, role.Name!));
claims.Add(new Claim(ClaimTypes.UserData, Newtonsoft.Json.JsonConvert.SerializeObject(user)));
@@ -70,7 +65,7 @@ public async Task SignIn(LoginViewModel model, string returnUrl =
await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, principal);
- return RedirectToLocal(returnUrl);
+ return RedirectToLocal(returnUrl!);
}
else
{
@@ -92,7 +87,7 @@ public async Task SignOut()
public IActionResult SignedOut()
{
- if (HttpContext.User.Identity.IsAuthenticated)
+ if (HttpContext.User.Identity!.IsAuthenticated)
{
return RedirectToAction(nameof(HomeController.Index), "Home");
}
@@ -106,7 +101,7 @@ public IActionResult Unauthorize()
[HttpGet]
[AllowAnonymous]
- public IActionResult Register(string returnUrl = null)
+ public IActionResult Register(string? returnUrl = null)
{
ViewData["ReturnUrl"] = returnUrl;
return View();
@@ -114,7 +109,7 @@ public IActionResult Register(string returnUrl = null)
[HttpPost]
[AllowAnonymous]
- public IActionResult Register(RegisterViewModel model, string returnUrl = null)
+ public IActionResult Register(RegisterViewModel model, string? returnUrl = null)
{
ViewData["ReturnUrl"] = returnUrl;
try
@@ -127,9 +122,9 @@ public IActionResult Register(RegisterViewModel model, string returnUrl = null)
HttpResponseMessage responseAddNewUser = Post("account/addnewuser", content);
Newtonsoft.Json.Linq.JObject resultAddNewUser = Newtonsoft.Json.Linq.JObject.Parse(responseAddNewUser.Content.ReadAsStringAsync().Result);
- HttpResponseMessage responseInitialized = null;
- Newtonsoft.Json.Linq.JObject resultInitialized = null;
- if ((bool)resultAddNewUser["succeeded"])
+ HttpResponseMessage? responseInitialized = null;
+ Newtonsoft.Json.Linq.JObject? resultInitialized = null;
+ if ((bool)resultAddNewUser["succeeded"]!)
{
responseInitialized = Get("administration/initializedcompany");
resultInitialized = Newtonsoft.Json.Linq.JObject.Parse((responseInitialized.Content.ReadAsStringAsync().Result));
@@ -137,7 +132,7 @@ public IActionResult Register(RegisterViewModel model, string returnUrl = null)
}
else
{
- ModelState.AddModelError(string.Empty, resultAddNewUser["errors"][0]["description"].ToString());
+ ModelState.AddModelError(string.Empty, resultAddNewUser["errors"]![0]!["description"]!.ToString());
return View(model);
}
}
diff --git a/src/AccountGoWeb/Controllers/AdministrationController.cs b/src/AccountGoWeb/Controllers/AdministrationController.cs
index a05f3f301..148b81334 100644
--- a/src/AccountGoWeb/Controllers/AdministrationController.cs
+++ b/src/AccountGoWeb/Controllers/AdministrationController.cs
@@ -1,14 +1,11 @@
using Dto.Administration;
using Dto.Security;
using Microsoft.AspNetCore.Mvc;
-using Microsoft.Extensions.Configuration;
-using System;
-using System.Net.Http;
namespace AccountGoWeb.Controllers
{
- [Microsoft.AspNetCore.Authorization.Authorize]
- public class AdministrationController : BaseController
+ //[Microsoft.AspNetCore.Authorization.Authorize]
+ public class AdministrationController : BaseController
{
public AdministrationController(IConfiguration config)
{
@@ -125,13 +122,13 @@ public async System.Threading.Tasks.Task AuditLogs()
HttpResponseMessage responseAddNewUser = Post("account/addnewuser", content);
Newtonsoft.Json.Linq.JObject resultAddNewUser = Newtonsoft.Json.Linq.JObject.Parse(responseAddNewUser.Content.ReadAsStringAsync().Result);
- if ((bool)resultAddNewUser["succeeded"])
+ if ((bool)resultAddNewUser["succeeded"]!)
{
return RedirectToAction(nameof(AdministrationController.Users), "Administration");
}
else
{
- ModelState.AddModelError(string.Empty, resultAddNewUser["errors"][0]["description"].ToString());
+ ModelState.AddModelError(string.Empty, resultAddNewUser["errors"]![0]!["description"]!.ToString());
return View(model);
}
}
diff --git a/src/AccountGoWeb/Controllers/BaseController.cs b/src/AccountGoWeb/Controllers/BaseController.cs
index aafb66c5b..8a4193f01 100644
--- a/src/AccountGoWeb/Controllers/BaseController.cs
+++ b/src/AccountGoWeb/Controllers/BaseController.cs
@@ -1,20 +1,18 @@
using Microsoft.AspNetCore.Mvc;
-using Microsoft.Extensions.Configuration;
-using System.Net.Http;
namespace AccountGoWeb.Controllers
{
public class BaseController : Controller
{
- protected IConfiguration _baseConfig;
+ protected IConfiguration? _baseConfig;
protected async System.Threading.Tasks.Task GetAsync(string uri)
{
string responseJson = string.Empty;
using (var client = new HttpClient())
{
- var baseUri = _baseConfig["ApiUrl"];
- client.BaseAddress = new System.Uri(baseUri);
+ var baseUri = _baseConfig!["ApiUrl"];
+ client.BaseAddress = new System.Uri(baseUri!);
client.DefaultRequestHeaders.Accept.Clear();
var response = await client.GetAsync(baseUri + uri);
if (response.IsSuccessStatusCode)
@@ -22,7 +20,7 @@ protected async System.Threading.Tasks.Task GetAsync(string uri)
responseJson = await response.Content.ReadAsStringAsync();
}
}
- return Newtonsoft.Json.JsonConvert.DeserializeObject(responseJson);
+ return Newtonsoft.Json.JsonConvert.DeserializeObject(responseJson)!;
}
protected HttpResponseMessage Get(string uri)
@@ -30,8 +28,8 @@ protected HttpResponseMessage Get(string uri)
string responseJson = string.Empty;
using (var client = new HttpClient())
{
- var baseUri = _baseConfig["ApiUrl"];
- client.BaseAddress = new System.Uri(baseUri);
+ var baseUri = _baseConfig!["ApiUrl"];
+ client.BaseAddress = new System.Uri(baseUri!);
client.DefaultRequestHeaders.Accept.Clear();
var response = client.GetAsync(baseUri + uri);
return response.Result;
@@ -43,8 +41,8 @@ protected async System.Threading.Tasks.Task PostAsync(string uri, String
string responseJson = string.Empty;
using (var client = new HttpClient())
{
- var baseUri = _baseConfig["ApiUrl"];
- client.BaseAddress = new System.Uri(baseUri);
+ var baseUri = _baseConfig!["ApiUrl"];
+ client.BaseAddress = new System.Uri(baseUri!);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Add("UserName", GetCurrentUserName());
@@ -55,7 +53,7 @@ protected async System.Threading.Tasks.Task PostAsync(string uri, String
}
}
- return Newtonsoft.Json.JsonConvert.DeserializeObject(responseJson);
+ return Newtonsoft.Json.JsonConvert.DeserializeObject(responseJson)!;
}
protected HttpResponseMessage Post(string uri, StringContent data)
@@ -63,8 +61,8 @@ protected HttpResponseMessage Post(string uri, StringContent data)
string responseJson = string.Empty;
using (var client = new HttpClient())
{
- var baseUri = _baseConfig["ApiUrl"];
- client.BaseAddress = new System.Uri(baseUri);
+ var baseUri = _baseConfig!["ApiUrl"];
+ client.BaseAddress = new System.Uri(baseUri!);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Add("UserName", GetCurrentUserName());
@@ -76,7 +74,7 @@ protected HttpResponseMessage Post(string uri, StringContent data)
protected bool HasPermission(string permission)
{
- if (HttpContext.User.Identity.IsAuthenticated)
+ if (HttpContext.User.Identity!.IsAuthenticated)
{
System.Collections.Generic.IList permissions = new System.Collections.Generic.List();
@@ -87,11 +85,11 @@ protected bool HasPermission(string permission)
if (current.Type == System.Security.Claims.ClaimTypes.UserData)
{
Newtonsoft.Json.Linq.JObject userData = Newtonsoft.Json.Linq.JObject.Parse(current.Value);
- foreach(var r in userData["Roles"])
+ foreach(var r in userData["Roles"]!)
{
- foreach(var p in r["Permissions"])
+ foreach(var p in r["Permissions"]!)
{
- permissions.Add(p["Name"].ToString());
+ permissions.Add(p["Name"]!.ToString());
}
}
}
@@ -105,7 +103,7 @@ protected bool HasPermission(string permission)
protected string GetCurrentUserName()
{
- if (HttpContext.User.Identity.IsAuthenticated)
+ if (HttpContext.User.Identity!.IsAuthenticated)
{
var claimsEnumerator = HttpContext.User.Claims.GetEnumerator();
while (claimsEnumerator.MoveNext())
diff --git a/src/AccountGoWeb/Controllers/ContactController.cs b/src/AccountGoWeb/Controllers/ContactController.cs
index fd3e1a60a..f22788253 100644
--- a/src/AccountGoWeb/Controllers/ContactController.cs
+++ b/src/AccountGoWeb/Controllers/ContactController.cs
@@ -1,11 +1,5 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
+using Dto.Common;
using Microsoft.AspNetCore.Mvc;
-using Microsoft.Extensions.Configuration;
-using System.Net.Http;
-using Dto.Common;
// For more information on enabling MVC for empty projects, visit http://go.microsoft.com/fwlink/?LinkID=397860
namespace AccountGoWeb.Controllers
@@ -35,8 +29,8 @@ public async System.Threading.Tasks.Task Contacts(int partyId = 0
//return View(model: contacts);
using (var client = new HttpClient())
{
- var baseUri = _baseConfig["ApiUrl"];
- client.BaseAddress = new System.Uri(baseUri);
+ var baseUri = _baseConfig!["ApiUrl"];
+ client.BaseAddress = new System.Uri(baseUri!);
client.DefaultRequestHeaders.Accept.Clear();
var response = await client.GetAsync(baseUri + "contact/contacts?partyId=" + partyId + "&partyType=" + partyType);
if (response.IsSuccessStatusCode)
@@ -57,7 +51,7 @@ public async System.Threading.Tasks.Task Contacts(int partyId = 0
///
public IActionResult Contact(int id = 0, int partyId = 0, int partyType = 0)
{
- Contact contact = null;
+ Contact? contact = null;
if (id == 0) // creating new contact
{
diff --git a/src/AccountGoWeb/Controllers/DashboardController.cs b/src/AccountGoWeb/Controllers/DashboardController.cs
index c8791445a..0753e5208 100644
--- a/src/AccountGoWeb/Controllers/DashboardController.cs
+++ b/src/AccountGoWeb/Controllers/DashboardController.cs
@@ -1,9 +1,8 @@
using Microsoft.AspNetCore.Mvc;
-using Microsoft.Extensions.Configuration;
namespace AccountGoWeb.Controllers
{
- [Microsoft.AspNetCore.Authorization.Authorize]
+ //[Microsoft.AspNetCore.Authorization.Authorize]
public class DashboardController : BaseController
{
public DashboardController(IConfiguration config)
@@ -19,7 +18,7 @@ public IActionResult Index()
public IActionResult MonthlySales()
{
- ViewBag.ApiMontlySales = _baseConfig["ApiUrl"] + "sales/getmonthlysales";
+ ViewBag.ApiMontlySales = _baseConfig!["ApiUrl"] + "sales/getmonthlysales";
return View();
}
}
diff --git a/src/AccountGoWeb/Controllers/FinancialsController.cs b/src/AccountGoWeb/Controllers/FinancialsController.cs
index bbe60f680..f33c1b61f 100644
--- a/src/AccountGoWeb/Controllers/FinancialsController.cs
+++ b/src/AccountGoWeb/Controllers/FinancialsController.cs
@@ -1,196 +1,215 @@
using Microsoft.AspNetCore.Mvc;
-using System.Collections.Generic;
namespace AccountGoWeb.Controllers
{
- [Microsoft.AspNetCore.Authorization.Authorize]
- public class FinancialsController : BaseController
+ //[Microsoft.AspNetCore.Authorization.Authorize]
+ public class FinancialsController : BaseController
+ {
+ private readonly ILogger _logger;
+
+ public FinancialsController(IConfiguration config, ILogger logger)
{
- public FinancialsController(Microsoft.Extensions.Configuration.IConfiguration config)
- {
- _baseConfig = config;
- }
+ _baseConfig = config;
+ _logger = logger;
+ }
- public IActionResult AddJournalEntry()
- {
- ViewBag.PageContentHeader = "Add Journal Entry";
- return View();
- }
+ public IActionResult AddJournalEntry()
+ {
+ ViewBag.PageContentHeader = "Add Journal Entry";
+ return View();
+ }
- public IActionResult JournalEntry(int id)
- {
- ViewBag.PageContentHeader = "Journal Entry";
- return View();
- }
+ public IActionResult JournalEntry(int id)
+ {
+ ViewBag.PageContentHeader = "Journal Entry";
+ return View();
+ }
- public async System.Threading.Tasks.Task Accounts()
+ public async Task Accounts()
+ {
+ ViewBag.PageContentHeader = "Chart of Accounts";
+
+ using (var client = new System.Net.Http.HttpClient())
+ {
+ var baseUri = _baseConfig!["ApiUrl"];
+ _logger.LogInformation($"+++++++++++++++ baseUri={baseUri} +++++++++++++++");
+ client.BaseAddress = new System.Uri(baseUri!);
+ client.DefaultRequestHeaders.Accept.Clear();
+ var response = await client.GetAsync(baseUri + "financials/accounts");
+ if (response.IsSuccessStatusCode)
{
- ViewBag.PageContentHeader = "Accounts";
-
- using (var client = new System.Net.Http.HttpClient())
- {
- var baseUri = _baseConfig["ApiUrl"];
- client.BaseAddress = new System.Uri(baseUri);
- client.DefaultRequestHeaders.Accept.Clear();
- var response = await client.GetAsync(baseUri + "financials/accounts");
- if (response.IsSuccessStatusCode)
- {
- var responseJson = await response.Content.ReadAsStringAsync();
- return View(model: responseJson);
- }
- }
-
- return View();
+ var responseJson = await response.Content.ReadAsStringAsync();
+ var accountModels = Newtonsoft.Json.JsonConvert.DeserializeObject>(responseJson);
+ return View(accountModels);
}
+ }
+
+ return View();
+ }
+
+ public async Task Account(int? id = null)
+ {
+ Dto.Financial.Account? accountModel = null;
+ if (id == null)
+ {
+ accountModel = new Dto.Financial.Account();
+ }
+ else
+ {
+ accountModel = await GetAsync("financials/account?id=" + id);
+ }
+
+ ViewBag.PageContentHeader = "Account";
+ return View(accountModel);
+ }
- public async System.Threading.Tasks.Task Account(int? id = null)
+ public async System.Threading.Tasks.Task JournalEntries()
+ {
+ ViewBag.PageContentHeader = "Journal Entries";
+
+ using (var client = new System.Net.Http.HttpClient())
+ {
+ var baseUri = _baseConfig!["ApiUrl"];
+ client.BaseAddress = new System.Uri(baseUri!);
+ client.DefaultRequestHeaders.Accept.Clear();
+ var response = await client.GetAsync(baseUri + "financials/journalentries");
+ if (response.IsSuccessStatusCode)
{
- Dto.Financial.Account accountModel = null;
- if (id == null)
- {
- accountModel = new Dto.Financial.Account();
- }
- else
- {
- accountModel = await GetAsync("financials/account?id=" + id);
- }
-
- ViewBag.PageContentHeader = "Account";
- return View(accountModel);
+ var responseJson = await response.Content.ReadAsStringAsync();
+ return View(model: responseJson);
}
+ }
+
+ return View();
+ }
- public async System.Threading.Tasks.Task JournalEntries()
+ public async System.Threading.Tasks.Task GeneralLedger()
+ {
+ ViewBag.PageContentHeader = "General Ledger";
+
+ using (var client = new System.Net.Http.HttpClient())
+ {
+ var baseUri = _baseConfig!["ApiUrl"];
+ client.BaseAddress = new System.Uri(baseUri!);
+ client.DefaultRequestHeaders.Accept.Clear();
+ var response = await client.GetAsync(baseUri + "financials/generalledger");
+ if (response.IsSuccessStatusCode)
{
- ViewBag.PageContentHeader = "Journal Entries";
-
- using (var client = new System.Net.Http.HttpClient())
- {
- var baseUri = _baseConfig["ApiUrl"];
- client.BaseAddress = new System.Uri(baseUri);
- client.DefaultRequestHeaders.Accept.Clear();
- var response = await client.GetAsync(baseUri + "financials/journalentries");
- if (response.IsSuccessStatusCode)
- {
- var responseJson = await response.Content.ReadAsStringAsync();
- return View(model: responseJson);
- }
- }
-
- return View();
+ var responseJson = await response.Content.ReadAsStringAsync();
+ return View(model: responseJson);
}
+ }
+
+ return View();
+ }
- public async System.Threading.Tasks.Task GeneralLedger()
+ public async System.Threading.Tasks.Task TrialBalance()
+ {
+ ViewBag.PageContentHeader = "Trial Balance";
+
+ using (var client = new System.Net.Http.HttpClient())
+ {
+ var baseUri = _baseConfig!["ApiUrl"];
+ client.BaseAddress = new System.Uri(baseUri!);
+ client.DefaultRequestHeaders.Accept.Clear();
+ var response = await client.GetAsync(baseUri + "financials/trialbalance");
+ if (response.IsSuccessStatusCode)
{
- ViewBag.PageContentHeader = "General Ledger";
-
- using (var client = new System.Net.Http.HttpClient())
- {
- var baseUri = _baseConfig["ApiUrl"];
- client.BaseAddress = new System.Uri(baseUri);
- client.DefaultRequestHeaders.Accept.Clear();
- var response = await client.GetAsync(baseUri + "financials/generalledger");
- if (response.IsSuccessStatusCode)
- {
- var responseJson = await response.Content.ReadAsStringAsync();
- return View(model: responseJson);
- }
- }
-
- return View();
+ var responseJson = await response.Content.ReadAsStringAsync();
+ var trialBalanceModel = Newtonsoft.Json.JsonConvert.DeserializeObject>(responseJson);
+ return View(trialBalanceModel);
}
+ }
+
+ return View();
+ }
- public async System.Threading.Tasks.Task TrialBalance()
+ public async System.Threading.Tasks.Task BalanceSheet()
+ {
+ ViewBag.PageContentHeader = "Balance Sheet";
+
+ using (var client = new System.Net.Http.HttpClient())
+ {
+ var baseUri = _baseConfig!["ApiUrl"];
+ client.BaseAddress = new System.Uri(baseUri!);
+ client.DefaultRequestHeaders.Accept.Clear();
+ var response = await client.GetAsync(baseUri + "financials/balancesheet");
+ if (response.IsSuccessStatusCode)
{
- ViewBag.PageContentHeader = "Trial Balance";
-
- using (var client = new System.Net.Http.HttpClient())
- {
- var baseUri = _baseConfig["ApiUrl"];
- client.BaseAddress = new System.Uri(baseUri);
- client.DefaultRequestHeaders.Accept.Clear();
- var response = await client.GetAsync(baseUri + "financials/trialbalance");
- if (response.IsSuccessStatusCode)
- {
- var responseJson = await response.Content.ReadAsStringAsync();
- var trialBalanceModel = Newtonsoft.Json.JsonConvert.DeserializeObject>(responseJson);
- return View(trialBalanceModel);
- }
- }
-
- return View();
+ var responseJson = await response.Content.ReadAsStringAsync();
+ var balanceSheetModel = Newtonsoft.Json.JsonConvert.DeserializeObject>(responseJson);
+ return View(balanceSheetModel);
}
+ }
+ return View();
+ // return View(new List()); // Use this statement to test the view with an empty balance sheet
+
+ //var Dto = _financialService.BalanceSheet().ToList();
+ //var dt = Helpers.CollectionHelper.ConvertTo(Dto);
+ //var incomestatement = _financialService.IncomeStatement();
+ //var netincome = incomestatement.Where(a => a.IsExpense == false).Sum(a => a.Amount) - incomestatement.Where(a => a.IsExpense == true).Sum(a => a.Amount);
+
+ // TODO: Add logic to get the correct account for accumulated profit/loss. Currently, the account code is hard-coded here.
+ // Solution 1: Add two columns in general ledger setting for the account id of accumulated profit and loss.
+ // Solution 2: Add column to Account table to flag if account is net income (profit and loss)
+ //if (netincome < 0)
+ //{
+ // var loss = Dto.Where(a => a.AccountCode == "30500").FirstOrDefault();
+ // loss.Amount = netincome;
+ //}
+ //else
+ //{
+ // var profit = Dto.Where(a => a.AccountCode == "30400").FirstOrDefault();
+ // profit.Amount = netincome;
+ //}
+
+ //return View(Dto);
+ }
+
+ public async Task IncomeStatement()
+ {
+ ViewBag.PageContentHeader = "Income Statement";
+
+ using (var client = new System.Net.Http.HttpClient())
+ {
+ var baseUri = _baseConfig!["ApiUrl"];
+ client.BaseAddress = new System.Uri(baseUri!);
+ client.DefaultRequestHeaders.Accept.Clear();
- public async System.Threading.Tasks.Task BalanceSheet()
+ try
{
- ViewBag.PageContentHeader = "Balance Sheet";
-
- using (var client = new System.Net.Http.HttpClient())
- {
- var baseUri = _baseConfig["ApiUrl"];
- client.BaseAddress = new System.Uri(baseUri);
- client.DefaultRequestHeaders.Accept.Clear();
- var response = await client.GetAsync(baseUri + "financials/balancesheet");
- if (response.IsSuccessStatusCode)
- {
- var responseJson = await response.Content.ReadAsStringAsync();
- var balanceSheetModel = Newtonsoft.Json.JsonConvert.DeserializeObject>(responseJson);
- return View(balanceSheetModel);
- }
- }
-
- return View();
- //var Dto = _financialService.BalanceSheet().ToList();
- //var dt = Helpers.CollectionHelper.ConvertTo(Dto);
- //var incomestatement = _financialService.IncomeStatement();
- //var netincome = incomestatement.Where(a => a.IsExpense == false).Sum(a => a.Amount) - incomestatement.Where(a => a.IsExpense == true).Sum(a => a.Amount);
-
- // TODO: Add logic to get the correct account for accumulated profit/loss. Currently, the account code is hard-coded here.
- // Solution 1: Add two columns in general ledger setting for the account id of accumulated profit and loss.
- // Solution 2: Add column to Account table to flag if account is net income (profit and loss)
- //if (netincome < 0)
- //{
- // var loss = Dto.Where(a => a.AccountCode == "30500").FirstOrDefault();
- // loss.Amount = netincome;
- //}
- //else
- //{
- // var profit = Dto.Where(a => a.AccountCode == "30400").FirstOrDefault();
- // profit.Amount = netincome;
- //}
-
- //return View(Dto);
+ var response = await client.GetAsync(baseUri + "financials/incomestatement");
+ if (response.IsSuccessStatusCode)
+ {
+ var responseJson = await response.Content.ReadAsStringAsync();
+ var incomeStatementModel = Newtonsoft.Json.JsonConvert.DeserializeObject>(responseJson);
+ return View(incomeStatementModel);
+ }
+ else
+ {
+ ViewBag.Error = "Failed to fetch income statement data.";
+ }
}
-
- public async System.Threading.Tasks.Task IncomeStatement()
+ catch (Exception ex)
{
- ViewBag.PageContentHeader = "Income Statement";
-
- using (var client = new System.Net.Http.HttpClient())
- {
- var baseUri = _baseConfig["ApiUrl"];
- client.BaseAddress = new System.Uri(baseUri);
- client.DefaultRequestHeaders.Accept.Clear();
- var response = await client.GetAsync(baseUri + "financials/incomestatement");
- if (response.IsSuccessStatusCode)
- {
- var responseJson = await response.Content.ReadAsStringAsync();
- var incomeStatementModel = Newtonsoft.Json.JsonConvert.DeserializeObject>(responseJson);
- return View(incomeStatementModel);
- }
- }
-
- return View();
- //var Dto = _financialService.IncomeStatement();
- //return View(Dto);
+ ViewBag.Error = $"Error: {ex.Message}";
}
+ }
- public IActionResult Banks()
- {
- ViewBag.PageContentHeader = "Cash/Banks";
+ return View(new List());
+ }
- var banks = GetAsync>("financials/cashbanks").Result;
- return View(banks);
- }
+ public IActionResult Banks()
+ {
+ ViewBag.PageContentHeader = "Cash/Banks";
+
+ var banks = GetAsync>("financials/cashbanks").Result;
+
+ return View(banks);
}
+
+
+
+ }
}
diff --git a/src/AccountGoWeb/Controllers/GoodController.cs b/src/AccountGoWeb/Controllers/GoodController.cs
new file mode 100644
index 000000000..93b676218
--- /dev/null
+++ b/src/AccountGoWeb/Controllers/GoodController.cs
@@ -0,0 +1,74 @@
+using Microsoft.AspNetCore.Mvc;
+
+namespace AccountGoWeb.Controllers
+{
+ public class GoodController : Controller
+ {
+ protected IConfiguration? _configuration;
+
+ protected HttpResponseMessage Get(string uri)
+ {
+ string responseJson = string.Empty;
+ using (var client = new HttpClient())
+ {
+ string? baseUri = _configuration!["ApiUrl"];
+ client.BaseAddress = new System.Uri(baseUri!);
+ client.DefaultRequestHeaders.Accept.Clear();
+ var response = client.GetAsync(baseUri + uri);
+ return response.Result;
+ }
+ }
+
+ protected HttpResponseMessage Post(string uri, StringContent data)
+ {
+ string responseJson = string.Empty;
+ using (var client = new HttpClient())
+ {
+ string? baseUri = _configuration!["ApiUrl"];
+ client.BaseAddress = new System.Uri(baseUri!);
+ client.DefaultRequestHeaders.Accept.Clear();
+ client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
+ //client.DefaultRequestHeaders.Add("UserName", GetCurrentUserName());
+
+ var response = client.PostAsync(baseUri + uri, data);
+ return response.Result;
+ }
+ }
+
+ protected async System.Threading.Tasks.Task GetAsync(string uri)
+ {
+ string responseJson = string.Empty;
+ using (var client = new HttpClient())
+ {
+ string? baseUri = _configuration!["ApiUrl"];
+ client.BaseAddress = new System.Uri(baseUri!);
+ client.DefaultRequestHeaders.Accept.Clear();
+ var response = await client.GetAsync(baseUri + uri);
+ if (response.IsSuccessStatusCode)
+ {
+ responseJson = await response.Content.ReadAsStringAsync();
+ }
+ }
+ return Newtonsoft.Json.JsonConvert.DeserializeObject(responseJson)!;
+ }
+
+ protected async System.Threading.Tasks.Task PostAsync(string uri, StringContent data)
+ {
+ string responseJson = string.Empty;
+ using (var client = new HttpClient())
+ {
+ string? baseUri = _configuration!["ApiUrl"];
+ client.BaseAddress = new System.Uri(baseUri!);
+ client.DefaultRequestHeaders.Accept.Clear();
+ //client.DefaultRequestHeaders.Add("UserName", GetCurrentUserName());
+
+ var response = await client.PostAsync(baseUri + uri, data);
+ if (response.IsSuccessStatusCode)
+ {
+ responseJson = await response.Content.ReadAsStringAsync();
+ }
+ }
+ return Newtonsoft.Json.JsonConvert.DeserializeObject(responseJson)!;
+ }
+ }
+}
diff --git a/src/AccountGoWeb/Controllers/HomeController.cs b/src/AccountGoWeb/Controllers/HomeController.cs
index d7b5a2def..ee4b0b00a 100644
--- a/src/AccountGoWeb/Controllers/HomeController.cs
+++ b/src/AccountGoWeb/Controllers/HomeController.cs
@@ -1,9 +1,8 @@
using Microsoft.AspNetCore.Mvc;
-using Microsoft.Extensions.Configuration;
namespace AccountGoWeb.Controllers
{
- [Microsoft.AspNetCore.Authorization.Authorize]
+ //[Microsoft.AspNetCore.Authorization.Authorize]
public class HomeController : BaseController
{
public HomeController(IConfiguration config)
@@ -14,7 +13,7 @@ public HomeController(IConfiguration config)
public IActionResult Index()
{
ViewBag.PageContentHeader = "Dashboard";
- ViewBag.ApiMontlySales = _baseConfig["ApiUrl"] + "sales/getmonthlysales";
+ ViewBag.ApiMontlySales = _baseConfig!["ApiUrl"] + "sales/getmonthlysales";
return View();
}
}
diff --git a/src/AccountGoWeb/Controllers/InventoryController.cs b/src/AccountGoWeb/Controllers/InventoryController.cs
index e15c5645b..e357ecce3 100644
--- a/src/AccountGoWeb/Controllers/InventoryController.cs
+++ b/src/AccountGoWeb/Controllers/InventoryController.cs
@@ -1,26 +1,28 @@
using Dto.Inventory;
using Microsoft.AspNetCore.Mvc;
-using System.Net.Http;
namespace AccountGoWeb.Controllers
{
- [Microsoft.AspNetCore.Authorization.Authorize]
+ // [Microsoft.AspNetCore.Authorization.Authorize]
public class InventoryController : BaseController
{
- public InventoryController(Microsoft.Extensions.Configuration.IConfiguration config)
+ private readonly ILogger _logger;
+ public InventoryController(Microsoft.Extensions.Configuration.IConfiguration config,
+ ILogger logger)
{
_baseConfig = config;
Models.SelectListItemHelper._config = config;
+ _logger = logger;
}
- public async System.Threading.Tasks.Task Items()
+ public async Task Index()
{
ViewBag.PageContentHeader = "Items";
using (var client = new System.Net.Http.HttpClient())
{
- var baseUri = _baseConfig["ApiUrl"];
- client.BaseAddress = new System.Uri(baseUri);
+ var baseUri = _baseConfig!["ApiUrl"];
+ client.BaseAddress = new System.Uri(baseUri!);
client.DefaultRequestHeaders.Accept.Clear();
var response = await client.GetAsync(baseUri + "inventory/items");
if (response.IsSuccessStatusCode)
@@ -33,14 +35,14 @@ public async System.Threading.Tasks.Task Items()
return View();
}
- public async System.Threading.Tasks.Task ICJ()
+ public async Task ICJ()
{
ViewBag.PageContentHeader = "Inventory Control Journal";
using (var client = new System.Net.Http.HttpClient())
{
- var baseUri = _baseConfig["ApiUrl"];
- client.BaseAddress = new System.Uri(baseUri);
+ var baseUri = _baseConfig!["ApiUrl"];
+ client.BaseAddress = new System.Uri(baseUri!);
client.DefaultRequestHeaders.Accept.Clear();
var response = await client.GetAsync(baseUri + "inventory/icj");
if (response.IsSuccessStatusCode)
@@ -53,9 +55,10 @@ public async System.Threading.Tasks.Task ICJ()
return View();
}
- public IActionResult Item(int id = -1)
+ public IActionResult Item(int id)
{
- Item itemModel = null;
+ _logger.LogInformation("GetItem: " + id);
+ Item? itemModel = null;
if (id == -1)
{
ViewBag.PageContentHeader = "Item Customer";
@@ -76,6 +79,39 @@ public IActionResult Item(int id = -1)
return View(itemModel);
}
+ public IActionResult AddItem(){
+ ViewBag.PageContentHeader = "New Item";
+
+ ViewBag.ItemCategories = Models.SelectListItemHelper.ItemCategories();
+ ViewBag.Measurements = Models.SelectListItemHelper.UnitOfMeasurements();
+ ViewBag.ItemTaxGroups = Models.SelectListItemHelper.ItemTaxGroups();
+ ViewBag.PreferredVendorId = Models.SelectListItemHelper.Vendors();
+ ViewBag.Accounts = Models.SelectListItemHelper.Accounts();
+
+ Item itemModel = new Item();
+
+ return View(itemModel);
+ }
+
+ [HttpPost]
+ public IActionResult AddItem(Item itemModel){
+ ViewBag.PageContentHeader = "New Item";
+
+ if (ModelState.IsValid) {
+ _logger.LogInformation("Item Model is Valid: " + itemModel.Description);
+ var serialize = Newtonsoft.Json.JsonConvert.SerializeObject(itemModel);
+ var content = new StringContent(serialize);
+ content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json");
+ var response = Post("Inventory/SaveItem", content);
+ _logger.LogInformation("Response: " + response);
+ if (response.IsSuccessStatusCode)
+ return RedirectToAction("Items");
+ }
+
+ return View(itemModel);
+ }
+
+ [HttpPost]
public IActionResult SaveItem(Item itemModel)
{
if (ModelState.IsValid)
@@ -86,7 +122,7 @@ public IActionResult SaveItem(Item itemModel)
var response = PostAsync("inventory/saveitem", content);
- return RedirectToAction("Items");
+ return RedirectToAction("Index");
}
ViewBag.Accounts = Models.SelectListItemHelper.Accounts();
@@ -94,13 +130,12 @@ public IActionResult SaveItem(Item itemModel)
ViewBag.Measurements = Models.SelectListItemHelper.UnitOfMeasurements();
ViewBag.ItemCategories = Models.SelectListItemHelper.ItemCategories();
-
if (itemModel.Id > 0)
ViewBag.PageContentHeader = "Item Item";
else
ViewBag.PageContentHeader = "New Card";
- return View("Item", itemModel);
+ return View("Index");
}
}
}
diff --git a/src/AccountGoWeb/Controllers/PurchasingController.cs b/src/AccountGoWeb/Controllers/PurchasingController.cs
index d8215259c..e51d8364e 100644
--- a/src/AccountGoWeb/Controllers/PurchasingController.cs
+++ b/src/AccountGoWeb/Controllers/PurchasingController.cs
@@ -1,16 +1,17 @@
-using Microsoft.AspNetCore.Mvc;
-using Microsoft.Extensions.Configuration;
-using System.Net.Http;
+using Dto.Purchasing;
+using Microsoft.AspNetCore.Mvc;
namespace AccountGoWeb.Controllers
{
- [Microsoft.AspNetCore.Authorization.Authorize]
+ //[Microsoft.AspNetCore.Authorization.Authorize]
public class PurchasingController : BaseController
{
- public PurchasingController(IConfiguration config)
+ private readonly ILogger _logger;
+ public PurchasingController(IConfiguration config, ILogger logger)
{
_baseConfig = config;
Models.SelectListItemHelper._config = config;
+ _logger = logger;
}
public IActionResult Index()
@@ -24,7 +25,7 @@ public IActionResult PurchaseOrders()
string purchaseOrders = GetAsync("purchasing/purchaseorders")
.Result
- .ToString();
+ .ToString()!;
return View(model: purchaseOrders);
}
@@ -32,21 +33,106 @@ public IActionResult PurchaseOrders()
public IActionResult AddPurchaseOrder()
{
ViewBag.PageContentHeader = "Add Purchase Order";
+ PurchaseOrder purchaseOrderModel = new PurchaseOrder();
+ purchaseOrderModel.PurchaseOrderLines = new List { new PurchaseOrderLine {
+ Amount = 0,
+ Discount = 0,
+ ItemId = 1,
+ Quantity = 1,
+ } };
+ purchaseOrderModel.No = new System.Random().Next(1, 99999).ToString();
ViewBag.Vendors = Models.SelectListItemHelper.Vendors();
+ ViewBag.PaymentTerms = Models.SelectListItemHelper.PaymentTerms();
+ ViewBag.Items = Models.SelectListItemHelper.Items();
+ ViewBag.Measurements = Models.SelectListItemHelper.Measurements();
- return View();
+ return View(purchaseOrderModel);
+ }
+
+ [HttpPost]
+ public IActionResult AddPurchaseOrder(PurchaseOrder purchaseOrder, string addRowBtn)
+ {
+ ViewBag.PageContentHeader = "Add Purchase Order";
+
+ if (!string.IsNullOrEmpty(addRowBtn))
+ {
+ purchaseOrder.PurchaseOrderLines.Add(new PurchaseOrderLine
+ {
+ Amount = 0,
+ Discount = 0,
+ ItemId = 1,
+ Quantity = 1
+ });
+
+ ViewBag.Vendors = Models.SelectListItemHelper.Vendors();
+ ViewBag.PaymentTerms = Models.SelectListItemHelper.PaymentTerms();
+ ViewBag.Items = Models.SelectListItemHelper.Items();
+ ViewBag.Measurements = Models.SelectListItemHelper.Measurements();
+
+ return View(purchaseOrder);
+ }
+ else if (ModelState.IsValid)
+ {
+ var serialize = Newtonsoft.Json.JsonConvert.SerializeObject(purchaseOrder);
+ var content = new StringContent(serialize);
+ content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json");
+
+ var response = PostAsync("purchasing/savepurchaseorder", content);
+
+ return RedirectToAction("PurchaseOrders");
+ }
+
+ return View("PurchaseOrders");
+ }
+
+ public IActionResult PurchaseInvoice(int id)
+ {
+ ViewBag.PageContentHeader = "Purchase Invoice";
+
+ PurchaseInvoice? purchaseInvoiceModel = null;
+
+ if (id == 0)
+ {
+ ViewBag.PageContentHeader = "New Purchase Invoice";
+ return View("PurchaseInvoice");
+ }
+ else
+ {
+ purchaseInvoiceModel = GetAsync("Purchasing/PurchaseInvoice?id=" + id).Result;
+ }
+
+ ViewBag.Vendors = Models.SelectListItemHelper.Vendors();
+ ViewBag.PaymentTerms = Models.SelectListItemHelper.PaymentTerms();
+ ViewBag.Items = Models.SelectListItemHelper.Items();
+ ViewBag.Measurements = Models.SelectListItemHelper.Measurements();
+
+ return View(purchaseInvoiceModel);
}
- public IActionResult PurchaseOrder(int purchId = 0)
+
+ public IActionResult PurchaseOrder(int id)
{
ViewBag.PageContentHeader = "Purchase Order";
- var purchOrderDto = GetAsync("purchasing/purchaseorder?id=" + purchId).Result;
+ PurchaseOrder? purchaseOrderModel = null;
+
+ if (id == 0)
+ {
+ ViewBag.PageContentHeader = "New Purchase Order";
+ return View();
+ }
+ else
+ {
+ purchaseOrderModel = GetAsync("Purchasing/PurchaseOrder?id=" + id).Result;
+ }
ViewBag.Vendors = Models.SelectListItemHelper.Vendors();
+ ViewBag.PaymentTerms = Models.SelectListItemHelper.PaymentTerms();
+ ViewBag.Items = Models.SelectListItemHelper.Items();
+ ViewBag.Measurements = Models.SelectListItemHelper.Measurements();
- return View();
+ return View(purchaseOrderModel);
}
public async System.Threading.Tasks.Task PurchaseInvoices()
@@ -54,8 +140,8 @@ public async System.Threading.Tasks.Task PurchaseInvoices()
ViewBag.PageContentHeader = "Purchase Invoices";
using (var client = new HttpClient())
{
- var baseUri = _baseConfig["ApiUrl"];
- client.BaseAddress = new System.Uri(baseUri);
+ var baseUri = _baseConfig!["ApiUrl"];
+ client.BaseAddress = new System.Uri(baseUri!);
client.DefaultRequestHeaders.Accept.Clear();
var response = await client.GetAsync(baseUri + "purchasing/purchaseinvoices");
if (response.IsSuccessStatusCode)
@@ -67,18 +153,59 @@ public async System.Threading.Tasks.Task PurchaseInvoices()
return View();
}
- public IActionResult AddPurchaseInvoice(int purchId = 0)
+ public IActionResult AddPurchaseInvoice()
{
ViewBag.PageContentHeader = "New Invoice";
- return View();
+ PurchaseInvoice purchaseInvoiceModel = new PurchaseInvoice();
+ purchaseInvoiceModel.PurchaseInvoiceLines = new List { new PurchaseInvoiceLine {
+ Amount = 0,
+ Discount = 0,
+ ItemId = 1,
+ Quantity = 1,
+ } };
+ purchaseInvoiceModel.No = new System.Random().Next(1, 99999).ToString();
+
+ ViewBag.Vendors = Models.SelectListItemHelper.Vendors();
+ ViewBag.PaymentTerms = Models.SelectListItemHelper.PaymentTerms();
+ ViewBag.Items = Models.SelectListItemHelper.Items();
+ ViewBag.Measurements = Models.SelectListItemHelper.Measurements();
+
+ return View(purchaseInvoiceModel);
}
- public IActionResult PurchaseInvoice(int id)
+ [HttpPost]
+ public async System.Threading.Tasks.Task AddPurchaseInvoice(PurchaseInvoice purchaseInvoice, string addRowBtn)
{
- ViewBag.PageContentHeader = "Purchase Invoice";
+ ViewBag.PageContentHeader = "New Invoice";
+ if (!string.IsNullOrEmpty(addRowBtn))
+ {
+ purchaseInvoice.PurchaseInvoiceLines.Add(new PurchaseInvoiceLine
+ {
+ Amount = 0,
+ Discount = 0,
+ ItemId = 1,
+ Quantity = 1
+ });
- ViewBag.Vendors = Models.SelectListItemHelper.Vendors();
+ ViewBag.Vendors = Models.SelectListItemHelper.Vendors();
+ ViewBag.PaymentTerms = Models.SelectListItemHelper.PaymentTerms();
+ ViewBag.Items = Models.SelectListItemHelper.Items();
+ ViewBag.Measurements = Models.SelectListItemHelper.Measurements();
+
+ return View(purchaseInvoice);
+ }
+ else if (ModelState.IsValid)
+ {
+ var serialize = Newtonsoft.Json.JsonConvert.SerializeObject(purchaseInvoice);
+ var content = new StringContent(serialize);
+ content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json");
+
+ var response = await PostAsync("Purchasing/SavePurchaseInvoice", content);
+ _logger.LogInformation("Purchase Invoice Saved" + purchaseInvoice.Id);
+
+ return RedirectToAction("PurchaseInvoices");
+ }
return View();
}
@@ -95,8 +222,8 @@ public async System.Threading.Tasks.Task Vendors()
ViewBag.PageContentHeader = "Vendors";
using (var client = new HttpClient())
{
- var baseUri = _baseConfig["ApiUrl"];
- client.BaseAddress = new System.Uri(baseUri);
+ var baseUri = _baseConfig!["ApiUrl"];
+ client.BaseAddress = new System.Uri(baseUri!);
client.DefaultRequestHeaders.Accept.Clear();
var response = await client.GetAsync(baseUri + "purchasing/vendors");
if (response.IsSuccessStatusCode)
@@ -109,7 +236,7 @@ public async System.Threading.Tasks.Task Vendors()
}
public IActionResult Vendor(int id = -1)
{
- Dto.Purchasing.Vendor vendorModel = null;
+ Dto.Purchasing.Vendor? vendorModel = null;
if (id == -1)
{
ViewBag.PageContentHeader = "New Vendor";
@@ -169,7 +296,7 @@ public IActionResult Payment(int id)
VendorId = invoice.VendorId,
VendorName = invoice.VendorName,
InvoiceAmount = invoice.Amount,
- AmountPaid = invoice.AmountPaid,
+ AmountPaid = invoice.AmountPaid,
Date = invoice.InvoiceDate
};
@@ -177,7 +304,7 @@ public IActionResult Payment(int id)
return View(model);
}
-
+
[HttpPost]
public IActionResult Payment(Models.Purchasing.Payment model)
{
diff --git a/src/AccountGoWeb/Controllers/QuotationsController.cs b/src/AccountGoWeb/Controllers/QuotationsController.cs
index cbe402648..85174e4b1 100644
--- a/src/AccountGoWeb/Controllers/QuotationsController.cs
+++ b/src/AccountGoWeb/Controllers/QuotationsController.cs
@@ -1,14 +1,17 @@
-using System.Net.Http;
+using Dto.Sales;
using Microsoft.AspNetCore.Mvc;
-using Microsoft.Extensions.Configuration;
namespace AccountGoWeb.Controllers
{
- [Microsoft.AspNetCore.Authorization.Authorize]
- public class QuotationsController : BaseController
+ //[Microsoft.AspNetCore.Authorization.Authorize]
+ public class QuotationsController : GoodController
{
- public QuotationsController(IConfiguration config) {
- _baseConfig = config;
+ //private readonly IConfiguration _configuration;
+ private readonly ILogger _logger;
+ public QuotationsController(IConfiguration config, ILogger logger)
+ {
+ _configuration = config;
+ _logger = logger;
}
public IActionResult Index()
@@ -22,8 +25,8 @@ public async System.Threading.Tasks.Task Quotations()
using (var client = new HttpClient())
{
- var baseUri = _baseConfig["ApiUrl"];
- client.BaseAddress = new System.Uri(baseUri);
+ var baseUri = _configuration!["ApiUrl"];
+ client.BaseAddress = new System.Uri(baseUri!);
client.DefaultRequestHeaders.Accept.Clear();
var response = await client.GetAsync(baseUri + "sales/quotations");
if (response.IsSuccessStatusCode)
@@ -36,18 +39,106 @@ public async System.Threading.Tasks.Task Quotations()
return View();
}
+ [HttpGet]
public IActionResult AddSalesQuotation()
{
ViewBag.PageContentHeader = "Add Sales Quotation";
- return View();
+ SalesQuotation model = new SalesQuotation();
+ model.SalesQuotationLines = new List { new SalesQuotationLine {
+ Amount = 0,
+ Quantity = 1,
+ Discount = 0,
+ ItemId = 1,
+ MeasurementId = 1,
+ } };
+ model.No = new System.Random().Next(1, 99999).ToString(); // TODO: Replace with system generated numbering.
+
+ ViewBag.Customers = Models.SelectListItemHelper.Customers();
+ ViewBag.Items = Models.SelectListItemHelper.Items();
+ ViewBag.PaymentTerms = Models.SelectListItemHelper.PaymentTerms();
+ ViewBag.Measurements = Models.SelectListItemHelper.Measurements();
+
+ return View(model);
}
- public IActionResult Quotation()
+ [HttpPost]
+ public async Task AddSalesQuotation(Dto.Sales.SalesQuotation model, string? addRowBtn)
{
- ViewBag.PageContentHeader = "Sales Quotation";
+ if (!string.IsNullOrEmpty(addRowBtn))
+ {
+ _logger.LogInformation("Add Row Button Clicked");
+ model.SalesQuotationLines.Add(new SalesQuotationLine
+ {
+ Amount = 0,
+ Quantity = 1,
+ Discount = 0,
+ ItemId = 1,
+ MeasurementId = 1,
+ });
+ ViewBag.Customers = Models.SelectListItemHelper.Customers();
+ ViewBag.Items = Models.SelectListItemHelper.Items();
+ ViewBag.PaymentTerms = Models.SelectListItemHelper.PaymentTerms();
+ ViewBag.Measurements = Models.SelectListItemHelper.Measurements();
- return View();
+ return View(model);
+
+ }
+ else if (ModelState.IsValid)
+ {
+ var serialize = Newtonsoft.Json.JsonConvert.SerializeObject(model);
+ var content = new StringContent(serialize);
+ content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json");
+
+ using (var client = new HttpClient())
+ {
+ var baseUri = _configuration!["ApiUrl"];
+ client.BaseAddress = new Uri(baseUri!);
+ var response = await client.PostAsync("sales/savequotation", content);
+
+ if (response.IsSuccessStatusCode) {
+ _logger.LogInformation("Quotation has been successfully saved.");
+ } else {
+ _logger.LogInformation("Quotation save failed.");
+ }
+ return RedirectToAction("quotations");
+ }
+ } else {
+ _logger.LogInformation("Model State is not valid.");
+ return RedirectToAction("quotations");
+ }
+
+ }
+
+ [HttpGet]
+ public IActionResult Quotation(int id)
+ {
+ ViewBag.PageContentHeader = "Sales";
+
+ SalesQuotation? model = null;
+
+ if (id == 0)
+ {
+ ViewBag.PageContentHeader = "Add Sales Quotation";
+ return View("AddSalesQuotation");
+ }
+ else
+ {
+ model = GetAsync("Sales/Quotation?id=" + id).Result;
+ @ViewBag.Id = model.Id;
+ @ViewBag.QuotationDate = model.QuotationDate;
+ @ViewBag.CustomerName = model.CustomerName;
+ @ViewBag.PaymentTermId = model.PaymentTermId;
+ @ViewBag.SalesQuotationLines = model.SalesQuotationLines;
+ @ViewBag.TotalAmount = model.Amount;
+ }
+
+ @ViewBag.Customers = Models.SelectListItemHelper.Customers();
+ ViewBag.Items = Models.SelectListItemHelper.Items();
+ @ViewBag.PaymentTerms = Models.SelectListItemHelper.PaymentTerms();
+ @ViewBag.Measurements = Models.SelectListItemHelper.Measurements();
+
+ return View(model);
}
}
}
diff --git a/src/AccountGoWeb/Controllers/SPAProxyController.cs b/src/AccountGoWeb/Controllers/SPAProxyController.cs
index 67313350c..b17b3bbd4 100644
--- a/src/AccountGoWeb/Controllers/SPAProxyController.cs
+++ b/src/AccountGoWeb/Controllers/SPAProxyController.cs
@@ -1,10 +1,7 @@
-using System.Net.Http;
-using System.Text;
-using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
-using Microsoft.Extensions.Configuration;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
+using System.Text;
namespace AccountGoWeb.Controllers
{
diff --git a/src/AccountGoWeb/Controllers/SalesController.cs b/src/AccountGoWeb/Controllers/SalesController.cs
index ec582bf86..81ccb0eb9 100644
--- a/src/AccountGoWeb/Controllers/SalesController.cs
+++ b/src/AccountGoWeb/Controllers/SalesController.cs
@@ -1,19 +1,21 @@
using AccountGoWeb.Models;
using Dto.Sales;
using Microsoft.AspNetCore.Mvc;
-using Microsoft.Extensions.Configuration;
-using System.Collections.Generic;
-using System.Net.Http;
+using Newtonsoft.Json;
namespace AccountGoWeb.Controllers
{
- [Microsoft.AspNetCore.Authorization.Authorize]
- public class SalesController : BaseController
+ //[Microsoft.AspNetCore.Authorization.Authorize]
+ public class SalesController : GoodController
{
- public SalesController(IConfiguration config)
+ // private readonly IConfiguration _configuration;
+ private readonly ILogger _logger;
+
+ public SalesController(IConfiguration config, ILogger logger)
{
- _baseConfig = config;
+ _configuration = config;
Models.SelectListItemHelper._config = config;
+ _logger = logger;
}
public IActionResult Index()
@@ -26,8 +28,8 @@ public async System.Threading.Tasks.Task SalesOrders()
ViewBag.PageContentHeader = "Sales Orders";
using (var client = new HttpClient())
{
- var baseUri = _baseConfig["ApiUrl"];
- client.BaseAddress = new System.Uri(baseUri);
+ var baseUri = _configuration!["ApiUrl"];
+ client.BaseAddress = new System.Uri(baseUri!);
client.DefaultRequestHeaders.Accept.Clear();
var response = await client.GetAsync(baseUri + "sales/salesorders");
if (response.IsSuccessStatusCode)
@@ -42,26 +44,114 @@ public async System.Threading.Tasks.Task SalesOrders()
public IActionResult AddSalesOrder()
{
ViewBag.PageContentHeader = "Add Sales Order";
-
- return View();
+ SalesOrder salesOrderModel = new SalesOrder();
+ salesOrderModel.SalesOrderLines = new List { new SalesOrderLine {
+ Amount = 0,
+ Discount = 0,
+ ItemId = 1,
+ Quantity = 1,
+ } };
+ salesOrderModel.No = new System.Random().Next(1, 99999).ToString();
+
+ @ViewBag.Customers = Models.SelectListItemHelper.Customers();
+ @ViewBag.PaymentTerms = Models.SelectListItemHelper.PaymentTerms();
+ @ViewBag.Items = Models.SelectListItemHelper.Items();
+ @ViewBag.Measurements = Models.SelectListItemHelper.Measurements();
+
+ return View(salesOrderModel);
}
[HttpPost]
- public IActionResult AddSalesOrder(object Dto)
+ public IActionResult AddSalesOrder(SalesOrder Dto, string addRowBtn)
{
- return Ok();
+ if (!string.IsNullOrEmpty(addRowBtn))
+ {
+ Dto.SalesOrderLines.Add(new SalesOrderLine
+ {
+ Amount = 0,
+ Quantity = 1,
+ Discount = 0,
+ ItemId = 1,
+ MeasurementId = 1,
+ });
+
+ ViewBag.Customers = Models.SelectListItemHelper.Customers();
+ ViewBag.Items = Models.SelectListItemHelper.Items();
+ ViewBag.PaymentTerms = Models.SelectListItemHelper.PaymentTerms();
+ ViewBag.Measurements = Models.SelectListItemHelper.Measurements();
+
+ return View(Dto);
+ }
+ else if (ModelState.IsValid)
+ {
+ var serialize = Newtonsoft.Json.JsonConvert.SerializeObject(Dto);
+ var content = new StringContent(serialize);
+ content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json");
+
+ var response = Post("Sales/addsalesorder", content);
+ if (response.IsSuccessStatusCode)
+ return RedirectToAction("salesorders");
+ }
+ @ViewBag.Customers = Models.SelectListItemHelper.Customers();
+ @ViewBag.PaymentTerms = Models.SelectListItemHelper.PaymentTerms();
+ @ViewBag.Measurements = Models.SelectListItemHelper.Measurements();
+
+ return RedirectToAction("salesorders");
}
-
+
public IActionResult SalesOrder(int id)
{
ViewBag.PageContentHeader = "Sales Order";
- return View();
+ SalesOrder? salesOrderModel = null;
+ if (id == -1)
+ {
+ ViewBag.PageContentHeader = "Add Sales Order";
+ return View("AddSalesOrder");
+
+ }
+ else
+ {
+ salesOrderModel = GetAsync("Sales/SalesOrder?id=" + id).Result;
+ ViewBag.CustomerName = salesOrderModel.CustomerName;
+ ViewBag.OrderDate = salesOrderModel.OrderDate;
+ ViewBag.SalesOrderLines = salesOrderModel.SalesOrderLines;
+ ViewBag.TotalAmount = salesOrderModel.Amount;
+ }
+
+ @ViewBag.Customers = Models.SelectListItemHelper.Customers();
+ @ViewBag.PaymentTerms = Models.SelectListItemHelper.PaymentTerms();
+ @ViewBag.Items = Models.SelectListItemHelper.Items();
+ @ViewBag.Measurements = Models.SelectListItemHelper.Measurements();
+
+ return View(salesOrderModel);
}
public IActionResult SalesInvoice(int id)
{
ViewBag.PageContentHeader = "Sales Invoice";
- return View();
+ SalesInvoice? salesInvoiceModel = null;
+
+ if (id == 0)
+ {
+ ViewBag.PageContentHeader = "Add Sales Invoice";
+ return View("AddSalesInvoice");
+ }
+ else
+ {
+ salesInvoiceModel = GetAsync("Sales/SalesInvoice?id=" + id).Result;
+ ViewBag.Id = salesInvoiceModel.Id;
+ ViewBag.CustomerName = salesInvoiceModel.CustomerName;
+ ViewBag.InvoiceDate = salesInvoiceModel.InvoiceDate;
+ ViewBag.SalesInvoiceLines = salesInvoiceModel.SalesInvoiceLines;
+ ViewBag.TotalAmount = salesInvoiceModel.Amount;
+ }
+
+ @ViewBag.Customers = Models.SelectListItemHelper.Customers();
+ @ViewBag.PaymentTerms = Models.SelectListItemHelper.PaymentTerms();
+ @ViewBag.Items = Models.SelectListItemHelper.Items();
+ @ViewBag.Measurements = Models.SelectListItemHelper.Measurements();
+
+ return View("SalesInvoice", salesInvoiceModel);
}
public async System.Threading.Tasks.Task SalesInvoices()
@@ -69,8 +159,8 @@ public async System.Threading.Tasks.Task SalesInvoices()
ViewBag.PageContentHeader = "Sales Invoices";
using (var client = new HttpClient())
{
- var baseUri = _baseConfig["ApiUrl"];
- client.BaseAddress = new System.Uri(baseUri);
+ var baseUri = _configuration!["ApiUrl"];
+ client.BaseAddress = new System.Uri(baseUri!);
client.DefaultRequestHeaders.Accept.Clear();
var response = await client.GetAsync(baseUri + "sales/salesinvoices");
if (response.IsSuccessStatusCode)
@@ -78,47 +168,164 @@ public async System.Threading.Tasks.Task SalesInvoices()
var responseJson = await response.Content.ReadAsStringAsync();
return View(model: responseJson);
}
+
+ @ViewBag.Customers = Models.SelectListItemHelper.Customers();
+ @ViewBag.PaymentTerms = Models.SelectListItemHelper.PaymentTerms();
+ @ViewBag.Items = Models.SelectListItemHelper.Items();
+ @ViewBag.Measurements = Models.SelectListItemHelper.Measurements();
}
return View();
}
+ [HttpPost]
+ public async System.Threading.Tasks.Task SalesInvoice(SalesInvoice salesInvoiceModel)
+ {
+ if (ModelState.IsValid)
+ {
+ var serialize = Newtonsoft.Json.JsonConvert.SerializeObject(salesInvoiceModel);
+ var content = new StringContent(serialize);
+ content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json");
+ string ReadAsStringAsync = await content.ReadAsStringAsync();
+ _logger.LogInformation("SaveSalesInvoice: " + ReadAsStringAsync);
+ var response = Post("Sales/UpdateSalesInvoice", content);
+
+ if (response.IsSuccessStatusCode)
+ {
+ return RedirectToAction("SalesInvoices");
+ }
+ }
+
+ ViewBag.Customers = SelectListItemHelper.Customers();
+ ViewBag.PaymentTerms = SelectListItemHelper.PaymentTerms();
+ ViewBag.Items = SelectListItemHelper.Items();
+ ViewBag.Measurements = SelectListItemHelper.Measurements();
+ ViewBag.TotalAmount = salesInvoiceModel.Amount;
+
+ return View(salesInvoiceModel);
+ }
+
+ [HttpGet]
public IActionResult AddSalesInvoice()
{
ViewBag.PageContentHeader = "Add Sales Invoice";
- return View();
+ SalesInvoice salesInvoiceModel = new SalesInvoice();
+ salesInvoiceModel.SalesInvoiceLines = new List { new SalesInvoiceLine {
+ Amount = 0,
+ Discount = 0,
+ ItemId = 1,
+ Quantity = 1,
+ } };
+ salesInvoiceModel.No = new System.Random().Next(1, 99999).ToString(); // TODO: Replace with system generated numbering.
+
+ @ViewBag.Customers = Models.SelectListItemHelper.Customers();
+ @ViewBag.PaymentTerms = Models.SelectListItemHelper.PaymentTerms();
+ @ViewBag.Items = Models.SelectListItemHelper.Items();
+ @ViewBag.Measurements = Models.SelectListItemHelper.Measurements();
+
+ return View(salesInvoiceModel);
+ }
+
+ [HttpPost]
+ public async System.Threading.Tasks.Task AddSalesInvoice(SalesInvoice Dto, string? addRowBtn)
+ {
+ if (!string.IsNullOrEmpty(addRowBtn))
+ {
+ Dto.SalesInvoiceLines!.Add(new SalesInvoiceLine
+ {
+ Amount = 0,
+ Quantity = 1,
+ Discount = 0,
+ ItemId = 1,
+ MeasurementId = 1,
+ });
+
+ ViewBag.Customers = Models.SelectListItemHelper.Customers();
+ ViewBag.Items = Models.SelectListItemHelper.Items();
+ ViewBag.PaymentTerms = Models.SelectListItemHelper.PaymentTerms();
+ ViewBag.Measurements = Models.SelectListItemHelper.Measurements();
+
+ return View(Dto);
+ }
+ else if (ModelState.IsValid)
+ {
+ _logger.LogInformation("Posted value received: {Posted}", Dto.Posted);
+ var serialize = Newtonsoft.Json.JsonConvert.SerializeObject(Dto);
+ var content = new StringContent(serialize);
+ content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json");
+
+ _logger.LogInformation("AddSalesInvoice: " + await content.ReadAsStringAsync());
+ var response = Post("Sales/CreateSalesInvoice", content);
+
+ _logger.LogInformation("AddSalesInvoice response: " + response.ToString());
+ if (response.IsSuccessStatusCode)
+ return RedirectToAction("salesinvoices");
+ }
+
+ ViewBag.Customers = Models.SelectListItemHelper.Customers();
+ ViewBag.Items = Models.SelectListItemHelper.Items();
+ ViewBag.PaymentTerms = Models.SelectListItemHelper.PaymentTerms();
+ ViewBag.Measurements = Models.SelectListItemHelper.Measurements();
+
+ return View(Dto);
}
public async System.Threading.Tasks.Task SalesReceipts()
{
ViewBag.PageContentHeader = "Sales Receipts";
- using (var client = new HttpClient())
+ try
{
- var baseUri = _baseConfig["ApiUrl"];
- client.BaseAddress = new System.Uri(baseUri);
- client.DefaultRequestHeaders.Accept.Clear();
- var response = await client.GetAsync(baseUri + "sales/salesreceipts");
- if (response.IsSuccessStatusCode)
+ using (var client = new HttpClient())
{
- var responseJson = await response.Content.ReadAsStringAsync();
- return View(model: responseJson);
+ var baseUri = _configuration!["ApiUrl"];
+ client.BaseAddress = new Uri(baseUri!);
+ client.DefaultRequestHeaders.Accept.Clear();
+
+ var response = await client.GetAsync("sales/salesreceipts");
+ if (response.IsSuccessStatusCode)
+ {
+ var responseJson = await response.Content.ReadAsStringAsync();
+ return View(model: responseJson);
+ }
+ else
+ {
+ _logger.LogError("Failed to fetch sales receipts. API returned status code: {StatusCode}", response.StatusCode);
+ ViewBag.ErrorMessage = "Failed to load sales receipts. Please try again later.";
+ }
}
}
- return View();
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "An error occurred while fetching sales receipts.");
+ ViewBag.ErrorMessage = "An unexpected error occurred while loading sales receipts.";
+ }
+
+ // Return the view with an error message if the API call fails
+ return View(model: "[]");
}
+ [HttpGet]
public IActionResult AddReceipt()
{
- ViewBag.PageContentHeader = "New Receipt";
-
- var model = new Models.Sales.AddReceipt();
-
- ViewBag.Customers = Models.SelectListItemHelper.Customers();
- ViewBag.DebitAccounts = Models.SelectListItemHelper.CashBanks();
- ViewBag.CreditAccounts = Models.SelectListItemHelper.Accounts();
- ViewBag.CustomersDetail = Newtonsoft.Json.JsonConvert.SerializeObject(GetAsync>("sales/customers").Result);
-
- return View(model);
+ try
+ {
+ ViewBag.PageContentHeader = "New Receipt";
+ ViewBag.Customers = Models.SelectListItemHelper.Customers();
+ ViewBag.DebitAccounts = Models.SelectListItemHelper.CashBanks();
+ ViewBag.CreditAccounts = Models.SelectListItemHelper.Accounts();
+ ViewBag.CustomersDetail = Newtonsoft.Json.JsonConvert.SerializeObject(
+ GetAsync>("sales/customers").Result
+ );
+
+ var model = new Models.Sales.AddReceipt();
+ return View(model);
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "An error occurred while preparing the Add Receipt page.");
+ ViewBag.ErrorMessage = "Failed to load the page for adding a receipt. Please try again later.";
+ return View(new Models.Sales.AddReceipt());
+ }
}
[HttpPost]
@@ -126,32 +333,49 @@ public IActionResult AddReceipt(Models.Sales.AddReceipt model)
{
if (ModelState.IsValid)
{
- var serialize = Newtonsoft.Json.JsonConvert.SerializeObject(model);
- var content = new StringContent(serialize);
- content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json");
- var response = Post("sales/savereceipt", content);
- if(response.IsSuccessStatusCode)
- return RedirectToAction("salesreceipts");
+ try
+ {
+ var serialize = Newtonsoft.Json.JsonConvert.SerializeObject(model);
+ var content = new StringContent(serialize);
+ content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json");
+
+ var response = Post("sales/savereceipt", content);
+ if (response.IsSuccessStatusCode)
+ {
+ return RedirectToAction("SalesReceipts");
+ }
+ else
+ {
+ _logger.LogError("Failed to save receipt. API returned status code: {StatusCode}", response.StatusCode);
+ ViewBag.ErrorMessage = "Failed to save the receipt. Please try again.";
+ }
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "An error occurred while saving the receipt.");
+ ViewBag.ErrorMessage = "An unexpected error occurred. Please try again.";
+ }
}
+ // Reload dropdowns and return the view if validation or API call fails
ViewBag.PageContentHeader = "New Receipt";
-
ViewBag.Customers = Models.SelectListItemHelper.Customers();
ViewBag.DebitAccounts = Models.SelectListItemHelper.CashBanks();
ViewBag.CreditAccounts = Models.SelectListItemHelper.Accounts();
- ViewBag.CustomersDetail = Newtonsoft.Json.JsonConvert.SerializeObject(GetAsync>("sales/customers").Result);
+ ViewBag.CustomersDetail = Newtonsoft.Json.JsonConvert.SerializeObject(
+ GetAsync>("sales/customers").Result
+ );
return View(model);
}
-
public async System.Threading.Tasks.Task Customers()
{
ViewBag.PageContentHeader = "Customers";
using (var client = new HttpClient())
{
- var baseUri = _baseConfig["ApiUrl"];
- client.BaseAddress = new System.Uri(baseUri);
+ var baseUri = _configuration!["ApiUrl"];
+ client.BaseAddress = new System.Uri(baseUri!);
client.DefaultRequestHeaders.Accept.Clear();
var response = await client.GetAsync(baseUri + "sales/customers");
if (response.IsSuccessStatusCode)
@@ -162,10 +386,10 @@ public async System.Threading.Tasks.Task Customers()
}
return View();
}
-
+
public IActionResult Customer(int id = -1)
{
- Customer customerModel = null;
+ Customer? customerModel = null;
if (id == -1)
{
ViewBag.PageContentHeader = "New Customer";
@@ -185,24 +409,50 @@ public IActionResult Customer(int id = -1)
return View(customerModel);
}
- public IActionResult SaveCustomer(Customer customerModel)
+ [HttpPost]
+ public async System.Threading.Tasks.Task SaveSalesInvoice(SalesInvoice salesInvoiceModel)
{
if (ModelState.IsValid)
{
- var serialize = Newtonsoft.Json.JsonConvert.SerializeObject(customerModel);
+ var serialize = Newtonsoft.Json.JsonConvert.SerializeObject(salesInvoiceModel);
var content = new StringContent(serialize);
content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json");
- var response = PostAsync("sales/savecustomer", content);
+ string ReadAsStringAsync = await content.ReadAsStringAsync();
+ _logger.LogInformation("SaveSalesInvoice: " + ReadAsStringAsync);
+ var response = Post("Sales/SaveSalesInvoice", content);
+ if (response.IsSuccessStatusCode)
+ {
+ return RedirectToAction("SalesInvoices");
+ }
+ }
+ ViewBag.Customers = SelectListItemHelper.Customers();
+ ViewBag.PaymentTerms = SelectListItemHelper.PaymentTerms();
+ ViewBag.Items = SelectListItemHelper.Items();
+ ViewBag.Measurements = SelectListItemHelper.Measurements();
+
+ return View("SalesInvoice", salesInvoiceModel);
+ }
+
+ public async Task SaveCustomer(Customer customerModel)
+ {
+ if (ModelState.IsValid)
+ {
+ var serialize = Newtonsoft.Json.JsonConvert.SerializeObject(customerModel);
+ var content = new StringContent(serialize);
+ content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json");
+ string ReadAsStringAsync = await content.ReadAsStringAsync();
+ var response = await PostAsync("Sales/SaveCustomer", content);
return RedirectToAction("Customers");
}
- else {
+ else
+ {
ViewBag.Accounts = SelectListItemHelper.Accounts();
ViewBag.TaxGroups = SelectListItemHelper.TaxGroups();
ViewBag.PaymentTerms = SelectListItemHelper.PaymentTerms();
}
- if(customerModel.Id == -1)
+ if (customerModel.Id == -1)
ViewBag.PageContentHeader = "New Customer";
else
ViewBag.PageContentHeader = "Customer Card";
@@ -210,6 +460,7 @@ public IActionResult SaveCustomer(Customer customerModel)
return View("Customer", customerModel);
}
+
public IActionResult CustomerAllocations(int id)
{
ViewBag.PageContentHeader = "Customer Allocations";
@@ -217,38 +468,71 @@ public IActionResult CustomerAllocations(int id)
return View();
}
+ // [HttpGet]
public IActionResult Allocate(int id)
{
- ViewBag.PageContentHeader = "Receipt Allocation";
+ Console.WriteLine($"Allocate called with ID: {id}");
- var model = new Models.Sales.Allocate();
+ try
+ {
+ ViewBag.PageContentHeader = "Receipt Allocation";
- var receipt = GetAsync("sales/salesreceipt?id=" + id).Result;
+ var model = new Models.Sales.Allocate();
- ViewBag.CustomerName = receipt.CustomerName;
- ViewBag.ReceiptNo = receipt.ReceiptNo;
+ // Fetch receipt details
+ var receipt = GetAsync("sales/salesreceipt?id=" + id).Result;
+ if (receipt == null)
+ {
+ Console.WriteLine($"Receipt not found for ID: {id}");
+ _logger.LogError("Failed to fetch receipt with id: {id}", id);
+ return NotFound($"Receipt with id {id} not found.");
+ }
+
+ ViewBag.CustomerName = receipt.CustomerName;
+ ViewBag.ReceiptNo = receipt.ReceiptNo;
- model.CustomerId = receipt.CustomerId;
- model.ReceiptId = receipt.Id;
- model.Date = receipt.ReceiptDate;
- model.Amount = receipt.Amount;
- model.RemainingAmountToAllocate = receipt.RemainingAmountToAllocate;
+ model.CustomerId = receipt.CustomerId;
+ model.ReceiptId = receipt.Id;
+ model.Date = receipt.ReceiptDate;
+ model.Amount = receipt.Amount;
+ model.RemainingAmountToAllocate = receipt.RemainingAmountToAllocate;
- var invoices = GetAsync>("sales/customerinvoices?id=" + receipt.CustomerId).Result;
+ // Fetch customer invoices
+ _logger.LogInformation("Calling API: sales/customerinvoices?id={id}", receipt.CustomerId);
- foreach (var invoice in invoices) {
- if (invoice.Posted && invoice.TotalAllocatedAmount < invoice.Amount)
+ var invoices = GetAsync>("sales/customerinvoices?id=" + receipt.CustomerId).Result;
+ if (invoices == null)
{
- model.AllocationLines.Add(new Models.Sales.AllocationLine()
+ _logger.LogError("Failed to fetch invoices for customer with id: {CustomerId}", receipt.CustomerId);
+ return NotFound($"Invoices for customer with id {receipt.CustomerId} not found.");
+ }
+
+ foreach (var invoice in invoices)
+ {
+ _logger.LogInformation("Invoice: {Invoice}", JsonConvert.SerializeObject(invoice));
+ if (invoice.Posted && invoice.TotalAllocatedAmount < invoice.Amount)
+ {
+ model.AllocationLines.Add(new Models.Sales.AllocationLine()
+ {
+ InvoiceId = invoice.Id,
+ Amount = invoice.Amount,
+ AllocatedAmount = invoice.TotalAllocatedAmount
+ });
+ }
+ else
{
- InvoiceId = invoice.Id,
- Amount = invoice.Amount,
- AllocatedAmount = invoice.TotalAllocatedAmount
- });
+ _logger.LogInformation("Invoice excluded: Posted={Posted}, TotalAllocatedAmount={TotalAllocatedAmount}, Amount={Amount}",
+ invoice.Posted, invoice.TotalAllocatedAmount, invoice.Amount);
+ }
}
- }
- return View(model);
+ return View(model);
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "An error occurred while processing the Allocate action for id: {id}", id);
+ return StatusCode(500, "An error occurred while processing your request.");
+ }
}
[HttpPost]
@@ -256,7 +540,8 @@ public IActionResult Allocate(Models.Sales.Allocate model)
{
if (ModelState.IsValid)
{
- if (model.IsValid()) {
+ if (model.IsValid())
+ {
var serialize = Newtonsoft.Json.JsonConvert.SerializeObject(model);
var content = new StringContent(serialize);
content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json");
@@ -288,5 +573,22 @@ public IActionResult SalesInvoicePdf(int id)
salesInvoiceModel.SalesInvoiceLines = invoice.SalesInvoiceLines;
return View(salesInvoiceModel);
}
+
+ public async Task DeleteSalesInvoice(int id)
+ {
+ using (var client = new HttpClient())
+ {
+ var baseUri = _configuration!["ApiUrl"];
+ client.BaseAddress = new System.Uri(baseUri!);
+ client.DefaultRequestHeaders.Accept.Clear();
+ var response = await client.DeleteAsync(baseUri + "Sales/DeleteSalesInvoice?id=" + id);
+
+ if (response.IsSuccessStatusCode)
+ return RedirectToAction("SalesInvoices");
+ }
+
+ return RedirectToAction("SalesInvoices");
+ }
+
}
}
diff --git a/src/AccountGoWeb/Controllers/TaxController.cs b/src/AccountGoWeb/Controllers/TaxController.cs
index bbc4e9132..4fd7b9a42 100644
--- a/src/AccountGoWeb/Controllers/TaxController.cs
+++ b/src/AccountGoWeb/Controllers/TaxController.cs
@@ -1,43 +1,182 @@
-using Microsoft.AspNetCore.Mvc;
+using AccountGoWeb.Models.TaxSystem;
+using AutoMapper;
+using Dto.TaxSystem;
+using Microsoft.AspNetCore.Mvc;
+using System;
namespace AccountGoWeb.Controllers
{
- [Microsoft.AspNetCore.Authorization.Authorize]
+ //[Microsoft.AspNetCore.Authorization.Authorize]
public class TaxController : BaseController
{
- public TaxController(Microsoft.Extensions.Configuration.IConfiguration config)
+ private readonly IMapper _mapper;
+
+ public TaxController(Microsoft.Extensions.Configuration.IConfiguration config, IMapper mapper)
{
_baseConfig = config;
+ _mapper = mapper;
}
- public IActionResult Index() {
+ public IActionResult Index()
+ {
return RedirectToAction("taxes");
}
- public async System.Threading.Tasks.Task Taxes()
+ public async Task Taxes()
{
ViewBag.PageContentHeader = "Tax";
using (var client = new System.Net.Http.HttpClient())
{
- var baseUri = _baseConfig["ApiUrl"];
- client.BaseAddress = new System.Uri(baseUri);
+ var baseUri = _baseConfig!["ApiUrl"];
+ client.BaseAddress = new System.Uri(baseUri!);
client.DefaultRequestHeaders.Accept.Clear();
var response = await client.GetAsync(baseUri + "tax/taxes");
if (response.IsSuccessStatusCode)
{
var responseJson = await response.Content.ReadAsStringAsync();
- var taxSystemDto = Newtonsoft.Json.JsonConvert.DeserializeObject(responseJson);
- var taxSystemViewModel = new Models.TaxSystem.TaxSystemViewModel();
- taxSystemViewModel.Taxes = taxSystemDto.Taxes;
- taxSystemViewModel.ItemTaxGroups = taxSystemDto.ItemTaxGroups;
- taxSystemViewModel.TaxGroups = taxSystemDto.TaxGroups;
+ var taxSystemDto = Newtonsoft.Json.JsonConvert.DeserializeObject(responseJson);
+ var taxSystemViewModel = _mapper.Map(taxSystemDto);
+
return View(taxSystemViewModel);
}
}
return View();
}
+
+ public IActionResult AddNewTax()
+ {
+ ViewBag.PageContentHeader = "Add New Tax";
+
+ @ViewBag.TaxGroups = Models.SelectListItemHelper.TaxGroups();
+ @ViewBag.ItemTaxGroups = Models.SelectListItemHelper.ItemTaxGroups();
+
+ return View();
+ }
+
+ [HttpPost]
+ public IActionResult AddNewTax(TaxForCreation taxForCreationDto)
+ {
+ if (ModelState.IsValid)
+ {
+ var serialize = Newtonsoft.Json.JsonConvert.SerializeObject(taxForCreationDto);
+ var content = new StringContent(serialize);
+ content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json");
+
+ var response = Post("Tax/addnewtax", content);
+ if (response.IsSuccessStatusCode)
+ return RedirectToAction("Taxes");
+ }
+
+ @ViewBag.TaxGroups = Models.SelectListItemHelper.TaxGroups();
+ @ViewBag.ItemTaxGroups = Models.SelectListItemHelper.ItemTaxGroups();
+
+ return View();
+ }
+
+ public IActionResult EditTax(string tax, string taxGroup, string itemTaxGroup)
+ {
+ ViewBag.PageContentHeader = "Edit Tax";
+
+ // Mapping Dto to View Model
+ var taxObj = Newtonsoft.Json.JsonConvert.DeserializeObject(tax);
+ var taxGroupObj = Newtonsoft.Json.JsonConvert.DeserializeObject(taxGroup);
+ var itemTaxGroupObj = Newtonsoft.Json.JsonConvert.DeserializeObject(itemTaxGroup);
+
+ var editTaxViewModel = new Models.TaxSystem.EditTaxViewModel();
+ editTaxViewModel.Tax = _mapper.Map(taxObj);
+ editTaxViewModel.TaxGroup = _mapper.Map(taxGroupObj);
+ editTaxViewModel.ItemTaxGroup = _mapper.Map(itemTaxGroupObj);
+
+ @ViewBag.TaxGroups = Models.SelectListItemHelper.TaxGroups();
+ @ViewBag.ItemTaxGroups = Models.SelectListItemHelper.ItemTaxGroups();
+
+ return View(editTaxViewModel);
+ }
+
+ [HttpPost]
+ public async Task EditTax(EditTaxViewModel editTaxViewModel)
+ {
+ if (ModelState.IsValid)
+ {
+ var taxForUpdateDto = _mapper.Map(editTaxViewModel);
+
+ using (var client = new System.Net.Http.HttpClient())
+ {
+ var baseUri = _baseConfig!["ApiUrl"];
+ client.BaseAddress = new System.Uri(baseUri!);
+ client.DefaultRequestHeaders.Accept.Clear();
+
+ var serialize = Newtonsoft.Json.JsonConvert.SerializeObject(taxForUpdateDto);
+ var content = new StringContent(serialize);
+ content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json");
+
+ var response = await client.PutAsync(baseUri + "Tax/edittax", content);
+
+ if (response.IsSuccessStatusCode)
+ {
+ return RedirectToAction("Taxes");
+ }
+ }
+
+ return RedirectToAction("Taxes");
+ }
+
+ @ViewBag.TaxGroups = Models.SelectListItemHelper.TaxGroups();
+ @ViewBag.ItemTaxGroups = Models.SelectListItemHelper.ItemTaxGroups();
+
+ return View(editTaxViewModel);
+ }
+
+ public async Task DeleteTax(int id)
+ {
+ using (var client = new HttpClient())
+ {
+ var baseUri = _baseConfig!["ApiUrl"];
+ client.BaseAddress = new System.Uri(baseUri!);
+ client.DefaultRequestHeaders.Accept.Clear();
+ var response = await client.DeleteAsync(baseUri + "Tax/deletetax?id=" + id);
+
+ if(response.IsSuccessStatusCode)
+ return RedirectToAction("Taxes");
+ }
+
+ return RedirectToAction("Taxes");
+ }
+
+ public async Task DeleteTaxGroup(int id)
+ {
+ using (var client = new HttpClient())
+ {
+ var baseUri = _baseConfig!["ApiUrl"];
+ client.BaseAddress = new System.Uri(baseUri!);
+ client.DefaultRequestHeaders.Accept.Clear();
+ var response = await client.DeleteAsync(baseUri + "Tax/deletetaxgroup?id=" + id);
+
+ if (response.IsSuccessStatusCode)
+ return RedirectToAction("Taxes");
+ }
+
+ return RedirectToAction("Taxes");
+ }
+
+ public async Task DeleteItemTaxGroup(int id)
+ {
+ using (var client = new HttpClient())
+ {
+ var baseUri = _baseConfig!["ApiUrl"];
+ client.BaseAddress = new System.Uri(baseUri!);
+ client.DefaultRequestHeaders.Accept.Clear();
+ var response = await client.DeleteAsync(baseUri + "Tax/deleteitemtaxgroup?id=" + id);
+
+ if (response.IsSuccessStatusCode)
+ return RedirectToAction("Taxes");
+ }
+
+ return RedirectToAction("Taxes");
+ }
+
}
}
diff --git a/src/AccountGoWeb/MappingProfile.cs b/src/AccountGoWeb/MappingProfile.cs
new file mode 100644
index 000000000..86e45f5c1
--- /dev/null
+++ b/src/AccountGoWeb/MappingProfile.cs
@@ -0,0 +1,58 @@
+using AutoMapper;
+
+namespace AccountGoWeb
+{
+ public class MappingProfile : Profile
+ {
+ public MappingProfile()
+ {
+ CreateMap();
+ CreateMap();
+
+ #region TaxSystem
+
+ // TaxView Model
+ CreateMap().ReverseMap();
+ CreateMap().ReverseMap();
+ CreateMap()
+ .ForMember(dest => dest.Taxes, opt => opt.MapFrom((src, dest, i, context) =>
+ {
+ return context.Mapper.Map>(src.Taxes);
+ }))
+ .ReverseMap();
+ CreateMap().ReverseMap();
+ CreateMap()
+ .ForMember(dest => dest.Taxes, opt => opt.MapFrom((src, dest, i, context) =>
+ {
+ return context.Mapper.Map>(src.Taxes);
+ }))
+ .ReverseMap();
+ CreateMap()
+ .ForMember(dest => dest.Tax, opt => opt.MapFrom((src, dest, i, context) =>
+ {
+ return context.Mapper.Map(src.Tax);
+ }))
+ .ReverseMap();
+
+ // TaxSystemViewModel
+ CreateMap()
+ .ForMember(dest => dest.Taxes, opt => opt.MapFrom((src, dest, i, context) =>
+ {
+ return context.Mapper.Map>(src.Taxes);
+ }))
+ .ForMember(dest => dest.TaxGroups, opt => opt.MapFrom((src, dest, i, context) =>
+ {
+ return context.Mapper.Map>(src.TaxGroups);
+ }))
+ .ForMember(dest => dest.ItemTaxGroups, opt => opt.MapFrom((src, dest, i, context) =>
+ {
+ return context.Mapper.Map>(src.ItemTaxGroups);
+ })
+ )
+ .ReverseMap();
+
+ #endregion
+
+ }
+ }
+}
diff --git a/src/AccountGoWeb/Models/Account/LoginViewModel.cs b/src/AccountGoWeb/Models/Account/LoginViewModel.cs
index 2506b0433..418ef2eaa 100644
--- a/src/AccountGoWeb/Models/Account/LoginViewModel.cs
+++ b/src/AccountGoWeb/Models/Account/LoginViewModel.cs
@@ -1,18 +1,17 @@
using System.ComponentModel.DataAnnotations;
-namespace AccountGoWeb.Models.Account
+namespace AccountGoWeb.Models.Account;
+
+public class LoginViewModel
{
- public class LoginViewModel
- {
- [Required]
- [EmailAddress]
- public string Email { get; set; }
+ [Required]
+ [EmailAddress]
+ public string? Email { get; set; }
- [Required]
- [DataType(DataType.Password)]
- public string Password { get; set; }
+ [Required]
+ [DataType(DataType.Password)]
+ public string? Password { get; set; }
- [Display(Name = "Remember me?")]
- public bool RememberMe { get; set; }
- }
+ [Display(Name = "Remember me?")]
+ public bool RememberMe { get; set; }
}
diff --git a/src/AccountGoWeb/Models/Account/RegisterViewModel.cs b/src/AccountGoWeb/Models/Account/RegisterViewModel.cs
index b072ae25e..5fbd58e5f 100644
--- a/src/AccountGoWeb/Models/Account/RegisterViewModel.cs
+++ b/src/AccountGoWeb/Models/Account/RegisterViewModel.cs
@@ -1,29 +1,28 @@
using System.ComponentModel.DataAnnotations;
-namespace AccountGoWeb.Models.Account
+namespace AccountGoWeb.Models.Account;
+
+public class RegisterViewModel
{
- public class RegisterViewModel
- {
- [Required]
- [EmailAddress]
- [Display(Name = "Email")]
- public string Email { get; set; }
+ [Required]
+ [EmailAddress]
+ [Display(Name = "Email")]
+ public string? Email { get; set; }
- [Required]
- [StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)]
- [DataType(DataType.Password)]
- [Display(Name = "Password")]
- public string Password { get; set; }
+ [Required]
+ [StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)]
+ [DataType(DataType.Password)]
+ [Display(Name = "Password")]
+ public string? Password { get; set; }
- [DataType(DataType.Password)]
- [Display(Name = "Confirm password")]
- [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
- public string ConfirmPassword { get; set; }
+ [DataType(DataType.Password)]
+ [Display(Name = "Confirm password")]
+ [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
+ public string? ConfirmPassword { get; set; }
- [Display(Name = "First Name")]
- public string FirstName { get; set; }
+ [Display(Name = "First Name")]
+ public string? FirstName { get; set; }
- [Display(Name = "Last Name")]
- public string LastName { get; set; }
- }
+ [Display(Name = "Last Name")]
+ public string? LastName { get; set; }
}
diff --git a/src/AccountGoWeb/Models/Bogus/Student.cs b/src/AccountGoWeb/Models/Bogus/Student.cs
new file mode 100644
index 000000000..cd50037d1
--- /dev/null
+++ b/src/AccountGoWeb/Models/Bogus/Student.cs
@@ -0,0 +1,62 @@
+namespace AccountGoWeb.Models.Bogus;
+
+public class Student
+{
+ required public int? Id { get; set; }
+ required public string FirstName { get; set; }
+ required public string LastName { get; set; }
+ required public string School { get; set; }
+ public static IQueryable GetStudents()
+ {
+ int ndx = 0;
+ List students = new List() {
+ new Student() { Id = ++ndx, FirstName="Max", LastName="Pao", School="Science" },
+ new Student() { Id = ++ndx, FirstName="Tom", LastName="Fay", School="Mining" },
+ new Student() { Id = ++ndx, FirstName="Ann", LastName="Sun", School="Nursing" },
+ new Student() { Id = ++ndx, FirstName="Joe", LastName="Fox", School="Computing" },
+ new Student() { Id = ++ndx, FirstName="Sue", LastName="Mai", School="Mining" },
+ new Student() { Id = ++ndx, FirstName="Ben", LastName="Lau", School="Business" },
+ new Student() { Id = ++ndx, FirstName="Zoe", LastName="Ray", School="Mining" },
+ new Student() { Id = ++ndx, FirstName="Sam", LastName="Ash", School="Medicine" },
+ new Student() { Id = ++ndx, FirstName="Dan", LastName="Lee", School="Computing" },
+ new Student() { Id = ++ndx, FirstName="Pat", LastName="Day", School="Science" },
+ new Student() { Id = ++ndx, FirstName="Kim", LastName="Rex", School="Computing" },
+ new Student() { Id = ++ndx, FirstName="Tim", LastName="Ram", School="Business" },
+ new Student() { Id = ++ndx, FirstName="Rob", LastName="Wei", School="Mining" },
+ new Student() { Id = ++ndx, FirstName="Jan", LastName="Tex", School="Science" },
+ new Student() { Id = ++ndx, FirstName="Jim", LastName="Kid", School="Business" },
+ new Student() { Id = ++ndx, FirstName="Ben", LastName="Chu", School="Medicine" },
+ new Student() { Id = ++ndx, FirstName="Mia", LastName="Tao", School="Computing" },
+ new Student() { Id = ++ndx, FirstName="Ted", LastName="Day", School="Business" },
+ new Student() { Id = ++ndx, FirstName="Amy", LastName="Roy", School="Science" },
+ new Student() { Id = ++ndx, FirstName="Ian", LastName="Kit", School="Nursing" },
+ new Student() { Id = ++ndx, FirstName="Liz", LastName="Tan", School="Medicine" },
+ new Student() { Id = ++ndx, FirstName="Mat", LastName="Roy", School="Tourism" },
+ new Student() { Id = ++ndx, FirstName="Deb", LastName="Luo", School="Medicine" },
+ new Student() { Id = ++ndx, FirstName="Ana", LastName="Poe", School="Computing" },
+ new Student() { Id = ++ndx, FirstName="Lyn", LastName="Raj", School="Science" },
+ new Student() { Id = ++ndx, FirstName="Amy", LastName="Ash", School="Tourism" },
+ new Student() { Id = ++ndx, FirstName="Kim", LastName="Kid", School="Mining" },
+ new Student() { Id = ++ndx, FirstName="Bec", LastName="Fry", School="Nursing" },
+ new Student() { Id = ++ndx, FirstName="Eva", LastName="Lap", School="Computing" },
+ new Student() { Id = ++ndx, FirstName="Eli", LastName="Yim", School="Business" },
+ new Student() { Id = ++ndx, FirstName="Sam", LastName="Hui", School="Science" },
+ new Student() { Id = ++ndx, FirstName="Joe", LastName="Jin", School="Mining" },
+ new Student() { Id = ++ndx, FirstName="Liz", LastName="Kuo", School="Agriculture" },
+ new Student() { Id = ++ndx, FirstName="Ric", LastName="Mak", School="Tourism" },
+ new Student() { Id = ++ndx, FirstName="Pam", LastName="Day", School="Computing" },
+ new Student() { Id = ++ndx, FirstName="Stu", LastName="Gad", School="Business" },
+ new Student() { Id = ++ndx, FirstName="Tom", LastName="Bee", School="Tourism" },
+ new Student() { Id = ++ndx, FirstName="Bob", LastName="Lam", School="Agriculture" },
+ new Student() { Id = ++ndx, FirstName="Jim", LastName="Ots", School="Medicine" },
+ new Student() { Id = ++ndx, FirstName="Tom", LastName="Mag", School="Mining" },
+ new Student() { Id = ++ndx, FirstName="Hal", LastName="Doe", School="Agriculture" },
+ new Student() { Id = ++ndx, FirstName="Roy", LastName="Kim", School="Nursing" },
+ new Student() { Id = ++ndx, FirstName="Vis", LastName="Cox", School="Science" },
+ new Student() { Id = ++ndx, FirstName="Kay", LastName="Aga", School="Tourism" },
+ new Student() { Id = ++ndx, FirstName="Reo", LastName="Hui", School="Business" },
+ new Student() { Id = ++ndx, FirstName="Bob", LastName="Roe", School="Medicine" },
+ };
+ return students.AsQueryable();
+ }
+}
diff --git a/src/AccountGoWeb/Models/Financial/AccountViewModel.cs b/src/AccountGoWeb/Models/Financial/AccountViewModel.cs
new file mode 100644
index 000000000..604595389
--- /dev/null
+++ b/src/AccountGoWeb/Models/Financial/AccountViewModel.cs
@@ -0,0 +1,13 @@
+namespace AccountGoWeb.Models.Financial
+{
+ public class AccountViewModel
+ {
+ public string? AccountCode { get; set; }
+ public string? AccountName { get; set; }
+ public decimal TotalBalance { get; set; }
+ public decimal TotalDebitBalance { get; set; }
+ public decimal TotalCreditBalance { get; set; }
+ public IList? ChildAccounts { get; set; }
+
+ }
+}
diff --git a/src/AccountGoWeb/Models/Financial/GeneralLedgerSetting.cs b/src/AccountGoWeb/Models/Financial/GeneralLedgerSetting.cs
index 866794e6d..a947408b8 100644
--- a/src/AccountGoWeb/Models/Financial/GeneralLedgerSetting.cs
+++ b/src/AccountGoWeb/Models/Financial/GeneralLedgerSetting.cs
@@ -1,14 +1,13 @@
-namespace AccountGoWeb.Models.Financial
+namespace AccountGoWeb.Models.Financial;
+
+public class GeneralLedgerSetting
{
- public class GeneralLedgerSetting
- {
- public int Id { get; set; }
- public int? CompanyId { get; set; }
- public string CompanyCode { get; set; }
- public int? PayableAccountId { get; set; }
- public int? PurchaseDiscountAccountId { get; set; }
- public int? GoodsReceiptNoteClearingAccountId { get; set; }
- public int? SalesDiscountAccountId { get; set; }
- public int? ShippingChargeAccountId { get; set; }
- }
+ public int Id { get; set; }
+ public int? CompanyId { get; set; }
+ public string? CompanyCode { get; set; }
+ public int? PayableAccountId { get; set; }
+ public int? PurchaseDiscountAccountId { get; set; }
+ public int? GoodsReceiptNoteClearingAccountId { get; set; }
+ public int? SalesDiscountAccountId { get; set; }
+ public int? ShippingChargeAccountId { get; set; }
}
diff --git a/src/AccountGoWeb/Models/FinancialReports.cs b/src/AccountGoWeb/Models/FinancialReports.cs
index 7e755e404..8c34a7d9e 100644
--- a/src/AccountGoWeb/Models/FinancialReports.cs
+++ b/src/AccountGoWeb/Models/FinancialReports.cs
@@ -1,53 +1,42 @@
-//-----------------------------------------------------------------------
-//
-// Copyright (c) AccountGo. All rights reserved.
-// Marvin Perez
-// 1/11/2015 9:48:38 AM
-//
-//-----------------------------------------------------------------------
+namespace AccountGoWeb.Models;
-using System;
-
-namespace AccountGoWeb.Models
+public class TrialBalance
{
- public class TrialBalance
- {
- public int AccountId { get; set; }
- public string AccountCode { get; set; }
- public string AccountName { get; set; }
- public decimal Debit { get; set; }
- public decimal Credit { get; set; }
- }
+ public int AccountId { get; set; }
+ public string? AccountCode { get; set; }
+ public string? AccountName { get; set; }
+ public decimal Debit { get; set; }
+ public decimal Credit { get; set; }
+}
- public class BalanceSheet
- {
- public int AccountId { get; set; }
- public int AccountClassId { get; set; }
- public string AccountCode { get; set; }
- public string AccountName { get; set; }
- public decimal Amount { get; set; }
- }
+public class BalanceSheet
+{
+ public int AccountId { get; set; }
+ public int AccountClassId { get; set; }
+ public string? AccountCode { get; set; }
+ public string? AccountName { get; set; }
+ public decimal Amount { get; set; }
+}
- public class IncomeStatement
- {
- public int AccountId { get; set; }
- public bool IsExpense { get; set; }
- public string AccountCode { get; set; }
- public string AccountName { get; set; }
- public decimal Amount { get; set; }
- }
+public class IncomeStatement
+{
+ public int AccountId { get; set; }
+ public bool IsExpense { get; set; }
+ public string? AccountCode { get; set; }
+ public string? AccountName { get; set; }
+ public decimal Amount { get; set; }
+}
- public partial class MasterGeneralLedger
- {
- public int Id { get; set; }
- public int AccountId { get; set; }
- public int CurrencyId { get; set; }
- public string DocumentType { get; set; }
- public int TransactionNo { get; set; }
- public string AccountCode { get; set; }
- public string AccountName { get; set; }
- public DateTime Date { get; set; }
- public decimal Debit { get; set; }
- public decimal Credit { get; set; }
- }
+public partial class MasterGeneralLedger
+{
+ public int Id { get; set; }
+ public int AccountId { get; set; }
+ public int CurrencyId { get; set; }
+ public string? DocumentType { get; set; }
+ public int TransactionNo { get; set; }
+ public string? AccountCode { get; set; }
+ public string? AccountName { get; set; }
+ public DateTime Date { get; set; }
+ public decimal Debit { get; set; }
+ public decimal Credit { get; set; }
}
diff --git a/src/AccountGoWeb/Models/ObjectExtensions.cs b/src/AccountGoWeb/Models/ObjectExtensions.cs
index 7e3d8c24b..780d99dfb 100644
--- a/src/AccountGoWeb/Models/ObjectExtensions.cs
+++ b/src/AccountGoWeb/Models/ObjectExtensions.cs
@@ -1,16 +1,14 @@
using Newtonsoft.Json;
-using System.IO;
-namespace AccountGoWeb.Models
+namespace AccountGoWeb.Models;
+
+public static class ObjectExtensions
{
- public static class ObjectExtensions
+ public static string ToJson(this object obj)
{
- public static string ToJson(this object obj)
- {
- JsonSerializer js = JsonSerializer.Create(new JsonSerializerSettings());
- var jw = new StringWriter();
- js.Serialize(jw, obj);
- return jw.ToString();
- }
+ JsonSerializer js = JsonSerializer.Create(new JsonSerializerSettings());
+ var jw = new StringWriter();
+ js.Serialize(jw, obj);
+ return jw.ToString();
}
}
diff --git a/src/AccountGoWeb/Models/Purchasing/Payment.cs b/src/AccountGoWeb/Models/Purchasing/Payment.cs
index 58c9f230a..16aae98e5 100644
--- a/src/AccountGoWeb/Models/Purchasing/Payment.cs
+++ b/src/AccountGoWeb/Models/Purchasing/Payment.cs
@@ -1,19 +1,18 @@
-namespace AccountGoWeb.Models.Purchasing
+namespace AccountGoWeb.Models.Purchasing;
+
+public class Payment
{
- public class Payment
- {
- public int InvoiceId { get; set; }
- public string InvoiceNo { get; set; }
- public int VendorId { get; set; }
- public string VendorName { get; set; }
- public decimal InvoiceAmount { get; set; }
- public decimal AmountPaid { get; set; }
- public decimal Balance { get { return InvoiceAmount - AmountPaid; } }
- [ExpressiveAnnotations.Attributes.AssertThat("AmountToPay <= Balance", ErrorMessage = "Amount to pay cannot be greater than remaining amount to pay.")]
- [ExpressiveAnnotations.Attributes.AssertThat("AmountToPay > 0", ErrorMessage = "Amount to pay cannot be zero.")]
- public decimal AmountToPay { get; set; }
- [System.ComponentModel.DataAnnotations.Required]
- public int? AccountId { get; set; }
- public System.DateTime Date { get; set; }
- }
+ public int InvoiceId { get; set; }
+ public string? InvoiceNo { get; set; }
+ public int VendorId { get; set; }
+ public string? VendorName { get; set; }
+ public decimal InvoiceAmount { get; set; }
+ public decimal AmountPaid { get; set; }
+ public decimal Balance { get { return InvoiceAmount - AmountPaid; } }
+ [ExpressiveAnnotations.Attributes.AssertThat("AmountToPay <= Balance", ErrorMessage = "Amount to pay cannot be greater than remaining amount to pay.")]
+ [ExpressiveAnnotations.Attributes.AssertThat("AmountToPay > 0", ErrorMessage = "Amount to pay cannot be zero.")]
+ public decimal AmountToPay { get; set; }
+ [System.ComponentModel.DataAnnotations.Required]
+ public int? AccountId { get; set; }
+ public System.DateTime Date { get; set; }
}
diff --git a/src/AccountGoWeb/Models/Sales/AddSalesReceipt.cs b/src/AccountGoWeb/Models/Sales/AddSalesReceipt.cs
index 67f10e309..377a9ecdb 100644
--- a/src/AccountGoWeb/Models/Sales/AddSalesReceipt.cs
+++ b/src/AccountGoWeb/Models/Sales/AddSalesReceipt.cs
@@ -1,20 +1,19 @@
-namespace AccountGoWeb.Models.Sales
+namespace AccountGoWeb.Models.Sales;
+
+public class AddReceipt
{
- public class AddReceipt
- {
- [System.ComponentModel.DataAnnotations.Required]
- public int? AccountToDebitId { get; set; }
- [System.ComponentModel.DataAnnotations.Required]
- public int? AccountToCreditId { get; set; }
- [System.ComponentModel.DataAnnotations.Required]
- public int? CustomerId { get; set; }
- public System.DateTime ReceiptDate {get;set;}
- [ExpressiveAnnotations.Attributes.AssertThat("Amount > 0", ErrorMessage = "Amount cannot be zero.")]
- public decimal Amount { get; set; }
+ [System.ComponentModel.DataAnnotations.Required]
+ public int? AccountToDebitId { get; set; }
+ [System.ComponentModel.DataAnnotations.Required]
+ public int? AccountToCreditId { get; set; }
+ [System.ComponentModel.DataAnnotations.Required]
+ public int? CustomerId { get; set; }
+ public System.DateTime ReceiptDate {get;set;}
+ [ExpressiveAnnotations.Attributes.AssertThat("Amount > 0", ErrorMessage = "Amount cannot be zero.")]
+ public decimal Amount { get; set; }
- public AddReceipt()
- {
- ReceiptDate = System.DateTime.Now;
- }
+ public AddReceipt()
+ {
+ ReceiptDate = System.DateTime.Now;
}
}
diff --git a/src/AccountGoWeb/Models/Sales/Allocate.cs b/src/AccountGoWeb/Models/Sales/Allocate.cs
index 78da38d73..704ead295 100644
--- a/src/AccountGoWeb/Models/Sales/Allocate.cs
+++ b/src/AccountGoWeb/Models/Sales/Allocate.cs
@@ -1,51 +1,48 @@
-using System.Collections.Generic;
+namespace AccountGoWeb.Models.Sales;
-namespace AccountGoWeb.Models.Sales
+public class Allocate
{
- public class Allocate
- {
- [System.ComponentModel.DataAnnotations.Required]
- public int? CustomerId { get; set; }
- [System.ComponentModel.DataAnnotations.Required]
- public int? ReceiptId { get; set; }
- [System.ComponentModel.DataAnnotations.Required]
- public System.DateTime Date { get; set; }
- public decimal Amount { get; set; }
- public decimal RemainingAmountToAllocate { get; set; }
- public decimal SumAllocatedAmount { get { return ComputeSumToAllocateAmount(); } }
- public IList AllocationLines { get; set; }
-
- public Allocate()
- {
- AllocationLines = new List();
- }
+ [System.ComponentModel.DataAnnotations.Required]
+ public int? CustomerId { get; set; }
+ [System.ComponentModel.DataAnnotations.Required]
+ public int? ReceiptId { get; set; }
+ [System.ComponentModel.DataAnnotations.Required]
+ public System.DateTime Date { get; set; }
+ public decimal Amount { get; set; }
+ public decimal RemainingAmountToAllocate { get; set; }
+ public decimal SumAllocatedAmount { get { return ComputeSumToAllocateAmount(); } }
+ public IList AllocationLines { get; set; }
- private decimal ComputeSumToAllocateAmount()
- {
- decimal sum = 0;
+ public Allocate()
+ {
+ AllocationLines = new List();
+ }
- foreach (var line in AllocationLines) {
- sum += line.AmountToAllocate.GetValueOrDefault();
- }
+ private decimal ComputeSumToAllocateAmount()
+ {
+ decimal sum = 0;
- return sum;
+ foreach (var line in AllocationLines) {
+ sum += line.AmountToAllocate.GetValueOrDefault();
}
- public bool IsValid()
- {
- if (RemainingAmountToAllocate < SumAllocatedAmount)
- return false;
- else
- return true;
- }
+ return sum;
}
- public class AllocationLine
+ public bool IsValid()
{
- [System.ComponentModel.DataAnnotations.Required]
- public int? InvoiceId { get; set; }
- public decimal? Amount { get; set; }
- public decimal? AllocatedAmount { get; set; }
- public decimal? AmountToAllocate { get; set; }
- }
+ if (RemainingAmountToAllocate < SumAllocatedAmount)
+ return false;
+ else
+ return true;
+ }
}
+
+public class AllocationLine
+{
+ [System.ComponentModel.DataAnnotations.Required]
+ public int? InvoiceId { get; set; }
+ public decimal? Amount { get; set; }
+ public decimal? AllocatedAmount { get; set; }
+ public decimal? AmountToAllocate { get; set; }
+}
diff --git a/src/AccountGoWeb/Models/Sales/SalesQuotation.cs b/src/AccountGoWeb/Models/Sales/SalesQuotation.cs
new file mode 100644
index 000000000..226716fca
--- /dev/null
+++ b/src/AccountGoWeb/Models/Sales/SalesQuotation.cs
@@ -0,0 +1,21 @@
+namespace AccountGoWeb.Models.Sales;
+public class SalesQuotations {
+ [System.ComponentModel.DataAnnotations.Required]
+ public int CustomerId { get; set; }
+ [System.ComponentModel.DataAnnotations.Required]
+ public int PaymentTermId { get; set; }
+ [System.ComponentModel.DataAnnotations.Required]
+ public int ItemId { get; set; }
+ [System.ComponentModel.DataAnnotations.Required]
+ public int Quantity { get; set; }
+ [ExpressiveAnnotations.Attributes.AssertThat("Amount > 0", ErrorMessage = "Amount cannot be zero.")]
+ public decimal Amount { get; set; }
+ public System.DateTime Date { get; set; }
+ public decimal Discount { get; set; }
+
+ public SalesQuotations()
+ {
+ Date = System.DateTime.Now;
+ }
+
+}
\ No newline at end of file
diff --git a/src/AccountGoWeb/Models/SelectListItemHelper.cs b/src/AccountGoWeb/Models/SelectListItemHelper.cs
index 39b6ccf30..2546a4da1 100644
--- a/src/AccountGoWeb/Models/SelectListItemHelper.cs
+++ b/src/AccountGoWeb/Models/SelectListItemHelper.cs
@@ -1,152 +1,147 @@
-using Microsoft.Extensions.Configuration;
-using System.Collections.Generic;
-using System.Net.Http;
+namespace AccountGoWeb.Models;
-namespace AccountGoWeb.Models
+public static class SelectListItemHelper
{
- public static class SelectListItemHelper
- {
- public static IConfiguration _config;
+ public static IConfiguration? _config;
- public static IEnumerable Accounts()
- {
- var accounts = GetAsync>("common/postingaccounts").Result;
+ public static IEnumerable Accounts()
+ {
+ var accounts = GetAsync>("common/postingaccounts").Result;
- var selectAccounts = new HashSet();
- selectAccounts.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = "", Text = "" });
- foreach (var account in accounts)
- selectAccounts.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = account.Id.ToString(), Text = account.AccountName });
+ var selectAccounts = new HashSet();
+ selectAccounts.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = "", Text = "" });
+ foreach (var account in accounts)
+ selectAccounts.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = account.Id.ToString(), Text = account.AccountName });
- return selectAccounts;
- }
+ return selectAccounts;
+ }
- public static IEnumerable TaxGroups()
- {
- var taxGroups = GetAsync>("tax/taxgroups").Result;
- var selectTaxGroups = new HashSet();
- selectTaxGroups.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = "", Text = "" });
- foreach (var taxGroup in taxGroups)
- selectTaxGroups.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = taxGroup.Id.ToString(), Text = taxGroup.Description });
+ public static IEnumerable TaxGroups()
+ {
+ var taxGroups = GetAsync>("tax/taxgroups").Result;
+ var selectTaxGroups = new HashSet();
+ selectTaxGroups.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = "", Text = "" });
+ foreach (var taxGroup in taxGroups)
+ selectTaxGroups.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = taxGroup.Id.ToString(), Text = taxGroup.Description });
- return selectTaxGroups;
- }
+ return selectTaxGroups;
+ }
- public static IEnumerable ItemTaxGroups()
- {
- var itemtaxgroups = GetAsync>("tax/itemtaxgroups").Result;
- var selectitemtaxgroups = new HashSet();
- selectitemtaxgroups.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = "", Text = "" });
- foreach (var taxGroup in itemtaxgroups)
- selectitemtaxgroups.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = taxGroup.Id.ToString(), Text = taxGroup.Name });
+ public static IEnumerable ItemTaxGroups()
+ {
+ var itemtaxgroups = GetAsync>("tax/itemtaxgroups").Result;
+ var selectitemtaxgroups = new HashSet();
+ selectitemtaxgroups.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = "", Text = "" });
+ foreach (var taxGroup in itemtaxgroups)
+ selectitemtaxgroups.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = taxGroup.Id.ToString(), Text = taxGroup.Name });
- return selectitemtaxgroups;
- }
+ return selectitemtaxgroups;
+ }
- public static IEnumerable PaymentTerms()
- {
- var paymentTerms = GetAsync>("common/paymentterms").Result;
- var selectPaymentTerms = new HashSet();
- selectPaymentTerms.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = "", Text = "" });
- foreach (var term in paymentTerms)
- selectPaymentTerms.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = term.Id.ToString(), Text = term.Description });
+ public static IEnumerable PaymentTerms()
+ {
+ var paymentTerms = GetAsync>("common/paymentterms").Result;
+ var selectPaymentTerms = new HashSet();
+ selectPaymentTerms.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = "", Text = "" });
+ foreach (var term in paymentTerms)
+ selectPaymentTerms.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = term.Id.ToString(), Text = term.Description });
- return selectPaymentTerms;
- }
+ return selectPaymentTerms;
+ }
- public static IEnumerable UnitOfMeasurements()
- {
- var uoms = GetAsync>("common/measurements").Result;
- var selectUOMS = new HashSet();
- selectUOMS.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = "", Text = "" });
- foreach (var item in uoms)
- selectUOMS.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = item.Id.ToString(), Text = item.Description });
+ public static IEnumerable UnitOfMeasurements()
+ {
+ var uoms = GetAsync>("common/measurements").Result;
+ var selectUOMS = new HashSet();
+ selectUOMS.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = "", Text = "" });
+ foreach (var item in uoms)
+ selectUOMS.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = item.Id.ToString(), Text = item.Description });
- return selectUOMS;
- }
+ return selectUOMS;
+ }
- public static IEnumerable ItemCategories()
- {
- var categories = GetAsync>("common/itemcategories").Result;
- var selectCategories = new HashSet();
- selectCategories.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = "", Text = "" });
- foreach (var item in categories)
- selectCategories.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = item.Id.ToString(), Text = item.Name });
+ public static IEnumerable ItemCategories()
+ {
+ var categories = GetAsync>("common/itemcategories").Result;
+ var selectCategories = new HashSet();
+ selectCategories.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = "", Text = "" });
+ foreach (var item in categories)
+ selectCategories.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = item.Id.ToString(), Text = item.Name });
- return selectCategories;
- }
+ return selectCategories;
+ }
- public static IEnumerable CashBanks()
- {
- var cashBanks = GetAsync>("common/cashbanks").Result;
- var selectCashBanks = new HashSet();
- selectCashBanks.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = "", Text = "" });
- foreach (var item in cashBanks)
- selectCashBanks.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = item.Id.ToString(), Text = item.Name });
+ public static IEnumerable CashBanks()
+ {
+ var cashBanks = GetAsync>("common/cashbanks").Result;
+ var selectCashBanks = new HashSet();
+ selectCashBanks.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = "", Text = "" });
+ foreach (var item in cashBanks)
+ selectCashBanks.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = item.Id.ToString(), Text = item.Name });
- return selectCashBanks;
- }
+ return selectCashBanks;
+ }
- public static IEnumerable Customers()
- {
- var customers = GetAsync>("sales/customers").Result;
- var selectCustomers = new HashSet();
- selectCustomers.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = "", Text = "" });
- foreach (var item in customers)
- selectCustomers.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = item.Id.ToString(), Text = item.Name });
+ public static IEnumerable Customers()
+ {
+ var customers = GetAsync>("sales/customers").Result;
+ var selectCustomers = new HashSet();
+ selectCustomers.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = "", Text = "" });
+ foreach (var item in customers)
+ selectCustomers.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = item.Id.ToString(), Text = item.Name });
- return selectCustomers;
- }
+ return selectCustomers;
+ }
- public static IEnumerable Vendors()
- {
- var vendors = GetAsync>("purchasing/vendors").Result;
- var selectVendors = new HashSet();
- selectVendors.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = "", Text = "" });
- foreach (var item in vendors)
- selectVendors.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = item.Id.ToString(), Text = item.Name });
+ public static IEnumerable Vendors()
+ {
+ var vendors = GetAsync>("purchasing/vendors").Result;
+ var selectVendors = new HashSet();
+ selectVendors.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = "", Text = "" });
+ foreach (var item in vendors)
+ selectVendors.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = item.Id.ToString(), Text = item.Name });
- return selectVendors;
- }
+ return selectVendors;
+ }
- public static IEnumerable Items()
- {
- var items = GetAsync>("inventory/items").Result;
- var selectItems = new HashSet();
- selectItems.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = "", Text = "" });
- foreach (var item in items)
- selectItems.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = item.Id.ToString(), Text = item.Description });
+ public static IEnumerable Items()
+ {
+ var items = GetAsync>("inventory/items").Result;
+ var selectItems = new HashSet();
+ selectItems.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = "", Text = "" });
+ foreach (var item in items)
+ selectItems.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = item.Id.ToString(), Text = item.Description });
- return selectItems;
- }
+ return selectItems;
+ }
- public static IEnumerable Measurements()
- {
- var measurements = GetAsync>("inventory/items").Result;
- var selectMeasurements = new HashSet();
- selectMeasurements.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = "", Text = "" });
- foreach (var item in measurements)
- selectMeasurements.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = item.Id.ToString(), Text = item.Description });
+ public static IEnumerable Measurements()
+ {
+ var measurements = GetAsync>("common/measurements").Result;
+ var selectMeasurements = new HashSet();
+ selectMeasurements.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = "", Text = "" });
+ foreach (var item in measurements)
+ selectMeasurements.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = item.Id.ToString(), Text = item.Description });
- return selectMeasurements;
- }
+ return selectMeasurements;
+ }
- #region Private methods
- public static async System.Threading.Tasks.Task GetAsync(string uri)
+ #region Private methods
+ public static async System.Threading.Tasks.Task GetAsync(string uri)
+ {
+ string responseJson = string.Empty;
+ using (var client = new HttpClient())
{
- string responseJson = string.Empty;
- using (var client = new HttpClient())
+ var baseUri = _config!["ApiUrl"];
+ client.BaseAddress = new System.Uri(baseUri!);
+ client.DefaultRequestHeaders.Accept.Clear();
+ var response = await client.GetAsync(baseUri + uri);
+ if (response.IsSuccessStatusCode)
{
- var baseUri = _config["ApiUrl"];
- client.BaseAddress = new System.Uri(baseUri);
- client.DefaultRequestHeaders.Accept.Clear();
- var response = await client.GetAsync(baseUri + uri);
- if (response.IsSuccessStatusCode)
- {
- responseJson = await response.Content.ReadAsStringAsync();
- }
+ responseJson = await response.Content.ReadAsStringAsync();
}
- return Newtonsoft.Json.JsonConvert.DeserializeObject(responseJson);
}
- #endregion
+ return Newtonsoft.Json.JsonConvert.DeserializeObject(responseJson)!;
}
+ #endregion
}
diff --git a/src/AccountGoWeb/Models/TaxSystem/BaseViewModel.cs b/src/AccountGoWeb/Models/TaxSystem/BaseViewModel.cs
new file mode 100644
index 000000000..3164ec6b7
--- /dev/null
+++ b/src/AccountGoWeb/Models/TaxSystem/BaseViewModel.cs
@@ -0,0 +1,9 @@
+namespace AccountGoWeb.Models.TaxSystem
+{
+ public abstract class BaseViewModel
+ {
+ public virtual int Id { get; set; }
+ // TODO: Get the user from the logged in user
+ public string? ModifiedBy { get; set; }
+ }
+}
diff --git a/src/AccountGoWeb/Models/TaxSystem/EditTaxViewModel.cs b/src/AccountGoWeb/Models/TaxSystem/EditTaxViewModel.cs
new file mode 100644
index 000000000..68aded1b5
--- /dev/null
+++ b/src/AccountGoWeb/Models/TaxSystem/EditTaxViewModel.cs
@@ -0,0 +1,13 @@
+using System.ComponentModel.DataAnnotations;
+
+namespace AccountGoWeb.Models.TaxSystem
+{
+ public class EditTaxViewModel
+ {
+ public int SalesAccountId { get; set; }
+ public int PurchaseAccountId { get; set; }
+ public Tax? Tax { get; set; }
+ public TaxGroup? TaxGroup { get; set; }
+ public ItemTaxGroup? ItemTaxGroup { get; set; }
+ }
+}
diff --git a/src/AccountGoWeb/Models/TaxSystem/ItemTaxGroup.cs b/src/AccountGoWeb/Models/TaxSystem/ItemTaxGroup.cs
new file mode 100644
index 000000000..a525eb093
--- /dev/null
+++ b/src/AccountGoWeb/Models/TaxSystem/ItemTaxGroup.cs
@@ -0,0 +1,20 @@
+using System.ComponentModel.DataAnnotations;
+
+namespace AccountGoWeb.Models.TaxSystem
+{
+ public class ItemTaxGroup : BaseViewModel
+ {
+ [Required(ErrorMessage = "The Tax Group Name field is Required.")]
+ [StringLength(50)]
+ public string? Name { get; set; }
+
+ [Display(Name = "Fully Exempt")]
+ public bool IsFullyExempt { get; set; }
+ public IList Taxes { get; set; }
+
+ public ItemTaxGroup()
+ {
+ Taxes = new List();
+ }
+ }
+}
diff --git a/src/AccountGoWeb/Models/TaxSystem/ItemTaxGroupTax.cs b/src/AccountGoWeb/Models/TaxSystem/ItemTaxGroupTax.cs
new file mode 100644
index 000000000..8ed90b741
--- /dev/null
+++ b/src/AccountGoWeb/Models/TaxSystem/ItemTaxGroupTax.cs
@@ -0,0 +1,9 @@
+namespace AccountGoWeb.Models.TaxSystem
+{
+ public class ItemTaxGroupTax
+ {
+ public int TaxId { get; set; }
+ public int ItemTaxGroupId { get; set; }
+ public bool IsExempt { get; set; }
+ }
+}
diff --git a/src/AccountGoWeb/Models/TaxSystem/Tax.cs b/src/AccountGoWeb/Models/TaxSystem/Tax.cs
new file mode 100644
index 000000000..644a6af0c
--- /dev/null
+++ b/src/AccountGoWeb/Models/TaxSystem/Tax.cs
@@ -0,0 +1,20 @@
+using System.ComponentModel.DataAnnotations;
+
+namespace AccountGoWeb.Models.TaxSystem
+{
+ public class Tax : BaseViewModel
+ {
+ [Required(ErrorMessage = "The Tax Name field is Required.")]
+ [StringLength(50)]
+ public string? TaxName { get; set; }
+
+ [Required(ErrorMessage = "The Tax Code field is Required.")]
+ [StringLength(16)]
+ public string? TaxCode { get; set; }
+
+ [Range(0, 100, ErrorMessage = "The Rate field must be between 0 and 100.")]
+ public decimal Rate { get; set; }
+
+ public bool IsActive { get; set; }
+ }
+}
diff --git a/src/AccountGoWeb/Models/TaxSystem/TaxGroup.cs b/src/AccountGoWeb/Models/TaxSystem/TaxGroup.cs
new file mode 100644
index 000000000..eae959112
--- /dev/null
+++ b/src/AccountGoWeb/Models/TaxSystem/TaxGroup.cs
@@ -0,0 +1,20 @@
+using System.ComponentModel.DataAnnotations;
+
+namespace AccountGoWeb.Models.TaxSystem
+{
+ public class TaxGroup : BaseViewModel
+ {
+ [Required(ErrorMessage = "The Tax Group Name field is Required.")]
+ [StringLength(50)]
+ public string? Description { get; set; }
+ public bool TaxAppliedToShipping { get; set; }
+ public bool IsActive { get; set; }
+
+ public IList Taxes { get; set; }
+
+ public TaxGroup()
+ {
+ Taxes = new List();
+ }
+ }
+}
diff --git a/src/AccountGoWeb/Models/TaxSystem/TaxGroupTax.cs b/src/AccountGoWeb/Models/TaxSystem/TaxGroupTax.cs
new file mode 100644
index 000000000..7edf4094c
--- /dev/null
+++ b/src/AccountGoWeb/Models/TaxSystem/TaxGroupTax.cs
@@ -0,0 +1,8 @@
+namespace AccountGoWeb.Models.TaxSystem
+{
+ public class TaxGroupTax
+ {
+ public int TaxId { get; set; }
+ public int TaxGroupId { get; set; }
+ }
+}
diff --git a/src/AccountGoWeb/Models/TaxSystem/TaxSystemViewModel.cs b/src/AccountGoWeb/Models/TaxSystem/TaxSystemViewModel.cs
index 23f09a05d..46a4fcbbf 100644
--- a/src/AccountGoWeb/Models/TaxSystem/TaxSystemViewModel.cs
+++ b/src/AccountGoWeb/Models/TaxSystem/TaxSystemViewModel.cs
@@ -1,11 +1,9 @@
using Dto.TaxSystem;
-namespace AccountGoWeb.Models.TaxSystem
+namespace AccountGoWeb.Models.TaxSystem;
+public class TaxSystemViewModel
{
- public class TaxSystemViewModel
- {
- public System.Collections.Generic.IEnumerable Taxes { get; set; }
- public System.Collections.Generic.IEnumerable TaxGroups { get; set; }
- public System.Collections.Generic.IEnumerable ItemTaxGroups { get; set; }
- }
+ public System.Collections.Generic.IEnumerable? Taxes { get; set; }
+ public System.Collections.Generic.IEnumerable? TaxGroups { get; set; }
+ public System.Collections.Generic.IEnumerable? ItemTaxGroups { get; set; }
}
diff --git a/src/AccountGoWeb/Program.cs b/src/AccountGoWeb/Program.cs
index 79f367cc5..f75e21924 100644
--- a/src/AccountGoWeb/Program.cs
+++ b/src/AccountGoWeb/Program.cs
@@ -1,26 +1,53 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
-using Microsoft.AspNetCore.Hosting;
-using Microsoft.Extensions.Configuration;
-using Microsoft.Extensions.Hosting;
-using Microsoft.Extensions.Logging;
-
-namespace AccountGoWeb
+using AccountGoWeb.Components;
+using Microsoft.AspNetCore.Authentication.Cookies;
+
+var builder = WebApplication.CreateBuilder(args);
+
+builder.AddServiceDefaults();
+
+// Mapping
+builder.Services.AddAutoMapper(typeof(Program));
+
+builder.Services.AddControllersWithViews();
+
+string apiurl = System.Environment.GetEnvironmentVariable("APIURL") ?? "http://localhost:8001/api/";
+
+builder.Configuration["ApiUrl"] = apiurl;
+Console.WriteLine($"[ASPNETCORE SERVER] API URL {builder.Configuration["ApiUrl"]}");
+
+builder.Services.AddHttpClient();
+builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
+ .AddCookie(o => o.LoginPath = new PathString("/account/signin"));
+
+builder.Services
+ .AddRazorComponents()
+ .AddInteractiveServerComponents()
+ .AddCircuitOptions(options => options.DetailedErrors = true); // for debugging razor components
+
+var app = builder.Build();
+
+// Configure the HTTP request pipeline.
+if (!app.Environment.IsDevelopment())
{
- public class Program
- {
- public static void Main(string[] args)
- {
- CreateHostBuilder(args).Build().Run();
- }
-
- public static IHostBuilder CreateHostBuilder(string[] args) =>
- Host.CreateDefaultBuilder(args)
- .ConfigureWebHostDefaults(webBuilder =>
- {
- webBuilder.UseStartup();
- });
- }
+ app.UseExceptionHandler("/Home/Error");
+ // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
+ app.UseHsts();
}
+
+app.UseHttpsRedirection();
+app.UseStaticFiles();
+
+app.UseRouting();
+
+app.UseAuthentication();
+app.UseAntiforgery();
+app.UseAuthorization();
+
+app.MapControllerRoute(
+ name: "default",
+ pattern: "{controller=Home}/{action=Index}/{id?}");
+
+app.MapRazorComponents()
+ .AddInteractiveServerRenderMode();
+
+app.Run();
diff --git a/src/AccountGoWeb/Properties/launchSettings.json b/src/AccountGoWeb/Properties/launchSettings.json
index 0c2a63276..684f35562 100644
--- a/src/AccountGoWeb/Properties/launchSettings.json
+++ b/src/AccountGoWeb/Properties/launchSettings.json
@@ -13,9 +13,9 @@
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
- }
- },
- "AccountGoWeb": {
+ }
+ },
+ "AccountGoWeb": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
diff --git a/src/AccountGoWeb/Resource.Designer.cs b/src/AccountGoWeb/Resource.Designer.cs
index 2267688fc..4fa30fbab 100644
--- a/src/AccountGoWeb/Resource.Designer.cs
+++ b/src/AccountGoWeb/Resource.Designer.cs
@@ -8,55 +8,54 @@
//
//------------------------------------------------------------------------------
-namespace AccountGoWeb {
- using System;
- using System.Reflection;
+namespace AccountGoWeb;
+
+using System.Reflection;
+
+
+///
+/// A strongly-typed resource class, for looking up localized strings, etc.
+///
+// This class was auto-generated by the StronglyTypedResourceBuilder
+// class via a tool like ResGen or Visual Studio.
+// To add or remove a member, edit your .ResX file then rerun ResGen
+// with the /str option, or rebuild your VS project.
+[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+public class Resource {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ internal Resource() {
+ }
///
- /// A strongly-typed resource class, for looking up localized strings, etc.
+ /// Returns the cached ResourceManager instance used by this class.
///
- // This class was auto-generated by the StronglyTypedResourceBuilder
- // class via a tool like ResGen or Visual Studio.
- // To add or remove a member, edit your .ResX file then rerun ResGen
- // with the /str option, or rebuild your VS project.
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
- [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
- public class Resource {
-
- private static global::System.Resources.ResourceManager resourceMan;
-
- private static global::System.Globalization.CultureInfo resourceCulture;
-
- internal Resource() {
- }
-
- ///
- /// Returns the cached ResourceManager instance used by this class.
- ///
- [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
- public static global::System.Resources.ResourceManager ResourceManager {
- get {
- if (object.ReferenceEquals(resourceMan, null)) {
- global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("AccountGoWeb.Resource", typeof(Resource).GetTypeInfo().Assembly);
- resourceMan = temp;
- }
- return resourceMan;
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ public static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.ReferenceEquals(resourceMan, null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("AccountGoWeb.Resource", typeof(Resource).GetTypeInfo().Assembly);
+ resourceMan = temp;
}
+ return resourceMan;
}
-
- ///
- /// Overrides the current thread's CurrentUICulture property for all
- /// resource lookups using this strongly typed resource class.
- ///
- [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
- public static global::System.Globalization.CultureInfo Culture {
- get {
- return resourceCulture;
- }
- set {
- resourceCulture = value;
- }
+ }
+
+ ///
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ public static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
}
}
}
diff --git a/src/AccountGoWeb/Scripts/Home/Index.tsx b/src/AccountGoWeb/Scripts/Home/Index.tsx
deleted file mode 100644
index 997e4a6c0..000000000
--- a/src/AccountGoWeb/Scripts/Home/Index.tsx
+++ /dev/null
@@ -1,23 +0,0 @@
-import * as React from "react";
-import * as ReactDOM from "react-dom";
-
-interface IHomeProps {
- pageTitle: string;
-}
-
-class Home extends React.Component {
- render() {
- return (
-
- Tiles or widgets here!
-
- );
- }
-}
-
-ReactDOM.render(
- ,
- document.getElementById("home")
-);
-
-export default Home;
\ No newline at end of file
diff --git a/src/AccountGoWeb/Scripts/Quotations/SalesQuotation.tsx b/src/AccountGoWeb/Scripts/Quotations/SalesQuotation.tsx
deleted file mode 100644
index 5bd89650c..000000000
--- a/src/AccountGoWeb/Scripts/Quotations/SalesQuotation.tsx
+++ /dev/null
@@ -1,403 +0,0 @@
-import * as React from "react";
-import * as ReactDOM from "react-dom";
-import {observer} from "mobx-react";
-import * as d3 from "d3";
-import {autorun, observable} from 'mobx';
-import * as accounting from "accounting";
-
-import SelectCustomer from "../Shared/Components/SelectCustomer";
-import SelectPaymentTerm from "../Shared/Components/SelectPaymentTerm";
-import SelectLineItem from "../Shared/Components/SelectLineItem";
-import SelectLineMeasurement from "../Shared/Components/SelectLineMeasurement";
-
-import SalesQuotationLine from "../Shared/Stores/Quotations/SalesQuotationLine";
-import SalesQuotationStore from "../Shared/Stores/Quotations/SalesQuotationStore";
-
-
-let quotationId = window.location.search.split("?id=")[1];
-
-let store = new SalesQuotationStore(quotationId);
-
-@observer
-class ValidationErrors extends React.Component{
- render() {
-
- if (store.validationErrors !== undefined && store.validationErrors.length > 0) {
- var errors = [];
- store.validationErrors.map(function (item, index) {
- errors.push({item} );
- });
- return (
-
-
- );
- }
- return null;
- }
-}
-
-@observer
-class SaveQuotationButton extends React.Component{
- saveNewSalesQuotation(e) {
- store.saveNewQuotation();
- }
- //className = {!store.salesInvoice.posted && store.editMode
- render() {
- return (
-
- );
- }
-}
-
-class CancelQuotationButton extends React.Component{
- cancelOnClick() {
- let baseUrl = location.protocol
- + "//" + location.hostname
- + (location.port && ":" + location.port)
- + "/";
-
- window.location.href = baseUrl + 'quotations';
- }
-
- render() {
- return (
-