Compare commits

...

36 Commits

Author SHA1 Message Date
rowell_m_soriano
227ebe3906 adding variables via gitea variables
All checks were successful
Build and Deploy CPRNIMS / build-and-deploy (push) Successful in 3m36s
2026-06-29 16:21:34 +08:00
rowell_m_soriano
6b28e00102 fix: explicit exit 0 after robocopy success to prevent false step failures
All checks were successful
Build and Deploy CPRNIMS / build-and-deploy (push) Successful in 2m58s
2026-06-29 15:40:02 +08:00
rowell_m_soriano
34097298e0 Update Gitea CI/CD deployment workflow
Some checks failed
Build and Deploy CPRNIMS / build-and-deploy (push) Failing after 2m32s
2026-06-29 14:29:55 +08:00
rowell_m_soriano
2aa375cf55 Update Gitea CI/CD deployment workflow
Some checks are pending
Build and Deploy CPRNIMS / build-and-deploy (push) Waiting to run
2026-06-29 14:04:46 +08:00
rowell_m_soriano
d6c2d668ee Update Gitea CI/CD deployment workflow
Some checks are pending
Build and Deploy CPRNIMS / build-and-deploy (push) Waiting to run
2026-06-29 13:51:54 +08:00
rowell_m_soriano
8fdbe48640 Remove bin/obj/.vs build artifacts from tracking, apply .gitignore
Some checks are pending
Build and Deploy CPRNIMS / build-and-deploy (push) Waiting to run
2026-06-29 07:03:51 +08:00
rowell_m_soriano
12407aeaf5 Remove bin/obj/.vs build artifacts from tracking, apply .gitignore 2026-06-25 17:26:55 +08:00
rowell_m_soriano
84ba85490c Add .gitignore, remove build artifacts from tracking 2026-06-25 17:15:47 +08:00
rowell_m_soriano
c9fc25832f Add .gitignore and remove build artifacts from tracking 2026-06-25 16:43:25 +08:00
rowell_m_soriano
3d82fb67ba CICD deploy.yml 2026-06-25 16:05:33 +08:00
rowell_m_soriano
3c0be5eae2 CRUD for RIS, MRS, Inventory reports are working properly 2026-06-25 08:57:30 +08:00
rowell_m_soriano
440cdfcdb7 Features for option to select currency for each PO during PO Creation 2026-06-24 10:16:45 +08:00
rowell_m_soriano
fa03ef5a3d Full CRUD with RIS, MRS, Inventory including reports 2026-06-18 16:51:31 +08:00
rowell_m_soriano
44862d01b5 RIS creation, approval and Cancel working well 2026-06-15 16:41:50 +08:00
rowell_m_soriano
6710f04bd7 fixing bugs in custom po for unit price consistency 2026-05-21 13:55:15 +08:00
rowell_m_soriano
f2aee9645d Enhanced Shipping instructions and Custom PO for import 2026-05-20 16:50:48 +08:00
rowell_m_soriano
5c6fc08bf3 Roll back the Shipping instruction 2026-05-12 15:48:42 +08:00
rowell_m_soriano
67a501f4fc Fixing status bug in Supplier page 2026-05-05 13:03:52 +08:00
rowell_m_soriano
b02af975ac Adding validaiton for existing suppliers to prevent from duplication 2026-04-27 09:18:38 +08:00
rowell_m_soriano
d1c9c4b52b AI Driven Searching and tagging with button and UI/UX enhancement in canvassing partial only 2026-04-22 17:21:45 +08:00
rowell_m_soriano
3825a986f6 AI-Driven Supplier Search & Tagging 2026-04-21 11:59:21 +08:00
rowell_m_soriano
ee0f853a85 Fixing Qty submission in Item Cart and adding Item no searching in item management 2026-03-17 07:11:17 +08:00
rowell_m_soriano
a188699c56 UI/UX Enhancement 2026-03-13 14:48:15 +08:00
rowell_m_soriano
d770613286 Backend pagination for Item, Pr Tracking, approved pr, Deleted PR 2026-03-12 16:03:02 +08:00
rowell_m_soriano
1b06999f15 fixing bugs on custom PO 2026-03-11 14:26:41 +08:00
rowell_m_soriano
199c1271a0 Item removal enhancement on receiving page 2026-03-05 12:16:05 +08:00
rowell_m_soriano
d23347c299 PR item addition in existing PRNo 2026-03-02 12:25:08 +08:00
rowell_m_soriano
84bcc7aaa7 Custom PO working already all features 2026-02-27 10:29:27 +08:00
rowell_m_soriano
798f8f67ea minor issue for custom PO but working already, need to change the incormterms into autocomplete 2026-02-24 17:08:04 +08:00
rowell_m_soriano
da0af6a64e Partial for custom PO 2026-02-19 17:23:28 +08:00
rowell_m_soriano
11646fec68 PR Tabbed for Approved but no PO, Deleted items are working properly 2026-02-17 17:05:52 +08:00
rowell_m_soriano
99be1e9c8b fixing approval and returning approval name 2026-02-16 16:37:20 +08:00
rowell_m_soriano
9419130ee3 approval and project code maintenance is working properly 2026-02-16 09:18:27 +08:00
rowell_m_soriano
6e0551707e push only for upload attachment and project code but not working the autocomplete yet 2026-02-13 15:56:56 +08:00
rowell_m_soriano
0612679648 Project code maintenance and pr item attachment 2026-02-12 10:41:44 +08:00
rowell_m_soriano
33b839741f Multiple pr item approval 2026-02-10 14:19:30 +08:00
392 changed files with 36536 additions and 12772 deletions

211
.gitea/workflows/deploy.yml Normal file
View File

@ -0,0 +1,211 @@
name: Build and Deploy CPRNIMS
on:
push:
branches: [ main ]
jobs:
build-and-deploy:
runs-on: windows
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Clean previous publish output
shell: pwsh
run: |
Remove-Item -Recurse -Force "C:\ci-output\webapi" -ErrorAction SilentlyContinue
Remove-Item -Recurse -Force "C:\ci-output\webapps" -ErrorAction SilentlyContinue
- name: Publish WebApi
shell: pwsh
run: dotnet publish .\CPRNIMS.WebApi\CPRNIMS.WebApi.csproj -c Release -o C:\ci-output\webapi
- name: Publish WebApps
shell: pwsh
run: dotnet publish .\CPRNIMS.WebApps\CPRNIMS.WebApps.csproj -c Release -o C:\ci-output\webapps
# ---- Generate production config from Gitea Actions secrets (never committed to git) ----
- name: Write production appsettings - WebApi
shell: pwsh
env:
TAVILY_KEY: ${{ secrets.LLI_NON_INVENTORY_PROD_TAVILY_API_KEY }}
GROQ_KEY: ${{ secrets.LLI_NON_INVENTORY_PROD_GROQ_API_KEY }}
JWT_SECRET: ${{ secrets.LLI_NON_INVENTORY_PROD_JWT_SECRET }}
DB_CONN: ${{ secrets.LLI_NON_INVENTORY_PROD_DB_CONNECTION }}
LOCALPURCH_CONN: ${{ secrets.LLI_NON_INVENTORY_PROD_DB_LOCALPURCH_CONNECTION }}
run: |
$config = @{
Tavily = @{
ApiKey = $env:TAVILY_KEY
SearchUrl = "https://api.tavily.com/search"
}
Groq = @{
ApiKey = $env:GROQ_KEY
ApiUrl = "https://api.groq.com/openai/v1/chat/completions"
Model = "llama-3.1-8b-instant"
}
JWT = @{
ValidAudience = "https://lloydwebapi.lloydlab.com:2021"
ValidIssuer = "https://lloydwebapi.lloydlab.com:2021"
Secret = $env:JWT_SECRET
}
WebEndPoint = @{
ForgotPassword = "https://llipurchasingnoninventory.com:8080/"
SupplierForm = "https://llipurchasingnoninventory.com:8083/"
}
ConnectionStrings = @{
DefaultConnection = $env:DB_CONN
LocalPurchConn = $env:LOCALPURCH_CONN
}
}
$json = $config | ConvertTo-Json -Depth 5
$json | Out-File -FilePath "C:\ci-output\webapi\appsettings.Production.json" -Encoding utf8
Write-Host "Wrote appsettings.Production.json to webapi output (values masked in this log automatically)"
exit 0
# ---- Generate production config for WebApps (uses Variables, not Secrets, since BaseUrl isn't sensitive) ----
- name: Write production appsettings - WebApps
shell: pwsh
env:
API_BASE_URL: ${{ vars.LLI_NON_INVENTORY_PROD_API_BASE_URL }}
run: |
$config = @{
CommonEndpoints = @{
ApiDefaultHeaders = @{
BaseUrl = $env:API_BASE_URL
ESignaturePath = "https://llipurchasingnoninventory.com:8080/Content/Images/Signatures/"
ItemImages = "https://llipurchasingnoninventory.com:8080/content/images/"
ContentTypeMedia = "application/json"
Authorization = "token"
ErrorMessage = "api/ErrorLogs/ErrorMessage/"
}
}
}
$json = $config | ConvertTo-Json -Depth 5
$json | Out-File -FilePath "C:\ci-output\webapps\appsettings.Production.json" -Encoding utf8
Write-Host "Wrote appsettings.Production.json to webapps output"
exit 0
# ---- Backup current live deployment before touching anything ----
- name: Backup current live files
shell: pwsh
run: |
$stamp = Get-Date -Format "yyyyMMdd-HHmmss"
New-Item -ItemType Directory -Force -Path "C:\backups\$stamp" | Out-Null
# Mirror current live folders into the backup location (only if they exist / aren't empty)
if (Test-Path "C:\inetpub\cprnims-api") {
robocopy "C:\inetpub\cprnims-api" "C:\backups\$stamp\webapi" /MIR /R:2 /W:3 | Out-Null
}
if (Test-Path "C:\inetpub\cprnims-web") {
robocopy "C:\inetpub\cprnims-web" "C:\backups\$stamp\webapps" /MIR /R:2 /W:3 | Out-Null
}
# Record this backup's timestamp so later steps know where it lives
$stamp | Out-File -FilePath "C:\backups\latest.txt" -Encoding ascii -NoNewline
# Keep only the last 5 backups to avoid filling the disk
$all = Get-ChildItem "C:\backups" -Directory | Sort-Object Name -Descending
if ($all.Count -gt 5) {
$all | Select-Object -Skip 5 | Remove-Item -Recurse -Force
}
Write-Host "Backed up current deployment to C:\backups\$stamp"
exit 0
- name: Stop app pools
shell: pwsh
run: |
Import-Module WebAdministration
Stop-WebAppPool -Name "CPRNIMS-Api" -ErrorAction SilentlyContinue
Stop-WebAppPool -Name "CPRNIMS-Web" -ErrorAction SilentlyContinue
Start-Sleep -Seconds 3
- name: Deploy WebApi files
id: deploy_api
shell: pwsh
run: |
robocopy "C:\ci-output\webapi" "C:\inetpub\cprnims-api" /MIR /R:3 /W:5
$rc = $LASTEXITCODE
Write-Host "ROBOCOPY EXIT CODE: $rc"
if ($rc -ge 8) {
throw "robocopy failed for WebApi with exit code $rc"
}
exit 0
- name: Deploy WebApps files
id: deploy_web
shell: pwsh
run: |
robocopy "C:\ci-output\webapps" "C:\inetpub\cprnims-web" /MIR /R:3 /W:5
$rc = $LASTEXITCODE
Write-Host "ROBOCOPY EXIT CODE: $rc"
if ($rc -ge 8) {
throw "robocopy failed for WebApps with exit code $rc"
}
exit 0
- name: Start app pools
shell: pwsh
run: |
Import-Module WebAdministration
Start-WebAppPool -Name "CPRNIMS-Api"
Start-WebAppPool -Name "CPRNIMS-Web"
- name: Verify app pools are running
shell: pwsh
run: |
Start-Sleep -Seconds 3
Import-Module WebAdministration
$api = Get-WebAppPoolState -Name "CPRNIMS-Api"
$web = Get-WebAppPoolState -Name "CPRNIMS-Web"
Write-Host "CPRNIMS-Api: $($api.Value)"
Write-Host "CPRNIMS-Web: $($web.Value)"
if ($api.Value -ne "Started" -or $web.Value -ne "Started") {
throw "One or more app pools failed to start"
}
# ---- Rollback path: only runs if any prior step in this job failed ----
- name: ROLLBACK - restore previous backup
if: failure()
shell: pwsh
run: |
$stamp = Get-Content "C:\backups\latest.txt" -Raw
$backupPath = "C:\backups\$stamp"
Write-Host "Deployment failed - rolling back to backup: $backupPath"
Import-Module WebAdministration
Stop-WebAppPool -Name "CPRNIMS-Api" -ErrorAction SilentlyContinue
Stop-WebAppPool -Name "CPRNIMS-Web" -ErrorAction SilentlyContinue
Start-Sleep -Seconds 3
if (Test-Path "$backupPath\webapi") {
robocopy "$backupPath\webapi" "C:\inetpub\cprnims-api" /MIR /R:3 /W:5 | Out-Null
}
if (Test-Path "$backupPath\webapps") {
robocopy "$backupPath\webapps" "C:\inetpub\cprnims-web" /MIR /R:3 /W:5 | Out-Null
}
Start-WebAppPool -Name "CPRNIMS-Api"
Start-WebAppPool -Name "CPRNIMS-Web"
Write-Host "Rollback complete. Restored from $backupPath"
exit 0
- name: ROLLBACK - verify pools after restore
if: failure()
shell: pwsh
run: |
Start-Sleep -Seconds 3
Import-Module WebAdministration
$api = Get-WebAppPoolState -Name "CPRNIMS-Api"
$web = Get-WebAppPoolState -Name "CPRNIMS-Web"
Write-Host "After rollback - CPRNIMS-Api: $($api.Value)"
Write-Host "After rollback - CPRNIMS-Web: $($web.Value)"
if ($api.Value -ne "Started" -or $web.Value -ne "Started") {
Write-Host "WARNING: app pools still not running after rollback. Manual intervention needed."
}

48
.gitignore vendored Normal file
View File

@ -0,0 +1,48 @@
# Build output
[Bb]in/
[Oo]bj/
[Dd]ebug/
[Rr]elease/
x64/
x86/
build/
bld/
# Visual Studio
.vs/
*.user
*.suo
*.userosscache
*.sln.docstates
*.userprefs
# Publish output
publish/
*.publishsettings
PublishScripts/
# NuGet
*.nupkg
*.snupkg
packages/
!packages/build/
project.lock.json
project.fragment.lock.json
artifacts/
# Rider / VS Code (if anyone uses them)
.idea/
.vscode/
# Build results / logs
*.binlog
*.log
msbuild.log
msbuild.err
# Environment-specific config with secrets
appsettings.*.json
!appsettings.json
*.dev.json
secrets.json
*.pfx

Binary file not shown.

View File

@ -1,12 +0,0 @@
{
"Version": 1,
"WorkspaceRootPath": "D:\\sourcecode\\NonInventPurchasing\\",
"Documents": [],
"DocumentGroupContainers": [
{
"Orientation": 0,
"VerticalTabListWidth": 256,
"DocumentGroups": []
}
]
}

View File

@ -1,6 +0,0 @@
{
"ExpandedNodes": [
""
],
"PreviewInSolutionExplorer": false
}

View File

@ -7,7 +7,12 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="AutoMapper" Version="16.1.1" />
<PackageReference Include="CaptchaGen.NetCore" Version="1.1.2" />
<PackageReference Include="Dapper" Version="2.1.66" />
<PackageReference Include="FastReport.OpenSource" Version="2026.2.3" />
<PackageReference Include="FastReport.OpenSource.Export.PdfSimple" Version="2026.2.3" />
<PackageReference Include="FastReport.OpenSource.Web" Version="2026.2.3" />
<PackageReference Include="Google.Apis.Drive.v3" Version="1.67.0.3373" />
<PackageReference Include="Microsoft.AspNet.Identity.Core" Version="2.2.4" />
<PackageReference Include="Microsoft.AspNetCore.SignalR.Core" Version="1.2.0" />

View File

@ -1,6 +1,12 @@
using CPRNIMS.Infrastructure.Dto.Canvass;
using CPRNIMS.Domain.Services;
using CPRNIMS.Domain.Services.ICanvass;
using CPRNIMS.Infrastructure.Dto.Canvass;
using CPRNIMS.Infrastructure.Dto.Canvass.Request;
using CPRNIMS.Infrastructure.Dto.Canvass.Response;
using CPRNIMS.Infrastructure.Dto.Common;
using CPRNIMS.Infrastructure.Entities.Canvass;
using CPRNIMS.Infrastructure.Entities.Purchasing;
using CPRNIMS.Infrastructure.ViewModel.Canvass;
using System;
using System.Collections.Generic;
using System.Linq;
@ -9,46 +15,47 @@ using System.Threading.Tasks;
namespace CPRNIMS.Domain.Contracts.Canvass
{
public interface ICanvass
public interface ICanvass : ISupplier
{
#region Post Put
Task<RFQ> PostPerSupplierToken(CanvassDto CanvassDto);
Task<Result<StartCanvassResponse>> StartCanvass(CanvassVM canvass,CancellationToken ct);
Task<RFQ> PostPerSupplierToken(ForCanvassDto CanvassDto);
Task<ForCanvassFollowUp> PutSupplierCanvass(long canvassSupplierId);
Task<PRDetails> PostCanvass(CanvassDto CanvassDto);
Task<Suppliers> PostPutSupplier(CanvassDto CanvassDto);
Task<Suppliers> PostTaggingSupplier(CanvassDto CanvassDto);
Task<Suppliers> PostApprovedSupp(CanvassDto CanvassDto);
Task<SupplierResponse> PostPutSupplier(CanvassDto CanvassDto);
Task<SupplierResponse> PostTaggingSupplier(CanvassDto CanvassDto);
Task<SupplierResponse> PostApprovedSupp(CanvassDto CanvassDto);
Task<CanvassDetail> PostSuggestedSupp(CanvassDto CanvassDto);
Task<CanvassDetail> PutSuppUnitPrice(CanvassDto CanvassDto);
Task<CanvassDetail> PutSuppBidDetails(CanvassDto canvassDto);
Task<Suppliers> PostPutMySupplier(CanvassDto canvassDto);
Task<Suppliers> PostPutItemTagging(CanvassDto canvassDto);
Task<SupplierResponse> PostPutMySupplier(CanvassDto canvassDto);
Task<SupplierResponse> PostPutItemTagging(CanvassDto canvassDto);
Task<CanvassSupplier> UnlockFormLink(CanvassDto canvassDto);
#endregion
#region Get
Task<List<PRDetails>> GetCanvassById(CanvassDto CanvassDto);
Task<List<PRCanvassDetail>> GetCanvassById(CanvassDto CanvassDto);
Task<List<WOResponse>> GetCanvassWOResponse(CanvassDto CanvassDto);
Task<List<WOResponseById>> GetWOResponseBySuppId(CanvassDto CanvassDto);
Task<List<Suppliers>> GetSupplierById(CanvassDto CanvassDto);
Task<List<RFQReference>> GetRFQ(CanvassDto CanvassDto);
Task<List<SupplierResponseDto>> GetSupplierById(CanvassDto CanvassDto);
Task<List<RFQReference>> GetRFQ(ForCanvassDto CanvassDto);
Task<List<BiddingItem>> GetSupplierBid(CanvassDto CanvassDto);
Task<List<RFQPerSupplier>> GetSupplierBidByItem(CanvassDto CanvassDto);
Task<List<SupplierBidById>> GetSupplierBidById(CanvassDto CanvassDto);
Task<List<PerSupplier>> GetCanvassPerSupplier(CanvassDto CanvassDto);
Task<List<PRDetails>> GetCanvassPerSupplierEmail(CanvassDto CanvassDto);
Task<List<PRDetails>> GetCanvassPerSupplierId(CanvassDto itemCodeDto);
Task<PagedResult<PerSupplier>> GetCanvassPerSupplier(CanvassDto dto);
Task<PagedResult<ItemsForTagging>> GetItemsForTagging(CanvassDto dto);
Task<List<PRCanvassDetail>> GetCanvassPerSupplierEmail(CanvassDto CanvassDto);
Task<List<PRCanvassDetail>> GetCanvassPerSupplierId(CanvassDto itemCodeDto);
Task<List<ItemListWOEmail>> GetItemSupplierWOEmail(CanvassDto CanvassDto);
Task<List<Suppliers>> GetSupplierItemWOEmail(CanvassDto CanvassDto);
Task<List<PRDetails>> GetCanvassByPRNo(CanvassDto CanvassDto);
Task<List<SupplierResponseDto>> GetSupplierItemWOEmail(CanvassDto CanvassDto);
Task<List<PRCanvassDetail>> GetCanvassByPRNo(CanvassDto CanvassDto);
Task<List<CanvassGroupByPRNo>> GetCanvassGroupByPRNo(CanvassDto CanvassDto);
Task<List<PRDetails>> GetCanvassByItemNo(CanvassDto CanvassDto);
Task<List<PRDetails>> GetPRItemList(CanvassDto CanvassDto);
Task<List<PRDetails>> GetPRItem(CanvassDto CanvassDto);
Task<List<PRCanvassDetail>> GetCanvassByItemNo(CanvassDto CanvassDto);
Task<List<PRCanvassDetail>> GetPRItemList(CanvassDto CanvassDto);
Task<List<PRCanvassDetail>> GetPRItem(CanvassDto CanvassDto);
Task<List<Infrastructure.Entities.Canvass.PRList>> GetPRListByPRNo(CanvassDto canvassDto);
Task<List<ForCanvass>> GetForCanvassPerItem(CanvassDto CanvassDto);
Task<int> GetCanvassNo();
Task<List<ForCanvassFollowUp>> GetCanvassForFollowUp(CanvassDto itemDto);
Task<List<Suppliers>> GetMySuppliers(CanvassDto CanvassDto);
Task<List<SupplierResponseDto>> GetMySuppliers(CanvassDto CanvassDto);
Task<List<MyPRWOCanvass>> GetMyPRWOCanvass(CanvassDto itemDto);
Task<List<AlternativeOfferDetails>> GetAlternativeOfferByPRDetailId(CanvassDto itemDto);
Task<List<AllForCanvass>> GetAllForCanvass();

View File

@ -0,0 +1,23 @@
using CPRNIMS.Infrastructure.Dto.Canvass.Request;
using CPRNIMS.Infrastructure.Dto.Canvass.Response;
using CPRNIMS.Infrastructure.Entities.Canvass;
using CPRNIMS.Infrastructure.Entities.Purchasing;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CPRNIMS.Domain.Services.ICanvass
{
public interface ISupplier
{
Task<List<Suppliers>> GetSuppliers(CancellationToken ct);
Task<List<ForAISearchingTagging>> GetForAISearchingTagging(CancellationToken ct);
Task<List<ItemWithoutSupplier>> GetItemWithoutSupplier(CancellationToken ct);
Task<List<SupplierForCanvass>> GetSupplierForCanvass(int supplierId, string userName,CancellationToken ct);
Task<Result<SupplierResponse>> PostPutSupplierAsync(SupplierRequest request, CancellationToken ct);
Task<bool> SendRFQ(SupplierEmailRequest supplierEmailRequest);
Task DeleteAsync(long pRDetailsId, CancellationToken ct);
}
}

View File

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CPRNIMS.Domain.Contracts.Common
{
public interface ITransactionFacade
{
Task<T> ExecuteAsync<T>(Func<Task<T>> operation,CancellationToken ct);
Task ExecuteAsync(Func<Task> operation,CancellationToken ct);
}
}

View File

@ -13,6 +13,6 @@ namespace CPRNIMS.Domain.Contracts.Finance
{
Task<List<ForPayment>> GetAllClosedPO(RRDetailsDto itemDto);
Task<List<ReceivingDetail>> GetRRDetailByPO(RRDetailsDto itemDto);
Task<RRDetail> PostPutPayment(RRDetailsDto itemDto);
Task<RRDetailDto> PostPutPayment(RRDetailsDto itemDto);
}
}

View File

@ -1,4 +1,6 @@
using CPRNIMS.Infrastructure.Dto.Inventory;
using CPRNIMS.Infrastructure.Dto.Inventory.Request;
using CPRNIMS.Infrastructure.Dto.Inventory.Response;
using CPRNIMS.Infrastructure.Entities.Inventory;
using System;
using System.Collections.Generic;
@ -11,11 +13,15 @@ namespace CPRNIMS.Domain.Contracts.Inventory
public interface IInventory
{
Task<List<Lot>> GetLotNo(InventoryDto itemDto);
Task<List<Lot>> GetLotNoById(InventoryDto itemDto);//
Task<List<Lot>> GetLotNoById(InventoryDto itemDto);
Task<List<LotQtyByItem>> GetLotQtyByItem(InventoryDto itemDto);
Task<List<Infrastructure.Entities.Inventory.Inventory>> GetInventoryByUserId(InventoryDto itemDto);
Task<List<RequestItemDetail>> GetRequestedItemByUserId(InventoryDto itemDto);
Task<List<ItemDetail>> GetInventoryById(InventoryDto itemDto);
Task<PagedResult<InventoryResponse>> GetInventory(InventoryRequest request, CancellationToken ct);
Task<List<InventoryByIdResponse>> GetInventoryById(InventoryRequest itemDto, CancellationToken ct);
Task<TransactContextDto?> GetTransactContextAsync(int inventoryId, CancellationToken ct);
Task<IReadOnlyList<DisciplineDto>> GetDisciplinesAsync(CancellationToken ct);
Task<Infrastructure.Entities.Inventory.Inventory> PostPutReqApproval(InventoryDto itemDto);
Task<RequestItem> PostPutReqItems(InventoryDto itemDto);
Task<Lot> PostPutLotNo(InventoryDto itemDto);

View File

@ -0,0 +1,17 @@
using CPRNIMS.Infrastructure.Dto.Inventory.Reports;
using CPRNIMS.Infrastructure.Dto.Inventory.Request;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CPRNIMS.Domain.Contracts.Inventory
{
public interface IInventoryReports
{
Task<RISReportDto> GetRISReportAsync(InventoryReportsRequest request, string userName, int? departmentId, CancellationToken ct);
Task<MRSReportDto> GetMRSReportAsync(InventoryReportsRequest request, string userName, int? departmentId, CancellationToken ct);
Task<InventoryReportDto> GetInventoryReportAsync(InventoryReportsRequest request,string userName, int? departmentId, CancellationToken ct);
}
}

View File

@ -0,0 +1,22 @@
using CPRNIMS.Infrastructure.Dto.Inventory;
using CPRNIMS.Infrastructure.Dto.Inventory.Request;
using CPRNIMS.Infrastructure.Entities.Inventory;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CPRNIMS.Domain.Contracts.Inventory
{
public interface IMRS
{
Task<MRSPagedResult> GetPagedAsync(MRSFilterDto filter, CancellationToken ct,int? departmentId = null, string? userName = "");
Task<IReadOnlyList<RISSearchResultDto>> SearchRISForReturnAsync(string? risNoQuery, int? projectCodeId, CancellationToken ct);
Task<IReadOnlyList<ProjectCodeOptionDto>> GetProjectsWithOpenRISAsync(string? nameQuery, CancellationToken ct);
Task<MRS?> GetByIdAsync(long mrsId, CancellationToken ct);
Task<MRS> CreateAsync(CreateMRSRequest dto, string createdBy, CancellationToken ct);
Task ApproveAsync(long mrsId, string approvedBy, CancellationToken ct);
Task CancelAsync(CancelMRSRequest request, string canceledBy, CancellationToken ct);
}
}

View File

@ -0,0 +1,22 @@
using CPRNIMS.Infrastructure.Dto.Inventory;
using CPRNIMS.Infrastructure.Dto.Inventory.Request;
using CPRNIMS.Infrastructure.Dto.Inventory.Response;
using CPRNIMS.Infrastructure.Entities.Inventory;
using CPRNIMS.Infrastructure.Entities.Purchasing;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CPRNIMS.Domain.Contracts.Inventory
{
public interface IRIS
{
Task<RISPagedResult> GetPagedAsync(RISFilterDto filter, CancellationToken ct, int? departmentId = null, string? userName = "");
Task<RISResponse?> GetByIdAsync(long risId, CancellationToken ct);
Task<Infrastructure.Entities.Inventory.RIS> CreateAsync(CreateRISRequest dto, string createdBy, CancellationToken ct);
Task ApproveAsync(ApproveRISRequest request, string approvedBy, CancellationToken ct);
Task CancelAsync(CancelRISRequest request,string canceledBy, CancellationToken ct);
}
}

View File

@ -2,6 +2,7 @@
using CPRNIMS.Infrastructure.Entities.Account;
using CPRNIMS.Infrastructure.Entities.Items;
using CPRNIMS.Infrastructure.Entities.Purchasing;
using CPRNIMS.Infrastructure.Models.Common;
using System;
using System.Collections.Generic;
using System.Linq;
@ -13,19 +14,22 @@ namespace CPRNIMS.Domain.Contracts.Items
public interface IItem
{
Task<List<Departments>> GetDepartment(ItemCodeDto itemCode);
Task<List<ItemList>> GetItemList(ItemCodeDto itemCode);
Task<PagedResult<ItemList>> GetItemList(ItemCodeDto itemCode);
Task<List<ItemCart>> GetItemCart(ItemDto itemDto);
Task<List<Item>> GetItemDetail(ItemDto itemDto);
Task<List<ItemDtos>> GetItemDetail(ItemDto itemDto);
Task<List<ItemLocalization>> GetItemLocalization(ItemDto itemDto);
Task<List<ItemCategory>> GetItemCateg(ItemDto itemDto);
Task<List<ItemColor>> GetItemColor(ItemDto itemDto);
Task<List<UnitOfMessure>> GetItemUOM(ItemDto itemDto);
Task<List<NotifUserKey>> GetNotifUserKey(ItemDto itemDto);
Task<long> GetPRNo();
Task<ItemCart> PostPurchRequest(ItemDto itemDto);
Task<IReadOnlyList<ProjectCodes>> GetProjectCode();
Task<IReadOnlyList<ProjectCodes>> GetProjectCodeByTerm(string? fileName);
Task<(long, long)> GetPRNo();
Task<ResponseObject> PostPurchRequest(ItemDto itemDto);
Task<ItemCodeDto> PostPutItem(ItemCodeDto itemDto);
Task<Item> PutItemDetail(ItemDto itemDto);
Task<ItemCart> PostPutItemCart(ItemDto itemDto);
Task<ItemCart> PostPutItemPath(ItemDto itemDto);
Task PostPutAttachment(AttachmentRequest attach);
}
}

View File

@ -1,4 +1,5 @@
using CPRNIMS.Infrastructure.Dto.PO;
using CPRNIMS.Infrastructure.Dto.Canvass.Response;
using CPRNIMS.Infrastructure.Dto.PO;
using CPRNIMS.Infrastructure.Entities.Canvass;
using CPRNIMS.Infrastructure.Entities.Common;
using CPRNIMS.Infrastructure.Entities.LocalDb.NonInvent;
@ -15,6 +16,8 @@ namespace CPRNIMS.Domain.Contracts.PO
public interface IPurchaseOrder
{
#region Get
Task<POFormData> GetPOFormDataAsync(long? poId);
Task<List<Infrastructure.Entities.PO.PO>> GetPOListByTerm(PODto itemDto);
Task<List<IncomingShipmentDto>> GetIncomingShipment(PODto itemDto);
Task<List<IndexCard>> GetIndexCard(PODto poDto);
Task<List<PurchaseOrder>> GetForPOApprovalByPRNo(PODto PODto);
@ -35,11 +38,12 @@ namespace CPRNIMS.Domain.Contracts.PO
Task<List<SystemSettings>> GetLatestPO2(PODto pODto);
Task<List<DocRequired>> GetDocRequired(PODto pODto);
Task<List<OtherCharges>> GetOtherCharges(PODto itemDto);
Task<List<Suppliers>> GetSuppliers(PODto itemDto);
Task<List<SupplierResponseDto>> GetSuppliers(PODto itemDto);
Task<List<CreatedPO>> GetCreatedPO(PODto pODto);
Task<List<POItemDetail>> GetPOItemDetail(PODto pODto);
Task<List<CreatedPO>> GetMyCreatedPO(PODto pODto);
Task<List<Incoterm>> GetIncoterms(PODto itemDto);
Task<List<Incoterm>> GetIncotermsByName(PODto itemDto);
Task<List<PRPOSummaryCount>> GetPRPOSummaryReport(PODto itemDto);
Task<List<PRPOSummaryItem>> GetPRPOSummaryItem(PODto itemDto);
PODto CreatePoDto(POVM PODto, byte docRequirementId, int otherChargesId, long prDetailsId
@ -52,6 +56,7 @@ namespace CPRNIMS.Domain.Contracts.PO
Task<PurchaseOrder> PostPutPO(PODto PODto);
Task<OtherCharges> PostSuppCharges(PODto poDto);
Task<CustomPO> PostPutCustomPO(PODto pODto);
Task<CustomPO> PutExistingPO(PODto pODto);
Task<DocRequired>PostSuppDocRequirements(PODto poDto);
Task<PurchaseOrder> PostPOToSupplier(PODto PODto);
Task<Suppliers> PostApprovedSupplier(PODto PODto);
@ -65,6 +70,7 @@ namespace CPRNIMS.Domain.Contracts.PO
Task<Incoterm> PostPutIncoterms(PODto pODto);
Task<bool> DeleteIncShip(PODto poDto);
Task<bool> PostIncShipFollowUp(PODto pODto);
Task<IReadOnlyList<Currencies>> GetCurrencies(string currencyName, CancellationToken ct);
#endregion
}
}

View File

@ -1,7 +1,10 @@
using CPRNIMS.Infrastructure.Dto.PR;
using CPRNIMS.Infrastructure.Dto.Items;
using CPRNIMS.Infrastructure.Dto.PR;
using CPRNIMS.Infrastructure.Dto.PR.Response;
using CPRNIMS.Infrastructure.Entities.Common;
using CPRNIMS.Infrastructure.Entities.Purchasing;
using CPRNIMS.Infrastructure.Entities.SMTP;
using CPRNIMS.Infrastructure.Models.Common;
using System;
using System.Collections.Generic;
using System.Linq;
@ -18,22 +21,29 @@ namespace CPRNIMS.Domain.Contracts.PR
Task<List<ForReceiving>> GetForReceiving(PRDto PRDto);
Task<List<Dashboard>> GetDashBoard(PRDto PRDto);
Task<List<ItemApproval>> GetMyPR(PRDto PRDto);
Task<List<PRList>> GetAllPR(PRDto PRDto);
Task<PagedResult<DetailedPRTracking>> GetDetailedPRTracking(PRDto PRDto);
Task<PagedResult<Infrastructure.Entities.Purchasing.PRList>> GetAllPR(PRDto PRDto);
Task<PagedResult<Infrastructure.Entities.Purchasing.PRList>> GetPRArchived(PRDto pRDto);
Task<List<Infrastructure.Entities.Canvass.PRList>> GetPRListByPRNo(PRDto PRDto);
Task<List<NotifUserKey>> GetNotifUserKey(PRDto PRDto);
Task<List<PRDetails>> GetPRDetailByPRNo(PRDto PRDto);
Task<List<PRItemList>> GetPRDetailByPRNo(PRDto PRDto);
Task<List<PRTracking>> GetPRStatusById(PRDto PRDto);
Task<List<RRReport>> GetDetailedPRTracking(PRDto PRDto);
Task<List<AlternativeOffer>> GetSupplierAlternativeOffer(PRDto PRDto);
Task<List<AlternativeOfferDetails>> GetSupplierAlterOfferDetails(PRDto PRDto);
Task<List<NotificationById>> GetNotificationById(PRDto PRDto);
Task<List<PRDto>> GetApproverName(PRDto PRDto);
Task<List<PRDto>> GetApproverNameByPRNo(PRDto PRDto);
Task<List<ProjectCodes>> GetProjectCodes(PRDto pRDto);
Task<PagedResult<DeletedPR>> GetDeletedPR(PRDto pRDto);
Task<PagedResult<ApprovedPR>> GetApprovedPR(PRDto pRDto);
Task<MessageResponse> PRItemRemoval(PRDto pRDto);
Task<PRDetails> PostPRApproveReject(PRDto PRDto);
Task<PRDetails> PostPutReceiving(PRDto PRDto);
Task<PRDetails> PutPOClose(PRDto PRDto);
Task<PRDetails> PutItemDetail(PRDto PRDto);
Task<PRDetails> PostPutDeniedItem(PRDto PRDto);
Task<PRResponse> PostPRApproveReject(PRDto PRDto);
Task<PRResponse> PostPutReceiving(PRDto PRDto);
Task<PRResponse> PutPOClose(PRDto PRDto);
Task<PRResponse> PutItemDetail(PRDto PRDto);
Task<PRResponse> PostPutDeniedItem(PRDto PRDto);
Task<AlternativeOfferDetails> PutSupplierAlterOffer(PRDto pRDto);
Task<ResponseObject> PostPutProjectCode(PRDto prDto);
Task<ResponseObject> PostItemInPR(PRDto dto);
}
}

View File

@ -12,7 +12,7 @@ namespace CPRNIMS.Domain.Contracts.Receiving
public interface IReceiving
{
Task<List<ReceivingDetail>> GetRRDetailByPO(ItemDto itemDto);
Task<List<RRDetail>> GetRRDetail(ItemDto itemDto);
Task<List<RRDetailDto>> GetRRDetail(ItemDto itemDto);
Task<List<ForReceiving>> GetForReceiving(ItemDto itemDto);
Task<List<RR>> GetRR(ItemDto itemDto);
Task<List<RRSeries>> GetLatestRRNo(ItemDto itemDto);

View File

@ -0,0 +1,16 @@
using CPRNIMS.Infrastructure.Dto.Inventory.Reports;
using FastReport;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CPRNIMS.Domain.Contracts.Reports
{
public interface IReportBuilder
{
Task<Report> RISBuildAsync(DateTime dateFrom, DateTime dateTo, string templatePath, CancellationToken ct);
Task<Report> MRSBuildAsync(DateTime dateFrom, DateTime dateTo, string templatePath, CancellationToken ct);
}
}

View File

@ -0,0 +1,16 @@
using CPRNIMS.Infrastructure.Dto.Inventory.Reports;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CPRNIMS.Domain.Contracts.Reports
{
public interface IReportDataService
{
List<RISRowDto> GetMain(DateTime dateFrom, DateTime dateTo);
List<DisciplineAggDto> GetDisciplines(DateTime dateFrom, DateTime dateTo);
List<TopRecipientDto> GetRecipients(DateTime dateFrom, DateTime dateTo);
}
}

View File

@ -0,0 +1,24 @@
using CPRNIMS.Infrastructure.Dto.Canvass.Request;
using CPRNIMS.Infrastructure.Dto.Canvass.Response;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using CPRNIMS.Infrastructure.Entities.Canvass;
namespace CPRNIMS.Domain.Profile.Canvass
{
public class SupplierRequestProfile : AutoMapper.Profile
{
public SupplierRequestProfile()
{
CreateMap<SupplierRequest, Suppliers>();
CreateMap<Suppliers, SupplierResponse>();
CreateMap<SupplierResponse, SupplierRequest>().ReverseMap();
CreateMap<StartCanvassRequest, ForAISearchingTagging>();
CreateMap<ForAISearchingTagging, StartCanvassResponse>().ReverseMap();
}
}
}

View File

@ -57,6 +57,7 @@ namespace CPRNIMS.Domain.Services.Account
new Claim(ClaimTypes.NameIdentifier, user.Id),
new Claim("FullName", user.FullName ?? ""),
new Claim("Company", user.Company ?? ""),
new Claim("DepartmentId", Convert.ToString(user.DepartmentId)),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
};

View File

@ -26,44 +26,36 @@ namespace CPRNIMS.Domain.Services.Account
}
public async Task<List<object>> GetAllUsersProfile()
{
try
{
var usersWithRolesAndAttachments = await (from user in _userManager.Users
join userRole in _dbContext.IdentityUserRoles on user.Id equals userRole.UserId into userRoles
from ur in userRoles.DefaultIfEmpty()
join role in _dbContext.Roles on ur.RoleId equals role.Id into roles
from r in roles.DefaultIfEmpty()
join attachment in _dbContext.Attachments on user.Id equals attachment.AttachmentId into attachments
from a in attachments.DefaultIfEmpty()
select new
{
user.Id,
Role = r != null ? r.Name ?? "N/A" : "N/A",
URL = a != null ? a.URL ?? "N/A" : "N/A",
FileName = a != null ? a.FileName ?? "N/A" : "N/A",
user.Company,
user.DepartmentId,
user.UserName,
user.FullName,
user.Email,
user.EmailConfirmed,
Address = user.Address ?? "N/A",
PhoneNumber = user.PhoneNumber ?? "N/A",
user.LockoutEnd,
user.LockoutEnabled,
user.CreatedBy,
user.UpdatedBy,
user.CreatedDate,
user.UpdatedDate
}).ToListAsync();
var usersWithRolesAndAttachments = await (from user in _userManager.Users
join userRole in _dbContext.IdentityUserRoles on user.Id equals userRole.UserId into userRoles
from ur in userRoles.DefaultIfEmpty()
join role in _dbContext.Roles on ur.RoleId equals role.Id into roles
from r in roles.DefaultIfEmpty()
join attachment in _dbContext.Attachments on user.Id equals attachment.AttachmentId into attachments
from a in attachments.DefaultIfEmpty()
select new
{
user.Id,
Role = r != null ? r.Name ?? "N/A" : "N/A",
URL = a != null ? a.URL ?? "404userImage" : "404userImage",
FileName = a != null ? a.FileName ?? "404userImage.jpg" : "404userImage.jpg",
user.Company,
user.DepartmentId,
user.UserName,
user.FullName,
user.Email,
user.EmailConfirmed,
Address = user.Address ?? "N/A",
PhoneNumber = user.PhoneNumber ?? "N/A",
user.LockoutEnd,
user.LockoutEnabled,
user.CreatedBy,
user.UpdatedBy,
user.CreatedDate,
user.UpdatedDate
}).ToListAsync();
return usersWithRolesAndAttachments.Cast<object>().ToList();
}
catch (Exception ex)
{
ex.ToString();
throw;
}
return usersWithRolesAndAttachments.Cast<object>().ToList();
}
public async Task AssignUserRole(RegisterModel registerModel)
{

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,453 @@
using CPRNIMS.Infrastructure.Dto.Canvass.Response;
using CPRNIMS.Infrastructure.Dto.Canvass.Result;
using Microsoft.Extensions.Configuration;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace CPRNIMS.Domain.Services.Canvass
{
public class SupplierSearchService
{
private readonly HttpClient _httpClient;
private readonly IConfiguration _config;
// Common contact page suffixes to try
private static readonly string[] ContactPaths =
{ "/contact", "/contact-us", "/pages/contact-us", "/about/contact", "/about" };
/// <summary>
/// Uses Groq to fuzzy-match a new supplier against existing ones.
/// Handles rebranding, spacing in phone numbers, name variations, etc.
/// Returns the matched existing SupplierId, or null if no match.
/// </summary>
public async Task<int?> FindMatchingExistingSupplierAsync(
SupplierResponse incoming,
List<SupplierResponse> existingSuppliers)
{
if (!existingSuppliers.Any()) return null;
// ── Layer 1: Exact C# match (fast, free, no API call) ──────────────
var incomingEmail = (incoming.EmailAddress ?? "").Trim().ToLower();
var incomingPhone = NormalizePhone(incoming.ContactNo ?? "");
var incomingDomain = ExtractDomain(incoming.Website ?? "");
foreach (var s in existingSuppliers)
{
var existEmail = (s.EmailAddress ?? "").Trim().ToLower();
var existPhone = NormalizePhone(s.ContactNo ?? "");
var existDomain = ExtractDomain(s.Website ?? "");
if (!string.IsNullOrEmpty(incomingEmail) && incomingEmail == existEmail)
return s.SupplierId;
if (!string.IsNullOrEmpty(incomingPhone) && incomingPhone == existPhone)
return s.SupplierId;
if (!string.IsNullOrEmpty(incomingDomain) && incomingDomain == existDomain)
return s.SupplierId;
}
// ── Layer 2: Fuzzy C# pre-filter — narrow to top candidates ────────
var incomingName = (incoming.SupplierName ?? "").ToLower();
var candidates = existingSuppliers
.Where(s =>
{
var name = (s.SupplierName ?? "").ToLower();
// Keep if first word matches (e.g. "Linde" in "Linde PH" vs "Linde Philippines")
var incomingFirstWord = incomingName.Split(' ').FirstOrDefault() ?? "";
var existFirstWord = name.Split(' ').FirstOrDefault() ?? "";
return !string.IsNullOrEmpty(incomingFirstWord)
&& incomingFirstWord.Length > 2 // ignore short words like "co", "ph"
&& existFirstWord.StartsWith(incomingFirstWord, StringComparison.OrdinalIgnoreCase);
})
.Take(5) // max 5 candidates to Groq — well within token limit
.Select(s => new
{
s.SupplierId,
s.SupplierName,
s.EmailAddress,
s.ContactNo,
s.Website
})
.ToList();
// No fuzzy candidates found — it's a new supplier
if (!candidates.Any()) return null;
// ── Layer 3: Groq fuzzy match — only on small candidate list ────────
var incomingJson = JsonSerializer.Serialize(new
{
incoming.SupplierName,
incoming.EmailAddress,
incoming.ContactNo,
incoming.Website
});
var candidatesJson = JsonSerializer.Serialize(candidates);
var prompt =
"TASK: Determine if the INCOMING supplier already exists in the CANDIDATES list.\n\n" +
"MATCHING RULES (any one is enough):\n" +
"1. Same email address (case-insensitive).\n" +
"2. Same phone number after stripping spaces, dashes, country codes.\n" +
"3. Same company despite rebranding, abbreviation, or spacing differences.\n" +
"4. Same website domain (ignore www, http/https).\n\n" +
"If matched: respond ONLY { \"matched\": true, \"supplierId\": <number> }\n" +
"If not matched: respond ONLY { \"matched\": false, \"supplierId\": null }\n" +
"No explanation. No markdown. JSON only.\n\n" +
$"INCOMING:\n{incomingJson}\n\n" +
$"CANDIDATES:\n{candidatesJson}";
var payload = new
{
model = _config["Groq:Model"] ?? "llama-3.1-8b-instant",
stream = false,
max_tokens = 50,
temperature = 0,
messages = new[]
{
new { role = "system", content = "You are a supplier deduplication engine. Return ONLY valid JSON. No markdown. No explanation." },
new { role = "user", content = prompt }
}
};
var request = new HttpRequestMessage(HttpMethod.Post, _config["Groq:ApiUrl"]);
request.Headers.Add("Authorization", $"Bearer {_config["Groq:ApiKey"]}");
request.Content = new StringContent(
JsonSerializer.Serialize(payload), Encoding.UTF8, "application/json");
var response = await _httpClient.SendAsync(request);
response.EnsureSuccessStatusCode();
var body = await response.Content.ReadAsStringAsync();
var groqResp = JsonSerializer.Deserialize<GroqResponse>(body,
new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
var rawText = groqResp?.Choices?[0]?.Message?.Content ?? string.Empty;
rawText = Regex.Replace(rawText, @"```[a-z]*|```", "").Trim();
var match = JsonSerializer.Deserialize<GroqMatchResult>(rawText,
new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
return match?.Matched == true ? match.SupplierId : null;
}
public SupplierSearchService(HttpClient httpClient, IConfiguration config)
{
_httpClient = httpClient;
_config = config;
}
public async Task<List<SupplierResponse>> SearchAndFilterSuppliersAsync(
string itemName, string itemDescription, bool isInternational)
{
var locality = isInternational
? "all over Asia including Philippines"
: "Philippines";
// Step 1: Tavily — get supplier URLs
var (searchContent, supplierUrls) = await SearchTavilyAsync(itemName, itemDescription, locality);
// Step 2: Fetch contact pages from discovered URLs
var contactContent = await FetchContactPagesAsync(supplierUrls);
// Step 3: Combine search + contact content, send to Groq
var combined = searchContent + " CONTACT_PAGES_DATA: " + contactContent;
var suppliers = await FilterWithGroqAsync(itemName, itemDescription, combined,isInternational);
return suppliers;
}
// ── Tavily ──
private async Task<(string content, List<string> urls)> SearchTavilyAsync(
string itemName, string itemDescription,string locality)
{
try
{
var query = $"{itemName} {itemDescription} suppliers {locality} budget price contact email phone";
var payload = new
{
query,
max_results = 10,
search_depth = "advanced",
include_answer = false
};
var request = new HttpRequestMessage(HttpMethod.Post, _config["Tavily:SearchUrl"]);
request.Headers.Add("Authorization", $"Bearer {_config["Tavily:ApiKey"]}");
request.Content = new StringContent(
JsonSerializer.Serialize(payload), Encoding.UTF8, "application/json");
var response = await _httpClient.SendAsync(request);
response.EnsureSuccessStatusCode();
var body = await response.Content.ReadAsStringAsync();
var result = JsonSerializer.Deserialize<TavilySearchResult>(body,
new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
var sb = new StringBuilder();
var urls = new List<string>();
int i = 1;
foreach (var r in result?.Results ?? new())
{
// Clean text
var clean = Regex.Replace(r.Content ?? "", @"[^\x20-\x7E]", " ");
clean = Regex.Replace(clean, @"\s{3,}", " ");
if (clean.Length > 300) clean = clean[..300];
sb.Append($"{i}. Title:{r.Title}|URL:{r.Url}|Content:{clean}|");
// Collect base domain URLs for contact page fetching
try
{
var uri = new Uri(r.Url);
var baseUrl = $"{uri.Scheme}://{uri.Host}";
if (!urls.Contains(baseUrl)) urls.Add(baseUrl);
}
catch { }
i++;
}
var fullText = sb.ToString();
if (fullText.Length > 2000) fullText = fullText[..2000];
return (fullText, urls);
}
catch (Exception ex)
{
ex.ToString();
throw;
}
}
// ── Fetch Contact Pages ───
private async Task<string> FetchContactPagesAsync(List<string> baseUrls)
{
var sb = new StringBuilder();
// Limit to top 5 domains to avoid timeout
foreach (var baseUrl in baseUrls.Take(5))
{
foreach (var path in ContactPaths)
{
try
{
var url = baseUrl + path;
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5));
var resp = await _httpClient.GetAsync(url, cts.Token);
if (!resp.IsSuccessStatusCode) continue;
var html = await resp.Content.ReadAsStringAsync();
// Strip HTML tags
var text = Regex.Replace(html, @"<[^>]+>", " ");
text = Regex.Replace(text, @"[^\x20-\x7E]", " ");
text = Regex.Replace(text, @"\s{3,}", " ");
// Extract only lines with contact signals
var contactLines = text.Split(' ', StringSplitOptions.RemoveEmptyEntries)
.Where(w => w.Contains("@")
|| Regex.IsMatch(w, @"\+?[\d\-\(\)]{7,}")
|| w.Contains("email")
|| w.Contains("phone")
|| w.Contains("contact")
|| w.Contains("mobile")
|| w.Contains("tel"))
.Take(50);
var contactText = string.Join(" ", contactLines);
if (!string.IsNullOrWhiteSpace(contactText))
{
sb.Append($"[{baseUrl}]: {contactText} | ");
break; // Found contact page for this domain, move to next
}
}
catch { /* timeout or unreachable — skip */ }
}
}
return sb.Length > 2000 ? sb.ToString()[..2000] : sb.ToString();
}
// ── Groq ─────────────────────────────────────────────────────────────────
private async Task<List<SupplierResponse>> FilterWithGroqAsync(
string itemName, string itemDescription, string searchContent, bool isInternational)
{
try
{
var localityRule = isInternational
? "1. Include suppliers from Philippines first, then other Asian countries (e.g. China, Japan, South Korea, Taiwan, India, Singapore).\n"
: "1. STRICT: Include ONLY suppliers based in the Philippines. Exclude ANY supplier from other countries — even if they ship to Philippines. If a supplier's country is not Philippines, skip it entirely.\n";
var prompt =
$"TASK: Extract up to 10 unique suppliers that sell: [{itemName}] — {itemDescription}.\n\n" +
"RULES:\n" +
localityRule +
"2. Prefer budget-friendly suppliers with known pricing.\n" +
"3. DEDUPLICATION (strict): Each entry must have a unique company_name, contact_email, AND phone_number.\n" +
" - If two entries share the same email OR phone number, keep only the first.\n" +
" - If two inferred emails resolve to the same address, keep only one.\n" +
"4. CONTACT EXTRACTION:\n" +
" - Look in the CONTACT_PAGES_DATA section for real emails and phone numbers.\n" +
" - Use exact values found. Do not fabricate contact details.\n" +
" - If no email is found for a domain, infer: sales@domain.com or info@domain.com.\n" +
" - If no phone is found, use null — do not guess.\n" +
"5. estimated_price_usd MUST be a number (e.g. 12.50) or null. NEVER a string.\n" +
"6. Exclude any supplier with no company_name or no contact_email.\n\n" +
"OUTPUT FORMAT:\n" +
"Return ONLY a valid raw JSON array. No markdown. No explanation. No extra text.\n" +
"Each object must have exactly these fields:\n" +
" company_name (string)\n" +
" country (string)\n" +
" phone_number (string | null)\n" +
" contact_email (string | null)\n" +
" website (string | null)\n" +
" estimated_price_usd (number | null)\n" +
" item_specifications (string | null)\n\n" +
$"DATA:\n{searchContent}";
var payload = new
{
model = _config["Groq:Model"] ?? "llama-3.1-8b-instant",
stream = false,
max_tokens = 2048,
temperature = 0.1,
messages = new[]
{
new { role = "system", content = "You are a supplier data extractor. Extract real contact details from provided content. Return ONLY a valid JSON array, no markdown, no explanation." },
new { role = "user", content = prompt }
}
};
var request = new HttpRequestMessage(HttpMethod.Post, _config["Groq:ApiUrl"]);
request.Headers.Add("Authorization", $"Bearer {_config["Groq:ApiKey"]}");
request.Content = new StringContent(
JsonSerializer.Serialize(payload), Encoding.UTF8, "application/json");
var response = await _httpClient.SendAsync(request);
response.EnsureSuccessStatusCode();
var body = await response.Content.ReadAsStringAsync();
var groqResp = JsonSerializer.Deserialize<GroqResponse>(body,
new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
var rawText = groqResp?.Choices?[0]?.Message?.Content ?? string.Empty;
var match = Regex.Match(rawText, @"\[[\s\S]*\]");
if (!match.Success) return new List<SupplierResponse>();
// Add the converter to the shared options
var jsonOptions = new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true,
Converters = { new FlexibleDecimalConverter() }
};
var groqList = JsonSerializer.Deserialize<List<GroqSupplierResult>>(match.Value, jsonOptions)
?? new List<GroqSupplierResult>();
var seenNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
var seenEmails = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
var seenPhones = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
var suppliers = new List<SupplierResponse>();
var allowedCountries = isInternational
? new HashSet<string>(StringComparer.OrdinalIgnoreCase)
{
"Philippines", "China", "Japan", "South Korea", "Taiwan",
"India", "Singapore", "Malaysia", "Thailand", "Vietnam",
"Indonesia", "Hong Kong"
}
: new HashSet<string>(StringComparer.OrdinalIgnoreCase)
{
"Philippines"
};
foreach (var s in groqList)
{
var key = (s.CompanyName ?? "").Trim().ToLower();
var email = (s.ContactEmail ?? "").Trim().ToLower();
var phone = NormalizePhone(s.PhoneNumber ?? "");
// Skip if no company name
if (string.IsNullOrEmpty(key)) continue;
// Skip if no email
if (string.IsNullOrEmpty(email)) continue;
// ✅ Skip if company name, email, OR phone already seen
if (seenNames.Contains(key)) continue;
if (seenEmails.Contains(email)) continue;
if (!string.IsNullOrEmpty(phone) && seenPhones.Contains(phone)) continue;
seenNames.Add(key);
seenEmails.Add(email);
if (!string.IsNullOrEmpty(phone)) seenPhones.Add(phone);
suppliers.Add(new SupplierResponse
{
SupplierName = s.CompanyName,
EmailAddress = s.ContactEmail,
ContactNo = s.PhoneNumber ?? string.Empty,
Address = s.Country ?? string.Empty,
IsActive = true,
VatInc = false,
Currency = "PHP",
CurrencyId = 1,
PaymentTermsId = 1,
PaymentTerms = "30 Days",
LeadTime = "7-14 Days",
TinNo = string.Empty,
ContactPerson = string.Empty,
Website = s.Website ?? string.Empty,
});
if (suppliers.Count >= 10) break;
}
return suppliers;
}
catch (Exception ex)
{
ex.ToString();
throw;
}
}
private static string NormalizePhone(string phone)
{
if (string.IsNullOrWhiteSpace(phone)) return string.Empty;
// Strip everything except digits
var digits = Regex.Replace(phone, @"\D", "");
// Remove leading country code "1" for US/CA numbers (11 digits starting with 1)
if (digits.Length == 11 && digits.StartsWith("1"))
digits = digits[1..];
return digits;
}
private static string ExtractDomain(string url)
{
if (string.IsNullOrWhiteSpace(url)) return string.Empty;
try
{
if (!url.StartsWith("http")) url = "https://" + url;
var host = new Uri(url).Host;
return host.StartsWith("www.") ? host[4..] : host;
}
catch { return string.Empty; }
}
}
}

View File

@ -0,0 +1,49 @@
using CPRNIMS.Domain.Contracts.Common;
using CPRNIMS.Infrastructure.Database;
using Microsoft.EntityFrameworkCore;
namespace CPRNIMS.Domain.Services.Common
{
public class TransactionFacade : ITransactionFacade
{
private readonly NonInventoryDbContext _db;
public TransactionFacade(NonInventoryDbContext db)
=> _db = db ?? throw new ArgumentNullException(nameof(db));
public async Task<T> ExecuteAsync<T>(Func<Task<T>> operation, CancellationToken ct = default)
{
ArgumentNullException.ThrowIfNull(operation);
var strategy = _db.Database.CreateExecutionStrategy();
return await strategy.ExecuteAsync(async () =>
{
await using var tx = await _db.Database.BeginTransactionAsync(ct);
try
{
var result = await operation();
await _db.SaveChangesAsync(ct);
await tx.CommitAsync(ct);
return result;
}
catch
{
await tx.RollbackAsync(ct);
throw;
}
});
}
public async Task ExecuteAsync(Func<Task> operation, CancellationToken ct = default)
{
ArgumentNullException.ThrowIfNull(operation);
await ExecuteAsync<bool>(async () =>
{
await operation();
return true;
}, ct);
}
}
}

View File

@ -0,0 +1,47 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CPRNIMS.Domain.Services
{
public static class ContentTypeHelper
{
public static string GetContentType(string fileName)
{
var extension = Path.GetExtension(fileName).ToLowerInvariant();
return extension switch
{
".pdf" => "application/pdf",
".doc" => "application/msword",
".docx" => "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
".pptx" => "application/vnd.openxmlformats-officedocument.presentationml.presentation",
".xls" => "application/vnd.ms-excel",
".xlsx" => "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
".png" => "image/png",
".jpg" or ".jpeg" => "image/jpeg",
".gif" => "image/gif",
".txt" => "text/plain",
_ => "application/octet-stream"
};
}
public static string ValidateFile(string filePath, string uploadsPath)
{
var message = "";
// Security: Prevent directory traversal attacks
var fullPath = Path.GetFullPath(filePath);
if (!fullPath.StartsWith(Path.GetFullPath(uploadsPath)))
{
message = "Invalid file path";
}
if (!System.IO.File.Exists(filePath))
{
message = "File not found";
}
return message;
}
}
}

View File

@ -40,7 +40,7 @@ namespace CPRNIMS.Domain.Services.Finance
return allItems ?? new List<ReceivingDetail>();
}
public async Task<RRDetail> PostPutPayment(RRDetailsDto itemDto)
public async Task<RRDetailDto> PostPutPayment(RRDetailsDto itemDto)
{
await _dbContext.Database
.ExecuteSqlRawAsync("EXEC PostPutPayment @UserId, @PONo, @POTypeId, @PRDetailsId",
@ -48,7 +48,7 @@ namespace CPRNIMS.Domain.Services.Finance
new SqlParameter("@PONo", itemDto.PONo),
new SqlParameter("@POTypeId", itemDto.POTypeId),
new SqlParameter("@PRDetailsId", itemDto.PRDetailsId));
return new RRDetail();
return new RRDetailDto();
}
}
}

View File

@ -1,9 +1,11 @@
using CPRNIMS.Domain.Contracts.Inventory;
using CPRNIMS.Infrastructure.Database;
using CPRNIMS.Infrastructure.Dto.Inventory;
using CPRNIMS.Infrastructure.Dto.Items;
using CPRNIMS.Infrastructure.Entities.Finance;
using CPRNIMS.Infrastructure.Dto.Inventory.Request;
using CPRNIMS.Infrastructure.Dto.Inventory.Response;
using CPRNIMS.Infrastructure.Entities.Account;
using CPRNIMS.Infrastructure.Entities.Inventory;
using Microsoft.AspNetCore.Identity;
using Microsoft.Data.SqlClient;
using Microsoft.EntityFrameworkCore;
using System;
@ -17,69 +19,224 @@ namespace CPRNIMS.Domain.Services.Inventory
public class Inventory : IInventory
{
private readonly NonInventoryDbContext _dbContext;
public Inventory(NonInventoryDbContext dbContext)
private readonly UserManager<ApplicationUser> _userManager;
public Inventory(NonInventoryDbContext dbContext, UserManager<ApplicationUser> userManager)
{
_dbContext = dbContext;
_userManager = userManager;
}
public async Task<List<Infrastructure.Entities.Inventory.ItemDetail>> GetInventoryById(InventoryDto itemDto)
public async Task<TransactContextDto?> GetTransactContextAsync(int inventoryId, CancellationToken ct)
{
try
{
var allItems = await _dbContext.ItemDetails
.FromSqlRaw($"EXEC GetInventoryById @UserId = '{itemDto.UserId}',@InventoryId = '{itemDto.InventoryId}'")
.ToListAsync();
return allItems ?? new List<Infrastructure.Entities.Inventory.ItemDetail>();
}
catch (SqlException ex)
{
ex.ToString();
throw;
}
}
public async Task<List<Infrastructure.Entities.Inventory.Inventory>>
GetInventoryByUserId(InventoryDto itemDto)
{
try
{
if(itemDto.IsSorting == false)
var inv = await _dbContext.Inventories
.Where(i => i.InventoryId == inventoryId && i.IsActive)
.Select(i => new
{
itemDto.DateFrom=DateTime.Now;
itemDto.DateTo = DateTime.Now;
}
var allItems = await _dbContext.Inventories
.FromSqlRaw($"EXEC GetInventoryByUserId @UserId,@DateFrom,@DateTo,@IsSorting",
new SqlParameter("@UserId", itemDto.UserId),
new SqlParameter("@DateFrom", itemDto.DateFrom),
new SqlParameter("@DateTo", itemDto.DateTo),
new SqlParameter("@IsSorting", itemDto.IsSorting))
.ToListAsync();
i.InventoryId,
i.QtyOnHand,
i.QtyIn,
i.QtyOut,
return allItems ?? new List<Infrastructure.Entities.Inventory.Inventory>();
}
catch (SqlException ex)
LotNo = i.Lot != null ? i.Lot.LotName : null,
Department = i.User != null && i.User.Department != null
? i.User.Department.Department
: null,
i.ItemNo,
FirstDetail = i.InventTrans
.Where(t => t.IsActive)
.SelectMany(t => t.InventTransDetails)
.Where(d => d.PRDetails != null
&& d.PRDetails.PRs != null
&& d.IsActive)
.Select(d => new
{
d.PRDetails!.ItemName,
PRNo = d.PRDetails.PRs!.PRNo
})
.FirstOrDefault()
})
.FirstOrDefaultAsync(ct);
if (inv == null) return null;
// Computed property QtyAvailableToReturn can't be used in EF Where,
// so filter after projection using a raw expression in the query.
var openRIS = await _dbContext.RIS
.Where(r => r.InventoryId == inventoryId
&& r.Status == 1)
.Select(r => new RISReferenceDto
{
RISId = r.RISId,
RISNo = r.RISNo,
QtyIssued = r.QtyIssued,
TotalReturned = r.MaterialReturns
.Where(m => m.Status != 2)
.Sum(m => (int?)m.QtyReturned) ?? 0,
DisciplineName = r.Discipline.DisciplineName,
CreatedDate = r.CreatedDate
})
// Can't use the computed property here — EF won't translate it
// so we repeat the expression inline
.Where(r => r.QtyIssued - r.TotalReturned > 0)
.OrderByDescending(r => r.CreatedDate)
.ToListAsync(ct);
var disciplines = await GetDisciplinesAsync(ct);
var projectCodes = await GetProjectCodesAsync(ct);
return new TransactContextDto
{
ex.ToString();
throw;
InventoryId = inv.InventoryId,
ItemName = inv.FirstDetail?.ItemName ?? "—",
PRNo = inv.FirstDetail.PRNo,
ItemNo = inv.ItemNo,
LotNo = inv.LotNo,
Department = inv.Department,
QtyOnHand = inv.QtyOnHand,
QtyIn = inv.QtyIn,
QtyOut = inv.QtyOut,
ProjectCodes = projectCodes,
Disciplines = disciplines,
OpenRISList = openRIS
};
}
public async Task<IReadOnlyList<DisciplineDto>> GetDisciplinesAsync(CancellationToken ct)
{
return await _dbContext.Disciplines
.AsNoTracking()
.OrderBy(d => d.DisciplineName)
.Select(d => new DisciplineDto
{
DisciplineId = d.DisciplineId,
DisciplineName = d.DisciplineName
})
.ToListAsync(ct);
}
public async Task<IReadOnlyList<ProjectCodeDto>> GetProjectCodesAsync(CancellationToken ct)
{
return await _dbContext.ProjectCodes
.Where(p => p.StatusName != "Completed" && p.IsActive)
.OrderBy(d => d.ProjectName)
.Select(d => new ProjectCodeDto
{
ProjectCodeId = d.ProjectCodeId,
ProjectCode = d.ProjectCode ?? "N/A",
ProjectName = d.ProjectName ?? "N/A"
})
.ToListAsync(ct);
}
public async Task<List<ItemDetail>> GetInventoryById(InventoryDto itemDto)
{
var allItems = await _dbContext.ItemDetails
.FromSqlRaw($"EXEC GetInventoryById @UserId = '{itemDto.UserId}',@InventoryId = '{itemDto.InventoryId}'")
.ToListAsync();
return allItems ?? new List<Infrastructure.Entities.Inventory.ItemDetail>();
}
public async Task<PagedResult<InventoryResponse>> GetInventory(InventoryRequest request, CancellationToken ct)
{
var parameters = new[]
{
new SqlParameter("@UserId", request.UserId),
new SqlParameter("@SearchPRNo", request.SearchPRNo ?? ""),
new SqlParameter("@SearchItemNo", request.SearchItemNo ?? ""),
new SqlParameter("@SearchItemName", request.SearchItemName ?? ""),
new SqlParameter("@SearchDept", request.SearchDept ?? ""),
new SqlParameter("@SearchProjectCode",request.SearchProjectCode ?? ""),
new SqlParameter("@PageNumber", request.PageNumber),
new SqlParameter("@PageSize", request.PageSize)
};
var departmentList = new List<string>();
int totalCount = 0;
var items = new List<InventoryResponse>();
await using var conn = _dbContext.Database.GetDbConnection();
await conn.OpenAsync(ct);
using var cmd = conn.CreateCommand();
cmd.CommandText = @"EXEC GetInventory @UserId, @SearchPRNo, @SearchItemNo, @SearchItemName, @SearchDept,@SearchProjectCode, @PageNumber, @PageSize";
foreach (var p in parameters) cmd.Parameters.Add(p);
cmd.CommandTimeout = 60;
using var reader = await cmd.ExecuteReaderAsync(ct);
while (await reader.ReadAsync(ct))
departmentList.Add(reader.GetString(0));
await reader.NextResultAsync(ct);
if (await reader.ReadAsync(ct))
totalCount = reader.GetInt32(0);
await reader.NextResultAsync(ct);
while (await reader.ReadAsync(ct))
{
items.Add(new InventoryResponse
{
InventoryId = reader.GetInt32(reader.GetOrdinal("InventoryId")),
QtyIn = reader["QtyIn"] as decimal? ?? 0,
QtyOut = reader["QtyOut"] as decimal? ?? 0,
QtyOnHand = reader["QtyOnHand"] as decimal? ?? 0,
LotNo = reader["LotNo"]?.ToString(),
PRNo = Convert.ToInt64(reader["PRNo"]),
UserId = reader["UserId"]?.ToString(),
ItemName = reader["ItemName"]?.ToString(),
ItemNo = Convert.ToInt64(reader["ItemNo"]),
ItemDescription = reader["ItemDescription"]?.ToString(),
ItemCategoryName = reader["ItemCategoryName"]?.ToString(),
Department = reader["Department"]?.ToString(),
ProjectCode = reader["ProjectCode"]?.ToString(),
CreatedDate = reader["CreatedDate"] == DBNull.Value
? DateTime.MinValue
: Convert.ToDateTime(reader["CreatedDate"])
});
}
await conn.CloseAsync();
return new PagedResult<InventoryResponse>
{
Data = items,
TotalCount = totalCount,
PageNumber = request.PageNumber,
PageSize = request.PageSize,
DepartmentList = departmentList
};
}
public async Task<List<InventoryByIdResponse>> GetInventoryById(InventoryRequest itemDto,CancellationToken ct)
{
var allItems = await _dbContext.InventoryByIdResponses
.FromSqlRaw($"EXEC GetInventoryById @InventoryId",
new SqlParameter("@InventoryId", itemDto.InventoryId))
.ToListAsync(ct);
return allItems ?? new List<InventoryByIdResponse>();
}
public async Task<List<Infrastructure.Entities.Inventory.Inventory>>GetInventoryByUserId(InventoryDto itemDto)
{
if (itemDto.IsSorting == false)
{
itemDto.DateFrom = DateTime.Now;
itemDto.DateTo = DateTime.Now;
}
var allItems = await _dbContext.Inventories
.FromSqlRaw($"EXEC GetInventoryByUserId @UserId,@DateFrom,@DateTo,@IsSorting",
new SqlParameter("@UserId", itemDto.UserId),
new SqlParameter("@DateFrom", itemDto.DateFrom),
new SqlParameter("@DateTo", itemDto.DateTo),
new SqlParameter("@IsSorting", itemDto.IsSorting))
.ToListAsync();
return allItems ?? new List<Infrastructure.Entities.Inventory.Inventory>();
}
public async Task<List<Lot>> GetLotNoById(InventoryDto itemDto)
{
try
{
var allItems = await _dbContext.Lots
.FromSqlRaw($"EXEC GetLotById @UserId = '{itemDto.UserId}'")
.ToListAsync();
var allItems = await _dbContext.Lots
.FromSqlRaw($"EXEC GetLotById @UserId = '{itemDto.UserId}'")
.ToListAsync();
return allItems ?? new List<Lot>();
}
catch (SqlException ex)
{
ex.ToString();
throw;
}
return allItems ?? new List<Lot>();
}
public async Task<List<Lot>> GetLotNo(InventoryDto itemDto)
@ -94,125 +251,77 @@ namespace CPRNIMS.Domain.Services.Inventory
public async Task<Lot> PostPutLotNo(InventoryDto itemDto)
{
try
{
await _dbContext.Database
.ExecuteSqlRawAsync("EXEC PostPutLotNo @UserId, @LotId, @LotTypeId,@LotName",
new SqlParameter("@LotId", itemDto.LotId != null ? itemDto.LotId : 0L),
new SqlParameter("@UserId", itemDto.UserId),
new SqlParameter("@LotTypeId", itemDto.LotTypeId),
new SqlParameter("@LotName", itemDto.LotName));
return new Lot();
}
catch (SqlException ex)
{
ex.ToString();
throw;
}
await _dbContext.Database
.ExecuteSqlRawAsync("EXEC PostPutLotNo @UserId, @LotId, @LotTypeId,@LotName",
new SqlParameter("@LotId", itemDto.LotId != null ? itemDto.LotId : 0L),
new SqlParameter("@UserId", itemDto.UserId),
new SqlParameter("@LotTypeId", itemDto.LotTypeId),
new SqlParameter("@LotName", itemDto.LotName));
return new Lot();
}
public async Task<Infrastructure.Entities.Inventory.Inventory> PostPutReqApproval(InventoryDto itemDto)
{
try
{
await _dbContext.Database
.ExecuteSqlRawAsync("EXEC PostPutReqApproval @UserId, @ItemNo, @Status, @Remarks",
new SqlParameter("@ItemNo", itemDto.InventoryId != null ? itemDto.InventoryId : 0L),
new SqlParameter("@UserId", itemDto.UserId),
new SqlParameter("@Status", itemDto.Status),
new SqlParameter("@Remarks", itemDto.Remarks ?? "N/A"));
return new Infrastructure.Entities.Inventory.Inventory();
}
catch (SqlException ex)
{
ex.ToString();
throw;
}
await _dbContext.Database
.ExecuteSqlRawAsync("EXEC PostPutReqApproval @UserId, @ItemNo, @Status, @Remarks",
new SqlParameter("@ItemNo", itemDto.InventoryId != null ? itemDto.InventoryId : 0L),
new SqlParameter("@UserId", itemDto.UserId),
new SqlParameter("@Status", itemDto.Status),
new SqlParameter("@Remarks", itemDto.Remarks ?? "N/A"));
return new Infrastructure.Entities.Inventory.Inventory();
}
public async Task<ItemDetail> PostPutLotBin(InventoryDto itemDto)
{
try
{
await _dbContext.Database
.ExecuteSqlRawAsync("EXEC PostPutLotBin @UserId, @LotId, @InventoryId",
new SqlParameter("@InventoryId", itemDto.InventoryId),
new SqlParameter("@UserId", itemDto.UserId),
new SqlParameter("@LotId", itemDto.LotId));
return new ItemDetail();
}
catch (SqlException ex)
{
ex.ToString();
throw;
}
await _dbContext.Database
.ExecuteSqlRawAsync("EXEC PostPutLotBin @UserId, @LotId, @InventoryId",
new SqlParameter("@InventoryId", itemDto.InventoryId),
new SqlParameter("@UserId", itemDto.UserId),
new SqlParameter("@LotId", itemDto.LotId));
return new ItemDetail();
}
public async Task<RequestItem> PostPutReqItems(InventoryDto itemDto)
{
try
if (itemDto.QtyReceived == null || itemDto.QtyReceived == 0)
{
if(itemDto.QtyReceived == null || itemDto.QtyReceived == 0)
{
itemDto.QtyReceived = 0;
}
if(itemDto.LotId == null || itemDto.LotId == 0)
{
itemDto.LotId = 0;
}
await _dbContext.Database
.ExecuteSqlRawAsync("EXEC PostPutReqItems @UserId, @RequestItemId, @ItemNo, @QtyRequest,@Status,@IsApproved,@QtyReceived,@LotId",
new SqlParameter("@UserId", itemDto.UserId),
new SqlParameter("@ItemNo", itemDto.ItemNo),
new SqlParameter("@RequestItemId", itemDto.RequestItemId != null ? itemDto.RequestItemId : 0L),
new SqlParameter("@QtyRequest", itemDto.QtyRequest),
new SqlParameter("@Status", itemDto.Status),
new SqlParameter("@IsApproved", itemDto.IsApproved),
new SqlParameter("@QtyReceived", itemDto.QtyReceived),
new SqlParameter("@LotId", itemDto.LotId));
return new RequestItem();
itemDto.QtyReceived = 0;
}
catch (SqlException ex)
if (itemDto.LotId == null || itemDto.LotId == 0)
{
ex.ToString();
throw;
itemDto.LotId = 0;
}
await _dbContext.Database
.ExecuteSqlRawAsync("EXEC PostPutReqItems @UserId, @RequestItemId, @ItemNo, @QtyRequest,@Status,@IsApproved,@QtyReceived,@LotId",
new SqlParameter("@UserId", itemDto.UserId),
new SqlParameter("@ItemNo", itemDto.ItemNo),
new SqlParameter("@RequestItemId", itemDto.RequestItemId != null ? itemDto.RequestItemId : 0L),
new SqlParameter("@QtyRequest", itemDto.QtyRequest),
new SqlParameter("@Status", itemDto.Status),
new SqlParameter("@IsApproved", itemDto.IsApproved),
new SqlParameter("@QtyReceived", itemDto.QtyReceived),
new SqlParameter("@LotId", itemDto.LotId));
return new RequestItem();
}
public async Task<List<RequestItemDetail>> GetRequestedItemByUserId(InventoryDto itemDto)
{
try
{
var allItems = await _dbContext.RequestItemDetails
var allItems = await _dbContext.RequestItemDetails
.FromSqlRaw($"EXEC GetRequestedItemByUserId @UserId = '{itemDto.UserId}', " +
$"@RequestItemId = '{itemDto.RequestItemId}',@WithoutStocks = '{itemDto.WithoutStocks}'")
.ToListAsync();
return allItems ?? new List<RequestItemDetail>();
}
catch (SqlException ex)
{
ex.ToString();
throw;
}
return allItems ?? new List<RequestItemDetail>();
}
public async Task<List<LotQtyByItem>> GetLotQtyByItem(InventoryDto itemDto)
{
try
{
var allItems = await _dbContext.LotQtyByItems
.FromSqlRaw($"EXEC GetLotQtyByItem @UserId = '{itemDto.UserId}', " +
$"@ItemNo = '{itemDto.ItemNo}',@LotId = '{itemDto.LotId}'")
.ToListAsync();
var allItems = await _dbContext.LotQtyByItems
.FromSqlRaw($"EXEC GetLotQtyByItem @UserId = '{itemDto.UserId}', " +
$"@ItemNo = '{itemDto.ItemNo}',@LotId = '{itemDto.LotId}'")
.ToListAsync();
return allItems ?? new List<LotQtyByItem>();
}
catch (SqlException ex)
{
ex.ToString();
throw;
}
return allItems ?? new List<LotQtyByItem>();
}
}
}

View File

@ -0,0 +1,307 @@
using CPRNIMS.Domain.Contracts.Inventory;
using CPRNIMS.Infrastructure.Database;
using CPRNIMS.Infrastructure.Dto.Inventory.Reports;
using CPRNIMS.Infrastructure.Dto.Inventory.Request;
using Microsoft.Data.SqlClient;
using Microsoft.EntityFrameworkCore;
using System.Drawing.Printing;
using static System.Runtime.InteropServices.JavaScript.JSType;
namespace CPRNIMS.Domain.Services.Inventory
{
public class InventoryReports : IInventoryReports
{
private readonly NonInventoryDbContext _db;
public InventoryReports(NonInventoryDbContext db) => _db = db;
public async Task<RISReportDto> GetRISReportAsync(InventoryReportsRequest request, string userName, int? departmentId, CancellationToken ct)
{
var endDate = request.DateTo.Date.AddDays(1);
var allowedAllDeptUsers = new[] { "LSKRISUR24", "LSCYNDIZ25", "LSJONTAN25", "LHRIOCAS24" };
bool seeAllDepartments = !string.IsNullOrWhiteSpace(userName)
&& allowedAllDeptUsers.Contains(userName, StringComparer.OrdinalIgnoreCase);
var dateToInclusive = request.DateTo.AddDays(1);
var query = _db.RIS
.Include(r => r.Discipline)
.Include(r => r.Inventory)
.Include(r => r.MaterialReturns)
.Skip((request.Page - 1) * request.PageSize)
.Take(request.PageSize)
.Where(r => r.CreatedDate >= request.DateFrom && r.CreatedDate < dateToInclusive);
if (departmentId.HasValue && !seeAllDepartments)
{
query = query.Where(m =>
m.Inventory.User != null &&
m.Inventory.User.DepartmentId == departmentId.Value);
}
var rows = await query
.OrderByDescending(r => r.CreatedDate)
.Select(r => new RISReportRow
{
RISNo = r.RISNo,
CreatedDate = r.CreatedDate,
ItemName = r.PRDetail != null ? r.PRDetail.ItemName : "—",
ItemNo = r.Inventory.ItemNo,
DisciplineName = r.Discipline.DisciplineName,
ProjectName = r.ProjectCodes.ProjectName,
QtyIssued = r.QtyIssued,
TotalReturned = r.MaterialReturns
.Where(m => m.Status != 2)
.Sum(m => (int?)m.QtyReturned) ?? 0,
Status = r.Status,
StatusLabel = r.Status == 0 ? "Draft"
: r.Status == 1 ? "Approved"
: "Cancelled"
})
.ToListAsync(ct);
foreach (var row in rows)
row.NetIssued = row.QtyIssued - row.TotalReturned;
var summary = new RISReportSummary
{
TotalRIS = rows.Count,
TotalApproved = rows.Count(r => r.Status == 1),
TotalPending = rows.Count(r => r.Status == 0),
TotalCancelled = rows.Count(r => r.Status == 2),
TotalQtyIssued = rows.Sum(r => r.QtyIssued),
TotalQtyReturned = rows.Sum(r => r.TotalReturned),
TotalNetIssued = rows.Sum(r => r.NetIssued),
ApprovalRatePct = rows.Count > 0
? Math.Round(rows.Count(r => r.Status == 1) * 100m / rows.Count, 1)
: 0
};
var byDiscipline = rows
.GroupBy(r => r.DisciplineName)
.Select(g => new DisciplineCount { DisciplineName = g.Key, Count = g.Count() })
.OrderByDescending(d => d.Count)
.ToList();
var topRecipients = rows
.GroupBy(r => r.ProjectName)
.Select(g => new TopRecipient
{
IssuedTo = g.Key,
SlipCount = g.Count(),
TotalQty = g.Sum(r => r.QtyIssued)
})
.OrderByDescending(t => t.TotalQty)
.Take(5)
.ToList();
return new RISReportDto
{
ReportNo = $"RPT-RIS-{DateTime.Now:yyyyMM}-{Random.Shared.Next(1, 999):D3}",
DateFrom = request.DateFrom,
DateTo = request.DateTo,
Summary = summary,
Rows = rows,
ByDiscipline = byDiscipline,
TopRecipients = topRecipients
};
}
public async Task<MRSReportDto> GetMRSReportAsync(InventoryReportsRequest request, string userName, int? departmentId, CancellationToken ct)
{
var endDate = request.DateTo.Date.AddDays(1);
var allowedAllDeptUsers = new[] { "LSKRISUR24", "LSCYNDIZ25", "LSJONTAN25", "LHRIOCAS24" };
bool seeAllDepartments = !string.IsNullOrWhiteSpace(userName)
&& allowedAllDeptUsers.Contains(userName, StringComparer.OrdinalIgnoreCase);
var query = _db.MRS
.Include(m => m.RIS)
.Include(m => m.Inventory)
.ThenInclude(i => i.User)
.Skip((request.Page - 1) * request.PageSize)
.Take(request.PageSize)
.Where(m => m.CreatedDate >= request.DateFrom &&
m.CreatedDate < endDate);
if (departmentId.HasValue && !seeAllDepartments)
{
query = query.Where(m =>
m.Inventory.User != null &&
m.Inventory.User.DepartmentId == departmentId.Value);
}
var rows = await query
.OrderByDescending(m => m.CreatedDate)
.Select(m => new MRSReportRow
{
MRSNo = m.MRSNo,
CreatedDate = m.CreatedDate,
RISNo = m.RIS.RISNo,
ItemName = m.RIS.PRDetail != null ? m.RIS.PRDetail.ItemName : "—",
ReturnedBy = m.ReturnedBy,
QtyReturned = m.QtyReturned,
Condition = m.Condition ?? "Good",
Status = m.Status,
StatusLabel = m.Status == 0 ? "Draft"
: m.Status == 1 ? "Approved"
: "Cancelled"
})
.ToListAsync(ct);
// Total RIS qty issued in the same period (for the comparison panel)
var totalRISQty = await _db.RIS
.Where(r => r.CreatedDate >= request.DateFrom && r.CreatedDate < endDate
&& r.Status != 2)
.SumAsync(r => (int?)r.QtyIssued, ct) ?? 0;
var totalReturned = rows.Where(r => r.Status != 2).Sum(r => r.QtyReturned);
var goodCount = rows.Count(r => r.Condition == "Good");
var summary = new MRSReportSummary
{
TotalMRS = rows.Count,
TotalQtyReturned = totalReturned,
TotalQtyIssuedRIS = totalRISQty,
NetQtyConsumed = totalRISQty - totalReturned,
ReturnRatePct = totalRISQty > 0
? Math.Round(totalReturned * 100m / totalRISQty, 1)
: 0,
GoodConditionPct = rows.Count > 0
? Math.Round(goodCount * 100m / rows.Count, 1)
: 0
};
var byCondition = rows
.Where(r => r.Status != 2)
.GroupBy(r => r.Condition)
.Select(g => new ConditionTotal { Condition = g.Key, TotalQty = g.Sum(r => r.QtyReturned) })
.OrderByDescending(c => c.TotalQty)
.ToList();
return new MRSReportDto
{
ReportNo = $"RPT-MRS-{DateTime.Now:yyyyMM}-{Random.Shared.Next(1, 999):D3}",
DateFrom = request.DateFrom,
DateTo = request.DateTo,
Summary = summary,
Rows = rows,
ByCondition = byCondition
};
}
public async Task<InventoryReportDto> GetInventoryReportAsync(InventoryReportsRequest request, string userName, int? departmentId, CancellationToken ct)
{
var allowedAllDeptUsers = new[] { "LSKRISUR24", "LSCYNDIZ25", "LSJONTAN25", "LHRIOCAS24" };
bool seeAllDepartments = !string.IsNullOrWhiteSpace(userName)
&& allowedAllDeptUsers.Contains(userName, StringComparer.OrdinalIgnoreCase);
var endDate = request.DateTo.Date.AddDays(1);
var dto = new InventoryReportDto
{
ReportNo = $"RPT-INV-{DateTime.Now:yyyyMM}-{Random.Shared.Next(1, 999):D3}",
AsOf = endDate,
Rows = new List<InventoryReportRow>(),
ByCategory = new List<CategoryStockLevel>(),
Alerts = new List<InventoryAlert>(),
Summary = new InventoryReportSummary(),
Departments = new List<string>(),
Page = request.Page,
PageSize = request.PageSize
};
var conn = _db.Database.GetDbConnection();
await using var cmd = conn.CreateCommand();
cmd.CommandText = "dbo.GetInventoryReport";
cmd.CommandType = System.Data.CommandType.StoredProcedure;
cmd.Parameters.Add(new SqlParameter("@DateFrom", (object?)request.DateFrom ?? DBNull.Value));
cmd.Parameters.Add(new SqlParameter("@DateTo", (object?)request.DateTo ?? DBNull.Value));
cmd.Parameters.Add(new SqlParameter("@Department", (object?)request.Department ?? DBNull.Value));
cmd.Parameters.Add(new SqlParameter("@DepartmentId", (object?)departmentId ?? DBNull.Value));
cmd.Parameters.Add(new SqlParameter("@SeeAllDepartments", seeAllDepartments ? 1 : 0));
cmd.Parameters.Add(new SqlParameter("@Page", request.Page));
cmd.Parameters.Add(new SqlParameter("@PageSize", request.PageSize));
cmd.Parameters.Add(new SqlParameter("@Paginate", request.Paginate ? 1 : 0));
bool openedHere = conn.State != System.Data.ConnectionState.Open;
if (openedHere) await conn.OpenAsync(ct);
try
{
await using var reader = await cmd.ExecuteReaderAsync(ct);
// 0: departments
while (await reader.ReadAsync(ct))
dto.Departments.Add(reader.GetString(reader.GetOrdinal("Department")));
// 1: detail rows
if (await reader.NextResultAsync(ct))
{
while (await reader.ReadAsync(ct))
{
dto.Rows.Add(new InventoryReportRow
{
ItemName = reader.GetString(reader.GetOrdinal("ItemName")),
ItemNo = reader.GetInt64(reader.GetOrdinal("ItemNo")),
ItemCategoryName = reader.GetString(reader.GetOrdinal("ItemCategoryName")),
LotNo = reader.IsDBNull(reader.GetOrdinal("LotNo")) ? null : reader.GetString(reader.GetOrdinal("LotNo")),
Department = reader.IsDBNull(reader.GetOrdinal("Department")) ? null : reader.GetString(reader.GetOrdinal("Department")),
CurrencyCode = reader.IsDBNull(reader.GetOrdinal("CurrencyCode")) ? null : reader.GetString(reader.GetOrdinal("CurrencyCode")),
QtyIn = reader.GetDecimal(reader.GetOrdinal("QtyIn")),
QtyOut = reader.GetDecimal(reader.GetOrdinal("QtyOut")),
QtyOnHand = reader.GetDecimal(reader.GetOrdinal("QtyOnHand")),
UnitPrice = reader.GetDecimal(reader.GetOrdinal("UnitPrice")),
StockPct = reader.GetInt32(reader.GetOrdinal("StockPct"))
});
}
}
// 2: summary
if (await reader.NextResultAsync(ct) && await reader.ReadAsync(ct))
{
dto.Summary = new InventoryReportSummary
{
TotalSKUs = reader.GetInt32(reader.GetOrdinal("TotalSKUs")),
TotalOnHand = reader.GetDecimal(reader.GetOrdinal("TotalOnHand")),
TotalQtyIn = reader.GetDecimal(reader.GetOrdinal("TotalQtyIn")),
TotalQtyOut = reader.GetDecimal(reader.GetOrdinal("TotalQtyOut")),
TotalValue = reader.GetDecimal(reader.GetOrdinal("TotalValue")),
LowStockCount = reader.GetInt32(reader.GetOrdinal("LowStockCount")),
OutOfStockCount = reader.GetInt32(reader.GetOrdinal("OutOfStockCount"))
};
}
// 3: by category
if (await reader.NextResultAsync(ct))
while (await reader.ReadAsync(ct))
dto.ByCategory.Add(new CategoryStockLevel
{
CategoryName = reader.GetString(reader.GetOrdinal("CategoryName")),
AvgStockPct = reader.GetInt32(reader.GetOrdinal("AvgStockPct"))
});
// 4: alerts
if (await reader.NextResultAsync(ct))
while (await reader.ReadAsync(ct))
dto.Alerts.Add(new InventoryAlert
{
ItemName = reader.GetString(reader.GetOrdinal("ItemName")),
QtyOnHand = reader.GetDecimal(reader.GetOrdinal("QtyOnHand")),
Severity = reader.GetString(reader.GetOrdinal("Severity"))
});
// 5: total row count
if (await reader.NextResultAsync(ct) && await reader.ReadAsync(ct))
dto.TotalRows = reader.GetInt32(reader.GetOrdinal("TotalRows"));
}
finally
{
if (conn.State == System.Data.ConnectionState.Open)
await conn.CloseAsync();
}
return dto;
}
}
}

View File

@ -0,0 +1,260 @@
using CPRNIMS.Domain.Contracts.Common;
using CPRNIMS.Domain.Contracts.Inventory;
using CPRNIMS.Infrastructure.Database;
using CPRNIMS.Infrastructure.Dto.Inventory;
using CPRNIMS.Infrastructure.Dto.Inventory.Request;
using CPRNIMS.Infrastructure.Entities.Inventory;
using Microsoft.EntityFrameworkCore;
namespace CPRNIMS.Domain.Services.Inventory
{
public class MRS : IMRS
{
private readonly NonInventoryDbContext _db;
private readonly ITransactionFacade _transactionFacade;
public MRS(NonInventoryDbContext db, ITransactionFacade transactionFacade)
{
_db = db;
_transactionFacade = transactionFacade;
}
public async Task ApproveAsync(long mrsId, string approvedBy, CancellationToken ct)
{
//var user = await _userManager.FindByNameAsync(approvedBy);
//if (user != null)
//{
// bool isApprover2 = await _userManager.IsInRoleAsync(user, "APPROVER2");
// if (!isApprover2)
// {
// throw new Exception("You have no permission to approve this item.");
// }
//}
var rms = await _db.MRS.FindAsync(mrsId)
?? throw new InvalidOperationException("MRS not found.");
if (rms.Status != 0)
throw new InvalidOperationException("Only Draft MRS records can be approved.");
rms.Status = 1; // Approved
rms.ApprovedBy = approvedBy;
rms.ApprovedDate = DateTime.Now;
await _db.SaveChangesAsync(ct);
}
public async Task CancelAsync(CancelMRSRequest request,string canceledBy, CancellationToken ct)
{
//var user = await _userManager.FindByNameAsync(canceledBy);
//if (user != null)
//{
// bool isApprover2 = await _userManager.IsInRoleAsync(user, "APPROVER2");
// if (!isApprover2)
// {
// throw new Exception("You have no permission to cancel this item.");
// }
//}
await _transactionFacade.ExecuteAsync(async () =>
{
var mrs = await _db.MRS
.Include(m => m.Inventory)
.FirstOrDefaultAsync(m => m.MRSId == request.MRSId)
?? throw new InvalidOperationException("MRS not found.");
if (mrs.Status == 2)
throw new InvalidOperationException("MRS is already cancelled.");
// Reverse the return: deduct qty back out
mrs.Inventory.QtyOut = Math.Max(0m, mrs.Inventory.QtyOut) + mrs.QtyReturned;
mrs.Inventory.QtyOnHand = mrs.Inventory.QtyIn - mrs.Inventory.QtyOut;
mrs.Reason = request.Reason;
mrs.Status = 2;
mrs.CanceledDate = DateTime.Now;
mrs.CanceledBy = canceledBy;
}, ct);
}
public async Task<Infrastructure.Entities.Inventory.MRS> CreateAsync(CreateMRSRequest dto, string createdBy, CancellationToken ct)
{
return await _transactionFacade.ExecuteAsync(async () =>
{
var ris = await _db.RIS
.Include(r => r.Inventory)
.FirstOrDefaultAsync(r => r.RISId == dto.RISId, ct)
?? throw new InvalidOperationException("Referenced RIS not found.");
if (dto.QtyReturned > ris.QtyIssued)
throw new InvalidOperationException(
$"Cannot return more than issued. Issued: {ris.QtyIssued}.");
var mrsNo = await GenerateMRSNoAsync();
var mrs = new Infrastructure.Entities.Inventory.MRS
{
MRSNo = mrsNo,
RISId = dto.RISId,
InventoryId = ris.InventoryId,
ReturnedBy = dto.ReturnedBy,
QtyReturned = dto.QtyReturned,
Condition = dto.Condition,
Remarks = dto.Remarks,
Status = 1,//Matic Approve for now
CreatedBy = createdBy,
CreatedDate = DateTime.Now
};
_db.MRS.Add(mrs);
var inventory = ris.Inventory;
inventory.QtyOut = Math.Max(0m, inventory.QtyOut - dto.QtyReturned);
inventory.QtyOnHand = inventory.QtyIn - inventory.QtyOut;
var trans = await _db.InventTrans
.FirstOrDefaultAsync(t => t.InventoryId == ris.InventoryId && t.IsActive == true, ct)!;
_db.InventTransDetails.Add(new InventTransDetail
{
InventTransId = trans.InventTransId,
TransTypeId = 6,
QtyIn = dto.QtyReturned,
CreatedDate = DateTime.Now,
Remarks = $"MRS: {mrsNo} — return from MRS: {ris.RISNo}",
IsActive = true
});
return mrs;
}, ct);
}
public async Task<Infrastructure.Entities.Inventory.MRS?> GetByIdAsync(long mrsId, CancellationToken ct)
=> await _db.MRS
.Include(r => r.Inventory)
.Include(r => r.RIS)
.FirstOrDefaultAsync(r => r.RISId == mrsId, ct);
public async Task<MRSPagedResult> GetPagedAsync(MRSFilterDto filter, CancellationToken ct,
int? departmentId = null, string? userName = "")
{
var allowedAllDeptUsers = new[] { "LSKRISUR24", "LSCYNDIZ25", "LSJONTAN25", "LHRIOCAS24" };
bool seeAllDepartments = !string.IsNullOrWhiteSpace(userName)
&& allowedAllDeptUsers.Contains(userName, StringComparer.OrdinalIgnoreCase);
var q = _db.MRS
.Include(m => m.RIS)
.Include(m => m.Inventory)
.AsQueryable();
if (departmentId.HasValue && !seeAllDepartments)
{
q = q.Where(itd =>
itd.Inventory.User.DepartmentId == departmentId.Value);
}
if (!string.IsNullOrWhiteSpace(filter.SearchMRSNo))
q = q.Where(m => m.MRSNo.Contains(filter.SearchMRSNo));
if (filter.RISId.HasValue)
q = q.Where(m => m.RISId == filter.RISId.Value);
if (filter.Status.HasValue)
q = q.Where(m => m.Status == filter.Status.Value);
if (filter.DateFrom.HasValue)
q = q.Where(m => m.CreatedDate >= filter.DateFrom.Value);
if (filter.DateTo.HasValue)
q = q.Where(m => m.CreatedDate <= filter.DateTo.Value.AddDays(1));
var total = await q.CountAsync(ct);
var data = await q
.OrderByDescending(m => m.CreatedDate)
.Skip((filter.PageNumber - 1) * filter.PageSize)
.Take(filter.PageSize)
.Select(m => new MRSPagedDto
{
MRSId = m.MRSId,
MRSNo = m.MRSNo,
RISId = m.RISId,
RISNo = m.RIS.RISNo,
InventoryId = m.InventoryId,
ItemName = m.Inventory.InventTrans
.SelectMany(t => t.InventTransDetails)
.Select(d => d.PRDetails != null ? d.PRDetails.ItemName : "—")
.FirstOrDefault() ?? "—",
ReturnedBy = m.ReturnedBy,
QtyReturned = m.QtyReturned,
Condition = m.Condition,
Remarks = m.Remarks,
Status = m.Status,
CreatedBy = m.CreatedBy,
CreatedDate = m.CreatedDate,
ApprovedBy = m.ApprovedBy,
ApprovedDate = m.ApprovedDate
})
.ToListAsync(ct);
return new MRSPagedResult { Data = data, RecordsTotal = total };
}
private async Task<string> GenerateMRSNoAsync()
{
var year = DateTime.Now.Year;
var month = DateTime.Now.Month.ToString("D2");
var count = await _db.MRS.CountAsync(m => m.CreatedDate.Year == year) + 1;
return $"MRS-{year}{month}-{count:D4}";
}
public async Task<IReadOnlyList<RISSearchResultDto>> SearchRISForReturnAsync(string? risNoQuery, int? projectCodeId, CancellationToken ct)
{
var query = _db.RIS
.Where(r => r.Status == 1);
if (projectCodeId.HasValue)
query = query.Where(r => r.ProjectCodeId == projectCodeId.Value);
if (!string.IsNullOrWhiteSpace(risNoQuery))
query = query.Where(r => r.RISNo.Contains(risNoQuery));
return await query
.Select(r => new RISSearchResultDto
{
RISId = r.RISId,
RISNo = r.RISNo,
ProjectCodeId = r.ProjectCodeId,
ProjectCode = r.ProjectCodes.ProjectCode ?? "N/A",
ProjectName = r.ProjectCodes.ProjectName ?? "N/A",
DisciplineName = r.Discipline.DisciplineName,
QtyAvailableToReturn = r.QtyIssued - r.MaterialReturns.Sum(m => m.QtyReturned)
})
.Where(r => r.QtyAvailableToReturn > 0)
.OrderByDescending(r => r.RISId)
.Take(20)
.ToListAsync(ct);
}
public async Task<IReadOnlyList<ProjectCodeOptionDto>> GetProjectsWithOpenRISAsync(string? nameQuery, CancellationToken ct)
{
var query = _db.RIS
.Where(r => r.Status == 1 && r.QtyIssued > r.MaterialReturns.Sum(m => m.QtyReturned));
if (!string.IsNullOrWhiteSpace(nameQuery))
query = query.Where(r =>
r.ProjectCodes.ProjectName.Contains(nameQuery) ||
r.ProjectCodes.ProjectCode.Contains(nameQuery));
return await query
.Select(r => new ProjectCodeOptionDto
{
ProjectCodeId = r.ProjectCodeId,
ProjectCode = r.ProjectCodes.ProjectCode ?? "N/A",
ProjectName = r.ProjectCodes.ProjectName ?? "N/A"
})
.Distinct()
.OrderBy(p => p.ProjectName)
.Take(20)
.ToListAsync(ct);
}
}
}

View File

@ -0,0 +1,331 @@
using CPRNIMS.Domain.Contracts.Common;
using CPRNIMS.Domain.Contracts.Inventory;
using CPRNIMS.Infrastructure.Database;
using CPRNIMS.Infrastructure.Dto.Inventory;
using CPRNIMS.Infrastructure.Dto.Inventory.Request;
using CPRNIMS.Infrastructure.Dto.Inventory.Response;
using CPRNIMS.Infrastructure.Entities.Inventory;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CPRNIMS.Domain.Services.Inventory
{
public class RIS : IRIS
{
private readonly NonInventoryDbContext _db;
private readonly ITransactionFacade _transactionFacade;
public RIS(NonInventoryDbContext db, ITransactionFacade transactionFacade)
{
_db = db;
_transactionFacade = transactionFacade;
}
public async Task<Infrastructure.Entities.Inventory.RIS> CreateAsync(CreateRISRequest dto, string createdBy, CancellationToken ct)
{
return await _transactionFacade.ExecuteAsync(async () =>
{
var inventory = await _db.Inventories
.FirstOrDefaultAsync(i => i.InventoryId == dto.InventoryId, ct)
?? throw new InvalidOperationException("Inventory record not found.");
if (inventory.QtyOnHand < dto.QtyIssued)
throw new InvalidOperationException(
$"Insufficient stock. On hand: {inventory.QtyOnHand}, requested: {dto.QtyIssued}.");
var risNo = await GenerateRISNoAsync(ct);
var ris = new Infrastructure.Entities.Inventory.RIS
{
RISNo = risNo,
InventoryId = dto.InventoryId,
PRDetailId = dto.PRDetailId,
ProjectCodeId = dto.ProjectCodeId,
DisciplineId = dto.DisciplineId,
QtyIssued = dto.QtyIssued,
Remarks = dto.Remarks,
Status = 1,//Approved alredy 0 is Draft
CreatedBy = createdBy,
CreatedDate = DateTime.Now
};
_db.RIS.Add(ris);
var trans = await _db.InventTrans
.Where(t => t.InventoryId == dto.InventoryId && t.IsActive == true)
.FirstOrDefaultAsync(ct)
?? throw new InvalidOperationException(
"No active InventTrans found for this inventory record.");
_db.InventTransDetails.Add(new InventTransDetail
{
InventTransId = trans.InventTransId,
TransTypeId = 5,
PRDetailId = dto.PRDetailId,
QtyOut = dto.QtyIssued,
CreatedDate = DateTime.Now,
Remarks = $"RIS: {risNo}",
IsActive = true
});
inventory.QtyOut = Math.Max(0m, inventory.QtyOut) + dto.QtyIssued;
inventory.QtyOnHand = Math.Max(0m, inventory.QtyIn) - (decimal)inventory.QtyOut;
return ris;
}, ct);
}
public async Task ApproveAsync(ApproveRISRequest request, string approvedBy, CancellationToken ct)
{
//var user = await _userManager.FindByNameAsync(approvedBy);
//if (user != null)
//{
// bool isApprover2 = await _userManager.IsInRoleAsync(user, "APPROVER2");
// if (!isApprover2)
// {
// throw new Exception("You have no permission to approved this item.");
// }
//}
var ris = await _db.RIS.FindAsync(request.RISId, ct)
?? throw new InvalidOperationException("RIS not found.");
if (ris.Status != 0)
throw new InvalidOperationException("Only Draft RIS records can be approved.");
ris.Status = 1; // Approved
ris.ApprovedBy = approvedBy;
ris.ApprovedDate = DateTime.Now;
await _db.SaveChangesAsync(ct);
}
public async Task CancelAsync(CancelRISRequest request,string canceledBy, CancellationToken ct)
{
//var user = await _userManager.FindByNameAsync(canceledBy);
//if (user != null)
//{
// bool isApprover2 = await _userManager.IsInRoleAsync(user, "APPROVER2");
// if (!isApprover2)
// {
// throw new Exception("You have no permission to cancel this item.");
// }
//}
await _transactionFacade.ExecuteAsync(async () =>
{
var ris = await _db.RIS
.Include(r => r.Inventory)
.FirstOrDefaultAsync(r => r.RISId == request.RISId, ct)
?? throw new InvalidOperationException("RIS not found.");
if (ris.Status == 2)
throw new InvalidOperationException("RIS is already cancelled.");
//Check if already approved the related RIS No to MRS must cannot be cancel
var mrs = await _db.MRS.FirstOrDefaultAsync(m => m.RISId == request.RISId, ct);
if (mrs != null)
{
if (mrs.Status == 1)
{
throw new InvalidOperationException(
$"MRS #{mrs.MRSNo} has already been approved in relation to RIS #{ris.RISNo}.");
}
mrs.Status = 2;
mrs.CanceledDate = DateTime.Now;
mrs.CanceledBy = canceledBy;
mrs.Reason = "Canceled in RIS already";
}
ris.Inventory.QtyOut = Math.Max(0m, ris.Inventory.QtyOut - ris.QtyIssued);
ris.Inventory.QtyOnHand = ris.Inventory.QtyIn - ris.Inventory.QtyOut;
ris.Reason = request.Reason;
ris.Status = 2; // Cancelled
var trans = await _db.InventTrans
.Where(t => t.InventoryId == ris.InventoryId && t.IsActive == true)
.FirstOrDefaultAsync(ct)
?? throw new InvalidOperationException(
"No active InventTrans found for this inventory record.");
_db.InventTransDetails.Add(new InventTransDetail
{
InventTransId = trans.InventTransId,
TransTypeId = 5,
PRDetailId = ris.PRDetailId,
QtyIn = ris.QtyIssued,//Return the issued Qty
CreatedDate = DateTime.Now,
Remarks = request.Reason,
IsActive = true
});
}, ct);
}
private async Task<string> GenerateRISNoAsync(CancellationToken ct)
{
var year = DateTime.Now.Year;
var month = DateTime.Now.Month.ToString("D2");
var count = await _db.RIS
.CountAsync(r => r.CreatedDate.Year == year,ct) + 1;
return $"RIS-{year}{month}-{count:D4}"; // e.g. RIS-202606-0001
}
public async Task<RISPagedResult> GetPagedAsync(RISFilterDto filter, CancellationToken ct,
int? departmentId = null, string? userName = "")
{
var allowedAllDeptUsers = new[] { "LSKRISUR24", "LSCYNDIZ25", "LSJONTAN25", "LHRIOCAS24" };
bool seeAllDepartments = !string.IsNullOrWhiteSpace(userName)
&& allowedAllDeptUsers.Contains(userName, StringComparer.OrdinalIgnoreCase);
var q = _db.RIS
.Include(r => r.Discipline)
.Include(r => r.Inventory)
.Include(r => r.MaterialReturns)
.AsQueryable();
if (departmentId.HasValue && !seeAllDepartments)
{
q = q.Where(itd =>
itd.Inventory.User.DepartmentId == departmentId.Value);
}
// Status filter (default to Draft=0 if null)
if (filter.Status.HasValue)
q = q.Where(r => r.Status == filter.Status.Value);
//else
// q = q.Where(r => r.Status == 0);
// RIS No
if (!string.IsNullOrWhiteSpace(filter.SearchRISNo))
q = q.Where(r => r.RISNo.Contains(filter.SearchRISNo));
// Item Name
if (!string.IsNullOrWhiteSpace(filter.SearchItemName))
q = q.Where(r => r.Inventory.InventTrans
.SelectMany(t => t.InventTransDetails)
.Any(d => d.PRDetails != null &&
d.PRDetails.ItemName.Contains(filter.SearchItemName)));
// Issued To is Project code/name
if (!string.IsNullOrWhiteSpace(filter.SearchIssuedTo))
q = q.Where(r => r.ProjectCodes.ProjectCode.Contains(filter.SearchIssuedTo)
|| r.ProjectCodes.ProjectName.Contains(filter.SearchIssuedTo));
// Discipline
if (!string.IsNullOrWhiteSpace(filter.Discipline))
q = q.Where(r => r.Discipline.DisciplineName == filter.Discipline);
// Date range (if you ever add date filters)
if (filter.DateFrom.HasValue)
q = q.Where(r => r.CreatedDate >= filter.DateFrom.Value);
if (filter.DateTo.HasValue)
q = q.Where(r => r.CreatedDate <= filter.DateTo.Value.AddDays(1));
var total = await q.CountAsync(ct);
var data = await q
.OrderByDescending(r => r.CreatedDate)
.Skip((filter.PageNumber - 1) * filter.PageSize)
.Take(filter.PageSize)
.Select(r => new RISResponse
{
RISId = r.RISId,
RISNo = r.RISNo,
InventoryId = r.InventoryId,
ItemName = r.Inventory.InventTrans
.SelectMany(t => t.InventTransDetails)
.Select(d => d.PRDetails != null ? d.PRDetails.ItemName : "—")
.FirstOrDefault() ?? "—",
ItemNo = r.Inventory.ItemNo,
LotNo = r.Inventory.Lot != null ? r.Inventory.Lot.LotName : null,
ProjectName = r.ProjectCodes.ProjectName,
ProjectCode = r.ProjectCodes.ProjectCode,
DisciplineName = r.Discipline.DisciplineName,
DisciplineId = r.DisciplineId,
QtyIssued = r.QtyIssued,
Remarks = r.Remarks,
Status = r.Status,
CreatedBy = r.CreatedBy,
CreatedDate = r.CreatedDate,
ApprovedBy = r.ApprovedBy,
ApprovedDate = r.ApprovedDate,
MRSCount = r.MaterialReturns.Count(m => m.Status != 2),
TotalReturned = r.MaterialReturns
.Where(m => m.Status != 2)
.Sum(m => m.QtyReturned)
})
.ToListAsync(ct);
// Full department list (never filtered)
var departments = await _db.Departments
.Select(d => d.Department)
.OrderBy(d => d)
.ToListAsync(ct);
var disciplines = await GetDisciplinesAsync(ct);
return new RISPagedResult
{
Data = data,
RecordsTotal = total,
DepartmentList = departments,
DisciplineList = disciplines
};
}
public async Task<IReadOnlyList<DisciplineDto>> GetDisciplinesAsync(CancellationToken ct)
{
return await _db.Disciplines
.OrderBy(d => d.DisciplineName)
.Select(d => new DisciplineDto
{
DisciplineId = d.DisciplineId,
DisciplineName = d.DisciplineName
})
.ToListAsync(ct);
}
public async Task<IReadOnlyList<ProjectCodeDto>> GetProjectCodesAsync(CancellationToken ct)
{
return await _db.ProjectCodes
.Where(p=>p.StatusName !="Completed")
.OrderBy(d => d.ProjectName)
.Select(d => new ProjectCodeDto
{
ProjectCodeId= d.ProjectCodeId,
ProjectCode = d.ProjectCode ?? "N/A",
ProjectName = d.ProjectName ?? "N/A"
})
.ToListAsync(ct);
}
public async Task<RISResponse?> GetByIdAsync(long risId, CancellationToken ct)
{
return await _db.RIS
.Where(r => r.RISId == risId)
.Select(r => new RISResponse
{
RISId = r.RISId,
RISNo = r.RISNo,
InventoryId = r.InventoryId,
ProjectCodeId = r.ProjectCodeId,
DisciplineName = r.Discipline.DisciplineName,
DisciplineId = r.DisciplineId,
QtyIssued = r.QtyIssued,
Remarks = r.Remarks,
Status = r.Status,
CreatedBy = r.CreatedBy,
CreatedDate = r.CreatedDate,
ApprovedBy = r.ApprovedBy,
ApprovedDate = r.ApprovedDate,
MRSCount = r.MaterialReturns.Count(m => m.Status != 2),
TotalReturned = r.MaterialReturns
.Where(m => m.Status != 2)
.Sum(m => m.QtyReturned)
})
.FirstOrDefaultAsync(ct);
}
}
}

View File

@ -1,16 +1,12 @@
using CPRNIMS.Domain.Contracts.Account;
using CPRNIMS.Domain.Contracts.Items;
using CPRNIMS.Domain.Contracts.Items;
using CPRNIMS.Infrastructure.Database;
using CPRNIMS.Infrastructure.Dto.Canvass;
using CPRNIMS.Infrastructure.Dto.Items;
using CPRNIMS.Infrastructure.Entities.Account;
using CPRNIMS.Infrastructure.Entities.Canvass;
using CPRNIMS.Infrastructure.Entities.Items;
using CPRNIMS.Infrastructure.Entities.Purchasing;
using CPRNIMS.Infrastructure.Models.Common;
using Microsoft.Data.SqlClient;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
@ -26,384 +22,355 @@ namespace CPRNIMS.Domain.Services.Items
}
public async Task<ItemCodeDto> PostPutItem(ItemCodeDto itemDto)
{
try
var messCodeParam = new SqlParameter("@MessCode", SqlDbType.TinyInt)
{
var messCodeParam = new SqlParameter("@MessCode", SqlDbType.TinyInt)
{
Direction = ParameterDirection.Output
};
var messageParam = new SqlParameter("@Message", SqlDbType.VarChar, 500)
{
Direction = ParameterDirection.Output
};
var itemCodeParam = new SqlParameter("@ItemCode", SqlDbType.BigInt)
{
Direction = ParameterDirection.Output
};
await _dbContext.Database.ExecuteSqlRawAsync(
"EXEC PostPutItem @ItemCodeId, @ItemName, @ItemDescription, @ItemCategoryId, @Status, @UserId, " +
"@ItemCode OUTPUT, @MessCode OUTPUT, @Message OUTPUT",
new SqlParameter("@ItemCodeId", itemDto.ItemCodeId != null ? itemDto.ItemCodeId : 0L),
new SqlParameter("@ItemName", itemDto.ItemName ?? (object)DBNull.Value),
new SqlParameter("@ItemDescription", itemDto.ItemDescription ?? (object)DBNull.Value),
new SqlParameter("@ItemCategoryId", itemDto.ItemCategoryId),
new SqlParameter("@Status", itemDto.Status != null ? itemDto.Status : 4),
new SqlParameter("@UserId", itemDto.UserId ?? (object)DBNull.Value),
itemCodeParam,
messCodeParam,
messageParam
);
var messCode = (byte)messCodeParam.Value;
var message = messageParam.Value?.ToString();
var itemCode = itemCodeParam.Value != DBNull.Value ? (long?)itemCodeParam.Value : null;
return new ItemCodeDto
{
ItemCodeId = Convert.ToInt64(itemCode),
ItemName = itemDto.ItemName,
ItemDescription = itemDto.ItemDescription,
ItemCategoryId = itemDto.ItemCategoryId,
Status = itemDto.Status,
UserId = itemDto.UserId
};
}
catch (Exception ex)
Direction = ParameterDirection.Output
};
var messageParam = new SqlParameter("@Message", SqlDbType.VarChar, 500)
{
// You could log ex.Message or rethrow with a custom message
throw new Exception("An error occurred while executing PostPutItem.", ex);
}
Direction = ParameterDirection.Output
};
var itemCodeParam = new SqlParameter("@ItemCode", SqlDbType.BigInt)
{
Direction = ParameterDirection.Output
};
await _dbContext.Database.ExecuteSqlRawAsync(
"EXEC PostPutItem @ItemCodeId, @ItemName, @ItemDescription, @ItemCategoryId, @Status, @UserId, " +
"@ItemCode OUTPUT, @MessCode OUTPUT, @Message OUTPUT",
new SqlParameter("@ItemCodeId", itemDto.ItemCodeId != null ? itemDto.ItemCodeId : 0L),
new SqlParameter("@ItemName", itemDto.ItemName ?? (object)DBNull.Value),
new SqlParameter("@ItemDescription", itemDto.ItemDescription ?? (object)DBNull.Value),
new SqlParameter("@ItemCategoryId", itemDto.ItemCategoryId),
new SqlParameter("@Status", itemDto.Status != null ? itemDto.Status : 4),
new SqlParameter("@UserId", itemDto.UserId ?? (object)DBNull.Value),
itemCodeParam,
messCodeParam,
messageParam
);
var messCode = (byte)messCodeParam.Value;
var message = messageParam.Value?.ToString();
var itemCode = itemCodeParam.Value != DBNull.Value ? (long?)itemCodeParam.Value : null;
return new ItemCodeDto
{
ItemCodeId = Convert.ToInt64(itemCode),
ItemName = itemDto.ItemName,
ItemDescription = itemDto.ItemDescription,
ItemCategoryId = itemDto.ItemCategoryId,
Status = itemDto.Status,
UserId = itemDto.UserId
};
}
public async Task<Infrastructure.Entities.Items.Item> PutItemDetail(ItemDto itemDto)
{
try
{
await _dbContext.Database
.ExecuteSqlRawAsync($"EXEC PutItemDetail @ItemCodeId,@ItemLocalId,@ItemTypeId,@UOMId,@ItemColorId,@IsActive," +
$"@UserId,@ItemNo,@PRTypeId,@PackagingTypeId,@Qty,@ItemAttachId,@ItemAttachPath,@IsCommon,@ItemCategoryId," +
$"@RequestTypeId,@ItemName,@ItemDescription,@IsMDLD",
new SqlParameter("@ItemCodeId", itemDto.ItemCodeId != null ? itemDto.ItemCodeId : 0L),
new SqlParameter("@ItemLocalId", itemDto.ItemLocalId),
new SqlParameter("@ItemTypeId", itemDto.ItemTypeId),
new SqlParameter("@UOMId", itemDto.UOMId),
new SqlParameter("@ItemColorId", itemDto.ItemColorId),
new SqlParameter("@IsActive", itemDto.IsActive),
new SqlParameter("@UserId", itemDto.UserId),
new SqlParameter("@ItemNo", itemDto.ItemNo),
new SqlParameter("@PRTypeId", itemDto.PRTypeId),
new SqlParameter("@PackagingTypeId", itemDto.PackagingTypeId),
new SqlParameter("@Qty", itemDto.Qty),
new SqlParameter("@ItemAttachId", itemDto.ItemAttachId != null ? itemDto.ItemAttachId : 0L),
new SqlParameter("@ItemAttachPath", itemDto.ItemAttachPath ?? "N/A"),
new SqlParameter("@IsCommon", itemDto.IsCommon),
new SqlParameter("@ItemCategoryId", itemDto.ItemCategoryId),
new SqlParameter("@RequestTypeId", itemDto.RequestTypeId),
new SqlParameter("@ItemName", itemDto.ItemName),
new SqlParameter("@ItemDescription", itemDto.ItemDescription),
new SqlParameter("@IsMDLD", itemDto.IsMDLD));
await _dbContext.Database
.ExecuteSqlRawAsync($"EXEC PutItemDetail @ItemCodeId,@ItemLocalId,@ItemTypeId,@UOMId,@ItemColorId,@IsActive," +
$"@UserId,@ItemNo,@PRTypeId,@PackagingTypeId,@Qty,@ItemAttachId,@ItemAttachPath,@IsCommon,@ItemCategoryId," +
$"@RequestTypeId,@ItemName,@ItemDescription,@IsMDLD",
new SqlParameter("@ItemCodeId", itemDto.ItemCodeId != null ? itemDto.ItemCodeId : 0L),
new SqlParameter("@ItemLocalId", itemDto.ItemLocalId),
new SqlParameter("@ItemTypeId", itemDto.ItemTypeId),
new SqlParameter("@UOMId", itemDto.UOMId),
new SqlParameter("@ItemColorId", itemDto.ItemColorId),
new SqlParameter("@IsActive", itemDto.IsActive),
new SqlParameter("@UserId", itemDto.UserId),
new SqlParameter("@ItemNo", itemDto.ItemNo),
new SqlParameter("@PRTypeId", itemDto.PRTypeId),
new SqlParameter("@PackagingTypeId", itemDto.PackagingTypeId),
new SqlParameter("@Qty", itemDto.Qty),
new SqlParameter("@ItemAttachId", itemDto.ItemAttachId != null ? itemDto.ItemAttachId : 0L),
new SqlParameter("@ItemAttachPath", itemDto.ItemAttachPath ?? "N/A"),
new SqlParameter("@IsCommon", itemDto.IsCommon),
new SqlParameter("@ItemCategoryId", itemDto.ItemCategoryId),
new SqlParameter("@RequestTypeId", itemDto.RequestTypeId),
new SqlParameter("@ItemName", itemDto.ItemName),
new SqlParameter("@ItemDescription", itemDto.ItemDescription),
new SqlParameter("@IsMDLD", itemDto.IsMDLD));
return new Infrastructure.Entities.Items.Item();
}
catch (Exception ex)
{
ex.ToString();
throw;
}
return new Infrastructure.Entities.Items.Item();
}
public async Task<List<ItemLocalization>> GetItemLocalization(ItemDto itemDto)
{
try
{
var localizations = await _dbContext.ItemLocalizations
.Where(ic => ic.IsActive == true &&
EF.Functions.Like(ic.ItemLocalName, $"%{itemDto.ItemLocalName}%"))
.Take(15)
.ToListAsync();
return localizations ?? new List<ItemLocalization>();
}
catch (SqlException ex)
{
ex.ToString();
throw;
}
}
public async Task<List<ItemCategory>> GetItemCateg(ItemDto itemDto)
{
try
{
if(itemDto.ItemCategoryId ==0 || itemDto.ItemCategoryId == null)
{
var categories = await _dbContext.ItemCategories
.Where(ic => ic.IsActive == true)
.ToListAsync();
return categories ?? new List<ItemCategory>();
}
else
{
var categories = await _dbContext.ItemCategories
.Where(ic => ic.IsActive == true && ic.ItemCategoryId == itemDto.ItemCategoryId)
.ToListAsync();
return categories ?? new List<ItemCategory>();
}
}
catch (SqlException ex)
{
ex.ToString();
throw;
}
}
public async Task<List<Infrastructure.Entities.Items.Item>> GetItemDetail(ItemDto itemDto)
{
try
{
var allItems = await _dbContext.Items
.FromSqlRaw($"EXEC GetItemDetail @ItemCodeId,@UserId",
new SqlParameter("@ItemCodeId", itemDto.ItemCodeId),
new SqlParameter("@UserId", itemDto.UserId))
.ToListAsync();
return allItems ?? new List<Infrastructure.Entities.Items.Item>();
}
catch (SqlException ex)
{
ex.ToString();
throw;
}
}
public async Task<List<ItemList>> GetItemList(ItemCodeDto itemCode)
{
try
{
var allItems = await _dbContext.ItemList
.FromSqlRaw($"EXEC GetItemList @UserId = '{itemCode.UserId}'")
.ToListAsync();
return allItems ?? new List<ItemList>();
}
catch (SqlException ex)
{
ex.ToString();
throw;
}
}
public async Task<List<ItemColor>> GetItemColor(ItemDto itemDto)
{
try
{
var colors = await _dbContext.ItemColors
.Where(ic => EF.Functions.Like(ic.ItemColorName, $"%{itemDto.ItemColorName}%"))
.Take(5)
.ToListAsync();
return colors ?? new List<ItemColor>();
}
catch (SqlException ex)
{
ex.ToString();
throw;
}
}
public async Task<List<UnitOfMessure>> GetItemUOM(ItemDto itemDto)
{
try
{
var uoms = await _dbContext.UnitOfMessures
.Where(ic => ic.IsActive == true &&
EF.Functions.Like(ic.UOMName, $"%{itemDto.UOMName}%"))
.Take(150)
.ToListAsync();
return uoms ?? new List<UnitOfMessure>();
}
catch (SqlException ex)
{
ex.ToString();
throw;
}
}
public async Task<ItemAttachement> PostPutItemPath(ItemDto itemDto)
{
try
{
var isExist = await _dbContext.ItemAttachements
var isExist = await _dbContext.ItemAttachements
.FirstOrDefaultAsync(ia => ia.IsActive == true
&& ia.ItemNo == itemDto.ItemNo);
if(isExist != null)
{
isExist.ItemAttachPath = itemDto.ItemAttachPath;
await _dbContext.SaveChangesAsync();
return new ItemAttachement();
}
else
{
return new ItemAttachement();
}
}
catch (SqlException ex)
if (isExist != null)
{
ex.ToString();
throw;
isExist.ItemAttachPath = itemDto.ItemAttachPath;
await _dbContext.SaveChangesAsync();
return new ItemAttachement();
}
else
{
return new ItemAttachement();
}
}
public async Task<ItemCart> PostPutItemCart(ItemDto itemDto)
{
try
await _dbContext.Database
.ExecuteSqlRawAsync("EXEC PostPutItemCart @ItemCartId,@ItemNo,@UserId,@UOMId,@ItemColorId,@ItemCategoryId,@PackagingTypeId,@ItemAttachId,@ItemLocalId",
new SqlParameter("@ItemCartId", itemDto.ItemCartId != null ? itemDto.ItemCartId : 0L),
new SqlParameter("@ItemNo", itemDto.ItemNo != null ? itemDto.ItemNo : 0L),
new SqlParameter("@UOMId", itemDto.UOMId),
new SqlParameter("@ItemColorId", itemDto.ItemColorId),
new SqlParameter("@ItemCategoryId", itemDto.ItemCategoryId),
new SqlParameter("@PackagingTypeId", itemDto.PackagingTypeId),
new SqlParameter("@ItemAttachId", itemDto.ItemAttachId),
new SqlParameter("@UserId", itemDto.UserId),
new SqlParameter("@ItemLocalId", itemDto.ItemLocalId));
return new ItemCart();
}
public async Task<ResponseObject> PostPurchRequest(ItemDto itemDto)
{
var (messCode, message) = OutputParamMessage.CreateOutputParams();
if (itemDto.RequestTypeId == 1)//Internal
{
itemDto.Status = 2;
itemDto.IsApproved = 2;
await _dbContext.Database
.ExecuteSqlRawAsync("EXEC PostPutReqItems @UserId, @RequestItemId, @ItemNo, @QtyRequest,@Status,@IsApproved,@QtyReceived,@LotId," +
"@MessCode OUTPUT, @Message OUTPUT",
new SqlParameter("@UserId", itemDto.UserId),
new SqlParameter("@ItemNo", itemDto.ItemNo),
new SqlParameter("@RequestItemId", itemDto.RequestItemId != null ? itemDto.RequestItemId : 0L),
new SqlParameter("@QtyRequest", itemDto.Qty),
new SqlParameter("@Status", itemDto.Status),
new SqlParameter("@IsApproved", itemDto.IsApproved),
new SqlParameter("@QtyReceived", itemDto.QtyReceived),
new SqlParameter("@LotId", itemDto.LotId),
messCode,message);
}
else
{
await _dbContext.Database
.ExecuteSqlRawAsync("EXEC PostPutItemCart @ItemCartId,@ItemNo,@UserId,@UOMId,@ItemColorId,@ItemCategoryId,@PackagingTypeId,@ItemAttachId,@ItemLocalId",
new SqlParameter("@ItemCartId", itemDto.ItemCartId != null ? itemDto.ItemCartId : 0L),
new SqlParameter("@ItemNo", itemDto.ItemNo != null ? itemDto.ItemNo : 0L),
new SqlParameter("@UOMId", itemDto.UOMId),
new SqlParameter("@ItemColorId", itemDto.ItemColorId),
new SqlParameter("@ItemCategoryId", itemDto.ItemCategoryId),
new SqlParameter("@PackagingTypeId", itemDto.PackagingTypeId),
new SqlParameter("@ItemAttachId", itemDto.ItemAttachId),
new SqlParameter("@UserId", itemDto.UserId),
new SqlParameter("@ItemLocalId", itemDto.ItemLocalId));
return new ItemCart();
}
catch (SqlException ex)
{
ex.ToString();
throw;
.ExecuteSqlRawAsync("EXEC PostPurchRequest @ItemCartId, @IsActive, @UserId,@ItemCount," +
"@PRNo,@DateNeeded,@Qty,@ChargeTo,@Remarks,@ProjectCodeId,@MessCode OUTPUT, @Message OUTPUT",
new SqlParameter("@ItemCartId", itemDto.ItemCartId != null ? itemDto.ItemCartId : 0L),
new SqlParameter("@IsActive", 1),
new SqlParameter("@UserId", itemDto.UserId),
new SqlParameter("@ItemCount", itemDto.ItemCount),
new SqlParameter("@PRNo", itemDto.PRNo),
new SqlParameter("@DateNeeded", itemDto.DateNeeded),
new SqlParameter("@Qty", itemDto.Qty),
new SqlParameter("@ChargeTo", itemDto.ChargeTo),
new SqlParameter("@Remarks", itemDto.Remarks ?? "N/A"),
new SqlParameter("@ProjectCodeId", itemDto.ProjectCodeId),
messCode, message);
}
return new ResponseObject() {
messCode= (byte)messCode.Value,
message= message.Value.ToString()
};
}
public async Task<List<ItemCart>> GetItemCart(ItemDto itemDto)
public async Task PostPutAttachment(AttachmentRequest attach)
{
try
var existing = await _dbContext.PRAttachments
.FirstOrDefaultAsync(a => a.PRId == attach.PRId);
if (existing == null)
{
var allItems = await _dbContext.ItemCarts
.FromSqlRaw($"EXEC GetItemCart @UserId,@RequestTypeId,@IsCount",
new SqlParameter("@UserId", itemDto.UserId),
new SqlParameter("@RequestTypeId", itemDto.RequestTypeId),
new SqlParameter("@IsCount", itemDto.IsCount))
.ToListAsync();
return allItems ?? new List<ItemCart>();
}
catch (SqlException ex)
{
ex.ToString();
throw;
}
}
public async Task<ItemCart> PostPurchRequest(ItemDto itemDto)
{
try
{
if(itemDto.RequestTypeId == 1)//Internal
var attchmnt = new PRAttachments()
{
itemDto.Status = 2;
itemDto.IsApproved = 2;
await _dbContext.Database
.ExecuteSqlRawAsync("EXEC PostPutReqItems @UserId, @RequestItemId, @ItemNo, @QtyRequest,@Status,@IsApproved,@QtyReceived,@LotId",
new SqlParameter("@UserId", itemDto.UserId),
new SqlParameter("@ItemNo", itemDto.ItemNo),
new SqlParameter("@RequestItemId", itemDto.RequestItemId != null ? itemDto.RequestItemId : 0L),
new SqlParameter("@QtyRequest", itemDto.Qty),
new SqlParameter("@Status", itemDto.Status),
new SqlParameter("@IsApproved", itemDto.IsApproved),
new SqlParameter("@QtyReceived", itemDto.QtyReceived),
new SqlParameter("@LotId", itemDto.LotId));
}
else
{
await _dbContext.Database
.ExecuteSqlRawAsync("EXEC PostPurchRequest @ItemCartId, @IsActive, @UserId,@ItemCount,@PRNo,@DateNeeded,@Qty,@ChargeTo,@Remarks",
new SqlParameter("@ItemCartId", itemDto.ItemCartId != null ? itemDto.ItemCartId : 0L),
new SqlParameter("@IsActive", 1),
new SqlParameter("@UserId", itemDto.UserId),
new SqlParameter("@ItemCount", itemDto.ItemCount),
new SqlParameter("@PRNo", itemDto.PRNo),
new SqlParameter("@DateNeeded", itemDto.DateNeeded),
new SqlParameter("@Qty", itemDto.Qty),
new SqlParameter("@ChargeTo", itemDto.ChargeTo),
new SqlParameter("@Remarks", itemDto.Remarks));
}
return new ItemCart();
FileName = attach.FileName,
OrigFileName = attach.OrigFileName,
PRId = attach.PRId
};
await _dbContext.PRAttachments.AddAsync(attchmnt);
}
catch (SqlException ex)
else
{
ex.ToString();
throw;
}
}
public async Task<long> GetPRNo()
{
try
{
// Query the PRs table
var latestPR = await _dbContext.PRs
.OrderByDescending(ic => ic.PRNo) // Sort by PRNo in descending order
.FirstOrDefaultAsync(); // Retrieve the first record
if (latestPR != null)
{
return latestPR.PRNo;
}
else
{
return 0; // Example: Return 0 if no records found
}
}
catch (SqlException ex)
{
// Handle the exception (log, rethrow, etc.)
ex.ToString();
throw;
existing.OrigFileName = attach.OrigFileName;
existing.FileName = attach.FileName;
}
await _dbContext.SaveChangesAsync();
}
Task<ItemCart> IItem.PostPutItemPath(ItemDto itemDto)
{
throw new NotImplementedException();
}
public async Task<List<ItemCart>> GetItemCart(ItemDto itemDto)
{
var allItems = await _dbContext.ItemCarts
.FromSqlRaw($"EXEC GetItemCart @UserId,@RequestTypeId,@IsCount",
new SqlParameter("@UserId", itemDto.UserId),
new SqlParameter("@RequestTypeId", itemDto.RequestTypeId),
new SqlParameter("@IsCount", itemDto.IsCount))
.ToListAsync();
public async Task <List<Departments>> GetDepartment(ItemCodeDto itemCode)
return allItems ?? new List<ItemCart>();
}
public async Task<(long, long)> GetPRNo()
{
try
{
var departments = await _dbContext.Departments
.Where(d => d.IsActive == true)
.ToListAsync();
return departments;
var latestPR = await _dbContext.PRs
.Where(ic => ic.PRNo != null)
.OrderByDescending(ic => ic.PRNo)
.FirstOrDefaultAsync();
if (latestPR != null)
return (latestPR.PRNo + 1, latestPR.PRId + 1);
else
return (0, 0);
}
catch (Exception ex)
{
// Log the exception or handle it as needed
throw;
}
}
public async Task<List<ItemLocalization>> GetItemLocalization(ItemDto itemDto)
{
var localizations = await _dbContext.ItemLocalizations
.Where(ic => ic.IsActive == true &&
EF.Functions.Like(ic.ItemLocalName, $"%{itemDto.ItemLocalName}%"))
.Take(15)
.ToListAsync();
return localizations ?? new List<ItemLocalization>();
}
public async Task<List<ItemCategory>> GetItemCateg(ItemDto itemDto)
{
if (itemDto.ItemCategoryId == 0 || itemDto.ItemCategoryId == null)
{
var categories = await _dbContext.ItemCategories
.Where(ic => ic.IsActive == true)
.ToListAsync();
return categories ?? new List<ItemCategory>();
}
else
{
var categories = await _dbContext.ItemCategories
.Where(ic => ic.IsActive == true && ic.ItemCategoryId == itemDto.ItemCategoryId)
.ToListAsync();
return categories ?? new List<ItemCategory>();
}
}
public async Task<List<ItemDtos>> GetItemDetail(ItemDto itemDto)
{
var allItems = await _dbContext.ItemDtos
.FromSqlRaw($"EXEC GetItemDetail @ItemCodeId,@UserId",
new SqlParameter("@ItemCodeId", itemDto.ItemCodeId),
new SqlParameter("@UserId", itemDto.UserId))
.ToListAsync();
return allItems ?? new List<ItemDtos>();
}
public async Task<PagedResult<ItemList>> GetItemList(ItemCodeDto dto)
{
var parameters = new[]
{
new SqlParameter("@UserId", dto.UserId),
new SqlParameter("@SearchItemNo", dto.SearchItemNo ?? ""),
new SqlParameter("@SearchItemName", dto.SearchItemName ?? ""),
new SqlParameter("@SearchCategory", dto.SearchCategory ?? ""),
new SqlParameter("@PageNumber", dto.PageNumber),
new SqlParameter("@PageSize", dto.PageSize)
};
int totalCount = 0;
var items = new List<ItemList>();
var categoryList = new List<string>();
// Use ADO.NET to read two result sets
var conn = _dbContext.Database.GetDbConnection();
await conn.OpenAsync();
using var cmd = conn.CreateCommand();
cmd.CommandText = "EXEC GetItemList @UserId, @SearchItemNo,@SearchItemName,@SearchCategory, @PageNumber, @PageSize";
foreach (var p in parameters) cmd.Parameters.Add(p);
cmd.CommandTimeout = 60;
using var reader = await cmd.ExecuteReaderAsync();
while (await reader.ReadAsync())
categoryList.Add(reader.GetString(0));
await reader.NextResultAsync();
if (await reader.ReadAsync())
totalCount = reader.GetInt32(0);
await reader.NextResultAsync();
while (await reader.ReadAsync())
{
items.Add(new ItemList
{
ItemCodeId = Convert.ToInt64(reader["ItemCodeId"]),
ItemNo = Convert.ToInt64(reader["ItemNo"]),
ItemName = reader["ItemName"]?.ToString(),
ItemDescription = reader["ItemDescription"]?.ToString(),
ItemCategoryName = reader["ItemCategoryName"]?.ToString(),
CartItemCount = Convert.ToInt32(reader["CartItemCount"])
});
}
await conn.CloseAsync();
return new PagedResult<ItemList>
{
Data = items,
TotalCount = totalCount,
CategoryList = categoryList,
PageNumber = dto.PageNumber,
PageSize = dto.PageSize
};
}
public async Task<List<ItemColor>> GetItemColor(ItemDto itemDto)
{
var colors = await _dbContext.ItemColors
.Where(ic => EF.Functions.Like(ic.ItemColorName, $"%{itemDto.ItemColorName}%"))
.Take(5)
.ToListAsync();
return colors ?? new List<ItemColor>();
}
public async Task<List<UnitOfMessure>> GetItemUOM(ItemDto itemDto)
{
var uoms = await _dbContext.UnitOfMessures
.Where(ic => ic.IsActive == true &&
EF.Functions.Like(ic.UOMName, $"%{itemDto.UOMName}%"))
.Take(150)
.ToListAsync();
return uoms ?? new List<UnitOfMessure>();
}
public async Task <List<Departments>> GetDepartment(ItemCodeDto itemCode)
{
return await _dbContext.Departments
.Where(d => d.IsActive == true)
.ToListAsync();
}
public async Task<List<NotifUserKey>> GetNotifUserKey(ItemDto itemDto)
{
try
{
var allItems = await _dbContext.NotifUserKeys
.FromSqlRaw($"EXEC GetNotifUserKey @UserId,@Status,@PRDetailsId,@PRNo",
new SqlParameter("@UserId", itemDto.UserId),
new SqlParameter("@Status", itemDto.Status),
new SqlParameter("@PRDetailsId", itemDto.PRDetailsId),
new SqlParameter("@PRNo", itemDto.PRNo))
.ToListAsync();
var allItems = await _dbContext.NotifUserKeys
.FromSqlRaw($"EXEC GetNotifUserKey @UserId,@Status,@PRDetailsId,@PRNo",
new SqlParameter("@UserId", itemDto.UserId),
new SqlParameter("@Status", itemDto.Status),
new SqlParameter("@PRDetailsId", itemDto.PRDetailsId),
new SqlParameter("@PRNo", itemDto.PRNo))
.ToListAsync();
return allItems ?? new List<NotifUserKey>();
}
catch (SqlException ex)
{
ex.ToString();
throw;
}
return allItems ?? new List<NotifUserKey>();
}
public async Task<IReadOnlyList<ProjectCodes>> GetProjectCode()
{
return await _dbContext.ProjectCodes
.AsNoTracking()
.ToListAsync();
}
public async Task<IReadOnlyList<ProjectCodes>> GetProjectCodeByTerm(string? term)
{
return await _dbContext.ProjectCodes
.AsNoTracking()
.Where(p => p.StatusName != "Completed" && p.IsActive
&& EF.Functions.Like(p.ProjectCode, $"%{term}%"))
.ToListAsync();
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,19 +1,21 @@
using CPRNIMS.Domain.Contracts.PR;
using CPRNIMS.Infrastructure.Database;
using CPRNIMS.Infrastructure.Dto.Items;
using CPRNIMS.Infrastructure.Dto.PR;
using CPRNIMS.Infrastructure.Dto.PR.Response;
using CPRNIMS.Infrastructure.Entities.Common;
using CPRNIMS.Infrastructure.Entities.PO;
using CPRNIMS.Infrastructure.Entities.Purchasing;
using CPRNIMS.Infrastructure.Entities.SMTP;
using CPRNIMS.Infrastructure.Models.Common;
using Microsoft.Data.SqlClient;
using Microsoft.EntityFrameworkCore;
using static CPRNIMS.Domain.Services.OutputParamMessage;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json.Linq;
using static CPRNIMS.Domain.Services.OutputParamMessage;
namespace CPRNIMS.Domain.Services.PR
{
@ -25,15 +27,392 @@ namespace CPRNIMS.Domain.Services.PR
_dbContext = dbContext;
}
#region Get
public async Task<List<PRList>> GetAllPR(PRDto PRDto)
public async Task<List<NotificationById>> GetNotificationById(PRDto PRDto)
{
var allItems = await _dbContext.PRLists
.FromSqlRaw($"EXEC GetAllPR @UserId,@IsArchived",
new SqlParameter("@UserId", PRDto.UserId),
new SqlParameter("@IsArchived", PRDto.IsArchived))
var allItems = await _dbContext.NotificationByIds
.FromSqlRaw("EXEC GetNotificationById @UserId,@PRDetailsId,@AppsModuleId",
new SqlParameter("@UserId", PRDto.UserId),
new SqlParameter("@PRDetailsId", PRDto.PRDetailsId),
new SqlParameter("@AppsModuleId", PRDto.AppsModuleId))
.ToListAsync();
return allItems ?? new List<PRList>();
return allItems ?? new List<NotificationById>();
}
public async Task<List<ProjectCodes>> GetProjectCodes(PRDto pRDto)
{
return await _dbContext.ProjectCodes.ToListAsync();
}
public async Task<PagedResult<DeletedPR>> GetDeletedPR(PRDto dto)
{
var parameters = new[]
{
new SqlParameter("@UserId", dto.UserId),
new SqlParameter("@IsArchived", dto.IsArchived),
new SqlParameter("@SearchPRNo", dto.SearchPRNo ?? ""),
new SqlParameter("@SearchItemName", dto.SearchItemName ?? ""),
new SqlParameter("@SearchDept", dto.SearchDept ?? ""),
new SqlParameter("@PageNumber", dto.PageNumber),
new SqlParameter("@PageSize", dto.PageSize)
};
int totalCount = 0;
var items = new List<DeletedPR>();
var conn = _dbContext.Database.GetDbConnection();
await conn.OpenAsync();
using var cmd = conn.CreateCommand();
cmd.CommandText = @"EXEC GetDeletedPR @UserId,
@SearchPRNo, @SearchItemName, @SearchDept,
@PageNumber, @PageSize";
foreach (var p in parameters) cmd.Parameters.Add(p);
using var reader = await cmd.ExecuteReaderAsync();
// First result set = total count
if (await reader.ReadAsync())
totalCount = reader.GetInt32(0);
// Second result set = paged rows
await reader.NextResultAsync();
while (await reader.ReadAsync())
{
items.Add(new DeletedPR
{
PRId = reader["PRId"] as long? ?? 0,
PRNo = reader["PRNo"] as long? ?? 0,
PRDetailsId = reader["PRDetailsId"] as long? ?? 0,
ItemNo = reader["ItemNo"] as long? ?? 0,
ItemName = reader["ItemName"]?.ToString(),
Department = reader["Department"]?.ToString(),
Remarks = reader["Remarks"]?.ToString(),
DateNeeded = reader["DateNeeded"] as DateTime? ?? DateTime.UtcNow,
CreatedDate = reader["CreatedDate"] as DateTime? ?? DateTime.UtcNow,
AttestedDate = reader["AttestedDate"]?.ToString(),
ApprovedDate = reader["ApprovedDate"]?.ToString(),
ApprovedBy = reader["ApprovedBy"]?.ToString(),
AttestedBy = reader["AttestedBy"]?.ToString(),
CreatedBy = reader["CreatedBy"]?.ToString(),
Qty = Convert.ToDecimal(reader["Qty"])
});
}
await conn.CloseAsync();
return new PagedResult<DeletedPR>
{
Data = items,
TotalCount = totalCount,
PageNumber = dto.PageNumber,
PageSize = dto.PageSize
};
}
public async Task<PagedResult<DetailedPRTracking>> GetDetailedPRTracking(PRDto dto)
{
var parameters = new[]
{
new SqlParameter("@UserId", dto.UserId),
new SqlParameter("@SearchPRNo", dto.SearchPRNo ?? ""),
new SqlParameter("@SearchItemNo", dto.SearchItemNo ?? ""),
new SqlParameter("@SearchItemName", dto.SearchItemName ?? ""),
new SqlParameter("@SearchDept", dto.SearchDept ?? ""),
new SqlParameter("@SearchStatusName", dto.SearchStatusName ?? ""),
new SqlParameter("@PageNumber", dto.PageNumber),
new SqlParameter("@PageSize", dto.PageSize)
};
var statusList = new List<string>();
int totalCount = 0;
var items = new List<DetailedPRTracking>();
var conn = _dbContext.Database.GetDbConnection();
await conn.OpenAsync();
using var cmd = conn.CreateCommand();
cmd.CommandText = @"EXEC GetDetailedPRTracking @UserId,
@SearchPRNo, @SearchItemNo, @SearchItemName, @SearchDept, @SearchStatusName,
@PageNumber, @PageSize";
foreach (var p in parameters) cmd.Parameters.Add(p);
cmd.CommandTimeout = 60;
using var reader = await cmd.ExecuteReaderAsync();
while (await reader.ReadAsync())
statusList.Add(reader.GetString(0));
await reader.NextResultAsync();
if (await reader.ReadAsync())
totalCount = reader.GetInt32(0);
await reader.NextResultAsync();
while (await reader.ReadAsync())
{
items.Add(new DetailedPRTracking
{
PRNo = Convert.ToInt64(reader["PRNo"]),
PRDetailsId = Convert.ToInt64(reader["PRDetailsId"]),
PRBy = reader["PRBy"]?.ToString(),
PRTypeName = reader["PRTypeName"]?.ToString(),
PRDate = reader["PRDate"] as DateTime? ?? DateTime.UtcNow,
AttestedBy = reader["AttestedBy"]?.ToString(),
ApprovedBy = reader["ApprovedBy"]?.ToString(),
CanvassDate = reader["CanvassDate"]?.ToString(),
CanvassBy = reader["CanvassBy"]?.ToString(),
CanvassNo = reader["CanvassNo"]?.ToString(),
PONo = reader["PONo"]?.ToString(),
POBy = reader["POBy"]?.ToString(),
POQty = Convert.ToDecimal(reader["POQty"]),
PODate = reader["PODate"]?.ToString(),
RRDate = reader["RRDate"]?.ToString(),
ReceivedDate = reader["ReceivedDate"]?.ToString(),
ReceivedBy = reader["ReceivedBy"]?.ToString(),
AcknowledgeBy = reader["AcknowledgeBy"]?.ToString(),
AcknowledgeDate = reader["AcknowledgeDate"]?.ToString(),
Specification = reader["Specification"]?.ToString(),
RRNo = Convert.ToInt64(reader["RRNo"]),
Department = reader["Department"]?.ToString(),
ItemCategoryName = reader["ItemCategoryName"]?.ToString(),
ItemName = reader["ItemName"]?.ToString(),
ItemDescription = reader["ItemDescription"]?.ToString(),
Status = Convert.ToInt16(reader["Status"]),
StatusName = reader["StatusName"]?.ToString(),
NewPRNo = reader["NewPRNo"]?.ToString(),
DateNeeded = reader["DateNeeded"] as DateTime? ?? DateTime.UtcNow,
ItemNo = Convert.ToInt64(reader["ItemNo"]),
Qty = Convert.ToDecimal(reader["Qty"]),
QuantityReceived = Convert.ToDecimal(reader["QuantityReceived"]),
UOMName = reader["UOMName"]?.ToString(),
ItemAttachPath = reader["ItemAttachPath"]?.ToString(),
Remarks = reader["Remarks"]?.ToString(),
});
}
await conn.CloseAsync();
return new PagedResult<DetailedPRTracking>
{
Data = items,
TotalCount = totalCount,
PageNumber = dto.PageNumber,
PageSize = dto.PageSize,
StatusList = statusList
};
}
public async Task<PagedResult<ApprovedPR>> GetApprovedPR(PRDto dto)
{
var parameters = new[]
{
new SqlParameter("@UserId", dto.UserId),
new SqlParameter("@SearchPRNo", dto.SearchPRNo ?? ""),
new SqlParameter("@SearchItemName", dto.SearchItemName ?? ""),
new SqlParameter("@SearchDept", dto.SearchDept ?? ""),
new SqlParameter("@SearchStatusName", dto.SearchStatusName ?? ""),
new SqlParameter("@PageNumber", dto.PageNumber),
new SqlParameter("@PageSize", dto.PageSize)
};
var statusList = new List<string>();
int totalCount = 0;
var items = new List<ApprovedPR>();
var conn = _dbContext.Database.GetDbConnection();
await conn.OpenAsync();
using var cmd = conn.CreateCommand();
cmd.CommandText = @"EXEC GetApprovedPR @UserId,
@SearchPRNo, @SearchItemName, @SearchDept, @SearchStatusName,
@PageNumber, @PageSize";
foreach (var p in parameters) cmd.Parameters.Add(p);
cmd.CommandTimeout = 60;
using var reader = await cmd.ExecuteReaderAsync();
// Result set 1 — distinct status list
while (await reader.ReadAsync())
statusList.Add(reader.GetString(0));
// Result set 2 — total count
await reader.NextResultAsync();
if (await reader.ReadAsync())
totalCount = reader.GetInt32(0);
// Result set 3 — paged rows
await reader.NextResultAsync();
while (await reader.ReadAsync())
{
items.Add(new ApprovedPR
{
PRId = reader["PRId"] as long? ?? 0,
PRNo = reader["PRNo"] as long? ?? 0,
PRDetailsId = reader["PRDetailsId"] as long? ?? 0,
ItemNo = reader["ItemNo"] as long? ?? 0,
ItemName = reader["ItemName"]?.ToString(),
Department = reader["Department"]?.ToString(),
StatusName = reader["StatusName"]?.ToString(),
DateNeeded = reader["DateNeeded"] as DateTime? ?? DateTime.UtcNow,
CreatedDate = reader["CreatedDate"] as DateTime? ?? DateTime.UtcNow,
AttestedDate = reader["AttestedDate"]?.ToString(),
ApprovedDate = reader["ApprovedDate"]?.ToString(),
Qty = Convert.ToDecimal(reader["Qty"]),
ApprovedBy = reader["ApprovedBy"]?.ToString(),
AttestedBy = reader["AttestedBy"]?.ToString(),
CreatedBy = reader["CreatedBy"]?.ToString(),
RemainingDays = reader["RemainingDays"] as int? ?? 0,
});
}
await conn.CloseAsync();
return new PagedResult<ApprovedPR>
{
Data = items,
TotalCount = totalCount,
PageNumber = dto.PageNumber,
PageSize = dto.PageSize,
StatusList = statusList
};
}
public async Task<PagedResult<Infrastructure.Entities.Purchasing.PRList>> GetAllPR(PRDto dto)
{
var parameters = new[]
{
new SqlParameter("@UserId", dto.UserId),
new SqlParameter("@SearchPRNo", dto.SearchPRNo ?? ""),
new SqlParameter("@SearchItemName", dto.SearchItemName ?? ""),
new SqlParameter("@SearchDept", dto.SearchDept ?? ""),
new SqlParameter("@PageNumber", dto.PageNumber),
new SqlParameter("@PageSize", dto.PageSize)
};
int totalCount = 0;
var items = new List<Infrastructure.Entities.Purchasing.PRList>();
var conn = _dbContext.Database.GetDbConnection();
await conn.OpenAsync();
using var cmd = conn.CreateCommand();
cmd.CommandText = @"EXEC GetAllPR @UserId,
@SearchPRNo, @SearchItemName, @SearchDept,
@PageNumber, @PageSize";
foreach (var p in parameters) cmd.Parameters.Add(p);
using var reader = await cmd.ExecuteReaderAsync();
if (await reader.ReadAsync())
totalCount = reader.GetInt32(0);
await reader.NextResultAsync();
while (await reader.ReadAsync())
{
items.Add(new Infrastructure.Entities.Purchasing.PRList
{
PRId = reader["PRId"] as long? ?? 0,
PRNo = reader["PRNo"] as long? ?? 0,
NewPRNo = reader["NewPRNo"]?.ToString(),
AggreItemName = reader["AggreItemName"]?.ToString(),
CreatedDate = reader["CreatedDate"] as DateTime? ?? DateTime.UtcNow,
DateNeeded = reader["DateNeeded"] as DateTime? ?? DateTime.UtcNow,
CreatedBy = reader["CreatedBy"]?.ToString(),
Department = reader["Department"]?.ToString(),
ApprovedBy = reader["ApprovedBy"]?.ToString(),
AttestedBy = reader["AttestedBy"]?.ToString(),
Remarks = reader["Remarks"]?.ToString(),
Status = reader["Status"] as short? ?? 0,
});
}
await conn.CloseAsync();
return new PagedResult<Infrastructure.Entities.Purchasing.PRList>
{
Data = items,
TotalCount = totalCount,
PageNumber = dto.PageNumber,
PageSize = dto.PageSize
};
}
public async Task<PagedResult<Infrastructure.Entities.Purchasing.PRList>> GetPRArchived(PRDto dto)
{
var parameters = new[]
{
new SqlParameter("@UserId", dto.UserId),
new SqlParameter("@SearchPRNo", dto.SearchPRNo ?? ""),
new SqlParameter("@SearchItemName", dto.SearchItemName ?? ""),
new SqlParameter("@SearchDept", dto.SearchDept ?? ""),
new SqlParameter("@PageNumber", dto.PageNumber),
new SqlParameter("@PageSize", dto.PageSize)
};
int totalCount = 0;
var items = new List<Infrastructure.Entities.Purchasing.PRList>();
var conn = _dbContext.Database.GetDbConnection();
await conn.OpenAsync();
using var cmd = conn.CreateCommand();
cmd.CommandText = @"EXEC GetPRArchived @UserId,
@SearchPRNo, @SearchItemName, @SearchDept,
@PageNumber, @PageSize";
foreach (var p in parameters) cmd.Parameters.Add(p);
using var reader = await cmd.ExecuteReaderAsync();
if (await reader.ReadAsync())
totalCount = reader.GetInt32(0);
await reader.NextResultAsync();
while (await reader.ReadAsync())
{
items.Add(new Infrastructure.Entities.Purchasing.PRList
{
PRId = reader["PRId"] as long? ?? 0,
PRNo = reader["PRNo"] as long? ?? 0,
NewPRNo = reader["NewPRNo"]?.ToString(),
AggreItemName = reader["AggreItemName"]?.ToString(),
CreatedDate = reader["NewPRNo"] as DateTime? ?? DateTime.UtcNow,
DateNeeded = reader["DateNeeded"] as DateTime? ?? DateTime.UtcNow,
CreatedBy = reader["CreatedBy"]?.ToString(),
Department = reader["Department"]?.ToString(),
ApprovedBy = reader["ApprovedBy"]?.ToString(),
AttestedBy = reader["AttestedBy"]?.ToString(),
Remarks = reader["Remarks"]?.ToString(),
Status = reader["Status"] as short? ?? 0,
});
}
await conn.CloseAsync();
return new PagedResult<Infrastructure.Entities.Purchasing.PRList>
{
Data = items,
TotalCount = totalCount,
PageNumber = dto.PageNumber,
PageSize = dto.PageSize
};
}
public async Task<List<PRDto>> GetApproverNameByPRNo(PRDto PRDto)
{
var result = await _dbContext.Approved
.Where(a => a.PRNo == PRDto.PRNo && (a.ApproverId == 1 || a.ApproverId == 2))
.GroupBy(a => a.PRNo)
.Select(g => new PRDto
{
AttestedBy = g.Where(x => x.ApproverId == 1 && x.ApprovedBy != null)
.Select(x => x.ApprovedBy)
.FirstOrDefault(),
ApprovedBy = g.Where(x => x.ApproverId == 2 && x.ApprovedBy != null)
.Select(x => x.ApprovedBy)
.FirstOrDefault()
})
.ToListAsync();
if (result.Any() && (result[0].AttestedBy != null || result[0].ApprovedBy != null))
{
return result;
}
return new List<PRDto>();
}
public async Task<List<PRDto>> GetApproverName(PRDto PRDto)
{
@ -109,15 +488,15 @@ namespace CPRNIMS.Domain.Services.PR
return allItems ?? new List<NotifUserKey>();
}
public async Task<List<PRDetails>> GetPRDetailByPRNo(PRDto PRDto)
public async Task<List<PRItemList>> GetPRDetailByPRNo(PRDto PRDto)
{
var allItems = await _dbContext.PRDetails
var allItems = await _dbContext.PRItemLists
.FromSqlRaw($"EXEC GetPRDetailByPRNo @UserId, @PRNo",
new SqlParameter("@UserId", PRDto.UserId),
new SqlParameter("@PRNo", PRDto.PRNo))
.ToListAsync();
return allItems ?? new List<PRDetails>();
return allItems ?? new List<PRItemList>();
}
public async Task<List<PRTracking>> GetPRStatusById(PRDto PRDto)
{
@ -150,14 +529,6 @@ namespace CPRNIMS.Domain.Services.PR
return new List<Infrastructure.Entities.Canvass.PRList>();
}
public async Task<List<RRReport>> GetDetailedPRTracking(PRDto PRDto)
{
var allItems = await _dbContext.DetailedPRTrackings
.FromSqlRaw("EXEC GetDetailedPRTracking @UserId",
new SqlParameter("@UserId", PRDto.UserId)).ToListAsync();
return allItems ?? new List<RRReport>();
}
public async Task<List<AlternativeOffer>> GetSupplierAlternativeOffer(PRDto PRDto)
{
var rfq = await _dbContext.AlternativeOffers
@ -175,94 +546,62 @@ namespace CPRNIMS.Domain.Services.PR
}
#endregion
#region Post Put
public async Task<PRDetails> PostPRApproveReject(PRDto PRDto)
public async Task<PRResponse> PostPRApproveReject(PRDto PRDto)
{
try
{
await _dbContext.Database
.ExecuteSqlRawAsync("EXEC PostPRApproveReject @UserId, @ItemNo, @Status, @PRDetailsId, @Remarks",
new SqlParameter("@ItemNo", PRDto.ItemNo != null ? PRDto.ItemNo : 0L),
new SqlParameter("@UserId", PRDto.UserId),
new SqlParameter("@Status", PRDto.Status),
new SqlParameter("@PRDetailsId", PRDto.PRDetailsId),
new SqlParameter("@Remarks", PRDto.Remarks ?? "N/A"));
return new PRDetails();
}
catch (SqlException ex)
{
ex.ToString();
throw;
}
await _dbContext.Database
.ExecuteSqlRawAsync("EXEC PostPRApproveReject @UserId, @ItemNo, @Status, @PRDetailsId, @Remarks",
new SqlParameter("@ItemNo", PRDto.ItemNo != null ? PRDto.ItemNo : 0L),
new SqlParameter("@UserId", PRDto.UserId),
new SqlParameter("@Status", PRDto.Status),
new SqlParameter("@PRDetailsId", PRDto.PRDetailsId),
new SqlParameter("@Remarks", PRDto.Remarks ?? "N/A"));
return new PRResponse();
}
public async Task<PRDetails> PutItemDetail(PRDto PRDto)
public async Task<PRResponse> PutItemDetail(PRDto PRDto)
{
try
{
await _dbContext.Database
.ExecuteSqlRawAsync($"EXEC PutPRItemDetail @UserId, @ItemLocalId, @UOMId, @ItemColorId," +
$"@Qty,@ItemCategoryId,@PRDetailsId,@Remarks,@ItemName,@ItemDescription",
new SqlParameter("@PRDetailsId", PRDto.PRDetailsId != null ? PRDto.PRDetailsId : 0L),
new SqlParameter("@ItemLocalId", PRDto.ItemLocalId),
new SqlParameter("@UOMId", PRDto.UOMId),
new SqlParameter("@ItemColorId", PRDto.ItemColorId),
new SqlParameter("@UserId", PRDto.UserId),
new SqlParameter("@Qty", PRDto.Qty),
new SqlParameter("@ItemCategoryId", PRDto.ItemCategoryId),
new SqlParameter("@Remarks", PRDto.Remarks),
new SqlParameter("@ItemName", PRDto.ItemName),
new SqlParameter("@ItemDescription", PRDto.ItemDescription));
return new PRDetails();
}
catch (SqlException ex)
{
ex.ToString();
throw;
}
await _dbContext.Database
.ExecuteSqlRawAsync($"EXEC PutPRItemDetail @UserId, @ItemLocalId, @UOMId, @ItemColorId," +
$"@Qty,@ItemCategoryId,@PRDetailsId,@Remarks,@ItemName,@ItemDescription",
new SqlParameter("@PRDetailsId", PRDto.PRDetailsId != null ? PRDto.PRDetailsId : 0L),
new SqlParameter("@ItemLocalId", PRDto.ItemLocalId),
new SqlParameter("@UOMId", PRDto.UOMId),
new SqlParameter("@ItemColorId", PRDto.ItemColorId),
new SqlParameter("@UserId", PRDto.UserId),
new SqlParameter("@Qty", PRDto.Qty),
new SqlParameter("@ItemCategoryId", PRDto.ItemCategoryId),
new SqlParameter("@Remarks", PRDto.Remarks),
new SqlParameter("@ItemName", PRDto.ItemName),
new SqlParameter("@ItemDescription", PRDto.ItemDescription));
return new PRResponse();
}
public async Task<PRDetails> PostPutDeniedItem(PRDto PRDto)
public async Task<PRResponse> PostPutDeniedItem(PRDto PRDto)
{
try
{
await _dbContext.Database
await _dbContext.Database
.ExecuteSqlRawAsync("EXEC PostPutDeniedItem @UserId,@PRDetailsId,@Remarks",
new SqlParameter("@UserId", PRDto.UserId),
new SqlParameter("@PRDetailsId", PRDto.PRDetailsId),
new SqlParameter("@Remarks", PRDto.Remarks ?? "N/A"));
return new PRDetails();
}
catch (SqlException ex)
{
ex.ToString();
throw;
}
return new PRResponse();
}
public async Task<PRDetails> PostPutReceiving(PRDto PRDto)
public async Task<PRResponse> PostPutReceiving(PRDto PRDto)
{
try
{
await _dbContext.Database
.ExecuteSqlRawAsync($"EXEC PostPutReceiving @UserId, @PONo, @POTypeId, @EmailAddress, @DRNo, @DocTypeId, @QuantityReceived,@RRNo,@PRDetailsId,@Remarks,@ReceivedDate,@IsCompleted",
new SqlParameter("@UserId", PRDto.UserId),
new SqlParameter("@PONo", PRDto.PONo),
new SqlParameter("@POTypeId", PRDto.POTypeId),
new SqlParameter("@EmailAddress", PRDto.EmailAddress),
new SqlParameter("@DRNo", PRDto.DRNo),
new SqlParameter("@DocTypeId", PRDto.DocTypeId),
new SqlParameter("@QuantityReceived", PRDto.QuantityReceived),
new SqlParameter("@RRNo", PRDto.RRNo),
new SqlParameter("@PRDetailsId", PRDto.PRDetailsId),
new SqlParameter("@Remarks", PRDto.Remarks ?? "N/A"),
new SqlParameter("@ReceivedDate", PRDto.ReceivedDate),
new SqlParameter("@IsCompleted", PRDto.IsCompleted));
return new PRDetails();
}
catch (SqlException ex)
{
ex.ToString();
throw;
}
await _dbContext.Database
.ExecuteSqlRawAsync($"EXEC PostPutReceiving @UserId, @PONo, @POTypeId, @EmailAddress, @DRNo, @DocTypeId, @QuantityReceived,@RRNo,@PRDetailsId,@Remarks,@ReceivedDate,@IsCompleted",
new SqlParameter("@UserId", PRDto.UserId),
new SqlParameter("@PONo", PRDto.PONo),
new SqlParameter("@POTypeId", PRDto.POTypeId),
new SqlParameter("@EmailAddress", PRDto.EmailAddress),
new SqlParameter("@DRNo", PRDto.DRNo),
new SqlParameter("@DocTypeId", PRDto.DocTypeId),
new SqlParameter("@QuantityReceived", PRDto.QuantityReceived),
new SqlParameter("@RRNo", PRDto.RRNo),
new SqlParameter("@PRDetailsId", PRDto.PRDetailsId),
new SqlParameter("@Remarks", PRDto.Remarks ?? "N/A"),
new SqlParameter("@ReceivedDate", PRDto.ReceivedDate),
new SqlParameter("@IsCompleted", PRDto.IsCompleted));
return new PRResponse();
}
public async Task<PRDetails> PutPOClose(PRDto PRDto)
public async Task<PRResponse> PutPOClose(PRDto PRDto)
{
await _dbContext.Database
.ExecuteSqlRawAsync("EXEC PutPOClose @UserId, @PONo, @POTypeId, @EmailAddress,@PRDetailsId,@DocTypeId,@PRNo,@Remarks",
@ -274,7 +613,7 @@ namespace CPRNIMS.Domain.Services.PR
new SqlParameter("@PRDetailsId", PRDto.PRDetailsId),
new SqlParameter("@PRNo", PRDto.PRNo),
new SqlParameter("@Remarks", PRDto.Remarks ?? "N/A"));
return new PRDetails();
return new PRResponse();
}
public async Task<AlternativeOfferDetails> PutSupplierAlterOffer(PRDto pRDto)
{
@ -285,19 +624,26 @@ namespace CPRNIMS.Domain.Services.PR
new SqlParameter("@CanvassDetailId", pRDto.CanvassDetailId));
return new AlternativeOfferDetails();
}
public async Task<List<NotificationById>> GetNotificationById(PRDto PRDto)
private async Task<bool> IsUsingAsync(int projectCodeId)
{
var allItems = await _dbContext.NotificationByIds
.FromSqlRaw("EXEC GetNotificationById @UserId,@PRDetailsId,@AppsModuleId",
new SqlParameter("@UserId", PRDto.UserId),
new SqlParameter("@PRDetailsId", PRDto.PRDetailsId),
new SqlParameter("@AppsModuleId", PRDto.AppsModuleId))
.ToListAsync();
return allItems ?? new List<NotificationById>();
return await (from pr in _dbContext.PRs
join pod in _dbContext.PODetails on pr.PRNo equals pod.PRNo
where pr.ProjectCodeId == projectCodeId
&& !pod.IsRemoved
&& pr.IsActive
select pr).AnyAsync();
}
private async Task<bool> ProjectStatusChanges(int projectCodeId,string? status)
{
var project = await _dbContext.ProjectCodes.FirstOrDefaultAsync(pc=>pc.ProjectCodeId==projectCodeId);
if (project == null)
return false;
if (project.StatusName == status)
return false;
else
return true;
}
public async Task<MessageResponse> PRItemRemoval(PRDto prDto)
{
var (messCode, message) = CreateOutputParams();
@ -318,6 +664,84 @@ namespace CPRNIMS.Domain.Services.PR
};
return response;
}
public async Task<ResponseObject> PostPutProjectCode(PRDto prDto)
{
if (prDto == null) throw new ArgumentNullException(nameof(prDto));
var existing = await _dbContext.ProjectCodes
.FirstOrDefaultAsync(p => p.ProjectCodeId == prDto.ProjectCodeId);
if (existing == null)
{
var project = new ProjectCodes
{
ProjectCode = prDto.ProjectCode,
ProjectName = prDto.ProjectName,
DeliveryAddress = prDto.DeliveryAddress,
MaxDays = prDto.MaxDays,
StatusName = prDto.StatusName,
IsActive = prDto.IsActive
};
await _dbContext.ProjectCodes.AddAsync(project);
}
else
{
if (await IsUsingAsync(prDto.ProjectCodeId) && await ProjectStatusChanges(prDto.ProjectCodeId,prDto.StatusName) == false)
{
return new ResponseObject()
{
message = "Cannot update this project code because it is already being used in a Purchase Order (PO).",
messCode = 0,
success = false,
};
}
if (await IsUsingAsync(prDto.ProjectCodeId))
{
existing.StatusName = prDto.StatusName;
}
else
{
existing.ProjectCode = prDto.ProjectCode;
existing.ProjectName = prDto.ProjectName;
existing.DeliveryAddress = prDto.DeliveryAddress;
existing.MaxDays = prDto.MaxDays;
existing.StatusName = prDto.StatusName;
existing.IsActive = prDto.IsActive;
}
}
await _dbContext.SaveChangesAsync();
return new ResponseObject()
{
message = "Project code detail successfully updated",
messCode = 1,
success = true
};
}
public async Task<ResponseObject> PostItemInPR(PRDto dto)
{
var (messCode, message) = CreateOutputParams();
await _dbContext.Database.ExecuteSqlRawAsync(
"EXEC PostItemInPR @UserId,@ItemNo,@Qty,@PRNo,@MessCode OUTPUT,@Message OUTPUT",
new SqlParameter("@UserId", dto.UserId),
new SqlParameter("@ItemNo", dto.ItemNo),
new SqlParameter("@Qty", dto.Qty),
new SqlParameter("@PRNo", dto.PRNo),
messCode,
message
);
var response = new ResponseObject
{
message = message.Value?.ToString(),
messCode = Convert.ToByte(messCode.Value)
};
return response;
}
#endregion
}
}

View File

@ -23,113 +23,65 @@ namespace CPRNIMS.Domain.Services.Receiving
#region Get
public async Task<List<Infrastructure.Entities.Receiving.RRReport>> GetRRReport(ItemDto itemDto)
{
try
if (!itemDto.IsSorting)
{
if (!itemDto.IsSorting)
{
itemDto.DateFrom = DateTime.Today;
itemDto.DateTo = DateTime.Today.AddDays(1).AddSeconds(-1);
}
var allItems = await _dbContext.RRReports
.FromSqlRaw($"EXEC GetRRReport @DateFrom,@DateTo,@IsSorting",
new SqlParameter("@DateFrom", itemDto.DateFrom),
new SqlParameter("@DateTo", itemDto.DateTo),
new SqlParameter("@IsSorting", itemDto.IsSorting))
.ToListAsync();
return allItems ?? new List<Infrastructure.Entities.Receiving.RRReport>();
}
catch (SqlException ex)
{
ex.ToString();
throw;
itemDto.DateFrom = DateTime.Today;
itemDto.DateTo = DateTime.Today.AddDays(1).AddSeconds(-1);
}
var allItems = await _dbContext.RRReports
.FromSqlRaw($"EXEC GetRRReport @DateFrom,@DateTo,@IsSorting",
new SqlParameter("@DateFrom", itemDto.DateFrom),
new SqlParameter("@DateTo", itemDto.DateTo),
new SqlParameter("@IsSorting", itemDto.IsSorting))
.ToListAsync();
return allItems ?? new List<Infrastructure.Entities.Receiving.RRReport>();
}
public async Task<List<ForReceiving>> GetForReceiving(ItemDto itemDto)
{
try
{
var allItems = await _dbContext.ForReceivings
.FromSqlRaw($"EXEC GetForReceiving @UserId,@IsDenied",
new SqlParameter("@UserId", itemDto.UserId),
new SqlParameter("@IsDenied", itemDto.IsDenied))
.ToListAsync();
var allItems = await _dbContext.ForReceivings
.FromSqlRaw($"EXEC GetForReceiving @UserId,@IsDenied",
new SqlParameter("@UserId", itemDto.UserId),
new SqlParameter("@IsDenied", itemDto.IsDenied))
.ToListAsync();
return allItems ?? new List<ForReceiving>();
}
catch (SqlException ex)
{
ex.ToString();
throw;
}
return allItems ?? new List<ForReceiving>();
}
public async Task<List<RR>> GetRR(ItemDto itemDto)
{
try
{
var allItems = await _dbContext.RRs
var allItems = await _dbContext.RRs
.FromSqlRaw($"EXEC GetRR @UserId",
new SqlParameter("@UserId", itemDto.UserId))
.ToListAsync();
return allItems ?? new List<RR>();
}
catch (SqlException ex)
{
ex.ToString();
throw;
}
return allItems ?? new List<RR>();
}
public async Task<List<RRSeries>> GetLatestRRNo(ItemDto itemDto)
{
try
{
return await _dbContext.RRSeries.FromSqlRaw("EXEC GetLatestRRNo @UserId",
new SqlParameter("@UserId",itemDto.UserId)).ToListAsync();
}
catch (Exception)
{
throw;
}
return await _dbContext.RRSeries.FromSqlRaw("EXEC GetLatestRRNo @UserId",
new SqlParameter("@UserId", itemDto.UserId)).ToListAsync();
}
public async Task<List<ReceivingDetail>> GetRRDetailByPO(ItemDto itemDto)
{
try
{
var allItems = await _dbContext.ReceivingDetails
.FromSqlRaw($"EXEC GetRRDetailByPO @PONo,@POTypeId,@UserId",
new SqlParameter("@PONo", itemDto.PONo),
new SqlParameter("@POTypeId", itemDto.POTypeId),
new SqlParameter("@UserId", itemDto.UserId))
.ToListAsync();
var allItems = await _dbContext.ReceivingDetails
.FromSqlRaw($"EXEC GetRRDetailByPO @PONo,@POTypeId,@UserId",
new SqlParameter("@PONo", itemDto.PONo),
new SqlParameter("@POTypeId", itemDto.POTypeId),
new SqlParameter("@UserId", itemDto.UserId))
.ToListAsync();
return allItems ?? new List<ReceivingDetail>();
}
catch (SqlException ex)
{
ex.ToString();
throw;
}
return allItems ?? new List<ReceivingDetail>();
}
public async Task<List<RRDetail>> GetRRDetail(ItemDto itemDto)
public async Task<List<RRDetailDto>> GetRRDetail(ItemDto itemDto)
{
try
{
var allItems = await _dbContext.RRDetailss
.FromSqlRaw($"EXEC GetRRDetail @RRNo,@UserId",
var allItems = await _dbContext.RRDetailss
.FromSqlRaw("EXEC GetRRDetail @RRNo,@UserId",
new SqlParameter("@RRNo", itemDto.RRNo),
new SqlParameter("@UserId", itemDto.UserId))
.ToListAsync();
return allItems ?? new List<RRDetail>();
}
catch (SqlException ex)
{
ex.ToString();
throw;
}
return allItems ?? new List<RRDetailDto>();
}
#endregion
#region Post Put

View File

@ -0,0 +1,80 @@
using CPRNIMS.Domain.Contracts.Reports;
using CPRNIMS.Domain.UIContracts.Common;
using CPRNIMS.Infrastructure.Dto.Inventory.Reports;
using CPRNIMS.Infrastructure.Helper;
using FastReport;
using Microsoft.Extensions.Configuration;
using System.Data;
using System.Net.Http.Json;
using System.Text.Json;
namespace CPRNIMS.Infrastructure.Reports
{
public class ReportBuilder : IReportBuilder
{
private readonly IConfiguration _configuration;
private readonly TokenHelper _tokenHelper;
private readonly IApiConfigurationService _apiConfigurationService;
public ReportBuilder(IConfiguration configuration, TokenHelper tokenHelper,
IApiConfigurationService apiConfigurationService)
{
_configuration = configuration;
_tokenHelper = tokenHelper;
_apiConfigurationService = apiConfigurationService;
}
private static readonly JsonSerializerOptions _jsonOptions = new()
{
PropertyNameCaseInsensitive = true
};
public Task<Report> MRSBuildAsync(DateTime dateFrom, DateTime dateTo, string templatePath, CancellationToken ct)
{
throw new NotImplementedException();
}
public async Task<Report> RISBuildAsync(
DateTime dateFrom, DateTime dateTo, string templatePath, CancellationToken ct = default)
{
var token = await _tokenHelper.GetValidTokenAsync();
if (string.IsNullOrEmpty(token))
throw new InvalidOperationException("Token has been expired.");
var endpoint = _configuration["LLI:NonInvent:InventoryMgmt:RISReportData"]
?? throw new InvalidOperationException("RISReportData endpoint is not configured.");
// Append the date range as query string
var url = $"{endpoint}?dateFrom={dateFrom:yyyy-MM-dd}&dateTo={dateTo:yyyy-MM-dd}";
using var httpClient = _apiConfigurationService.CreateHttpClientWithDefaultHeaders(token);
var response = await httpClient.GetAsync(url, ct);
var json = await response.Content.ReadAsStringAsync(ct);
if (!response.IsSuccessStatusCode)
throw new InvalidOperationException(
$"Failed to fetch RIS report data. HTTP {(int)response.StatusCode}: {json}");
var dto = JsonSerializer.Deserialize<RISReportDataDto>(json, _jsonOptions)
?? new RISReportDataDto();
var report = new Report();
report.Load(templatePath);
// RegisterData accepts IEnumerable<object> — names must match the .frx datasources.
report.RegisterData(dto.Rows ?? new(), "TRIS");
report.RegisterData(dto.Disciplines ?? new(), "TDisciplineAgg");
report.RegisterData(dto.Recipients ?? new(), "TTopRecipients");
/* report.GetDataSource("Table").Enabled = true;
report.GetDataSource("Table1").Enabled = true;
report.GetDataSource("Table3").Enabled = true;*/
report.GetDataSource("TRIS").Enabled = true;
report.GetDataSource("TDisciplineAgg").Enabled = true;
report.GetDataSource("TTopRecipients").Enabled = true;
report.SetParameterValue("DateFrom", dateFrom);
report.SetParameterValue("DateTo", dateTo);
return report;
}
}
}

View File

@ -0,0 +1,109 @@
using CPRNIMS.Domain.Contracts.Reports;
using CPRNIMS.Infrastructure.Database;
using CPRNIMS.Infrastructure.Dto.Inventory.Reports;
using Dapper;
using Microsoft.Data.SqlClient;
using Microsoft.EntityFrameworkCore;
namespace CPRNIMS.Infrastructure.Reports
{
public class ReportDataService : IReportDataService
{
private readonly NonInventoryDbContext _context;
public ReportDataService(NonInventoryDbContext context) => _context = context;
private const string MainSql = """
SELECT
R.RISNo,
PR.PRNo,
R.QtyIssued,
R.IssuedTo,
CASE R.Status
WHEN 0 THEN 'Draft'
WHEN 1 THEN 'Approved'
WHEN 2 THEN 'Cancelled'
ELSE 'Unknown'
END AS StatusLabel,
CreatedBy.CreatedBy,
ApprovedBy.ApprovedBy,
R.ApprovedDate,
R.CreatedDate,
D.DisciplineName,
PRD.ItemName,
PRD.ItemNo,
IV.QtyIn,
IV.QtyOut,
IV.QtyOnHand,
DEP.Department AS DepartmentName,
ISNULL(MRS_AGG.TotalReturned, 0) AS TotalReturned,
ISNULL(MRS_AGG.MRSCount, 0) AS MRSCount,
R.QtyIssued - ISNULL(MRS_AGG.TotalReturned, 0) AS NetIssued
FROM dbo.RIS R
INNER JOIN dbo.Disciplines D ON R.DisciplineId = D.DisciplineId
INNER JOIN dbo.Inventory IV ON R.InventoryId = IV.InventoryId AND IV.IsActive = 1
LEFT JOIN dbo.Lot L ON IV.LotId = L.LotId
OUTER APPLY (SELECT U.FullName ApprovedBy FROM dbo.Users U WHERE R.ApprovedBy = U.UserName) ApprovedBy
OUTER APPLY (SELECT U2.FullName CreatedBy FROM dbo.Users U2 WHERE R.CreatedBy = U2.UserName) CreatedBy
INNER JOIN Users U ON IV.UserId = U.Id
LEFT JOIN dbo.Departments DEP ON U.DepartmentId = DEP.DepartmentId
LEFT JOIN dbo.PRDetails PRD ON R.PRDetailId = PRD.PRDetailsId AND PRD.IsActive = 1
LEFT JOIN dbo.PR PR ON PRD.PRId = PR.PRId AND PR.IsActive = 1
LEFT JOIN (
SELECT
RISId,
COUNT(*) AS MRSCount,
SUM(QtyReturned) AS TotalReturned
FROM dbo.MRS
WHERE Status != 2
GROUP BY RISId
) MRS_AGG ON R.RISId = MRS_AGG.RISId
WHERE R.Status != 2
AND R.CreatedDate >= @DateFrom
AND R.CreatedDate < DATEADD(DAY, 1, @DateTo)
ORDER BY R.CreatedDate DESC, R.RISNo ASC;
""";
private const string DisciplineSql = """
SELECT
D.DisciplineName,
COUNT(*) AS SlipCount
FROM dbo.RIS R
INNER JOIN dbo.Disciplines D ON R.DisciplineId = D.DisciplineId
WHERE R.Status != 2
AND R.CreatedDate >= @DateFrom
AND R.CreatedDate < DATEADD(DAY, 1, @DateTo)
GROUP BY D.DisciplineName
ORDER BY SlipCount DESC;
""";
private const string RecipientsSql = """
SELECT TOP 5
R.IssuedTo AS Name,
COUNT(*) AS SlipCount,
SUM(IV.QtyOut) AS QtyOut
FROM dbo.RIS R
INNER JOIN dbo.Inventory IV ON R.InventoryId = IV.InventoryId AND IV.IsActive = 1
WHERE R.Status != 2
AND R.CreatedDate >= @DateFrom
AND R.CreatedDate < DATEADD(DAY, 1, @DateTo)
GROUP BY R.IssuedTo
ORDER BY COUNT(*) DESC;
""";
public List<RISRowDto> GetMain(DateTime dateFrom, DateTime dateTo) =>
Query<RISRowDto>(MainSql, dateFrom, dateTo);
public List<DisciplineAggDto> GetDisciplines(DateTime dateFrom, DateTime dateTo) =>
Query<DisciplineAggDto>(DisciplineSql, dateFrom, dateTo);
public List<TopRecipientDto> GetRecipients(DateTime dateFrom, DateTime dateTo) =>
Query<TopRecipientDto>(RecipientsSql, dateFrom, dateTo);
private List<T> Query<T>(string sql, DateTime from, DateTime to)
{
using var conn = new SqlConnection(_context.Database.GetConnectionString());
return conn.Query<T>(sql, new { DateFrom = from, DateTo = to }).ToList();
}
}
}

View File

@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CPRNIMS.Domain.Services
{
public class Result<T>
{
public bool IsSuccess { get; set; }
public string? Error { get; set; }
public T? Value { get; set; }
private Result(bool isSuccess, T? value, string? error)
{
IsSuccess = isSuccess;
Error = error;
Value = value;
}
public static Result<T> Success(T value)
=> new Result<T>(true, value, null);
public static Result<T> Failure(string? error)
=> new Result<T>(false, default, error);
}
}

View File

@ -1,4 +1,5 @@
using CPRNIMS.Infrastructure.Models.Account;
using CPRNIMS.Infrastructure.Dto.Common;
using CPRNIMS.Infrastructure.Models.Account;
using CPRNIMS.Infrastructure.ViewModel.Canvass;
using CPRNIMS.Infrastructure.ViewModel.PR;
using System;
@ -11,10 +12,10 @@ namespace CPRNIMS.Domain.UIContracts.Canvass
{
public interface ICanvass
{
#region
Task<List<CanvassVM>> GetSupplierBid(User user, CanvassVM viewModel);
Task<List<CanvassVM>> GetSupplierBidByItem(User user, CanvassVM viewModel);
Task<List<CanvassVM>> GetSupplierBidById(User user, CanvassVM viewModel);
Task<List<CanvassVM>> GetCanvassPerSupplier(User user, CanvassVM viewModel);
Task<List<CanvassVM>> GetCanvassPerSupplierEmail(User user, CanvassVM viewModel);
Task<List<CanvassVM>> GetItemSupplierWOEmail(User user, CanvassVM viewModel);
Task<List<CanvassVM>> GetSupplierItemWOEmail(User user, CanvassVM viewModel);
@ -32,6 +33,13 @@ namespace CPRNIMS.Domain.UIContracts.Canvass
Task<List<CanvassVM>?> GetCanvassPerSupplierId(User user, CanvassVM viewModel);
Task<List<CanvassVM>?> GetCanvassGroupByPRNo(User user, CanvassVM viewModel);
Task<List<CanvassVM>?> GetAlternativeOfferByPRDetailId(User user, CanvassVM viewModels);
Task<PagedResult<CanvassVM>> GetCanvassPerSupplier(User user, CanvassVM viewModel);
Task<PagedResult<CanvassVM>> GetItemsForTagging(User user, CanvassVM dto);
#endregion
#region Post Put
Task<CanvassVM> PostSupplierForCanvass(User user, CanvassVM viewModel);
Task<CanvassVM> PostCanvass(User user, CanvassVM viewModel);
Task<CanvassVM> PostPutSupplier(User user, CanvassVM viewModel);
Task<CanvassVM> PostTaggingSupplier(User user, CanvassVM viewModel);
@ -42,5 +50,7 @@ namespace CPRNIMS.Domain.UIContracts.Canvass
Task<CanvassVM> PostPutMySupplier(User user, CanvassVM viewModel);
Task<CanvassVM> PostPutItemTagging(User user, CanvassVM viewModel);
Task<CanvassVM> UnlockFormLink(User user, CanvassVM viewModel);
Task<CanvassVM> StartCanvass(User user, CanvassVM viewModel);
#endregion
}
}

View File

@ -1,4 +1,6 @@
using CPRNIMS.Infrastructure.Dto.Inventory;
using CPRNIMS.Infrastructure.Dto.Inventory.Request;
using CPRNIMS.Infrastructure.Dto.Inventory.Response;
using CPRNIMS.Infrastructure.Models.Account;
using CPRNIMS.Infrastructure.ViewModel.Inventory;
using System;
@ -11,12 +13,15 @@ namespace CPRNIMS.Domain.UIContracts.Inventory
{
public interface IInventory
{
Task<TransactContextDto?> GetTransactContextAsync(int inventoryId);
Task<List<InventoryVM>> GetInventoryByUserId(User user, InventoryVM viewModel);
Task<List<InventoryVM>> GetRequestedItemByUserId(User user, InventoryVM viewModel);
Task<List<InventoryVM>> GetInventoryById(User user, InventoryVM viewModel);
Task<List<InventoryVM>> GetLotNo(User user, InventoryVM viewModel);
Task<List<InventoryVM>> GetLotQtyByItem(User user, InventoryVM viewModel);
Task<List<InventoryVM>> GetLotNoById(User user, InventoryVM viewModel);
Task<PagedResult<InventoryResponse>> GetInventory(User user, InventoryRequest request);
Task<InventoryVM> PostPutLotNo(User user, InventoryVM viewModel);
Task<InventoryVM> PostPutLotBin(User user, InventoryVM viewModel);
Task<InventoryVM> PostPutReqApproval(User user, InventoryVM viewModel);

View File

@ -0,0 +1,18 @@
using CPRNIMS.Infrastructure.Dto.Inventory.Reports;
using CPRNIMS.Infrastructure.Dto.Inventory.Request;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CPRNIMS.Domain.UIContracts.Inventory
{
public interface IInventoryReports
{
Task<RISReportDto> GetRISReportAsync(InventoryReportsRequest request, CancellationToken ct);
Task<MRSReportDto> GetMRSReportAsync(InventoryReportsRequest request, CancellationToken ct);
Task<InventoryReportDto> GetInventoryReportAsync(InventoryReportsRequest request, CancellationToken ct);
}
}

View File

@ -0,0 +1,22 @@
using CPRNIMS.Infrastructure.Dto.Common;
using CPRNIMS.Infrastructure.Dto.Inventory;
using CPRNIMS.Infrastructure.Dto.Inventory.Request;
using CPRNIMS.Infrastructure.Dto.Inventory.Response;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CPRNIMS.Domain.UIContracts.Inventory
{
public interface IMRS
{
Task<MRSPagedResponse> GetMRSPaged(MRSPagedRequest request, CancellationToken ct);
Task<ApiResponse<object>> CreateMRS(CreateMRSRequest request, CancellationToken ct);
Task<ApiResponse<object>> ApproveMRS(ApproveMRSRequest request, CancellationToken ct);
Task<ApiResponse<object>> CancelMRS(CancelMRSRequest request, CancellationToken ct);
Task<ApiResponse<List<SearchRISProjectCodeResponse>>> SearchRIS(SearchRISProjectCodeRequest request, CancellationToken ct);
Task<ApiResponse<List<ProjectCodeOptionResponse>>> SearchProjects(SearchRISProjectCodeRequest request, CancellationToken ct);
}
}

View File

@ -0,0 +1,20 @@
using CPRNIMS.Infrastructure.Dto.Common;
using CPRNIMS.Infrastructure.Dto.Inventory.Request;
using CPRNIMS.Infrastructure.Dto.Inventory.Response;
using CPRNIMS.Infrastructure.ViewModel.Inventory;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CPRNIMS.Domain.UIContracts.Inventory
{
public interface IRIS
{
Task<ApiResponse<object>> ApproveRIS(ApproveRISRequest request, CancellationToken ct);
Task<ApiResponse<object>> CancelRIS(CancelRISRequest request, CancellationToken ct);
Task<ApiResponse<object>> CreateRIS(CreateRISRequest request, CancellationToken ct);
Task<RISPagedResponse> GetRISPaged(RISPagedRequest request, CancellationToken ct);
}
}

View File

@ -13,7 +13,8 @@ namespace CPRNIMS.Domain.UIContracts.Items
{
public interface IItem
{
Task<List<ItemVM>> GetItemList(User user, ItemVM viewModel);
Task<PagedResult<ItemVM>> GetItemList(
User user, ItemVM viewModel);
Task<List<ItemVM>> GetItemDetail(User user, ItemVM viewModel);
Task<List<ItemVM>> GetItemCateg(User user, ItemVM viewModel);
Task<List<ItemVM>> GetItemLocalization(User userd, ItemVM viewModel);
@ -21,6 +22,7 @@ namespace CPRNIMS.Domain.UIContracts.Items
Task<List<ItemVM>> GetItemUOM(User user, ItemVM viewModel);
Task<List<ItemVM>> GetDepartment(User user, ItemVM viewModel);
Task<List<ItemVM>> GetItemCart(User user, ItemVM viewModel);
Task<List<ItemVM>?> GetProjectCodeByTerm(User user, ItemVM viewModels);
Task<ItemVM> PostPurchRequest(User user, ItemVM viewModel);
Task<ItemVM> PostPutItem(User user, ItemVM viewModel);
Task<ItemVM> PutItemDetail(User user, ItemVM viewModel);

View File

@ -0,0 +1,14 @@
using CPRNIMS.Infrastructure.Entities.PO;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CPRNIMS.Domain.UIContracts.PO
{
public interface ICustomPOService
{
Task<POFormData> GetPOFormDataAsync(long? poId = null);
}
}

View File

@ -11,6 +11,7 @@ namespace CPRNIMS.Domain.UIContracts.PO
public interface IPurchaseOrder
{
#region Get
Task<List<POVM>> GetCurrencies(User user, POVM viewModels);
Task<List<POVM>> GetSupplierBidById(User user, POVM viewModel);
Task<List<POVM>> GetSupplierBidByItem(User user, POVM viewModel);
Task<List<POVM>> GetSupplierBid(User user, POVM viewModel);
@ -40,6 +41,8 @@ namespace CPRNIMS.Domain.UIContracts.PO
Task<List<POVM>?> GetIndexCard(User user, POVM viewModel);
Task<List<POVM>?> GetPortOfDischarge(User user, POVM viewModels);
Task<List<POVM>?> GetIncomingShipment(User user, POVM viewModels);
Task<List<POVM>?> GetPOListByTerm(User user, POVM viewModels);
Task<List<POVM>?> GetIncotermsByName(User user, POVM viewModels);
#endregion
#region Post Put
Task<POVM> PostApprovedSupplier(User user, POVM viewModel);

View File

@ -1,6 +1,5 @@
using CPRNIMS.Infrastructure.Dto.Items;
using CPRNIMS.Infrastructure.Models.Account;
using CPRNIMS.Infrastructure.ViewModel.Items;
using CPRNIMS.Infrastructure.ViewModel.PR;
using System;
using System.Collections.Generic;
@ -12,21 +11,28 @@ namespace CPRNIMS.Domain.UIContracts.PR
{
public interface IPRequest
{
#region Get
Task<PagedResult<PRVM>> GetAllPR(User user, PRVM viewModel);
Task<PagedResult<PRVM>> GetDetailedPRTracking(User user, PRVM viewModel);
Task<PagedResult<PRVM>> GetPRArchived(User user, PRVM viewModel);
Task<PagedResult<PRVM>> GetApprovedPR(User user, PRVM viewModels);
Task<PagedResult<PRVM>> GetDeletedPR(User user, PRVM viewModels);
Task<List<PRVM>?> GetApproverName(User user, PRVM viewModels);
Task<List<PRVM>?> GetApproverNameByPRNo(User user, PRVM viewModels);
Task<List<PRVM>> GetForReceiving(User user, PRVM viewModel);
Task<List<PRVM>> GetItemDetailForReceiving(User user, PRVM viewModel);
Task<List<PRVM>> GetDashBoard(User user, PRVM viewModel);
Task<List<PRVM>> GetPRByRRId(User user, PRVM viewModel);
Task<List<PRVM>> GetRRDetailByPO(User user, PRVM viewModel);
Task<List<PRVM>> GetPRStatusById(User user, PRVM viewModel);
Task<List<PRVM>> GetAllPR(User user, PRVM viewModel);
Task<List<PRVM>> GetPRArchived(User user, PRVM viewModel);
Task<List<PRVM>> GetMyPR(User user, PRVM viewModel);
Task<List<PRVM>> GetPRDetailByPRNo(User user, PRVM viewModel);
Task<List<PRVM>?> GetPRListByPRNo(User user, PRVM viewModels);
Task<List<PRVM>?> GetDetailedPRTracking(User user, PRVM viewModel);
Task<List<PRVM>?> GetSupplierAlternativeOffer(User user, PRVM viewModel);
Task<List<PRVM>?> GetSupplierAlterOfferDetails(User user, PRVM viewModel);
Task<List<PRVM>?> GetProjectCodes(User user, PRVM viewModels);
#endregion
#region Post Put
Task<PRVM> PostPRApproveReject(User user, PRVM viewModel);
Task<PRVM> PostPutItemReceiving(User user, PRVM viewModel);
Task<PRVM> PutItemDetail(User user, PRVM viewModel);
@ -36,5 +42,10 @@ namespace CPRNIMS.Domain.UIContracts.PR
Task<PRVM> PutAlternativeOffer(User user, PRVM viewModel);
Task<PRVM> PutSupplierAlterOffer(User user, PRVM viewModel);
Task<PRVM> PRItemRemoval(User user, PRVM viewModel);
Task<PRVM> ApprovedSelectedPRItem(User user, PRVM viewModel);
Task<PRVM> PostPutProjectCode(User user, PRVM viewModel);
Task<PRVM> PostPutAttachment(User user, PRVM prVM);
Task<PRVM> PostItemInPR(User user, PRVM viewModel);
#endregion
}
}

View File

@ -1,5 +1,6 @@
using CPRNIMS.Domain.UIContracts.Canvass;
using CPRNIMS.Domain.UIContracts.Common;
using CPRNIMS.Infrastructure.Dto.Common;
using CPRNIMS.Infrastructure.Helper;
using CPRNIMS.Infrastructure.Models.Account;
using CPRNIMS.Infrastructure.Models.Common;
@ -123,6 +124,54 @@ namespace CPRNIMS.Domain.UIServices.Canvass
throw;
}
}
public async Task<PagedResult<CanvassVM>> SendGetPageListApiRequest
(User user, CanvassVM viewModel, string apiEndpoint)
{
var token = await _tokenHelper.GetValidTokenAsync();
try
{
if (string.IsNullOrEmpty(token))
{
return null;
}
viewModel.UserId = user.UserId;
var jsonContent = JsonSerializer.Serialize(viewModel);
var content = new StringContent(jsonContent, Encoding.UTF8, "application/json");
using (var httpClient = _apiConfigurationService.CreateHttpClientWithDefaultHeaders(token))
{
HttpResponseMessage response;
response = await httpClient.PostAsync(apiEndpoint, content);
var jsonResponse = await response.Content.ReadAsStringAsync();
if (response.IsSuccessStatusCode)
{
var options = new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
};
viewModel.messCode = 1;
var result = JsonSerializer.Deserialize<PagedResult<CanvassVM>>(jsonResponse, options);
return result;
}
else
{
var result = JsonSerializer.Deserialize<PagedResult<CanvassVM>>(jsonResponse);
viewModel.messCode = 0;
viewModel.errMessage = "Bad request";
return result;
}
}
}
catch (Exception ex)
{
throw;
}
}
#endregion
#region Get
@ -136,11 +185,6 @@ namespace CPRNIMS.Domain.UIServices.Canvass
return await SendGetApiRequest(user, viewModel,
_configuration["LLI:NonInvent:CanvassMgmt:GetSupplierBidByItem"]);
}
public async Task<List<CanvassVM>> GetCanvassPerSupplier(User user, CanvassVM viewModel)
{
return await SendGetApiRequest(user, viewModel,
_configuration["LLI:NonInvent:CanvassMgmt:GetCanvassPerSupplier"]);
}
public async Task<List<CanvassVM>> GetCanvassPerSupplierEmail(User user, CanvassVM viewModel)
{
return await SendGetApiRequest(user, viewModel,
@ -236,6 +280,16 @@ namespace CPRNIMS.Domain.UIServices.Canvass
return await SendGetApiRequest(user, viewModel,
_configuration["LLI:NonInvent:CanvassMgmt:GetAlternativeOfferByPRDetailId"]);
}
public async Task<PagedResult<CanvassVM>> GetCanvassPerSupplier(User user, CanvassVM viewModel)
{
return await SendGetPageListApiRequest(user, viewModel,
_configuration["LLI:NonInvent:CanvassMgmt:GetCanvassPerSupplier"]);
}
public async Task<PagedResult<CanvassVM>> GetItemsForTagging(User user, CanvassVM viewModel)
{
return await SendGetPageListApiRequest(user, viewModel,
_configuration["LLI:NonInvent:CanvassMgmt:GetItemsForTagging"]);
}
#endregion
#region Post Put
public async Task<CanvassVM> PostCanvass(User user, CanvassVM viewModel)
@ -288,6 +342,19 @@ namespace CPRNIMS.Domain.UIServices.Canvass
return await SendPostApiRequest(user, viewModel,
_configuration["LLI:NonInvent:CanvassMgmt:UnlockFormLink"]);
}
public async Task<CanvassVM> StartCanvass(User user, CanvassVM viewModel)
{
return await SendPostApiRequest(user, viewModel,
_configuration["LLI:NonInvent:CanvassMgmt:StartCanvass"]);
}
public async Task<CanvassVM> PostSupplierForCanvass(User user, CanvassVM viewModel)
{
return await SendPostApiRequest(user, viewModel,
_configuration["LLI:NonInvent:CanvassMgmt:PostSupplierForCanvass"]);
}
#endregion
}
}

View File

@ -1,9 +1,11 @@
using CPRNIMS.Domain.UIContracts.Common;
using CPRNIMS.Domain.UIContracts.Inventory;
using CPRNIMS.Infrastructure.Dto.Inventory;
using CPRNIMS.Infrastructure.Dto.Inventory.Request;
using CPRNIMS.Infrastructure.Dto.Inventory.Response;
using CPRNIMS.Infrastructure.Helper;
using CPRNIMS.Infrastructure.Models.Account;
using CPRNIMS.Infrastructure.Models.Common;
using CPRNIMS.Infrastructure.ViewModel.Finance;
using CPRNIMS.Infrastructure.ViewModel.Inventory;
using Microsoft.Extensions.Configuration;
using System;
@ -123,6 +125,73 @@ namespace CPRNIMS.Domain.UIServices.Inventory
throw;
}
}
public async Task<TransactContextDto?> GetTransactContextAsync(int inventoryId)
{
var token = await _tokenHelper.GetValidTokenAsync();
if (string.IsNullOrEmpty(token))
return null;
var apiEndpoint =
_configuration["LLI:NonInvent:InventoryMgmt:GetTransactContext"] ?? "api/InventoryMgmt/GetTransactContext";
using var httpClient = _apiConfigurationService.CreateHttpClientWithDefaultHeaders(token);
var response = await httpClient.GetAsync( $"{apiEndpoint}?inventoryId={inventoryId}");
if (!response.IsSuccessStatusCode)
return null;
var jsonResponse = await response.Content.ReadAsStringAsync();
return JsonSerializer.Deserialize<TransactContextDto>(jsonResponse,
new JsonSerializerOptions{PropertyNameCaseInsensitive = true});
}
public async Task<Infrastructure.Dto.Inventory.PagedResult<InventoryResponse>> SendGetPageListApiRequest
(User user, InventoryRequest request, string apiEndpoint)
{
var token = await _tokenHelper.GetValidTokenAsync();
try
{
if (string.IsNullOrEmpty(token))
{
return null;
}
request.UserId = user.UserId;
var jsonContent = JsonSerializer.Serialize(request);
var content = new StringContent(jsonContent, Encoding.UTF8, "application/json");
using (var httpClient = _apiConfigurationService.CreateHttpClientWithDefaultHeaders(token))
{
HttpResponseMessage response;
response = await httpClient.PostAsync(apiEndpoint, content);
var jsonResponse = await response.Content.ReadAsStringAsync();
if (response.IsSuccessStatusCode)
{
var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true };
var result = JsonSerializer.Deserialize<PagedResult<InventoryResponse>>(jsonResponse, options);
return result ?? new PagedResult<InventoryResponse>();
}
else
{
return new PagedResult<InventoryResponse>
{
IsSuccess = false,
ErrorMessage = $"API returned {response.StatusCode}"
};
}
}
}
catch (Exception ex)
{
throw;
}
}
#endregion
#region Get
public async Task<List<InventoryVM>> GetInventoryById(User user, InventoryVM viewModel)
@ -141,7 +210,11 @@ namespace CPRNIMS.Domain.UIServices.Inventory
return await SendGetApiRequest(user, viewModel,
_configuration["LLI:NonInvent:InventoryMgmt:GetLotNoById"]);
}
public async Task<Infrastructure.Dto.Inventory.PagedResult<InventoryResponse>> GetInventory(User user, InventoryRequest reqquest)
{
return await SendGetPageListApiRequest(user, reqquest,
_configuration["LLI:NonInvent:InventoryMgmt:GetInventory"]);
}
public async Task<List<InventoryVM>> GetInventoryByUserId(User user, InventoryVM viewModel)
{
return await SendGetApiRequest(user, viewModel,
@ -153,7 +226,11 @@ namespace CPRNIMS.Domain.UIServices.Inventory
return await SendGetApiRequest(user, viewModel,
_configuration["LLI:NonInvent:InventoryMgmt:GetRequestedItemByUserId"]);
}
public async Task<List<InventoryVM>> GetLotQtyByItem(User user, InventoryVM viewModel)
{
return await SendGetApiRequest(user, viewModel,
_configuration["LLI:NonInvent:InventoryMgmt:GetLotQtyByItem"]);
}
#endregion
#region Post Put
public async Task<InventoryVM> PostPutReqApproval(User user, InventoryVM viewModel)
@ -177,12 +254,6 @@ namespace CPRNIMS.Domain.UIServices.Inventory
return await SendPostApiRequest(user, viewModel,
_configuration["LLI:NonInvent:InventoryMgmt:PostPutReqItems"]);
}
public async Task<List<InventoryVM>> GetLotQtyByItem(User user, InventoryVM viewModel)
{
return await SendGetApiRequest(user, viewModel,
_configuration["LLI:NonInvent:InventoryMgmt:GetLotQtyByItem"]);
}
#endregion
}
}

View File

@ -0,0 +1,126 @@
using Azure.Core;
using CPRNIMS.Domain.UIContracts.Common;
using CPRNIMS.Domain.UIContracts.Inventory;
using CPRNIMS.Infrastructure.Dto.Inventory.Reports;
using CPRNIMS.Infrastructure.Dto.Inventory.Reports.Response;
using CPRNIMS.Infrastructure.Dto.Inventory.Request;
using CPRNIMS.Infrastructure.Helper;
using Microsoft.AspNetCore.WebUtilities;
using Microsoft.Extensions.Configuration;
using System.Text;
using System.Text.Json;
namespace CPRNIMS.Domain.UIServices.Inventory
{
public class InventoryReports : IInventoryReports
{
private readonly IConfiguration _configuration;
private readonly TokenHelper _tokenHelper;
private readonly IApiConfigurationService _apiConfigurationService;
public InventoryReports(IConfiguration configuration, TokenHelper tokenHelper, IApiConfigurationService apiConfigurationService)
{
_configuration = configuration;
_tokenHelper = tokenHelper;
_apiConfigurationService = apiConfigurationService;
}
private static readonly JsonSerializerOptions _jsonOpts = new()
{
PropertyNameCaseInsensitive = true
};
public async Task<InventoryReportDto> GetInventoryReportAsync(InventoryReportsRequest request, CancellationToken ct)
{
var token = await _tokenHelper.GetValidTokenAsync();
if (string.IsNullOrEmpty(token))
throw new InvalidOperationException("Token has been expired.");
var baseEndpoint = _configuration["LLI:NonInvent:InventoryMgmt:GetInventoryReport"]
?? throw new InvalidOperationException("GetInventoryReport endpoint is not configured.");
var qs = new Dictionary<string, string?>
{
["dateFrom"] = request.DateFrom.ToString("yyyy-MM-dd"),
["dateTo"] = request.DateTo.ToString("yyyy-MM-dd"),
["department"] = request.Department,
["page"] = request.Page.ToString(),
["pageSize"] = request.PageSize.ToString(),
["paginate"] = request.Paginate.ToString().ToLowerInvariant()
};
var url = QueryHelpers.AddQueryString(baseEndpoint, qs);
using var httpClient = _apiConfigurationService.CreateHttpClientWithDefaultHeaders(token);
var response = await httpClient.GetAsync(url, ct);
var json = await response.Content.ReadAsStringAsync(ct);
if (!response.IsSuccessStatusCode)
return new InventoryReportDto();
var result = JsonSerializer.Deserialize<InventoryReportDto>(json, _jsonOpts);
return result ?? new InventoryReportDto();
}
public async Task<MRSReportDto> GetMRSReportAsync(InventoryReportsRequest request, CancellationToken ct)
{
var token = await _tokenHelper.GetValidTokenAsync();
if (string.IsNullOrEmpty(token))
throw new InvalidOperationException("Token has been expired.");
var baseEndpoint = _configuration["LLI:NonInvent:InventoryMgmt:GetMRSReport"]
?? throw new InvalidOperationException("GetMRS endpoint is not configured.");
var qs = new Dictionary<string, string?>
{
["dateFrom"] = request.DateFrom.ToString("yyyy-MM-dd"),
["dateTo"] = request.DateTo.ToString("yyyy-MM-dd"),
["department"] = request.Department,
["page"] = request.Page.ToString(),
["pageSize"] = request.PageSize.ToString(),
["paginate"] = request.Paginate.ToString().ToLowerInvariant()
};
var url = QueryHelpers.AddQueryString(baseEndpoint, qs);
using var httpClient = _apiConfigurationService.CreateHttpClientWithDefaultHeaders(token);
var response = await httpClient.GetAsync(url, ct);
var json = await response.Content.ReadAsStringAsync(ct);
if (!response.IsSuccessStatusCode)
return new MRSReportDto { };
var result = JsonSerializer.Deserialize<MRSReportDto>(json, _jsonOpts);
return result ?? new MRSReportDto();
}
public async Task<RISReportDto> GetRISReportAsync(InventoryReportsRequest request, CancellationToken ct)
{
var token = await _tokenHelper.GetValidTokenAsync();
if (string.IsNullOrEmpty(token))
throw new InvalidOperationException("Token has been expired.");
var baseEndpoint = _configuration["LLI:NonInvent:InventoryMgmt:GetRISReport"]
?? throw new InvalidOperationException("GetMRS endpoint is not configured.");
var qs = new Dictionary<string, string?>
{
["dateFrom"] = request.DateFrom.ToString("yyyy-MM-dd"),
["dateTo"] = request.DateTo.ToString("yyyy-MM-dd"),
["department"] = request.Department,
["page"] = request.Page.ToString(),
["pageSize"] = request.PageSize.ToString(),
["paginate"] = request.Paginate.ToString().ToLowerInvariant()
};
var url = QueryHelpers.AddQueryString(baseEndpoint, qs);
using var httpClient = _apiConfigurationService.CreateHttpClientWithDefaultHeaders(token);
var response = await httpClient.GetAsync(url, ct);
var json = await response.Content.ReadAsStringAsync(ct);
if (!response.IsSuccessStatusCode)
return new RISReportDto {};
var result = JsonSerializer.Deserialize<RISReportDto>(json, _jsonOpts);
return result ?? new RISReportDto();
}
}
}

View File

@ -0,0 +1,197 @@
using Azure.Core;
using CPRNIMS.Domain.Services;
using CPRNIMS.Domain.UIContracts.Common;
using CPRNIMS.Domain.UIContracts.Inventory;
using CPRNIMS.Infrastructure.Dto.Common;
using CPRNIMS.Infrastructure.Dto.Inventory;
using CPRNIMS.Infrastructure.Dto.Inventory.Request;
using CPRNIMS.Infrastructure.Dto.Inventory.Response;
using CPRNIMS.Infrastructure.Helper;
using Microsoft.Extensions.Configuration;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
namespace CPRNIMS.Domain.UIServices.Inventory
{
public class MRS : IMRS
{
private readonly IConfiguration _configuration;
private readonly TokenHelper _tokenHelper;
private readonly IApiConfigurationService _apiConfigurationService;
public MRS(IConfiguration configuration, TokenHelper tokenHelper,IApiConfigurationService apiConfigurationService)
{
_configuration = configuration;
_tokenHelper = tokenHelper;
_apiConfigurationService = apiConfigurationService;
}
private static readonly JsonSerializerOptions _mrsJsonOpts = new()
{
PropertyNameCaseInsensitive = true
};
public async Task<MRSPagedResponse> GetMRSPaged(MRSPagedRequest request, CancellationToken ct)
{
var token = await _tokenHelper.GetValidTokenAsync();
if (string.IsNullOrEmpty(token))
throw new InvalidOperationException("Token has been expired.");
var baseEndpoint = _configuration["LLI:NonInvent:InventoryMgmt:GetMRS"]
?? throw new InvalidOperationException("GetMRS endpoint is not configured.");
var qs = new StringBuilder(baseEndpoint).Append('?');
qs.Append($"pageNumber={request.PageNumber}&pageSize={request.PageSize}");
if (!string.IsNullOrWhiteSpace(request.SearchMRSNo))
qs.Append($"&searchMRSNo={Uri.EscapeDataString(request.SearchMRSNo)}");
if (!string.IsNullOrWhiteSpace(request.SearchRISNo))
qs.Append($"&searchRISNo={Uri.EscapeDataString(request.SearchRISNo)}");
if (!string.IsNullOrWhiteSpace(request.SearchItemName))
qs.Append($"&searchItemName={Uri.EscapeDataString(request.SearchItemName)}");
if (!string.IsNullOrWhiteSpace(request.SearchReturnedBy))
qs.Append($"&searchReturnedBy={Uri.EscapeDataString(request.SearchReturnedBy)}");
if (request.Status.HasValue)
qs.Append($"&status={request.Status.Value}");
if (!string.IsNullOrWhiteSpace(request.Condition))
qs.Append($"&condition={Uri.EscapeDataString(request.Condition)}");
using var http = _apiConfigurationService.CreateHttpClientWithDefaultHeaders(token);
var response = await http.GetAsync(qs.ToString(), ct);
var json = await response.Content.ReadAsStringAsync(ct);
if (!response.IsSuccessStatusCode)
return new MRSPagedResponse { Data = [], RecordsTotal = 0 };
var result = JsonSerializer.Deserialize<MRSPagedResponse>(json, _mrsJsonOpts);
return result ?? new MRSPagedResponse();
}
public async Task<ApiResponse<object>> CreateMRS(CreateMRSRequest request, CancellationToken ct)
{
var token = await _tokenHelper.GetValidTokenAsync();
if (string.IsNullOrEmpty(token))
throw new InvalidOperationException("Token has been expired.");
var endpoint = _configuration["LLI:NonInvent:InventoryMgmt:CreateMRS"]
?? throw new InvalidOperationException("CreateMRS endpoint is not configured.");
using var http = _apiConfigurationService.CreateHttpClientWithDefaultHeaders(token);
using var content = new StringContent(JsonSerializer.Serialize(request), Encoding.UTF8, "application/json");
var response = await http.PostAsync(endpoint, content, ct);
var json = await response.Content.ReadAsStringAsync(ct);
var result = JsonSerializer.Deserialize<ApiResponse<object>>(json, _mrsJsonOpts)
?? new ApiResponse<object> { success = false, message = $"HTTP {(int)response.StatusCode}" };
if (!response.IsSuccessStatusCode)
result.success = false;
return result;
}
public async Task<ApiResponse<object>> ApproveMRS(ApproveMRSRequest request, CancellationToken ct)
{
var token = await _tokenHelper.GetValidTokenAsync();
if (string.IsNullOrEmpty(token))
throw new InvalidOperationException("Token has been expired.");
var endpoint = _configuration["LLI:NonInvent:InventoryMgmt:ApproveMRS"]
?? throw new InvalidOperationException("ApproveMRS endpoint is not configured.");
using var http = _apiConfigurationService.CreateHttpClientWithDefaultHeaders(token);
using var content = new StringContent(
JsonSerializer.Serialize(request),
Encoding.UTF8, "application/json");
var response = await http.PostAsync(endpoint, content, ct);
var json = await response.Content.ReadAsStringAsync(ct);
var result = JsonSerializer.Deserialize<ApiResponse<object>>(json, _mrsJsonOpts)
?? new ApiResponse<object> { success = false, message = $"HTTP {(int)response.StatusCode}" };
if (!response.IsSuccessStatusCode)
result.success = false;
return result;
}
public async Task<ApiResponse<object>> CancelMRS(CancelMRSRequest request, CancellationToken ct)
{
var token = await _tokenHelper.GetValidTokenAsync();
if (string.IsNullOrEmpty(token))
throw new InvalidOperationException("Token has been expired.");
var endpoint = _configuration["LLI:NonInvent:InventoryMgmt:CancelMRS"]
?? throw new InvalidOperationException("CancelMRS endpoint is not configured.");
using var http = _apiConfigurationService.CreateHttpClientWithDefaultHeaders(token);
using var content = new StringContent(
JsonSerializer.Serialize(request),
Encoding.UTF8, "application/json");
var response = await http.PostAsync(endpoint, content, ct);
var json = await response.Content.ReadAsStringAsync(ct);
var result = JsonSerializer.Deserialize<ApiResponse<object>>(json, _mrsJsonOpts)
?? new ApiResponse<object> { success = false, message = $"HTTP {(int)response.StatusCode}" };
if (!response.IsSuccessStatusCode)
result.success = false;
return result;
}
public async Task<ApiResponse<List<SearchRISProjectCodeResponse>>> SearchRIS(SearchRISProjectCodeRequest request, CancellationToken ct)
{
var token = await _tokenHelper.GetValidTokenAsync();
if (string.IsNullOrEmpty(token))
throw new InvalidOperationException("Token has been expired.");
var baseEndpoint = _configuration["LLI:NonInvent:InventoryMgmt:SearchRIS"]
?? throw new InvalidOperationException("GetMRS endpoint is not configured.");
var qs = new StringBuilder(baseEndpoint).Append('?');
if (!string.IsNullOrWhiteSpace(request.SearchRISNo))
qs.Append($"&searchRISNo={Uri.EscapeDataString(request.SearchRISNo)}");
if (!string.IsNullOrWhiteSpace(request.SearchRISNo))
qs.Append($"&projectCodeId= {request.SearchProjectCodeId}");
using var http = _apiConfigurationService.CreateHttpClientWithDefaultHeaders(token);
var response = await http.GetAsync(qs.ToString(), ct);
var json = await response.Content.ReadAsStringAsync(ct);
if (!response.IsSuccessStatusCode)
return new ApiResponse<List<SearchRISProjectCodeResponse>>{ };
var result = JsonSerializer.Deserialize<ApiResponse<List<SearchRISProjectCodeResponse>>>(json, _mrsJsonOpts);
return result ?? new ApiResponse<List<SearchRISProjectCodeResponse>>();
}
public async Task<ApiResponse<List<ProjectCodeOptionResponse>>> SearchProjects(SearchRISProjectCodeRequest request, CancellationToken ct)
{
var token = await _tokenHelper.GetValidTokenAsync();
if (string.IsNullOrEmpty(token))
throw new InvalidOperationException("Token has expired.");
var baseEndpoint = _configuration["LLI:NonInvent:InventoryMgmt:SearchProjects"]
?? throw new InvalidOperationException("SearchProjects endpoint is not configured.");
var qs = new StringBuilder(baseEndpoint);
if (!string.IsNullOrWhiteSpace(request.SearchProjectCode))
qs.Append('?').Append("searchProjectCode=").Append(Uri.EscapeDataString(request.SearchProjectCode));
using var http = _apiConfigurationService.CreateHttpClientWithDefaultHeaders(token);
var response = await http.GetAsync(qs.ToString(), ct);
var json = await response.Content.ReadAsStringAsync(ct);
if (!response.IsSuccessStatusCode)
return new ApiResponse<List<ProjectCodeOptionResponse>>();
var result = JsonSerializer.Deserialize<ApiResponse<List<ProjectCodeOptionResponse>>>(json, _mrsJsonOpts);
return result ?? new ApiResponse<List<ProjectCodeOptionResponse>>();
}
}
}

View File

@ -0,0 +1,157 @@
using CPRNIMS.Domain.UIContracts.Common;
using CPRNIMS.Domain.UIContracts.Inventory;
using CPRNIMS.Infrastructure.Dto.Common;
using CPRNIMS.Infrastructure.Dto.Inventory.Request;
using CPRNIMS.Infrastructure.Dto.Inventory.Response;
using CPRNIMS.Infrastructure.Dto.PR.Response;
using CPRNIMS.Infrastructure.Helper;
using Microsoft.Extensions.Configuration;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
namespace CPRNIMS.Domain.UIServices.Inventory
{
public class RIS : IRIS
{
private readonly IConfiguration _configuration;
private readonly TokenHelper _tokenHelper;
private readonly IApiConfigurationService _apiConfigurationService;
public RIS(IConfiguration configuration, TokenHelper tokenHelper,
IApiConfigurationService apiConfigurationService)
{
_configuration = configuration;
_tokenHelper = tokenHelper;
_apiConfigurationService = apiConfigurationService;
}
#region Get
public async Task<RISPagedResponse> GetRISPaged(RISPagedRequest request, CancellationToken ct)
{
var token = await _tokenHelper.GetValidTokenAsync();
if (string.IsNullOrEmpty(token))
throw new InvalidOperationException("Token has been expired.");
var baseEndpoint = _configuration["LLI:NonInvent:InventoryMgmt:GetRIS"]
?? throw new InvalidOperationException("GetRIS endpoint is not configured.");
// ── Build query string — GET request, no body ──
var qs = new StringBuilder(baseEndpoint).Append('?');
qs.Append($"pageNumber={request.PageNumber}");
qs.Append($"&pageSize={request.PageSize}");
if (!string.IsNullOrWhiteSpace(request.SearchRISNo))
qs.Append($"&searchRISNo={Uri.EscapeDataString(request.SearchRISNo)}");
if (!string.IsNullOrWhiteSpace(request.SearchItemName))
qs.Append($"&searchItemName={Uri.EscapeDataString(request.SearchItemName)}");
if (!string.IsNullOrWhiteSpace(request.SearchIssuedTo))
qs.Append($"&searchIssuedTo={Uri.EscapeDataString(request.SearchIssuedTo)}");
if (!string.IsNullOrWhiteSpace(request.Discipline))
qs.Append($"&discipline={Uri.EscapeDataString(request.Discipline)}");
if (request.Status.HasValue)
qs.Append($"&status={request.Status.Value}");
using var httpClient = _apiConfigurationService.CreateHttpClientWithDefaultHeaders(token);
// ── GET, no content body ──
var response = await httpClient.GetAsync(qs.ToString(), ct);
var json = await response.Content.ReadAsStringAsync(ct);
if (!response.IsSuccessStatusCode)
{
Console.WriteLine($"[GetRISPaged] Error {(int)response.StatusCode}: {json}");
return new RISPagedResponse { Data = [], RecordsTotal = 0 };
}
var result = JsonSerializer.Deserialize<RISPagedResponse>(json, _jsonOptions);
return result ?? new RISPagedResponse();
}
#endregion
#region Post Put
public async Task<ApiResponse<object>> ApproveRIS(ApproveRISRequest request, CancellationToken ct)
{
var token = await _tokenHelper.GetValidTokenAsync();
if (string.IsNullOrEmpty(token))
throw new InvalidOperationException("Token has been expired.");
var endpoint = _configuration["LLI:NonInvent:InventoryMgmt:ApproveRIS"]
?? throw new InvalidOperationException("ApproveRIS endpoint is not configured.");
using var httpClient = _apiConfigurationService.CreateHttpClientWithDefaultHeaders(token);
using var content = new StringContent(JsonSerializer.Serialize(request),Encoding.UTF8,"application/json");
var response = await httpClient.PutAsync(endpoint, content, ct);
var json = await response.Content.ReadAsStringAsync(ct);
var result = JsonSerializer.Deserialize<ApiResponse<object>>(json, _jsonOptions)
?? new ApiResponse<object> { success = false, message = $"HTTP {(int)response.StatusCode}" };
if (!response.IsSuccessStatusCode)
result.success = false;
return result;
}
public async Task<ApiResponse<object>> CancelRIS(CancelRISRequest request, CancellationToken ct)
{
var token = await _tokenHelper.GetValidTokenAsync();
if (string.IsNullOrEmpty(token))
throw new InvalidOperationException("Token has been expired.");
var endpoint = _configuration["LLI:NonInvent:InventoryMgmt:CancelRIS"]
?? throw new InvalidOperationException("CancelRIS endpoint is not configured.");
using var httpClient = _apiConfigurationService.CreateHttpClientWithDefaultHeaders(token);
using var content = new StringContent(JsonSerializer.Serialize(request), Encoding.UTF8, "application/json");
var response = await httpClient.PutAsync(endpoint, content, ct);
var json = await response.Content.ReadAsStringAsync(ct);
var result = JsonSerializer.Deserialize<ApiResponse<object>>(json, _jsonOptions)
?? new ApiResponse<object> { success = false, message = $"HTTP {(int)response.StatusCode}" };
if (!response.IsSuccessStatusCode)
result.success = false;
return result;
}
public async Task<ApiResponse<object>> CreateRIS(CreateRISRequest request, CancellationToken ct)
{
var token = await _tokenHelper.GetValidTokenAsync();
if (string.IsNullOrEmpty(token))
throw new InvalidOperationException("Token has been expired.");
var endpoint = _configuration["LLI:NonInvent:InventoryMgmt:CreateRIS"] ??
throw new InvalidOperationException("CreateRIS endpoint is not configured.");
using var httpClient = _apiConfigurationService.CreateHttpClientWithDefaultHeaders(token);
using var content = new StringContent(JsonSerializer.Serialize(request),Encoding.UTF8,"application/json");
var response = await httpClient.PostAsync(endpoint, content,ct);
var json = await response.Content.ReadAsStringAsync();
var result = JsonSerializer.Deserialize<ApiResponse<object>>(json, _jsonOptions)
?? new ApiResponse<object> { success = false, message = $"HTTP {(int)response.StatusCode}" };
if (!response.IsSuccessStatusCode)
result.success = false;
return result;
}
private static readonly JsonSerializerOptions _jsonOptions = new()
{
PropertyNameCaseInsensitive = true
};
#endregion
}
}

View File

@ -1,5 +1,6 @@
using CPRNIMS.Domain.UIContracts.Common;
using CPRNIMS.Domain.UIContracts.Items;
using CPRNIMS.Infrastructure.Dto.Items;
using CPRNIMS.Infrastructure.Helper;
using CPRNIMS.Infrastructure.Models.Account;
using CPRNIMS.Infrastructure.Models.Common;
@ -31,7 +32,61 @@ namespace CPRNIMS.Domain.UIServices.Items
_apiConfigurationService = apiConfigurationService;
}
#region SendRequest service
public async Task<PagedResult<ItemVM>> GetItemList(
Infrastructure.Models.Account.User user, ItemVM viewModel)
{
return await SendGetPageListApiRequest(user, viewModel,
_configuration["LLI:NonInvent:ItemMgmt:GetItemList"]);
}
public async Task<PagedResult<ItemVM>> SendGetPageListApiRequest
(Infrastructure.Models.Account.User user,ItemVM viewModel,string apiEndpoint)
{
var token = await _tokenHelper.GetValidTokenAsync();
try
{
if (string.IsNullOrEmpty(token))
{
// Handle token retrieval failure
return null;
}
viewModel.UserId = user.UserId;
var jsonContent = JsonSerializer.Serialize(viewModel);
var content = new StringContent(jsonContent, Encoding.UTF8, "application/json");
using (var httpClient = _apiConfigurationService.CreateHttpClientWithDefaultHeaders(token))
{
HttpResponseMessage response;
response = await httpClient.PostAsync(apiEndpoint, content);
var jsonResponse = await response.Content.ReadAsStringAsync();
if (response.IsSuccessStatusCode)
{
var options = new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
};
viewModel.messCode = 1;
var myArtWork = JsonSerializer.Deserialize<PagedResult<ItemVM>>(jsonResponse, options);
return myArtWork;
}
else
{
var myArtWork = JsonSerializer.Deserialize<PagedResult<ItemVM>>(jsonResponse);
viewModel.messCode = 0;
viewModel.message = "Bad request";
return myArtWork;
}
}
}
catch (Exception ex)
{
throw;
}
}
public async Task<ItemVM> SendPostApiRequest(Infrastructure.Models.Account.User user,
ItemVM viewModel, string apiEndpoint)
{
@ -129,6 +184,11 @@ namespace CPRNIMS.Domain.UIServices.Items
}
#endregion
#region Get Method
public async Task<List<ItemVM>> GetProjectCodeByTerm(Infrastructure.Models.Account.User user, ItemVM viewModel)
{
return await SendGetApiRequest(user, viewModel,
_configuration["LLI:NonInvent:ItemMgmt:GetProjectCodeByTerm"]);
}
public async Task<List<ItemVM>> GetItemDetail(Infrastructure.Models.Account.User user,
ItemVM viewModel)
{
@ -141,13 +201,13 @@ namespace CPRNIMS.Domain.UIServices.Items
return await SendGetApiRequest(user, viewModel,
_configuration["LLI:NonInvent:ItemMgmt:GetItemCart"]);
}
public async Task<List<ItemVM>> GetItemList(Infrastructure.Models.Account.User user,
/* public async Task<List<ItemVM>> GetItemList(Infrastructure.Models.Account.User user,
ItemVM viewModel)
{
return await SendGetApiRequest(user, viewModel,
_configuration["LLI:NonInvent:ItemMgmt:GetItemList"]);
}
*/
public async Task<List<ItemVM>> GetItemCateg(Infrastructure.Models.Account.User user, ItemVM viewModel)
{
return await SendGetApiRequest(user, viewModel,

View File

@ -0,0 +1,76 @@
using CPRNIMS.Domain.UIContracts.PO;
using CPRNIMS.Infrastructure.Entities.PO;
using CPRNIMS.Infrastructure.Helper;
using Google.Apis.Services;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
namespace CPRNIMS.Domain.UIServices.PO
{
public class CustomPOService : ICustomPOService
{
private readonly IHttpClientFactory _httpClientFactory;
private readonly TokenHelper _tokenHelper;
private readonly IConfiguration _configuration;
private readonly ILogger<CustomPOService> _logger;
public CustomPOService(
IHttpClientFactory httpClientFactory,
TokenHelper tokenHelper,
IConfiguration configuration,
ILogger<CustomPOService> logger)
{
_httpClientFactory = httpClientFactory;
_tokenHelper = tokenHelper;
_configuration = configuration;
_logger = logger;
}
public async Task<POFormData> GetPOFormDataAsync(long? poId = null)
{
try
{
var token = await _tokenHelper.GetValidTokenAsync();
if (string.IsNullOrEmpty(token))
throw new UnauthorizedAccessException("No valid token available.");
var httpClient = _httpClientFactory.CreateClient("AuthApi");
httpClient.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", token);
var url = _configuration["LLI:NonInvent:POMgmt:GetPOFormData"];
if (poId.HasValue)
url += $"?poId={poId}";
var response = await httpClient.GetAsync(url);
if (!response.IsSuccessStatusCode)
{
_logger.LogError("GetPOFormData failed: {StatusCode}", response.StatusCode);
return new POFormData();
}
var json = await response.Content.ReadAsStringAsync();
var result = JsonSerializer.Deserialize<POFormData>(json, new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true
});
return result ?? new POFormData();
}
catch (Exception ex)
{
_logger.LogError(ex, "Error in GetPOFormDataAsync");
return new POFormData();
}
}
}
}

View File

@ -126,6 +126,17 @@ namespace CPRNIMS.Domain.UIServices.PO
#endregion
#region Get
public async Task<List<POVM>?> GetIncotermsByName(User user, POVM viewModel)
{
return await SendGetApiRequest(user, viewModel,
_configuration["LLI:NonInvent:POMgmt:GetIncotermsByName"]);
}
public async Task<List<POVM>?> GetPOListByTerm(User user, POVM viewModel)
{
return await SendGetApiRequest(user, viewModel,
_configuration["LLI:NonInvent:POMgmt:GetPOListByTerm"]);
}
public async Task<List<POVM>?> GetIncomingShipment(User user, POVM viewModel)
{
return await SendGetApiRequest(user, viewModel,
@ -273,6 +284,11 @@ namespace CPRNIMS.Domain.UIServices.PO
return await SendGetApiRequest(user, viewModel,
_configuration["LLI:NonInvent:POMgmt:GetPortOfDischarge"]);
}
public async Task<List<POVM>> GetCurrencies(User user, POVM viewModel)
{
return await SendGetApiRequest(user, viewModel,
_configuration["LLI:NonInvent:POMgmt:GetCurrencies"]);
}
#endregion
#region Post Put
public async Task<POVM> PostApprovedSupplier(User user, POVM viewModel)

View File

@ -1,5 +1,6 @@
using CPRNIMS.Domain.UIContracts.Common;
using CPRNIMS.Domain.UIContracts.PR;
using CPRNIMS.Infrastructure.Dto.Items;
using CPRNIMS.Infrastructure.Helper;
using CPRNIMS.Infrastructure.Models.Account;
using CPRNIMS.Infrastructure.Models.Common;
@ -7,7 +8,6 @@ using CPRNIMS.Infrastructure.ViewModel.PR;
using Microsoft.Extensions.Configuration;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
namespace CPRNIMS.Domain.UIServices.PR
{
@ -116,15 +116,95 @@ namespace CPRNIMS.Domain.UIServices.PR
}
#endregion
#region Get
public async Task<List<PRVM>?> GetProjectCodes(User user, PRVM viewModel)
{
return await SendGetApiRequest(user, viewModel,
_configuration["LLI:NonInvent:PRMgmt:GetProjectCodes"]);
}
public async Task<List<PRVM>?> GetApproverName(User user, PRVM viewModel)
{
return await SendGetApiRequest(user, viewModel,
_configuration["LLI:NonInvent:PRMgmt:GetApproverName"]);
}
public async Task<List<PRVM>> GetAllPR(User user, PRVM viewModel)
public async Task<List<PRVM>?> GetApproverNameByPRNo(User user, PRVM viewModel)
{
return await SendGetApiRequest(user, viewModel,
_configuration["LLI:NonInvent:PRMgmt:GetAllPR"]);
_configuration["LLI:NonInvent:PRMgmt:GetApproverNameByPRNo"]);
}
public async Task<PagedResult<PRVM>> GetAllPR(
User user, PRVM viewModel)
{
return await SendGetPageListApiRequest(user, viewModel,
_configuration["LLI:NonInvent:PRMgmt:GetAllPR"]);
}
public async Task<PagedResult<PRVM>> GetPRArchived(
User user, PRVM viewModel)
{
return await SendGetPageListApiRequest(user, viewModel,
_configuration["LLI:NonInvent:PRMgmt:GetPRArchived"]);
}
public async Task<PagedResult<PRVM>> GetDeletedPR(User user, PRVM viewModel)
{
return await SendGetPageListApiRequest(user, viewModel,
_configuration["LLI:NonInvent:PRMgmt:GetDeletedPR"]);
}
public async Task<PagedResult<PRVM>> GetApprovedPR(User user, PRVM viewModel)
{
return await SendGetPageListApiRequest(user, viewModel,
_configuration["LLI:NonInvent:PRMgmt:GetApprovedPR"]);
}
public async Task<PagedResult<PRVM>> GetDetailedPRTracking(User user, PRVM viewModel)
{
return await SendGetPageListApiRequest(user, viewModel,
_configuration["LLI:NonInvent:PRMgmt:GetDetailedPRTracking"]);
}
public async Task<PagedResult<PRVM>> SendGetPageListApiRequest
(User user, PRVM viewModel, string apiEndpoint)
{
var token = await _tokenHelper.GetValidTokenAsync();
try
{
if (string.IsNullOrEmpty(token))
{
return null;
}
viewModel.UserId = user.UserId;
var jsonContent = JsonSerializer.Serialize(viewModel);
var content = new StringContent(jsonContent, Encoding.UTF8, "application/json");
using (var httpClient = _apiConfigurationService.CreateHttpClientWithDefaultHeaders(token))
{
HttpResponseMessage response;
response = await httpClient.PostAsync(apiEndpoint, content);
var jsonResponse = await response.Content.ReadAsStringAsync();
if (response.IsSuccessStatusCode)
{
var options = new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
};
viewModel.messCode = 1;
var myArtWork = JsonSerializer.Deserialize<PagedResult<PRVM>>(jsonResponse, options);
return myArtWork;
}
else
{
var myArtWork = JsonSerializer.Deserialize<PagedResult<PRVM>>(jsonResponse);
viewModel.messCode = 0;
viewModel.message = "Bad request";
return myArtWork;
}
}
}
catch (Exception ex)
{
throw;
}
}
public async Task<List<PRVM>> GetMyPR(User user, PRVM viewModel)
{
@ -166,21 +246,11 @@ namespace CPRNIMS.Domain.UIServices.PR
return await SendGetApiRequest(user, viewModel,
_configuration["LLI:NonInvent:PRMgmt:GetDashBoard"]);
}
public async Task<List<PRVM>> GetPRArchived(User user, PRVM viewModel)
{
return await SendGetApiRequest(user, viewModel,
_configuration["LLI:NonInvent:PRMgmt:GetPRArchived"]);
}
public async Task<List<PRVM>?> GetPRListByPRNo(User user, PRVM viewModel)
{
return await SendGetApiRequest(user, viewModel,
_configuration["LLI:NonInvent:PRMgmt:GetPRListByPRNo"]);
}
public async Task<List<PRVM>?> GetDetailedPRTracking(User user, PRVM viewModel)
{
return await SendGetApiRequest(user, viewModel,
_configuration["LLI:NonInvent:PRMgmt:GetDetailedPRTracking"]);
}
public async Task<List<PRVM>?> GetSupplierAlternativeOffer(User user, PRVM viewModel)
{
return await SendGetApiRequest(user, viewModel,
@ -248,6 +318,29 @@ namespace CPRNIMS.Domain.UIServices.PR
return await SendPostApiRequest(user, viewModel,
_configuration["LLI:NonInvent:PRMgmt:PRItemRemoval"]);
}
public async Task<PRVM> ApprovedSelectedPRItem(User user, PRVM viewModel)
{
return await SendPostApiRequest(user, viewModel,
_configuration["LLI:NonInvent:PRMgmt:ApprovedSelectedPRItem"]);
}
public async Task<PRVM> PostPutProjectCode(User user, PRVM viewModel)
{
return await SendPostApiRequest(user, viewModel,
_configuration["LLI:NonInvent:PRMgmt:PostPutProjectCode"]);
}
public async Task<PRVM> PostPutAttachment(User user, PRVM prVM)
{
return await SendPostApiRequest(user, prVM,
_configuration["LLI:NonInvent:PRMgmt:PostPutAttachment"]);
}
public async Task<PRVM> PostItemInPR(User user, PRVM prVM)
{
return await SendPostApiRequest(user, prVM,
_configuration["LLI:NonInvent:PRMgmt:PostItemInPR"]);
}
#endregion
}
}

View File

@ -23,4 +23,8 @@
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup>
<ItemGroup>
<Folder Include="Dto\PR\Request\" />
</ItemGroup>
</Project>

View File

@ -1,4 +1,6 @@
using CPRNIMS.Infrastructure.Entities.Account;
using CPRNIMS.Infrastructure.Dto.Canvass.Response;
using CPRNIMS.Infrastructure.Dto.Inventory.Response;
using CPRNIMS.Infrastructure.Entities.Account;
using CPRNIMS.Infrastructure.Entities.Canvass;
using CPRNIMS.Infrastructure.Entities.Common;
using CPRNIMS.Infrastructure.Entities.Finance;
@ -21,9 +23,7 @@ namespace CPRNIMS.Infrastructure.Database
public class NonInventoryDbContext : IdentityDbContext<ApplicationUser>
{
public NonInventoryDbContext(DbContextOptions<NonInventoryDbContext> options) : base(options) { }
public virtual DbSet<ItemCode> ItemCodes { get; set; }
public virtual DbSet<ItemList> ItemList { get; set; }
public virtual DbSet<Item> Items { get; set; }
#region Common
public DbSet<Departments> Departments { get; set; }
public DbSet<IdentityRole> IdentityRoles { get; set; }
public DbSet<AuthorizeRoles> AuthorizeRoles { get; set; }
@ -31,35 +31,57 @@ namespace CPRNIMS.Infrastructure.Database
public DbSet<IdentityUserRole<string>> IdentityUserRoles { get; set; }
public DbSet<ForgotPassword> ForgotPasswords { get; set; }
public virtual DbSet<Otps> Otps { get; set; }
public virtual DbSet<ErrorMessage> ErrorMessages { get; set; }
public virtual DbSet<ControllerAccess> ControllerAccess { get; set; }
public virtual DbSet<SMTPCredential> SMTPCredentials { get; set; }
#endregion
#region Item
public virtual DbSet<ItemCode> ItemCodes { get; set; }
public virtual DbSet<ItemList> ItemList { get; set; }
public virtual DbSet<Item> Items { get; set; }
public DbSet<ItemDtos> ItemDtos { get; set; }
public DbSet<Attachment> Attachments { get; set; }
public virtual DbSet<AttachmentExtension> AttachmentExtensions { get; set; }
public virtual DbSet<AttachmentFileType> AttachmentFileTypes { get; set; }
public virtual DbSet<ItemAttachement> ItemAttachements { get; set; }
public virtual DbSet<ErrorMessage> ErrorMessages { get; set; }
public virtual DbSet<ControllerAccess> ControllerAccess { get; set; }
public virtual DbSet<ItemCategory> ItemCategories { get; set; }
public virtual DbSet<UnitOfMessure> UnitOfMessures { get; set; }
public virtual DbSet<ItemColor> ItemColors { get; set; }
public virtual DbSet<ItemLocalization> ItemLocalizations { get; set; }
public virtual DbSet<ItemCart> ItemCarts { get; set; }
public virtual DbSet<ItemApproval> ItemApprovals { get; set; }
public virtual DbSet<Entities.Inventory.ItemDetail> ItemDetails { get; set; }
#endregion
#region PR
public virtual DbSet<PR> PRs { get; set; }
public virtual DbSet<Approved> Approved { get; set; }
public virtual DbSet<SMTPCredential> SMTPCredentials { get; set; }
public virtual DbSet<ApprovedPR> ApprovedPrs { get; set; }
public virtual DbSet<DeletedPR> DeletedPRs { get; set; }
public virtual DbSet<PRDetails> PRDetails { get; set; }
public virtual DbSet<PRItemList> PRItemLists { get; set; }
public DbSet<PRAttachments> PRAttachments { get; set; }
public DbSet<ProjectCodes> ProjectCodes { get; set; }
public virtual DbSet<Entities.Purchasing.PRList> PRLists { get; set; }
public virtual DbSet<Entities.Canvass.PRList> PRItemList { get; set; }
public virtual DbSet<PRWOCanvass> PRWOCanvasses { get; set; }
public virtual DbSet<Entities.PO.ItemDetail> PRItemDetails { get; set; }
public virtual DbSet<DetailedPRTracking> DetailedPRTrackings { get; set; }
public virtual DbSet<PRTracking> PRTrackings { get; set; }
public virtual DbSet<Dashboard> Dashboards { get; set; }
#endregion
#region Canvassing
public virtual DbSet<NotificationById> NotificationByIds { get; set; }
public virtual DbSet<AlternativeOffer> AlternativeOffers { get; set; }
public virtual DbSet<AlternativeOfferDetails> AlternativeOfferDetails { get; set; }
public virtual DbSet<MyPRWOCanvass> MyPRWOCanvass { get; set; }
public virtual DbSet<Entities.Purchasing.PRList> PRLists { get; set; }
public virtual DbSet<Entities.Canvass.PRList> PRItemList { get; set; }
public virtual DbSet<ItemApproval> ItemApprovals { get; set; }
public virtual DbSet<ForReceiving> ForReceivings { get; set; }
public virtual DbSet<Infrastructure.Entities.Receiving.RRReport> RRReports { get; set; }
public virtual DbSet<ReceivingDetail> ReceivingDetails { get; set; }
public virtual DbSet<RRDetail> RRDetails { get; set; }
public virtual DbSet<ForRR> ForRRs { get; set; }
public virtual DbSet<RR> RRs { get; set; }
public virtual DbSet<Canvass> Canvasses { get; set; }
public DbSet<SupplierForCanvass> SupplierForCanvass { get; set; }
public DbSet<SupplierResponseDto> SupplierResponses { get; set; }
public DbSet<SupplierItems> SupplierItems { get; set; }
public DbSet<ItemsForTagging> ItemsForTaggings { get; set; }
public virtual DbSet<ForCanvassFollowUp> ForCanvassFollowUps { get; set; }
public virtual DbSet<WOResponse> WOResponses { get; set; }
public virtual DbSet<WOResponseById> WOResponseByIds { get; set; }
@ -73,8 +95,13 @@ namespace CPRNIMS.Infrastructure.Database
public virtual DbSet<CanvassSupplier> CanvassSuppliers { get; set; }
public virtual DbSet<RFQReference> RFQReferences { get; set; }
public virtual DbSet<CanvassDetail> CanvassDetails { get; set; }
public virtual DbSet<PRCanvassDetail> PRCanvassDetails { get; set; }
public DbSet<ForAISearchingTagging> ForAISearchingTaggings { get; set; }
public virtual DbSet<CanvassGroupByPRNo> CanvassGroupByPRNos { get; set; }
public virtual DbSet<ForCanvass> ForCanvasses { get; set; }
#endregion
#region PO
public virtual DbSet<ForPO> ForPOs { get; set; }
public virtual DbSet<CreatedPO> CreatedPOs { get; set; }
public virtual DbSet<CustomPO> CustomPOs { get; set; }
@ -82,7 +109,9 @@ namespace CPRNIMS.Infrastructure.Database
public virtual DbSet<ForPOApproval> ForPOApprovals { get; set; }
public virtual DbSet<ApprovedPO> ApprovedPOs { get; set; }
public virtual DbSet<PurchaseOrder> PurchaseOrders { get; set; }
public virtual DbSet<ForPayment> ForPayments { get; set; }
public virtual DbSet<PO> POs { get; set; }
public DbSet<PODetails> PODetails { get; set; }
public virtual DbSet<PRPOSummaryCount> PRPOSummaryCounts { get; set; }
public virtual DbSet<PRPOSummaryItem> PRPOSummaryItems { get; set; }
public virtual DbSet<POItemDetail> POItemDetails { get; set; }
@ -90,32 +119,49 @@ namespace CPRNIMS.Infrastructure.Database
public virtual DbSet<PortOfDischarges> PortOfDischarges { get; set; }
public virtual DbSet<DocRequired> DocRequireds { get; set; }
public virtual DbSet<BiddingApproval> BiddingApprovals { get; set; }
public virtual DbSet<Entities.Receiving.RRDetail> RRDetailss { get; set; }
public virtual DbSet<RRSeries> RRSeries { get; set; }
public virtual DbSet<PRWOCanvass> PRWOCanvasses { get; set; }
public virtual DbSet<ForPayment> ForPayments { get; set; }
public virtual DbSet<Inventory> Inventories { get; set; }
public virtual DbSet<Entities.Inventory.ItemDetail> ItemDetails { get; set; }
public virtual DbSet<Entities.PO.ItemDetail> PRItemDetails { get; set; }
public virtual DbSet<Lot> Lots { get; set; }
public virtual DbSet<LotQtyByItem> LotQtyByItems { get; set; }
public virtual DbSet<RequestItem> RequestItems { get; set; }
public virtual DbSet<RequestItemDetail> RequestItemDetails { get; set; }
public virtual DbSet<NotifUserKey> NotifUserKeys { get; set; }
public virtual DbSet<ItemListForPO> ItemListForPOs { get; set; }
public virtual DbSet<CreatedPOPerSupId> CreatedPOPerSupIds { get; set; }
public virtual DbSet<PRTracking> PRTrackings { get; set; }
public virtual DbSet<Dashboard> Dashboards { get; set; }
public DbSet<IncomingShipment> IncomingShipments { get; set; }
public virtual DbSet<IncomingShipmentDto> IncomingShipmentDtos { get; set; }
public virtual DbSet<PaymentTerm> PaymentTerms { get; set; }
public virtual DbSet<Incoterm> Incoterms { get; set; }
public virtual DbSet<CentralPONo> CentralPONos { get; set; }
public virtual DbSet<RRReport> DetailedPRTrackings { get; set; }
public DbSet<IncomingShipment> IncomingShipments { get; set; }
public virtual DbSet<IncomingShipmentDto> IncomingShipmentDtos { get; set; }
public DbSet<Currencies> Currencies { get; set; }
#endregion
#region Inventory
public virtual DbSet<Inventory> Inventories { get; set; }
public virtual DbSet<Lot> Lots { get; set; }
public virtual DbSet<LotType> LotTypes { get; set; }
public virtual DbSet<LotQtyByItem> LotQtyByItems { get; set; }
public virtual DbSet<RequestItem> RequestItems { get; set; }
public virtual DbSet<RequestItemDetail> RequestItemDetails { get; set; }
public virtual DbSet<RIS> RIS { get; set; }
public virtual DbSet<MRS> MRS { get; set; }
public virtual DbSet<Discipline> Disciplines { get; set; }
public virtual DbSet<InventTrans> InventTrans { get; set; }
public virtual DbSet<InventTransDetail> InventTransDetails { get; set; }
public DbSet<InventoryByIdResponse> InventoryByIdResponses { get; set; }
#endregion
#region RR
public virtual DbSet<ForReceiving> ForReceivings { get; set; }
public virtual DbSet<Infrastructure.Entities.Receiving.RRReport> RRReports { get; set; }
public virtual DbSet<ReceivingDetail> ReceivingDetails { get; set; }
public virtual DbSet<RRDetailDto> RRDetailDtos { get; set; }
public virtual DbSet<ForRR> ForRRs { get; set; }
public virtual DbSet<RR> RRs { get; set; }
public virtual DbSet<Entities.Receiving.RRDetailDto> RRDetailss { get; set; }
public virtual DbSet<Entities.Receiving.RRDetails> RRDetails { get; set; }
public virtual DbSet<RRSeries> RRSeries { get; set; }
#endregion
#region Automation Part
public virtual DbSet<AllForCanvass> AllForCanvasses { get; set; }
public DbSet<ItemWithoutSupplier> ItemWithoutSuppliers { get; set; }
public DbSet<ErrorLog> ErrorLogs { get; set; }
#endregion
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
@ -128,7 +174,7 @@ namespace CPRNIMS.Infrastructure.Database
.Property(e => e.CanvassSupplierId)
.ValueGeneratedNever();
modelBuilder.Entity<RRReport>(b =>
modelBuilder.Entity<DetailedPRTracking>(b =>
{
b.ToTable("DetailsedPRTracking");
b.HasNoKey();
@ -143,6 +189,11 @@ namespace CPRNIMS.Infrastructure.Database
b.ToTable("PRPOSummaryItem");
b.HasNoKey();
});
modelBuilder.Entity<RR>(b =>
{
b.ToTable("RR");
b.HasNoKey();
});
modelBuilder.Entity<ApplicationUser>(b =>
{
b.ToTable("Users");
@ -150,7 +201,7 @@ namespace CPRNIMS.Infrastructure.Database
b.HasOne(u => u.Attachment)
.WithOne(a => a.ApplicationUser)
.HasForeignKey<Attachment>(a => a.AttachmentId)
.IsRequired(false); // Allow null if there is no attachment
.IsRequired(false);
});
modelBuilder.Entity<Attachment>(b =>
{
@ -158,7 +209,7 @@ namespace CPRNIMS.Infrastructure.Database
b.HasOne(a => a.AttachmentExtention)
.WithOne()
.HasForeignKey<Attachment>(a => a.ExtensionId)
.IsRequired(false); // Allow null if there is no extension
.IsRequired(false);
});
modelBuilder.Entity<ApplicationUser>(b =>
{
@ -216,6 +267,74 @@ namespace CPRNIMS.Infrastructure.Database
{
b.ToTable("UserRoles");
});
modelBuilder.Entity<Inventory>()
.HasOne(i => i.Lot)
.WithMany()
.HasForeignKey(i => i.LotId)
.OnDelete(DeleteBehavior.Restrict);
modelBuilder.Entity<Inventory>()
.HasOne(i => i.Item)
.WithMany()
.HasForeignKey(i => i.ItemNo)
.OnDelete(DeleteBehavior.Restrict);
modelBuilder.Entity<Item>()
.HasOne(i => i.ItemCode)
.WithMany()
.HasForeignKey(i => i.ItemCodeId)
.OnDelete(DeleteBehavior.Restrict);
modelBuilder.Entity<ItemCode>()
.HasOne(i => i.ItemCategory)
.WithMany()
.HasForeignKey(i => i.ItemCategoryId)
.OnDelete(DeleteBehavior.Restrict);
modelBuilder.Entity<InventTransDetail>(e =>
{
e.HasOne(i => i.PRDetails)
.WithMany()
.HasForeignKey(t => t.PRDetailId)
.OnDelete(DeleteBehavior.Restrict);
e.HasOne(r => r.RRDetails)
.WithMany()
.HasForeignKey(r => r.RRDetailId)
.IsRequired(false)
.HasForeignKey(r => r.RRDetailId)
.OnDelete(DeleteBehavior.Restrict);
});
modelBuilder.Entity<PRDetails>(e =>
{
e.HasOne(i => i.PRs)
.WithMany()
.HasForeignKey(t => t.PRId)
.OnDelete(DeleteBehavior.Restrict);
});
modelBuilder.Entity<RIS>(e => {
e.HasOne(r => r.Inventory)
.WithMany()
.HasForeignKey(r => r.InventoryId)
.OnDelete(DeleteBehavior.Restrict);
e.HasOne(r => r.Discipline)
.WithMany()
.HasForeignKey(r => r.DisciplineId);
e.HasOne(r => r.ProjectCodes)
.WithMany()
.HasForeignKey(r => r.ProjectCodeId);
});
modelBuilder.Entity<MRS>(e => {
e.HasOne(m => m.RIS)
.WithMany(r => r.MaterialReturns)
.HasForeignKey(m => m.RISId)
.OnDelete(DeleteBehavior.Restrict);
});
}
}
}

View File

@ -3,6 +3,7 @@ using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
@ -20,6 +21,7 @@ namespace CPRNIMS.Infrastructure.Dto.Account
public string URLAttachment { get; set; } = string.Empty;
public string? token { get; set; }
public string? company { get; set; }
public int? departmentId { get; set; }
public string? refreshToken { get; set; }
public DateTime expiresAt { get; set; }
public int expiresInSeconds { get; set; }

View File

@ -13,5 +13,6 @@ namespace CPRNIMS.Infrastructure.Dto.Account
public string FullName { get; init; } = default!;
public string Company { get; init; } = default!;
public IReadOnlyList<string> Roles { get; init; } = [];
public int? DepartmentId { get; set; }
}
}

View File

@ -1,4 +1,5 @@
using CPRNIMS.Infrastructure.Entities.Common;
using CPRNIMS.Infrastructure.Dto.Canvass.Request;
using CPRNIMS.Infrastructure.Entities.Common;
using CPRNIMS.Infrastructure.ViewModel.Items;
using System;
using System.Collections.Generic;
@ -9,7 +10,7 @@ using System.Threading.Tasks;
namespace CPRNIMS.Infrastructure.Dto.Canvass
{
public class CanvassDto : CommonProperties
public class CanvassDto : CanvassRequestSearch
{
public byte PaymentTermsId { get; set; } = 0;
public bool IsArchived { get; set; } = false;
@ -56,7 +57,7 @@ namespace CPRNIMS.Infrastructure.Dto.Canvass
public long CanvassDetailId { get; set; }
public long CanvassId { get; set; }
public decimal QtyRequest { get; set; }
//public byte IsApproved { get; set; }
public bool IsInternational { get; set; }
public long RRDetailId { get; set; }
public long PRDetailId { get; set; }
public decimal Quantity { get; set; }
@ -74,6 +75,7 @@ namespace CPRNIMS.Infrastructure.Dto.Canvass
public bool IsDenied { get; set; } = false;
public string? FullName { get; set; }
public string? Specification { get; set; }
public byte CurrencyId { get; set; } = 1;
public bool VatInc { get; set; }=false;
public string? TinNo { get; set; }

View File

@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CPRNIMS.Infrastructure.Dto.Canvass
{
public class CanvassItemDto
{
public long PRDetailsId { get; set; }
public long PRNo { get; set; }
public long ItemNo { get; set; }
public string ItemDescription { get; set; } = string.Empty;
public string ItemName { get; set; } = string.Empty;
}
}

View File

@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CPRNIMS.Infrastructure.Dto.Canvass
{
public class ForCanvassDto
{
public short Status {get;set;}
public string UserId { get; set; } = string.Empty;
public int SupplierId { get; set; }
public long PRNo { get; set; }
public long ItemNo { get; set; }
public int CanvassNo { get; set; }
public long PRDetailsId { get; set; }
public string FullName { get; set; } = string.Empty;
public string? Remarks { get; set; }
}
}

View File

@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using CPRNIMS.Infrastructure.Dto.Common;
namespace CPRNIMS.Infrastructure.Dto.Canvass.Request
{
public class CanvassRequestSearch : PagedRequest
{
public string SearchPRNo { get; set; } = string.Empty;
public string SearchItemName { get; set; } = string.Empty;
public string SearchItemNo { get; set; } = string.Empty;
public string SearchCreatedBy { get; set; } = string.Empty;
public string SearchSupplier { get; set; } = string.Empty;
public string SearchDepartment { get; set; } = string.Empty;
}
}

View File

@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CPRNIMS.Infrastructure.Dto.Canvass.Request
{
public class ForCanvassRequest
{
public string UserId { get; set; } = string.Empty;
public int SupplierId { get; set; }
public long PRNo { get; set; }
public long ItemNo { get; set; }
public int CanvassNo { get; set; }
public long PRDetailsId { get; set; }
}
}

View File

@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CPRNIMS.Infrastructure.Dto.Canvass.Request
{
public class SearchSupplierRequest
{
public long PRDetailsId { get; set; }
public long PRNo { get; set; }
public long ItemNo { get; set; }
public string ItemName { get; set; } = string.Empty;
public string ItemDescription { get; set; } = string.Empty;
public string FullName { get; set; } = string.Empty;
}
}

View File

@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
namespace CPRNIMS.Infrastructure.Dto.Canvass.Request
{
public class StartCanvassRequest
{
[JsonPropertyName("isInternational")]
public bool IsInternational { get; set; }
[JsonPropertyName("items")]
public List<CanvassItemDto> Items { get; set; } = new();
}
}

View File

@ -0,0 +1,29 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CPRNIMS.Infrastructure.Dto.Canvass.Request
{
public class SupplierEmailRequest
{
public string Subject { get; set; } = string.Empty;
public string SenderEmail { get; set; } = string.Empty;
public string Recipient { get; set; } = string.Empty;
public string DisplayName { get; set; } = string.Empty;
public int OutGoingPort { get; set; } = 587;
public string Password { get; set; } = string.Empty;
public string Token { get; set; } = string.Empty;
public string Server { get; set; } = string.Empty;
public string CC { get; set; } = string.Empty;
public bool IsCanvass { get; set; }
public string Purchaser { get; set; }=string.Empty;
public string UserName { get; set; } = string.Empty;
public string FormLink { get; set; } = string.Empty;
public string EmailAddress { get; set; } = string.Empty;
public string SupplierName { get; set; } = string.Empty;
public bool IsSuccess { get; set; }
public string AttachPath { get; set; } = string.Empty;
}
}

View File

@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CPRNIMS.Infrastructure.Dto.Canvass.Request
{
public class SupplierRequest
{
public string SupplierName { get; set; } = string.Empty;
public string EmailAddress { get; set; } = string.Empty;
public bool IsActive { get; set; } = true;
public string ContactNo { get; set; } = string.Empty;
public string ContactPerson { get; set; } = string.Empty;
public string LeadTime { get; set; } = string.Empty;
public bool IsVatable { get; set; } = false;
public byte PaymentTermsId { get; set; } = 1;
public byte CurrencyId { get; set; } = 1;
public string TinNo { get; set; } = string.Empty;
public string Address { get; set; } = string.Empty;
public long ItemNo { get; set; } = 0;
public string Website { get; set; } = string.Empty;
public int SupplierId { get; set; }
}
}

View File

@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CPRNIMS.Infrastructure.Dto.Canvass.Response
{
public class SearchSupplierResponse
{
}
}

View File

@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CPRNIMS.Infrastructure.Dto.Canvass.Response
{
public class StartCanvassResponse
{
public Guid Id { get; set; }
public bool IsInternational { get; set; }
public string UserId { get; set; } = string.Empty;
public List<CanvassItemDto> Items { get; set; } = new();
}
}

View File

@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CPRNIMS.Infrastructure.Dto.Canvass.Response
{
public class SupplierResponse
{
public int SupplierId { get; set; }
public string SupplierName { get; set; } = string.Empty;
public string? EmailAddress { get; set; }
public bool IsActive { get; set; }
public string? ContactNo { get; set; }
public string? ContactPerson { get; set; }
public string? LeadTime { get; set; }
public bool? IsVatable { get; set; }
public byte? PaymentTermsId { get; set; }
public byte? CurrencyId { get; set; }
public string? TinNo { get; set; }
public string? Address { get; set; }
public string? Website { get; set; }
public bool VatInc { get; set; }
public string Currency { get; set; }=string.Empty;
public string PaymentTerms { get; set; } = string.Empty;
}
}

View File

@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CPRNIMS.Infrastructure.Dto.Canvass.Response
{
public class SupplierResponseDto
{
[Key]
public int SupplierId { get; set; }
public string? SupplierName { get; set; }
public string? EmailAddress { get; set; }
public string? ContactNo { get; set; }
public string? ContactPerson { get; set; }
public string? LeadTime { get; set; }
public bool VatInc { get; set; }
public string? Currency { get; set; }
public string? PaymentTerms { get; set; }
public byte PaymentTermsId { get; set; }
public byte CurrencyId { get; set; }
public string? TinNo { get; set; }
public bool IsActive { get; set; }
}
}

View File

@ -0,0 +1,101 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace CPRNIMS.Infrastructure.Dto.Canvass.Result
{
public class GroqSupplierResult
{
[JsonPropertyName("company_name")]
public string CompanyName { get; set; } = string.Empty;
[JsonPropertyName("country")]
public string? Country { get; set; }
[JsonPropertyName("phone_number")]
public string? PhoneNumber { get; set; }
[JsonPropertyName("contact_email")]
public string? ContactEmail { get; set; }
[JsonPropertyName("website")]
public string? Website { get; set; }
[JsonPropertyName("source")]
public string? Source { get; set; }
[JsonConverter(typeof(FlexibleDecimalConverter))]
public decimal? EstimatedPriceUsd { get; set; }
[JsonPropertyName("item_specifications")]
public JsonElement? ItemSpecifications { get; set; }
}
public class FlexibleDecimalConverter : JsonConverter<decimal?>
{
public override decimal? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
switch (reader.TokenType)
{
case JsonTokenType.Number:
return reader.TryGetDecimal(out var num) ? num : null;
case JsonTokenType.String:
var str = reader.GetString()?.Trim();
if (string.IsNullOrWhiteSpace(str)) return null;
// Strip currency symbols and commas e.g. "$1,200.00" → 1200.00
str = Regex.Replace(str, @"[^\d.]", "");
return decimal.TryParse(str, NumberStyles.Any, CultureInfo.InvariantCulture, out var parsed)
? parsed
: null; // "contact for pricing", "varies", etc. → null
case JsonTokenType.Null:
default:
return null;
}
}
public override void Write(Utf8JsonWriter writer, decimal? value, JsonSerializerOptions options)
{
if (value.HasValue) writer.WriteNumberValue(value.Value);
else writer.WriteNullValue();
}
}
public class TavilySearchResult
{
public List<TavilyResult> Results { get; set; } = new();
}
public class TavilyResult
{
public string Title { get; set; } = string.Empty;
public string Url { get; set; } = string.Empty;
public string Content { get; set; } = string.Empty;
public double Score { get; set; }
}
public class GroqMatchResult
{
public bool Matched { get; set; }
public int? SupplierId { get; set; }
}
public class GroqResponse
{
public List<GroqChoice> Choices { get; set; } = new();
}
public class GroqChoice
{
public GroqMessage Message { get; set; } = new();
}
public class GroqMessage
{
public string Content { get; set; } = string.Empty;
}
}

View File

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CPRNIMS.Infrastructure.Dto.Common
{
public class ApiResponse<T>
{
public bool success { get; set; }
public string? message { get; set; }
public T? data { get; set; }
}
}

View File

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CPRNIMS.Infrastructure.Dto.Common
{
public class PagedRequest
{
public int PageNumber { get; set; }
public int PageSize { get; set; }
}
}

View File

@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CPRNIMS.Infrastructure.Dto.Common
{
public class PagedResult<T>
{
public List<T> Data { get; set; } = new List<T>();
public int TotalCount { get; set; }
public int PageNumber { get; set; }
public int PageSize { get; set; }
public List<string> ClientList { get; set; } = new List<string>();
public List<string> SupplierList { get; set; } = new List<string>();
public List<string> CategoryList { get; set; } = new List<string>();
public List<string> DepartmentList { get; set; } = new List<string>();
}
}

View File

@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CPRNIMS.Infrastructure.Dto.Inventory
{
public class DisciplineDto
{
public byte DisciplineId { get; set; }
public string DisciplineName { get; set; } = string.Empty;
}
public class ProjectCodeDto
{
public string ProjectCode { get; set; } = string.Empty;
public string ProjectName { get; set; } = string.Empty;
public int ProjectCodeId { get; set; }
}
}

View File

@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CPRNIMS.Infrastructure.Dto.Inventory
{
public class MRSFilterDto
{
public int PageNumber { get; set; } = 1;
public int PageSize { get; set; } = 12;
public string? SearchMRSNo { get; set; }
public long? RISId { get; set; }
public short? Status { get; set; }
public DateTime? DateFrom { get; set; }
public DateTime? DateTo { get; set; }
}
}

View File

@ -0,0 +1,30 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
namespace CPRNIMS.Infrastructure.Dto.Inventory
{
public class MRSPagedDto
{
public long MRSId { get; set; }
public string MRSNo { get; set; } = string.Empty;
public long RISId { get; set; }
public string? RISNo { get; set; }
public string? ItemName { get; set; }
public string? ReturnedBy { get; set; }
public decimal QtyReturned { get; set; }
public string? Condition { get; set; }
public string? Remarks { get; set; }
public short Status { get; set; }
public string? StatusLabel { get; set; }
public string? CreatedBy { get; set; }
public DateTime CreatedDate { get; set; }
public string? ApprovedBy { get; set; }
public DateTime? ApprovedDate { get; set; }
public int InventoryId { get; set; }
public List<MRSPagedDto> Data { get; set; } = [];
}
}

View File

@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CPRNIMS.Infrastructure.Dto.Inventory
{
public class MRSPagedRequest
{
public string? SearchMRSNo { get; set; }
public string? SearchRISNo { get; set; }
public string? SearchItemName { get; set; }
public string? SearchReturnedBy { get; set; }
public short? Status { get; set; }
public string? Condition { get; set; }
public int PageNumber { get; set; } = 1;
public int PageSize { get; set; } = 12;
}
}

View File

@ -0,0 +1,17 @@
using CPRNIMS.Infrastructure.Dto.Inventory.Response;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CPRNIMS.Infrastructure.Dto.Inventory
{
public class MRSPagedResult
{
public IEnumerable<MRSPagedDto> Data { get; set; } = [];
public int RecordsTotal { get; set; }
public List<string> DepartmentList { get; set; } = new List<string>();
public List<string> DisciplineList { get; set; } = new List<string>();
}
}

View File

@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CPRNIMS.Infrastructure.Dto.Inventory
{
public class PagedResult<T>
{
public List<T> Data { get; set; } = new List<T>();
public int TotalCount { get; set; }
public int PageNumber { get; set; }
public int PageSize { get; set; }
public List<string> DepartmentList { get; set; } = new List<string>();
public List<string> CategoryList { get; set; } = new List<string>();
public bool IsSuccess { get; set; } = true;
public string? ErrorMessage { get; set; }
}
}

View File

@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CPRNIMS.Infrastructure.Dto.Inventory
{
public class RISFilterDto
{
public string? SearchRISNo { get; set; }
public string? SearchItemName { get; set; }
public string? SearchIssuedTo { get; set; }
public string? Discipline { get; set; }
public short? Status { get; set; }
public int PageNumber { get; set; } = 1;
public int PageSize { get; set; } = 12;
public DateTime? DateFrom { get; set; }
public DateTime? DateTo { get; set; }
}
}

View File

@ -0,0 +1,17 @@
using CPRNIMS.Infrastructure.Dto.Inventory.Response;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CPRNIMS.Infrastructure.Dto.Inventory
{
public class RISPagedResult
{
public IEnumerable<RISResponse> Data { get; set; } = [];
public int RecordsTotal { get; set; }
public IEnumerable<string> DepartmentList { get; set; } = [];
public IEnumerable<DisciplineDto> DisciplineList { get; set; } = [];
}
}

View File

@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CPRNIMS.Infrastructure.Dto.Inventory
{
public class RISReferenceDto
{
public long RISId { get; set; }
public string RISNo { get; set; } = string.Empty;
public decimal QtyIssued { get; set; }
public decimal TotalReturned { get; set; }
public decimal QtyAvailableToReturn => QtyIssued - TotalReturned;
public string DisciplineName { get; set; } = string.Empty;
public DateTime CreatedDate { get; set; }
}
}

View File

@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CPRNIMS.Infrastructure.Dto.Inventory
{
public class RISSearchResultDto
{
public long RISId { get; set; }
public string RISNo { get; set; } = string.Empty;
public int ProjectCodeId { get; set; }
public string ProjectCode { get; set; } = string.Empty;
public string ProjectName { get; set; } = string.Empty;
public string DisciplineName { get; set; } = string.Empty;
public decimal QtyAvailableToReturn { get; set; }
}
public class ProjectCodeOptionDto
{
public int ProjectCodeId { get; set; }
public string ProjectCode { get; set; } = string.Empty;
public string ProjectName { get; set; } = string.Empty;
}
}

View File

@ -0,0 +1,50 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CPRNIMS.Infrastructure.Dto.Inventory.Reports
{
public class RISReportDataDto
{
public List<RISRowDto> Rows { get; set; } = new();
public List<DisciplineAggDto> Disciplines { get; set; } = new();
public List<TopRecipientDto> Recipients { get; set; } = new();
}
public class RISRowDto
{
public string? RISNo { get; set; }
public long? PRNo { get; set; }
public decimal QtyIssued { get; set; }
public string? IssuedTo { get; set; }
public string? StatusLabel { get; set; }
public string? CreatedBy { get; set; }
public string? ApprovedBy { get; set; }
public DateTime? ApprovedDate { get; set; }
public DateTime? CreatedDate { get; set; }
public string? DisciplineName { get; set; }
public string? ItemName { get; set; }
public long? ItemNo { get; set; }
public decimal QtyIn { get; set; }
public decimal QtyOut { get; set; }
public decimal QtyOnHand { get; set; }
public string? DepartmentName { get; set; }
public decimal TotalReturned { get; set; }
public int MRSCount { get; set; }
public decimal NetIssued { get; set; }
}
public class DisciplineAggDto
{
public string? DisciplineName { get; set; }
public int SlipCount { get; set; }
}
public class TopRecipientDto
{
public string? Name { get; set; }
public int SlipCount { get; set; }
public decimal QtyOut { get; set; }
}
}

View File

@ -0,0 +1,160 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CPRNIMS.Infrastructure.Dto.Inventory.Reports
{
public class RISReportDto
{
public string CompanyName { get; set; } = "Lloyd Laboratories Incorporated";
public string PreparedBy { get; set; } = "Finance Department";
public string ReportNo { get; set; } = string.Empty;
public DateTime DateFrom { get; set; }
public DateTime DateTo { get; set; }
public RISReportSummary Summary { get; set; } = new();
public List<RISReportRow> Rows { get; set; } = [];
public List<DisciplineCount> ByDiscipline { get; set; } = [];
public List<TopRecipient> TopRecipients { get; set; } = [];
}
public class RISReportSummary
{
public int TotalRIS { get; set; }
public int TotalApproved { get; set; }
public int TotalPending { get; set; }
public int TotalCancelled { get; set; }
public decimal TotalQtyIssued { get; set; }
public decimal TotalQtyReturned { get; set; }
public decimal TotalNetIssued { get; set; }
public decimal ApprovalRatePct { get; set; }
}
public class RISReportRow
{
public string RISNo { get; set; } = string.Empty;
public DateTime CreatedDate { get; set; }
public string ItemName { get; set; } = string.Empty;
public long ItemNo { get; set; }
public string DisciplineName { get; set; } = string.Empty;
public string ProjectName { get; set; } = string.Empty;
public decimal QtyIssued { get; set; }
public decimal TotalReturned { get; set; }
public decimal NetIssued { get; set; }
public short Status { get; set; }
public string StatusLabel { get; set; } = string.Empty;
}
public class DisciplineCount
{
public string DisciplineName { get; set; } = string.Empty;
public int Count { get; set; }
}
public class TopRecipient
{
public string IssuedTo { get; set; } = string.Empty;
public int SlipCount { get; set; }
public decimal TotalQty { get; set; }
}
public class MRSReportDto
{
public string CompanyName { get; set; } = "Lloyd Laboratories Incorporated";
public string PreparedBy { get; set; } = "Finance Department";
public string ReportNo { get; set; } = string.Empty;
public DateTime DateFrom { get; set; }
public DateTime DateTo { get; set; }
public MRSReportSummary Summary { get; set; } = new();
public List<MRSReportRow> Rows { get; set; } = [];
public List<ConditionTotal> ByCondition { get; set; } = [];
}
public class MRSReportSummary
{
public int TotalMRS { get; set; }
public decimal TotalQtyReturned { get; set; }
public decimal TotalQtyIssuedRIS { get; set; }
public decimal NetQtyConsumed { get; set; }
public decimal ReturnRatePct { get; set; }
public decimal GoodConditionPct { get; set; }
}
public class MRSReportRow
{
public string MRSNo { get; set; } = string.Empty;
public DateTime CreatedDate { get; set; }
public string RISNo { get; set; } = string.Empty;
public string ItemName { get; set; } = string.Empty;
public string ReturnedBy { get; set; } = string.Empty;
public decimal QtyReturned { get; set; }
public string Condition { get; set; } = string.Empty;
public short Status { get; set; }
public string StatusLabel { get; set; } = string.Empty;
}
public class ConditionTotal
{
public string Condition { get; set; } = string.Empty;
public decimal TotalQty { get; set; }
}
public class InventoryReportDto
{
public string CompanyName { get; set; } = "Lloyd Laboratories Incorporated";
public string PreparedBy { get; set; } = "Finance Department";
public string ReportNo { get; set; } = string.Empty;
public DateTime AsOf { get; set; }
public List<string> Departments { get; set; } = new();
public int Page { get; set; }
public int PageSize { get; set; }
public int TotalRows { get; set; }
public int TotalPages => PageSize > 0 ? (int)Math.Ceiling(TotalRows / (double)PageSize) : 0;
public InventoryReportSummary Summary { get; set; } = new();
public List<InventoryReportRow> Rows { get; set; } = [];
public List<CategoryStockLevel> ByCategory { get; set; } = [];
public List<InventoryAlert> Alerts { get; set; } = [];
}
public class InventoryReportSummary
{
public int TotalSKUs { get; set; }
public decimal TotalOnHand { get; set; }
public decimal TotalQtyIn { get; set; }
public decimal TotalQtyOut { get; set; }
public decimal TotalValue { get; set; }
public int LowStockCount { get; set; }
public int OutOfStockCount { get; set; }
}
public class InventoryReportRow
{
public string ItemName { get; set; } = string.Empty;
public long ItemNo { get; set; }
public string ItemCategoryName { get; set; } = string.Empty;
public string? LotNo { get; set; }
public decimal QtyIn { get; set; }
public decimal QtyOut { get; set; }
public decimal QtyOnHand { get; set; }
public decimal UnitPrice { get; set; }
public int StockPct { get; set; }
public string? Department { get; set; }
public string? CurrencyCode { get; set; }
}
public class CategoryStockLevel
{
public string CategoryName { get; set; } = string.Empty;
public int AvgStockPct { get; set; }
}
public class InventoryAlert
{
public string ItemName { get; set; } = string.Empty;
public decimal QtyOnHand { get; set; }
public string Severity { get; set; } = string.Empty; // "Critical" | "Low"
}
}

View File

@ -0,0 +1,14 @@
using CPRNIMS.Infrastructure.Dto.Inventory.Response;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CPRNIMS.Infrastructure.Dto.Inventory.Reports.Response
{
public class InventoryData
{
public List<InventoryReportDto> Data { get; set; } = [];
}
}

View File

@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CPRNIMS.Infrastructure.Dto.Inventory.Reports.Response
{
public class MRSData
{
public List<MRSReportDto> Data { get; set; } = [];
}
}

View File

@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CPRNIMS.Infrastructure.Dto.Inventory.Reports.Response
{
public class RISData
{
public List<RISReportDto> Data { get; set; } = [];
}
}

View File

@ -0,0 +1,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CPRNIMS.Infrastructure.Dto.Inventory.Request
{
public class ApproveMRSRequest { public long MRSId { get; set; } }
}

View File

@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CPRNIMS.Infrastructure.Dto.Inventory.Request
{
public class ApproveRISRequest
{
public long RISId { get; set; }
}
}

View File

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CPRNIMS.Infrastructure.Dto.Inventory.Request
{
public class CancelMRSRequest
{
public long MRSId { get; set; }
public string Reason { get; set; } = string.Empty;
}
}

View File

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CPRNIMS.Infrastructure.Dto.Inventory.Request
{
public class CancelRISRequest
{
public long RISId { get; set; }
public string Reason { get; set; } = string.Empty;
}
}

View File

@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CPRNIMS.Infrastructure.Dto.Inventory.Request
{
public class CreateMRSRequest
{
public long RISId { get; set; }
public decimal QtyReturned { get; set; }
public string ReturnedBy { get; set; } = string.Empty;
public string? Condition { get; set; }
public string? Remarks { get; set; }
}
}

View File

@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CPRNIMS.Infrastructure.Dto.Inventory.Request
{
public class CreateRISRequest
{
public int InventoryId { get; set; }
public long PRDetailId { get; set; }
public int ProjectCodeId { get; set; }
public byte DisciplineId { get; set; }
public decimal QtyIssued { get; set; }
public string? Remarks { get; set; }
}
}

View File

@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CPRNIMS.Infrastructure.Dto.Inventory.Request
{
public class InventoryReportsRequest
{
public DateTime DateFrom { get; set; }
public DateTime DateTo { get; set; }
public string? Department { get; set; }
public int Page { get; set; }
public int PageSize { get; set; }
public bool Paginate { get; set; }
}
}

Some files were not shown because too many files have changed in this diff Show More