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..caddf559f --- /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 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 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..498ad6141 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/* @@ -218,4 +226,5 @@ FakesAssemblies/ /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 + +
+ + + +
+
+ About +
+ +
+
@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

+ + + +@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
  • + } +
*@ + +
+ + + + + + + + + + + + + + + @for (int accountIdx = 0; accountIdx < accounts.Count(); ++accountIdx) + { + var account = accounts.ToList()[accountIdx]; + var accountTargetId = $"asset-{accountIdx}"; + + + + + + + + + + + + + + } + +
CodeNameBalanceDebitCreditActions
+ +
+
+ +} +@if (isAddModalVisible || isEditModalVisible) +{ + +} + +@if (isDeleteModalVisible) +{ + +} + +@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..610883631 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,100 @@ 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(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"); + _logger.LogInformation("Quotation ID is is : " + model.Id); + 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) + return RedirectToAction("quotations"); + } + } return View(); } + + [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 ( -
    -
      - {errors} -
    -
    - - ); - } - 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 ( - - ); - } -} - -@observer -class SalesQuotationHeader extends React.Component{ - onChangeQuotationDate(e) { - store.changedQuotationDate(e.target.value); - } - - - - onChangeCustomer(e) { - alert(''); - } - - onChangeReferenceNo(e) { - store.changedReferenceNo(e.target.value); - } - - - render() { - return ( -
    -
    - Customer Information - {store.salesQuotation.customerId} -
    -
    -
    -
    -
    Customer
    -
    -
    -
    -
    Payment Term
    -
    -
    -
    -
    -
    -
    Date
    -
    - -
    -
    -
    Reference no.
    -
    - -
    -
    -
    Status
    -
    - -
    -
    -
    -
    - ); - } -} - -@observer -class SalesQuotationLines extends React.Component{ - - - - addLineItem() { - - if (store.validationLine()) { - - var itemId, measurementId, quantity, amount, discount, code; - itemId = (document.getElementById("optNewItemId") as HTMLInputElement).value; - - measurementId = (document.getElementById("optNewMeasurementId") as HTMLInputElement).value; - quantity = (document.getElementById("txtNewQuantity") as HTMLInputElement).value; - amount = (document.getElementById("txtNewAmount") as HTMLInputElement).value; - discount = (document.getElementById("txtNewDiscount") as HTMLInputElement).value; - code = (document.getElementById("txtNewCode") as HTMLInputElement).value; - //console.log(`itemId: ${itemId} | measurementId: ${measurementId} | quantity: ${quantity} | amount: ${amount} | discount: ${discount}`); - store.addLineItem(0, itemId, measurementId, quantity, amount, discount, code); - - - (document.getElementById("optNewItemId") as HTMLInputElement).value = ""; - (document.getElementById("txtNewCode") as HTMLInputElement).value = ""; - (document.getElementById("optNewMeasurementId") as HTMLInputElement).value = ""; - (document.getElementById("txtNewQuantity") as HTMLInputElement).value = "1"; - (document.getElementById("txtNewAmount") as HTMLInputElement).value = ""; - (document.getElementById("txtNewDiscount") as HTMLInputElement).value = ""; - - } - - } - - onClickRemoveLineItem(i, e) { - store.removeLineItem(i); - } - - onChangeQuantity(e) { - store.updateLineItem(e.target.name, "quantity", e.target.value); - } - - onChangeAmount(e) { - store.updateLineItem(e.target.name, "amount", e.target.value); - } - - onChangeDiscount(e) { - store.updateLineItem(e.target.name, "discount", e.target.value); - } - - onChangeCode(e) { - store.updateLineItem(e.target.name, "code", e.target.value); - } - - - onFocusOutItem(e, isNew, i) { - - var isExisting = false; - for (var x = 0; x < store.commonStore.items.length; x++) { - if (store.commonStore.items[x].code == i.target.value) { - isExisting = true; - if (isNew) { - (document.getElementById("optNewItemId") as HTMLInputElement).value = store.commonStore.items[x].id; - (document.getElementById("optNewMeasurementId") as HTMLInputElement).value = store.commonStore.items[x].sellMeasurementId; - (document.getElementById("txtNewAmount") as HTMLInputElement).value = store.commonStore.items[x].price; - (document.getElementById("txtNewQuantity") as HTMLInputElement).value = "1"; - document.getElementById("txtNewCode").style.borderColor = ""; - } - else { - store.updateLineItem(e, "itemId", store.commonStore.items[x].id); - store.updateLineItem(e, "measurementId", store.commonStore.items[x].sellMeasurementId); - store.updateLineItem(e, "amount", store.commonStore.items[x].price); - store.updateLineItem(e, "quantity", 1); - i.target.style.borderColor = ""; - } - } - } - - if (!isExisting) - - if (isNew) { - (document.getElementById("optNewItemId") as HTMLInputElement).value = ""; - (document.getElementById("optNewMeasurementId") as HTMLInputElement).value = ""; - (document.getElementById("txtNewAmount") as HTMLInputElement).value = ""; - (document.getElementById("txtNewQuantity") as HTMLInputElement).value = ""; - document.getElementById("txtNewCode").style.borderColor = '#FF0000'; - //document.getElementById("txtNewCode").appendChild(span); - // document.getElementById("txtNewCode").style.border = 'solid'; - } - else { - //store.updateLineItem(e, "itemId", ""); - //store.updateLineItem(e, "measurementId", ""); - //store.updateLineItem(e, "amount", ""); - //store.updateLineItem(e, "quantity", ""); - i.target.style.borderColor = "red"; - //i.target.appendChild(span); - // i.target.style.border = "solid"; - - } - - } - - @observable lineNo = 0; - - - render() { - var newLine = 0; - var lineItems = []; - - for (var i = 0; i < store.salesQuotation.salesQuotationLines.length; i++) { - newLine = newLine + 10; - //var initialCode = this.onloadCode(store.salesQuotation.salesQuotationLines[i].itemId); // this is for initial value of code - - - lineItems.push( - - - - - - - - - {store.getLineTotal(i) } - - - - - ); - //autorun(() => this.lineNo = newLine); - } - - return ( -
    -
    - Line Items -
    -
    - - - - - - - - - - - - - - - - {lineItems} - - - - - - - - - - - - -
    NoItemCodeMeasurementQuantityAmountDiscountLine Total
    - -
    -
    -
    - ); - } -} - -@observer -class SalesQuotationTotals extends React.Component{ - render() { - return ( -
    -
    -
    -
    -
    {accounting.formatMoney(store.RTotal, { symbol: "", format: "%s%v" }) }
    -
    -
    {accounting.formatMoney(store.TTotal, { symbol: "", format: "%s%v" }) }
    -
    -
    {accounting.formatMoney(store.GTotal, { symbol: "", format: "%s%v" }) }
    -
    -
    -
    - ); - } -} - -@observer -class BookButton extends React.Component{ - bookOnClick(e) { - store.bookQuotation(); - } - - render() { - return ( - - - ); - } -} - -@observer -class EditButton extends React.Component { - onClickEditButton() { - // Remove " disabledControl" from current className - var nodes = document.getElementById("divSalesQuotationForm").getElementsByTagName('*'); - for (var i = 0; i < nodes.length; i++) { - var subStringLength = nodes[i].className.length - " disabledControl".length; - nodes[i].className = nodes[i].className.substring(0, subStringLength); - } - - store.changedEditMode(true); - } - render() { - return ( - - - Edit - - ); - } - -} - -export default class SalesQuotation extends React.Component { - render() { - return ( -
    -
    - -
    -
    - - - - -
    -
    - - - -
    -
    - ); - } -} - - -ReactDOM.render(, document.getElementById("divSalesQuotation")); - - - \ No newline at end of file diff --git a/src/AccountGoWeb/Scripts/Shared/Stores/AppState.tsx b/src/AccountGoWeb/Scripts/Shared/Stores/AppState.tsx deleted file mode 100644 index 1e237b89f..000000000 --- a/src/AccountGoWeb/Scripts/Shared/Stores/AppState.tsx +++ /dev/null @@ -1,4 +0,0 @@ -import {observable} from 'mobx'; - -export default class AppState { -} \ No newline at end of file diff --git a/src/AccountGoWeb/Scripts/Shared/Stores/Common/CommonStore.tsx b/src/AccountGoWeb/Scripts/Shared/Stores/Common/CommonStore.tsx deleted file mode 100644 index 5b289ee11..000000000 --- a/src/AccountGoWeb/Scripts/Shared/Stores/Common/CommonStore.tsx +++ /dev/null @@ -1,130 +0,0 @@ -import {observable, extendObservable, action} from 'mobx'; -import * as axios from "axios"; - -import Config = require("Config"); - -export default class CommonStore { - @observable customers = []; - @observable paymentTerms = []; - @observable items = []; - @observable measurements = []; - @observable vendors = []; - @observable accounts = []; - @observable salesQuotationStatus = []; - - constructor() { - this.loadCustomersLookup(); - this.loadPaymentTermsLookup(); - this.loadItemsLookup(); - this.loadMeasurementsLookup(); - this.loadVendorsLookup(); - this.loadAccountsLookup(); - this.loadQuotationStatusLookup(); - } - - loadCustomersLookup() { - let customers = this.customers; - axios.get(Config.apiUrl + "common/customers") - .then(function (result) { - const data = result.data; - for (var i = 0; i < Object.keys(data).length; i++) { - customers.push(data[i]); - } - }); - } - - loadPaymentTermsLookup() { - let paymentTerms = this.paymentTerms; - axios.get(Config.apiUrl + "common/paymentterms") - .then(function (result) { - const data = result.data; - for (var i = 0; i < Object.keys(data).length; i++) { - paymentTerms.push(data[i]); - } - }); - } - - loadVendorsLookup() { - let vendors = this.vendors; - axios.get(Config.apiUrl + "common/vendors") - .then(function (result) { - const data = result.data; - for (var i = 0; i < Object.keys(data).length; i++) { - vendors.push(data[i]); - } - }.bind(this)); - } - - loadItemsLookup() { - let items = this.items; - axios.get(Config.apiUrl + "common/items") - .then(function (result) { - const data = result.data; - for (var i = 0; i < Object.keys(data).length; i++) { - items.push(data[i]); - } - }); - } - - loadMeasurementsLookup() { - let measurements = this.measurements; - axios.get(Config.apiUrl + "common/measurements") - .then(function (result) { - const data = result.data; - for (var i = 0; i < Object.keys(data).length; i++) { - measurements.push(data[i]); - } - }); - } - - loadVoucherTypesLookup() { - } - - loadQuotationStatusLookup() { - let quotationStatus = this.salesQuotationStatus; - axios.get(Config.apiUrl + "common/salesquotationstatus") - .then(function (result) { - const data = result.data; - for (var i = 0; i < Object.keys(data).length; i++) - { - quotationStatus.push(data[i]); - } - }) - } - - loadAccountsLookup() { - let accounts = this.accounts; - axios.get(Config.apiUrl + "common/postingaccounts") - .then(function (result) { - const data = result.data; - for (var i = 0; i < Object.keys(data).length; i++) { - accounts.push(data[i]); - } - }); - } - - getApplicableTaxes(itemId: number, partyId: number) { - var result = axios.get(Config.apiUrl + "tax/gettax?itemId=" + itemId + "&partyId=" + partyId); - result.then(function (result) { - return result.data; - }); - } - - getSalesLineTaxAmount(quantity: number, amount: number, discount: number, taxes: any) { - var lineTaxTotal = 0; - amount = (amount * quantity) - discount; - taxes.map(function (tax) { - lineTaxTotal = lineTaxTotal + (amount - (amount / (1 + (tax.rate / 100)))); - }); - return lineTaxTotal; - } - - getPurhcaseLineTaxAmount(quantity: number, amount: number, discount: number, taxes: any) { - var lineTaxTotal = 0; - amount = (amount * quantity) - discount; - taxes.map(function (tax) { - lineTaxTotal = lineTaxTotal + (amount - (amount / (1 + (tax.rate / 100)))); - }); - return lineTaxTotal; - } -} \ No newline at end of file diff --git a/src/AccountGoWeb/Scripts/Shared/Stores/Purchasing/PurchaseInvoice.tsx b/src/AccountGoWeb/Scripts/Shared/Stores/Purchasing/PurchaseInvoice.tsx deleted file mode 100644 index 025b004e8..000000000 --- a/src/AccountGoWeb/Scripts/Shared/Stores/Purchasing/PurchaseInvoice.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import PurchaseInvoiceLine from "./PurchaseInvoiceLine"; - -export default class PurchaseInvoice { - id: number; - fromPurchaseOrderId: number; - vendorId: number; - invoiceDate: Date; - paymentTermId: number; - referenceNo: string; - posted: boolean; - readyForPosting: boolean; - purchaseInvoiceLines: PurchaseInvoiceLine[] = []; - statusId: number; - - constructor() { - this.id = 0; - this.posted = false; - this.readyForPosting = false; - - } -} \ No newline at end of file diff --git a/src/AccountGoWeb/Scripts/Shared/Stores/Purchasing/PurchaseInvoiceLine.tsx b/src/AccountGoWeb/Scripts/Shared/Stores/Purchasing/PurchaseInvoiceLine.tsx deleted file mode 100644 index 52be17a37..000000000 --- a/src/AccountGoWeb/Scripts/Shared/Stores/Purchasing/PurchaseInvoiceLine.tsx +++ /dev/null @@ -1,19 +0,0 @@ -export default class PurchaseInvoiceLine { - id = 0; - itemId; - measurementId; - quantity; - amount; - discount; - remainingQtyToInvoice: number; - - constructor(id, itemId, measurementId, quantity, amount, discount) { - this.id = id; - this.itemId = itemId; - this.measurementId = measurementId; - this.quantity = quantity; - this.amount = amount; - this.discount = discount; - this.remainingQtyToInvoice = quantity; - } -} \ No newline at end of file diff --git a/src/AccountGoWeb/Scripts/Shared/Stores/Purchasing/PurchaseOrder.tsx b/src/AccountGoWeb/Scripts/Shared/Stores/Purchasing/PurchaseOrder.tsx deleted file mode 100644 index b82284b5b..000000000 --- a/src/AccountGoWeb/Scripts/Shared/Stores/Purchasing/PurchaseOrder.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import PurchaseOrderLine from "./PurchaseOrderLine"; - -export default class PurchaseOrder { - id: number; - vendorId: number; - orderDate: Date; - paymentTermId: number; - referenceNo: string; - statusId: number; - purchaseOrderLines: PurchaseOrderLine[] = []; -} \ No newline at end of file diff --git a/src/AccountGoWeb/Scripts/Shared/Stores/Purchasing/PurchaseOrderLine.tsx b/src/AccountGoWeb/Scripts/Shared/Stores/Purchasing/PurchaseOrderLine.tsx deleted file mode 100644 index bd21b5b5f..000000000 --- a/src/AccountGoWeb/Scripts/Shared/Stores/Purchasing/PurchaseOrderLine.tsx +++ /dev/null @@ -1,19 +0,0 @@ -export default class PurchaseOrderLine { - id = 0; - itemId; - measurementId; - quantity; - amount; - discount; - code; - - constructor(id, itemId, measurementId, quantity, amount, discount, code) { - this.id = id; - this.itemId = itemId; - this.measurementId = measurementId; - this.quantity = quantity; - this.amount = amount; - this.discount = discount; - this.code = code; - } -} \ No newline at end of file diff --git a/src/AccountGoWeb/Scripts/Shared/Stores/Quotations/SalesQuotation.tsx b/src/AccountGoWeb/Scripts/Shared/Stores/Quotations/SalesQuotation.tsx deleted file mode 100644 index b692dffdf..000000000 --- a/src/AccountGoWeb/Scripts/Shared/Stores/Quotations/SalesQuotation.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import SalesQuotationLine from "./SalesQuotationLine"; - -export default class SalesQuotation { - id: number; - customerId: number; - quotationDate: Date; - paymentTermId: number; - referenceNo: string; - statusId: number; - salesQuotationLines: SalesQuotationLine[] = []; -} \ No newline at end of file diff --git a/src/AccountGoWeb/Scripts/Shared/Stores/Sales/SalesOrder.tsx b/src/AccountGoWeb/Scripts/Shared/Stores/Sales/SalesOrder.tsx deleted file mode 100644 index 4381b3189..000000000 --- a/src/AccountGoWeb/Scripts/Shared/Stores/Sales/SalesOrder.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import SalesOrderLine from "./SalesOrderLine"; - -//interface ISalesOrder { -// id; -// customerId; -// orderDate; -// paymentTermId; -// referenceNo; -// salesOrderLines: SalesOrderLine[]; -//} - -export default class SalesOrder { - id: number; - customerId: number; - orderDate: Date; - paymentTermId: number; - referenceNo: string; - statusId: number; - quotationId: number; - salesOrderLines: SalesOrderLine[] = []; -} \ No newline at end of file diff --git a/src/AccountGoWeb/Scripts/Shared/Stores/Sales/SalesOrderLine.tsx b/src/AccountGoWeb/Scripts/Shared/Stores/Sales/SalesOrderLine.tsx deleted file mode 100644 index d491ebb40..000000000 --- a/src/AccountGoWeb/Scripts/Shared/Stores/Sales/SalesOrderLine.tsx +++ /dev/null @@ -1,18 +0,0 @@ -export default class SalesOrderLine { - id: number; - itemId: number; - measurementId: number; - quantity: number; - amount: number; - discount: number; - code: number; - constructor(id, itemId, measurementId, quantity, amount, discount, code) { - this.id = id; - this.itemId = itemId; - this.measurementId = measurementId; - this.quantity = quantity; - this.amount = amount; - this.discount = discount; - this.code = code; - } -} \ No newline at end of file diff --git a/src/AccountGoWeb/Scripts/Shared/Stores/TaxSystem/Tax.tsx b/src/AccountGoWeb/Scripts/Shared/Stores/TaxSystem/Tax.tsx deleted file mode 100644 index 08993815f..000000000 --- a/src/AccountGoWeb/Scripts/Shared/Stores/TaxSystem/Tax.tsx +++ /dev/null @@ -1,6 +0,0 @@ -export default class SalesOrder { - id: number; - code: string; - name: string; - rate: number; -} \ No newline at end of file diff --git a/src/AccountGoWeb/Startup.cs b/src/AccountGoWeb/Startup.cs deleted file mode 100644 index d6a8e1e4d..000000000 --- a/src/AccountGoWeb/Startup.cs +++ /dev/null @@ -1,81 +0,0 @@ -using System; -using System.IO; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.HttpsPolicy; -using Microsoft.AspNetCore.Authentication.Cookies; -using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; -using Infrastructure.AssemblyLoader; - -namespace AccountGoWeb -{ - public class Startup - { - public Startup(IConfiguration configuration) - { - Configuration = configuration; - // var builder = new ConfigurationBuilder() - // .SetBasePath(env.ContentRootPath) - // .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) - // .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true) - // .AddEnvironmentVariables(); - // Configuration = builder.Build(); - - string urlhost = System.Environment.GetEnvironmentVariable("APIHOST") ?? "localhost"; - Configuration["ApiUrl"] = $"http://{urlhost}:8001/api/"; - System.Console.WriteLine($"[ASPNETCORE SERVER] API URL {Configuration["ApiUrl"]}"); - } - - public IConfiguration Configuration { get; } - - // This method gets called by the runtime. Use this method to add services to the container. - public void ConfigureServices(IServiceCollection services) - { - services.AddControllersWithViews(); - - services.AddSingleton(Configuration); - - services.AddHttpClient(); - - services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme) - .AddCookie(o => o.LoginPath = new PathString("/account/signin")); - - } - - // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. - public void Configure(IApplicationBuilder app, IWebHostEnvironment env) - { - if (env.IsDevelopment()) - { - app.UseDeveloperExceptionPage(); - } - else - { - 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.UseAuthorization(); - - app.UseEndpoints(endpoints => - { - endpoints.MapControllerRoute( - name: "default", - pattern: "{controller=Home}/{action=Index}/{id?}"); - }); - } - } -} diff --git a/src/AccountGoWeb/Views/Account/SignIn.cshtml b/src/AccountGoWeb/Views/Account/SignIn.cshtml index f8493b30c..37db6dd88 100644 --- a/src/AccountGoWeb/Views/Account/SignIn.cshtml +++ b/src/AccountGoWeb/Views/Account/SignIn.cshtml @@ -16,12 +16,12 @@ - - - + + + - - + +
    @@ -74,11 +74,11 @@
    - - - - - - + + + + + + diff --git a/src/AccountGoWeb/Views/Administration/Company.cshtml b/src/AccountGoWeb/Views/Administration/Company.cshtml index acb4dff48..c3e7bdbb0 100644 --- a/src/AccountGoWeb/Views/Administration/Company.cshtml +++ b/src/AccountGoWeb/Views/Administration/Company.cshtml @@ -12,6 +12,7 @@ }

    + @* *@

    +
    + +
    + + +
    +
    diff --git a/src/AccountGoWeb/Views/Contact/Contact.cshtml b/src/AccountGoWeb/Views/Contact/Contact.cshtml index 197a2dedb..03194cbf3 100644 --- a/src/AccountGoWeb/Views/Contact/Contact.cshtml +++ b/src/AccountGoWeb/Views/Contact/Contact.cshtml @@ -46,12 +46,12 @@ -
    + @*
    Fax
    -
    +
    *@
    Website
    @@ -68,7 +68,7 @@
    - + Close
    diff --git a/src/AccountGoWeb/Views/Dashboard/MonthlySales.cshtml b/src/AccountGoWeb/Views/Dashboard/MonthlySales.cshtml index c94ca011a..e3007bbbc 100644 --- a/src/AccountGoWeb/Views/Dashboard/MonthlySales.cshtml +++ b/src/AccountGoWeb/Views/Dashboard/MonthlySales.cshtml @@ -1,7 +1,7 @@  - + + \ No newline at end of file + + @childAccount.AccountCode + @childAccount.AccountName + @childAccount.TotalBalance + @childAccount.TotalDebitBalance + @childAccount.TotalCreditBalance + + + + + + + + } + + + + + + } + + + *@ + \ No newline at end of file diff --git a/src/AccountGoWeb/Views/Financials/AccountsPrev.cshtml b/src/AccountGoWeb/Views/Financials/AccountsPrev.cshtml new file mode 100644 index 000000000..6837eddf6 --- /dev/null +++ b/src/AccountGoWeb/Views/Financials/AccountsPrev.cshtml @@ -0,0 +1,91 @@ +@model string + +@{ + ViewBag.Title = "Chart of Accounts"; +} +
    +
    +
    +
    +
    + \ No newline at end of file diff --git a/src/AccountGoWeb/Views/Financials/BalanceSheet.cshtml b/src/AccountGoWeb/Views/Financials/BalanceSheet.cshtml index 59ea65cd7..1378569db 100644 --- a/src/AccountGoWeb/Views/Financials/BalanceSheet.cshtml +++ b/src/AccountGoWeb/Views/Financials/BalanceSheet.cshtml @@ -1,18 +1,21 @@ @model ICollection @{ - ViewBag.Title = "BalanceSheet"; - Layout = "~/Views/Shared/_Layout.cshtml"; + ViewBag.Title = "BalanceSheet"; + Layout = "~/Views/Shared/_Layout_bootstrap.cshtml"; } -
    -

    Balance Sheet

    + +@if (Model != null) +{ +
    +

    Balance Sheet

    -
    - - - - - - +
    +
    Account CodeAccount NameAmount
    + + + + + @foreach (var asset in Model.Where(a => a.AccountClassId == 1)) { @@ -21,52 +24,62 @@ } - - - - -
    Account CodeAccount NameAmount
    @asset.Amount
    Total Assets@Model.Where(a => a.AccountClassId == 1).Sum(a => a.Amount)
    + + Total Assets + @Model.Where(a => a.AccountClassId == 1).Sum(a => a.Amount) + +
    -
    - - - - - - - @foreach (var liability in Model.Where(a => a.AccountClassId == 2)) - { - - - - - - } - - - +
    +
    Account CodeAccount NamceAmount
    @Html.ActionLink((string)string.Format("{0}", liability.AccountCode), "account", new { id = liability.AccountId })@liability.AccountName@liability.Amount
    Total Liabilities@Model.Where(a => a.AccountClassId == 2).Sum(a => a.Amount)
    + + + + + + @foreach (var liability in Model.Where(a => a.AccountClassId == 2)) + { + + + + + } + + + +
    Account CodeAccount NamceAmount
    @Html.ActionLink((string)string.Format("{0}", liability.AccountCode), "account", new + { + id = + liability.AccountId + })@liability.AccountName@liability.Amount
    Total Liabilities@Model.Where(a => a.AccountClassId == 2).Sum(a => a.Amount)
    -
    -
    - - - - - - - @foreach (var equity in Model.Where(a => a.AccountClassId == 3)) - { - - - - - - } - - - + +
    +
    Account CodeAccount NamceAmount
    @Html.ActionLink((string)string.Format("{0}", equity.AccountCode), "account", new { id = equity.AccountId })@equity.AccountName@equity.Amount
    Total Equities@Model.Where(a => a.AccountClassId == 3).Sum(a => a.Amount)
    + + + + + + @foreach (var equity in Model.Where(a => a.AccountClassId == 3)) + { + + + + + } + + + +
    Account CodeAccount NamceAmount
    @Html.ActionLink((string)string.Format("{0}", equity.AccountCode), "account", new { id = equity.AccountId }) + @equity.AccountName@equity.Amount
    Total Equities@Model.Where(a => a.AccountClassId == 3).Sum(a => a.Amount)
    -
    +
    +} +else +{ +

    Error fetching data.

    +} \ No newline at end of file diff --git a/src/AccountGoWeb/Views/Financials/Banks.cshtml b/src/AccountGoWeb/Views/Financials/Banks.cshtml index 28e3abb2c..c8075c656 100644 --- a/src/AccountGoWeb/Views/Financials/Banks.cshtml +++ b/src/AccountGoWeb/Views/Financials/Banks.cshtml @@ -1,5 +1,8 @@ @model IEnumerable - +
    diff --git a/src/AccountGoWeb/Views/Financials/IncomeStatement.cshtml b/src/AccountGoWeb/Views/Financials/IncomeStatement.cshtml index dbf6a541e..54cf2ac2e 100644 --- a/src/AccountGoWeb/Views/Financials/IncomeStatement.cshtml +++ b/src/AccountGoWeb/Views/Financials/IncomeStatement.cshtml @@ -1,57 +1,70 @@ @model ICollection + @{ - ViewBag.Title = "IncomeStatement"; - Layout = "~/Views/Shared/_Layout.cshtml"; - var netIncome = Model.Where(a => a.IsExpense == false).Sum(a => a.Amount) - Model.Where(a => a.IsExpense == true).Sum(a => a.Amount); + ViewBag.Title = "Income Statement"; + Layout = "~/Views/Shared/_Layout_bootstrap.cshtml"; + + var netIncome = Model?.Where(a => !a.IsExpense).Sum(a => a.Amount) ?? 0 - + Model?.Where(a => a.IsExpense).Sum(a => a.Amount) ?? 0; }

    Income Statement

    -
    -

    Income Statement

    -
    -
    - - - - - - - @foreach (var asset in Model.Where(a => a.IsExpense == false)) - { +@if (ViewBag.Error != null) +{ +
    @ViewBag.Error
    +} +else if (Model == null || !Model.Any()) +{ +

    No data available to display.

    +} +else +{ +
    +

    Revenues

    +
    Account CodeAccount NameAmount
    - - - + + + - } - - - - -
    @Html.ActionLink((string)string.Format("{0}", asset.AccountCode), "account", new { id = asset.AccountId })@asset.AccountName@asset.AmountAccount CodeAccount NameAmount
    Total Revenues@Model.Where(a => a.IsExpense == false).Sum(a => a.Amount)
    -
    -
    - - - - - - - @foreach (var asset in Model.Where(a => a.IsExpense == true)) - { + @foreach (var item in Model.Where(a => !a.IsExpense)) + { + + + + + + } - - - + + - } - - - - -
    Account CodeAccount NameAmount
    @Html.ActionLink(item.AccountCode, "Account", new { id = item.AccountId })@item.AccountName@item.Amount
    @Html.ActionLink((string)string.Format("{0}", asset.AccountCode), "account", new { id = asset.AccountId })@asset.AccountName@asset.AmountTotal Revenues@Model.Where(a => !a.IsExpense).Sum(a => a.Amount)
    Total Expenses@Model.Where(a => a.IsExpense == true).Sum(a => a.Amount)
    -
    -
    - Net Income: @netIncome -
    \ No newline at end of file + +
    +
    +

    Expenses

    + + + + + + + @foreach (var item in Model.Where(a => a.IsExpense)) + { + + + + + + } + + + + +
    Account CodeAccount NameAmount
    @Html.ActionLink(item.AccountCode, "Account", new { id = item.AccountId })@item.AccountName@item.Amount
    Total Expenses@Model.Where(a => a.IsExpense).Sum(a => a.Amount)
    +
    +
    + Net Income: @netIncome +
    +} diff --git a/src/AccountGoWeb/Views/Financials/TrialBalance.cshtml b/src/AccountGoWeb/Views/Financials/TrialBalance.cshtml index 4bd9d2f1c..ad258f287 100644 --- a/src/AccountGoWeb/Views/Financials/TrialBalance.cshtml +++ b/src/AccountGoWeb/Views/Financials/TrialBalance.cshtml @@ -1,7 +1,7 @@ @model ICollection @{ ViewBag.Title = "TrialBalance"; - Layout = "~/Views/Shared/_Layout.cshtml"; + Layout = "~/Views/Shared/_Layout_bootstrap.cshtml"; }

    diff --git a/src/AccountGoWeb/Views/Home/Index.cshtml b/src/AccountGoWeb/Views/Home/Index.cshtml index c1bfb55ba..a4bb32f3a 100644 --- a/src/AccountGoWeb/Views/Home/Index.cshtml +++ b/src/AccountGoWeb/Views/Home/Index.cshtml @@ -1,10 +1,25 @@ -
    -
    - @Html.Partial("~/Views/Dashboard/_MonthlySales.cshtml") -
    -
    +@inject IConfiguration _configuration + +
    + Good Deed Books Logo +

    + @_configuration["GoodDeeds:SuperOrganizationName"] +

    -
    -
    -
    + + +
    +
    +
    + +
    +
    + +
    +
    + +
    +
    +
    +
    diff --git a/src/AccountGoWeb/Views/Inventory/Items.cshtml b/src/AccountGoWeb/Views/Inventory/Index.cshtml similarity index 90% rename from src/AccountGoWeb/Views/Inventory/Items.cshtml rename to src/AccountGoWeb/Views/Inventory/Index.cshtml index c336efead..c9e73bd99 100644 --- a/src/AccountGoWeb/Views/Inventory/Items.cshtml +++ b/src/AccountGoWeb/Views/Inventory/Index.cshtml @@ -1,7 +1,7 @@ @model string
    - + New Item @@ -16,7 +16,7 @@ \ No newline at end of file + + +
    +
    + @Html.ValidationSummary(true) +
    +
    +
    +
    Vendor Name
    +
    + + +
    +
    + @* Invoice Date *@ +
    +
    Date
    +
    + +
    +
    + @* Amount Paid *@ +
    +
    Amount Paid
    +
    + +
    +
    + @* Is Paid *@ +
    +
    Is Paid
    +
    + +
    +
    +
    + + + + + + + + + + + @for (int i = 0; i < Model.PurchaseInvoiceLines.Count; i++) + { + + + + + + + + } + + + + +
    ItemQuantityAmountDiscountMeasurement
    + @Html.DropDownListFor(model => model.PurchaseInvoiceLines[i].ItemId, + (IEnumerable)ViewBag.Items, new + { + @class = "form-control", + id = + "optItem" + }) + + + @Html.EditorFor(model => model.PurchaseInvoiceLines[i].Quantity, new + { + htmlAttributes = new + { + @class = "form-control" + } + }) + + @Html.EditorFor(model => model.PurchaseInvoiceLines[i].Amount, new + { + htmlAttributes = new + { + @class = "form-control" + } + }) + + @Html.EditorFor(model => model.PurchaseInvoiceLines[i].Discount, new + { + htmlAttributes = new + { + @class = "form-control" + } + }) + + @Html.DropDownListFor(model => model.PurchaseInvoiceLines[i].MeasurementId, + (IEnumerable)ViewBag.Measurements, + new { @class = "form-control", id = $"optMeasurement_{i}" }) + +
    + +
    +
    +
    + +
    + + Close +
    +
    \ No newline at end of file diff --git a/src/AccountGoWeb/Views/Purchasing/AddPurchaseOrder.cshtml b/src/AccountGoWeb/Views/Purchasing/AddPurchaseOrder.cshtml index 4b086b498..6aab77225 100644 --- a/src/AccountGoWeb/Views/Purchasing/AddPurchaseOrder.cshtml +++ b/src/AccountGoWeb/Views/Purchasing/AddPurchaseOrder.cshtml @@ -1,2 +1,107 @@ -
    - +@model Dto.Purchasing.PurchaseOrder + + + +
    +
    + @Html.ValidationSummary(true) +
    +
    +
    +
    Vendor Name
    +
    + + +
    +
    +
    +
    Completed
    +
    + +
    +
    +
    +
    Date
    +
    + +
    +
    +
    + + + + + + + + + + @for (int i = 0; i < Model.PurchaseOrderLines.Count; i++) { + + + + + + + + } + + + + + +
    ItemQuantityAmountDiscountMeasurement
    + @Html.DropDownListFor(model => model.PurchaseOrderLines[i].ItemId, + (IEnumerable)ViewBag.Items, + new { + @class = "form-control", + id = + "optItem" + }) + + + @Html.EditorFor(model => model.PurchaseOrderLines[i].Quantity, + new { + htmlAttributes = new { + @class = "form-control" + } + }) + + @Html.EditorFor(model => model.PurchaseOrderLines[i].Amount, + new { + htmlAttributes = new { + @class = "form-control" + } + }) + + @Html.EditorFor(model => model.PurchaseOrderLines[i].Discount, + new { + htmlAttributes = new { + @class = "form-control" + } + }) + + @Html.DropDownListFor(model => model.PurchaseOrderLines[i].MeasurementId, + (IEnumerable)ViewBag.Measurements, + new { @class = "form-control", id = $"optMeasurement_{i}" }) + +
    + +
    +
    + +
    + + Close +
    +
    +
    +@*
    *@ +@* *@ \ No newline at end of file diff --git a/src/AccountGoWeb/Views/Purchasing/PurchaseInvoice.cshtml b/src/AccountGoWeb/Views/Purchasing/PurchaseInvoice.cshtml index b15e3d4f7..50b7522a0 100644 --- a/src/AccountGoWeb/Views/Purchasing/PurchaseInvoice.cshtml +++ b/src/AccountGoWeb/Views/Purchasing/PurchaseInvoice.cshtml @@ -1,3 +1,139 @@ -
    +@model Dto.Purchasing.PurchaseInvoice - \ No newline at end of file + + + + +
    +
    + @Html.HiddenFor(m => m.Id) +
    +
    +
    +
    +
    Vendor Name
    +
    + + + @Html.HiddenFor(m => m.VendorId) +
    +
    + @* Amount *@ +
    +
    Amount
    +
    + @Model.Amount +
    +
    + @* Amount Paid *@ +
    +
    Amount Paid
    +
    + @Model.AmountPaid +
    +
    + @* Invoice Date *@ +
    +
    Invoice Date
    +
    + @Model.InvoiceDate +
    +
    + @* Posted *@ +
    +
    Posted
    +
    + @Model.Posted +
    +
    + @* Is Paid *@ +
    +
    Is Paid
    +
    + @Model.IsPaid +
    +
    +
    + + @* Table *@ + + + + + + + + + + @for (int i = 0; i < Model.PurchaseInvoiceLines.Count; i++) + { + + + + + + + + } + +
    ItemQuantityAmountDiscountMeasurement
    + + + + + + + + + + + + + + +
    +
    +
    +
    + +
    + + Close +
    +
    + +@section scripts{ + + +} \ No newline at end of file diff --git a/src/AccountGoWeb/Views/Purchasing/PurchaseInvoices.cshtml b/src/AccountGoWeb/Views/Purchasing/PurchaseInvoices.cshtml index 83e2d27c4..db94d0df4 100644 --- a/src/AccountGoWeb/Views/Purchasing/PurchaseInvoices.cshtml +++ b/src/AccountGoWeb/Views/Purchasing/PurchaseInvoices.cshtml @@ -45,7 +45,7 @@ selectedRow = selectedRows[0]; document.getElementById('linkMakePayment').setAttribute('href', 'payment/' + selectedRow.id); - document.getElementById('linkViewInvoice').setAttribute('href', 'purchaseinvoice?invoiceId=' + selectedRow.id); + document.getElementById('linkViewInvoice').setAttribute('href', 'purchaseinvoice?id=' + selectedRow.id); if(!selectedRow.isPaid && selectedRow.posted) document.getElementById('linkMakePayment').setAttribute('class', 'btn'); diff --git a/src/AccountGoWeb/Views/Purchasing/PurchaseOrder.cshtml b/src/AccountGoWeb/Views/Purchasing/PurchaseOrder.cshtml index a7f10ffe4..79c33fc6f 100644 --- a/src/AccountGoWeb/Views/Purchasing/PurchaseOrder.cshtml +++ b/src/AccountGoWeb/Views/Purchasing/PurchaseOrder.cshtml @@ -1,2 +1,127 @@ -
    - \ No newline at end of file +@model Dto.Purchasing.PurchaseOrder + + + + + +
    +
    + @Html.HiddenFor(m => m.Id) +
    +
    +
    +
    +
    Vendor Name
    +
    + + + @Html.HiddenFor(m => m.VendorId) +
    +
    + @* Amount *@ +
    +
    Amount
    +
    + @Model.Amount +
    +
    + @* Order Date *@ +
    +
    Order Date
    +
    + + +
    +
    + @* Completed *@ +
    +
    Completed
    +
    + + +
    +
    +
    + + @* Table *@ + + + + + + + + + + @for (int i = 0; i < Model.PurchaseOrderLines.Count; i++) + { + + + + + + + + } + +
    ItemQuantityAmountDiscountMeasurement
    + + + + + + + + + + + + + + +
    +
    +
    +
    + +
    + + Close +
    +
    + +@section scripts{ + + +} \ No newline at end of file diff --git a/src/AccountGoWeb/Views/Purchasing/PurchaseOrders.cshtml b/src/AccountGoWeb/Views/Purchasing/PurchaseOrders.cshtml index 397531fd4..21a03aa84 100644 --- a/src/AccountGoWeb/Views/Purchasing/PurchaseOrders.cshtml +++ b/src/AccountGoWeb/Views/Purchasing/PurchaseOrders.cshtml @@ -42,7 +42,7 @@ //document.getElementById('linkNewReceipt').setAttribute('href', 'addreceipt?purchId=' + selectedRow.id); document.getElementById('linkCreateInvoice').setAttribute('href', 'addpurchaseinvoice?purchId=' + selectedRow.id); - document.getElementById('linkViewOrder').setAttribute('href', 'purchaseorder?purchId=' + selectedRow.id); + document.getElementById('linkViewOrder').setAttribute('href', 'purchaseorder?id=' + selectedRow.id); if(selectedRow.purchaseInvoiceHeaderId === undefined){ document.getElementById('linkCreateInvoice').setAttribute('class', 'btn'); @@ -60,16 +60,16 @@ } - //if(selectedRow.completed) - //{ - // document.getElementById('linkCreateInvoice').setAttribute('class', ''); - // document.getElementById('linkNewReceipt').setAttribute('class', 'inactiveLink'); - //} - //else - //{ - // document.getElementById('linkCreateInvoice').setAttribute('class', 'inactiveLink'); - // document.getElementById('linkNewReceipt').setAttribute('class', ''); - //} + if(selectedRow.completed) + { + document.getElementById('linkCreateInvoice').setAttribute('class', ''); + document.getElementById('linkNewReceipt').setAttribute('class', 'inactiveLink'); + } + else + { + document.getElementById('linkCreateInvoice').setAttribute('class', 'inactiveLink'); + document.getElementById('linkNewReceipt').setAttribute('class', ''); + } } // wait for the document to be loaded, otherwise diff --git a/src/AccountGoWeb/Views/Purchasing/Vendor.cshtml b/src/AccountGoWeb/Views/Purchasing/Vendor.cshtml index 188989895..27e3a21d8 100644 --- a/src/AccountGoWeb/Views/Purchasing/Vendor.cshtml +++ b/src/AccountGoWeb/Views/Purchasing/Vendor.cshtml @@ -1,5 +1,11 @@ @model Dto.Purchasing.Vendor + + diff --git a/src/AccountGoWeb/Views/Quotations/AddSalesQuotation.cshtml b/src/AccountGoWeb/Views/Quotations/AddSalesQuotation.cshtml index 14d4e4d7e..eddd20580 100644 --- a/src/AccountGoWeb/Views/Quotations/AddSalesQuotation.cshtml +++ b/src/AccountGoWeb/Views/Quotations/AddSalesQuotation.cshtml @@ -1,2 +1,131 @@ -
    - +@model Dto.Sales.SalesQuotation + + + + +
    +
    + @Html.ValidationSummary(true) +
    +
    + @* Customer *@ +
    +
    Customer
    +
    + + +
    +
    + @* Payment Term *@ +
    +
    Payment Term
    +
    + + +
    +
    +
    + + + + + + + + + + @for (int i = 0; i < Model.SalesQuotationLines.Count; i++) + { + + + + + + + + + } + + + + +
    ItemQuantityAmountDiscountMeasurement
    + @Html.DropDownListFor(model => model.SalesQuotationLines[i].ItemId, + (IEnumerable)ViewBag.Items, new { @class = "form-control", id = "optItem" }) + + + @Html.EditorFor(model => model.SalesQuotationLines[i].Quantity, new + { + htmlAttributes = new + { + @class = "form-control" + } + }) + + @Html.EditorFor(model => model.SalesQuotationLines[i].Amount, new + { + htmlAttributes = new + { + @class = "form-control" + } + }) + + @Html.EditorFor(model => model.SalesQuotationLines[i].Discount, new + { + htmlAttributes = new + { + @class = "form-control" + } + }) + + @Html.DropDownListFor(model => model.SalesQuotationLines[i].MeasurementId, + (IEnumerable)ViewBag.Measurements, + new { @class = "form-control", id = $"optMeasurement_{i}" }) + +
    + +
    +
    +
    +
    +
    + +@section scripts { + +} \ No newline at end of file diff --git a/src/AccountGoWeb/Views/Quotations/Quotation.cshtml b/src/AccountGoWeb/Views/Quotations/Quotation.cshtml index 11cae02cc..8035de6ef 100644 --- a/src/AccountGoWeb/Views/Quotations/Quotation.cshtml +++ b/src/AccountGoWeb/Views/Quotations/Quotation.cshtml @@ -1,2 +1,122 @@ -
    - \ No newline at end of file +@model Dto.Sales.SalesQuotation + + + + + +
    +
    + @Html.HiddenFor(m => m.Id) +
    +
    +
    + @* Customer Name *@ +
    +
    Customer Name
    +
    + + + @Html.HiddenFor(m => m.CustomerId) +
    +
    + @* Quotation Date *@ +
    +
    Quotation Date
    +
    + +
    +
    + @* Payment Term *@ +
    +
    Payment Term
    +
    @ViewBag.PaymentTermId
    +
    + @* Total Amount *@ +
    +
    Total Amount
    +
    @ViewBag.TotalAmount
    +
    +
    + @* Table *@ + + + + + + + + + + @for (int i = 0; i < Model.SalesQuotationLines.Count; i++) { + + + + + + + + } + +
    ItemQuantityAmountDiscountMeasurement
    + + + + + + + + + + + + + + +
    +
    +
    +
    +
    + + Close +
    +
    + +@section scripts{ + + +} \ No newline at end of file diff --git a/src/AccountGoWeb/Views/Quotations/Quotations.cshtml b/src/AccountGoWeb/Views/Quotations/Quotations.cshtml index 052bcac1d..bfe7f309f 100644 --- a/src/AccountGoWeb/Views/Quotations/Quotations.cshtml +++ b/src/AccountGoWeb/Views/Quotations/Quotations.cshtml @@ -15,7 +15,7 @@
    -
    +
    @@ -43,11 +43,9 @@ var selectedRows = gridOptions.api.getSelectedRows(); selectedRow = selectedRows[0]; - document.getElementById('linkViewQuotation').setAttribute('href', 'quotation?id=' + selectedRow.id); + document.getElementById('linkViewQuotation').setAttribute('href', 'Quotation?id=' + selectedRow.id); document.getElementById('linkViewQuotation').setAttribute('class', 'btn'); - - if(selectedRow.status == 3) { document.getElementById('linkNewOrder').setAttribute('class', 'btn inactiveLink'); @@ -56,9 +54,6 @@ document.getElementById('linkNewOrder').setAttribute('href', '/sales/salesorder?quotationId=' + selectedRow.id); document.getElementById('linkNewOrder').setAttribute('class', 'btn'); } - - - } // wait for the document to be loaded, otherwise diff --git a/src/AccountGoWeb/Views/Sales/AddReceipt.cshtml b/src/AccountGoWeb/Views/Sales/AddReceipt.cshtml index 36996ae05..0f9ede2f1 100644 --- a/src/AccountGoWeb/Views/Sales/AddReceipt.cshtml +++ b/src/AccountGoWeb/Views/Sales/AddReceipt.cshtml @@ -1,6 +1,12 @@ @model AccountGoWeb.Models.Sales.AddReceipt -
    + + +
    @Html.ValidationSummary(true)
    diff --git a/src/AccountGoWeb/Views/Sales/AddSalesInvoice.cshtml b/src/AccountGoWeb/Views/Sales/AddSalesInvoice.cshtml index 356e804ee..17bd3f528 100644 --- a/src/AccountGoWeb/Views/Sales/AddSalesInvoice.cshtml +++ b/src/AccountGoWeb/Views/Sales/AddSalesInvoice.cshtml @@ -1,3 +1,154 @@ -
    +@model Dto.Sales.SalesInvoice - \ No newline at end of file + + + +
    + @Html.AntiForgeryToken() + @Html.ValidationSummary(true) +
    +
    + @* Customer *@ +
    +
    Customer
    +
    + + +
    +
    + @* Payment Term *@ +
    +
    Payment Term
    +
    + + +
    +
    + @* Posted *@ +
    +
    Posted
    +
    + + + +
    +
    + + + + + + + + + + + @for (int i = 0; i < Model.SalesInvoiceLines!.Count; i++) + { + + + + + + + + } + +
    ItemQuantityAmountDiscountMeasurement
    + + + + + + + + + + + + + + +
    +
    +
    +
    +
    + + Close +
    + + + diff --git a/src/AccountGoWeb/Views/Sales/AddSalesOrder.cshtml b/src/AccountGoWeb/Views/Sales/AddSalesOrder.cshtml index 9672f8008..dcfbc4315 100644 --- a/src/AccountGoWeb/Views/Sales/AddSalesOrder.cshtml +++ b/src/AccountGoWeb/Views/Sales/AddSalesOrder.cshtml @@ -1,3 +1,117 @@ -
    +@model Dto.Sales.SalesOrder + +
    +
    + @Html.AntiForgeryToken() + @Html.ValidationSummary(true) +
    +
    +
    +
    Customer
    +
    + + +
    +
    + @* Payment Term *@ +
    +
    Payment Term
    +
    + + +
    +
    + @* Amount *@ +
    +
    Amount
    +
    + + +
    +
    + +
    + + + + + + + + + @for (int i = 0; i < Model.SalesOrderLines.Count; i++) + { + + + + + + + + } + +
    ItemQuantityAmountDiscountMeasurement
    + @Html.DropDownListFor(model => model.SalesOrderLines[i].ItemId, + (IEnumerable)ViewBag.Items, new { @class = "form-control", id = "optItem" }) + + + @Html.EditorFor(model => model.SalesOrderLines[i].Quantity, new + { + htmlAttributes = new + { + @class = "form-control" + } + }) + + @Html.EditorFor(model => model.SalesOrderLines[i].Amount, new + { + htmlAttributes = new + { + @class = "form-control" + } + }) + + @Html.EditorFor(model => model.SalesOrderLines[i].Discount, new + { + htmlAttributes = new + { + @class = "form-control" + } + }) + + @Html.DropDownListFor(model => model.SalesOrderLines[i].MeasurementId, + (IEnumerable)ViewBag.Measurements, + new { @class = "form-control", id = $"optMeasurement_{i}" }) + +
    + +
    +
    +
    + + Close +
    +
    +@section Scripts { + +} \ No newline at end of file diff --git a/src/AccountGoWeb/Views/Sales/Allocate.cshtml b/src/AccountGoWeb/Views/Sales/Allocate.cshtml index 20c1631d3..fbabf6627 100644 --- a/src/AccountGoWeb/Views/Sales/Allocate.cshtml +++ b/src/AccountGoWeb/Views/Sales/Allocate.cshtml @@ -1,12 +1,14 @@ @model AccountGoWeb.Models.Sales.Allocate -
    + + @Html.AntiForgeryToken()

    General

    -
    @@ -55,7 +57,8 @@

    Invoice

    -
    @@ -86,7 +89,8 @@ @Model.AllocationLines[i].AllocatedAmount - + } @@ -100,4 +104,29 @@ Close
    - \ No newline at end of file + + + \ No newline at end of file diff --git a/src/AccountGoWeb/Views/Sales/Customer.cshtml b/src/AccountGoWeb/Views/Sales/Customer.cshtml index c5bc35a1d..e109b975a 100644 --- a/src/AccountGoWeb/Views/Sales/Customer.cshtml +++ b/src/AccountGoWeb/Views/Sales/Customer.cshtml @@ -1,4 +1,10 @@ @model Dto.Sales.Customer + +
    -
    + @*
    Fax
    -
    +
    *@
    Website
    @@ -73,13 +79,13 @@
    First Name
    - +
    Last Name
    - +
    @@ -87,25 +93,25 @@
    Phone
    - +
    -
    + @*
    Fax
    -
    +
    *@
    Website
    - +
    Email
    - +
    diff --git a/src/AccountGoWeb/Views/Sales/DonationInvoice.cshtml b/src/AccountGoWeb/Views/Sales/DonationInvoice.cshtml new file mode 100644 index 000000000..089d40d95 --- /dev/null +++ b/src/AccountGoWeb/Views/Sales/DonationInvoice.cshtml @@ -0,0 +1,121 @@ +@model Dto.Sales.SalesInvoice + + + +
    + +
    +
    + @Html.HiddenFor(m => m.Id) +
    +
    +
    + @* ID *@ +
    +
    ID
    +
    @Model.Id
    +
    + @* Customer Name *@ +
    +
    Customer Name
    +
    + + + @Html.HiddenFor(m => m.CustomerId) +
    +
    + @* Invoice Date *@ +
    +
    Invoice Date
    +
    + +
    +
    + @* Total Amount *@ +
    +
    Total Amount
    +
    @ViewBag.TotalAmount
    +
    +
    +
    + + @* Table *@ + + + + + + + + + + @for (int i = 0; i < Model.SalesInvoiceLines!.Count; i++) + { + + + + + + + + } + +
    ItemQuantityAmountDiscountMeasurement
    + + + + + + + + + + + + + + +
    +
    +
    +
    + + Close +
    +
    + +@section scripts{ + + +} \ No newline at end of file diff --git a/src/AccountGoWeb/Views/Sales/DonationInvoices.cshtml b/src/AccountGoWeb/Views/Sales/DonationInvoices.cshtml new file mode 100644 index 000000000..d1d7592cc --- /dev/null +++ b/src/AccountGoWeb/Views/Sales/DonationInvoices.cshtml @@ -0,0 +1,54 @@ +@model string + + +
    +
    +
    + \ No newline at end of file diff --git a/src/AccountGoWeb/Views/Sales/SalesInvoice.cshtml b/src/AccountGoWeb/Views/Sales/SalesInvoice.cshtml index 797c1b185..e5abbb8b5 100644 --- a/src/AccountGoWeb/Views/Sales/SalesInvoice.cshtml +++ b/src/AccountGoWeb/Views/Sales/SalesInvoice.cshtml @@ -1,2 +1,122 @@ -
    - \ No newline at end of file +@model Dto.Sales.SalesInvoice +@using System.Globalization + + +
    +
    + @Html.HiddenFor(m => m.Id) +
    +
    +
    + @* ID *@ +
    + + +
    ID
    +
    @Model.Id
    +
    + @* Customer Name *@ +
    +
    Customer Name
    +
    + + + @Html.HiddenFor(m => m.CustomerId) +
    +
    + @* Invoice Date *@ +
    +
    Invoice Date
    +
    + +
    +
    + @* Total Amount *@ +
    +
    Total Amount
    +
    @String.Format("{0:F2}", ViewBag.TotalAmount)
    +
    +
    +
    + + @* Table *@ + + + + + + + + + + @for (int i = 0; i < Model.SalesInvoiceLines!.Count; i++) + { + + + + + + + + } + +
    ItemQuantityAmountDiscountMeasurement
    + + + + + + + + + + + + + + + +
    +
    +
    +
    + + Close +
    +
    + +@section scripts{ + + +} \ No newline at end of file diff --git a/src/AccountGoWeb/Views/Sales/SalesInvoicePdf.cshtml b/src/AccountGoWeb/Views/Sales/SalesInvoicePdf.cshtml index 66b64f01e..6ce978657 100644 --- a/src/AccountGoWeb/Views/Sales/SalesInvoicePdf.cshtml +++ b/src/AccountGoWeb/Views/Sales/SalesInvoicePdf.cshtml @@ -114,7 +114,7 @@ apply the skin class to the body tag so the changes take effect. - @foreach (var item in Model.SalesInvoiceLines) + @foreach (var item in Model.SalesInvoiceLines!) { diff --git a/src/AccountGoWeb/Views/Sales/SalesInvoices.cshtml b/src/AccountGoWeb/Views/Sales/SalesInvoices.cshtml index 247e1c76f..b811ab6e0 100644 --- a/src/AccountGoWeb/Views/Sales/SalesInvoices.cshtml +++ b/src/AccountGoWeb/Views/Sales/SalesInvoices.cshtml @@ -1,53 +1,104 @@ @model string + +
    - \ No newline at end of file +@* Delete Modal*@ + + +@section scripts{ + +} diff --git a/src/AccountGoWeb/Views/Sales/SalesOrder.cshtml b/src/AccountGoWeb/Views/Sales/SalesOrder.cshtml index 1a31098f3..d3cbc83b6 100644 --- a/src/AccountGoWeb/Views/Sales/SalesOrder.cshtml +++ b/src/AccountGoWeb/Views/Sales/SalesOrder.cshtml @@ -1,2 +1,63 @@ -
    - \ No newline at end of file +@model Dto.Sales.SalesOrder + + + + +
    +
    +
    +
    +
    +
    +
    Customer Name
    +
    @ViewBag.CustomerName
    +
    + @* Order Date *@ +
    +
    Order Date
    +
    @ViewBag.OrderDate
    +
    + @* Total Amount *@ +
    +
    Total Amount
    +
    @ViewBag.TotalAmount
    +
    + + + + + + + + + + @for (int i = 0; i < Model.SalesOrderLines.Count; i++) + { + + + + + + + + } + +
    ItemQuantityAmountDiscountMeasurement
    @Model.SalesOrderLines[i].ItemDescription@Model.SalesOrderLines[i].Quantity@Model.SalesOrderLines[i].Amount@Model.SalesOrderLines[i].Discount@Model.SalesOrderLines[i].MeasurementDescription
    +
    +
    +
    +
    +
    \ No newline at end of file diff --git a/src/AccountGoWeb/Views/Sales/SalesReceipt.cshtml b/src/AccountGoWeb/Views/Sales/SalesReceipt.cshtml new file mode 100644 index 000000000..7aaef6632 --- /dev/null +++ b/src/AccountGoWeb/Views/Sales/SalesReceipt.cshtml @@ -0,0 +1,27 @@ +@model Dto.Sales.SalesReceipt + + + +
    +
    + @Html.HiddenFor(m => m.Id) +
    +
    +
    +
    +
    ID
    +
    @Model.Id
    +
    +
    +
    +
    +
    +
    \ No newline at end of file diff --git a/src/AccountGoWeb/Views/Sales/SalesReceipts.cshtml b/src/AccountGoWeb/Views/Sales/SalesReceipts.cshtml index 9aa7ccb2a..1e7c26f66 100644 --- a/src/AccountGoWeb/Views/Sales/SalesReceipts.cshtml +++ b/src/AccountGoWeb/Views/Sales/SalesReceipts.cshtml @@ -1,14 +1,26 @@ @model string + +
    @@ -18,39 +30,69 @@ var selectedRow = {}; var columnDefs = [ - {headerName: "Receipt", field: "id", width: 50}, - {headerName: "No", field: "receiptNo", width: 50}, - {headerName: "Customer Name", field: "customerName", width: 350}, - {headerName: "Receipt Date", field: "receiptDate", width: 100}, - {headerName: "Amount", field: "amount", width: 100}, - {headerName: "Left to Allocate", field: "remainingAmountToAllocate", width: 100} + { headerName: "Receipt", field: "id", width: 50 }, + { headerName: "No", field: "receiptNo", width: 50 }, + { headerName: "Customer Name", field: "customerName", width: 350 }, + { headerName: "Receipt Date", field: "receiptDate", width: 100 }, + { headerName: "Amount", field: "amount", width: 100 }, + { headerName: "Left to Allocate", field: "remainingAmountToAllocate", width: 100 } ]; var gridOptions = { columnDefs: columnDefs, rowData: @Html.Raw(Model), enableSorting: true, - // PROPERTIES - simple boolean / string / number properties rowSelection: 'single', onSelectionChanged: onSelectionChanged, + rowClassRules: { + 'highlighted-row': params => params.node.isSelected() // Add 'highlighted-row' to selected rows + }, }; function onSelectionChanged() { + console.log("Selection changed"); + + // Get all selected rows var selectedRows = gridOptions.api.getSelectedRows(); + console.log("Selected rows:", selectedRows); + + if (!selectedRows.length) { + console.log("No row selected"); + return; // Exit if no row is selected + } + + // Get the selected row selectedRow = selectedRows[0]; + console.log("Selected row data:", selectedRow); + + // Update the Allocate and View Receipt links + document.getElementById('linkAllocate').setAttribute('href', '/sales/allocate/' + selectedRow.id); + console.log("Updated Allocate link to:", 'allocate/' + selectedRow.id); - document.getElementById('linkAllocate').setAttribute('href', 'allocate/' + selectedRow.id); + document.getElementById('linkViewReceipt').setAttribute('href', '/sales/SalesReceipt?id=' + selectedRow.id); + console.log("Updated View Receipt link to:", 'SalesReceipt?id=' + selectedRow.id); - if(selectedRow.remainingAmountToAllocate > 0) + document.getElementById('linkViewReceipt').setAttribute('class', 'btn'); + + if (selectedRow.remainingAmountToAllocate > 0) { document.getElementById('linkAllocate').setAttribute('class', 'btn'); - else + console.log("Set Allocate button to active"); + } else { document.getElementById('linkAllocate').setAttribute('class', 'btn inactiveLink'); + console.log("Set Allocate button to inactive"); + } + + // Highlight the selected row + gridOptions.api.forEachNode(node => { + console.log("Processing row node with ID:", node.data.id); + node.setSelected(node.data.id === selectedRow.id); // Mark row as selected + }); } - // wait for the document to be loaded, otherwise - // ag-Grid will not find the div in the document. - document.addEventListener("DOMContentLoaded", function() { + document.addEventListener("DOMContentLoaded", function () { + console.log("Document loaded"); var eGridDiv = document.querySelector('#receipts'); new agGrid.Grid(eGridDiv, gridOptions); + console.log("ag-Grid initialized"); }); - \ No newline at end of file + diff --git a/src/AccountGoWeb/Views/Sales/salesorders.cshtml b/src/AccountGoWeb/Views/Sales/salesorders.cshtml index 81d7d9616..de9802629 100644 --- a/src/AccountGoWeb/Views/Sales/salesorders.cshtml +++ b/src/AccountGoWeb/Views/Sales/salesorders.cshtml @@ -43,8 +43,9 @@ function onSelectionChanged() { var selectedRows = gridOptions.api.getSelectedRows(); selectedRow = selectedRows[0]; + console.log(selectedRows); - document.getElementById('linkViewOrder').setAttribute('href', 'salesorder?orderId=' + selectedRow.id); + document.getElementById('linkViewOrder').setAttribute('href', 'SalesOrder?id=' + selectedRow.id); document.getElementById('linkViewOrder').setAttribute('class', 'btn'); document.getElementById('linkNewInvoice').setAttribute('href', 'salesinvoice?orderId=' + selectedRow.id); diff --git a/src/AccountGoWeb/Views/Shared/_Layout.cshtml b/src/AccountGoWeb/Views/Shared/_Layout.cshtml index 5e8ea9be4..88914a9d8 100644 --- a/src/AccountGoWeb/Views/Shared/_Layout.cshtml +++ b/src/AccountGoWeb/Views/Shared/_Layout.cshtml @@ -1,658 +1,53 @@ -@{ Layout = ""; } - + - - - - - AccountGo - - - - - - - - - - + + + + + + + Good Deed Books + + + + + + + - -