Compare commits

..

No commits in common. "main" and "Maintenance/March2026" have entirely different histories.

278 changed files with 8926 additions and 26182 deletions

View File

@ -1,211 +0,0 @@
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
View File

@ -1,48 +0,0 @@
# 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

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

View File

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

View File

@ -10,9 +10,6 @@
<PackageReference Include="AutoMapper" Version="16.1.1" /> <PackageReference Include="AutoMapper" Version="16.1.1" />
<PackageReference Include="CaptchaGen.NetCore" Version="1.1.2" /> <PackageReference Include="CaptchaGen.NetCore" Version="1.1.2" />
<PackageReference Include="Dapper" Version="2.1.66" /> <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="Google.Apis.Drive.v3" Version="1.67.0.3373" />
<PackageReference Include="Microsoft.AspNet.Identity.Core" Version="2.2.4" /> <PackageReference Include="Microsoft.AspNet.Identity.Core" Version="2.2.4" />
<PackageReference Include="Microsoft.AspNetCore.SignalR.Core" Version="1.2.0" /> <PackageReference Include="Microsoft.AspNetCore.SignalR.Core" Version="1.2.0" />

View File

@ -1,12 +1,9 @@
using CPRNIMS.Domain.Services; using CPRNIMS.Domain.Services.ICanvass;
using CPRNIMS.Domain.Services.ICanvass;
using CPRNIMS.Infrastructure.Dto.Canvass; using CPRNIMS.Infrastructure.Dto.Canvass;
using CPRNIMS.Infrastructure.Dto.Canvass.Request; using CPRNIMS.Infrastructure.Dto.Canvass.Request;
using CPRNIMS.Infrastructure.Dto.Canvass.Response; using CPRNIMS.Infrastructure.Dto.Canvass.Response;
using CPRNIMS.Infrastructure.Dto.Common;
using CPRNIMS.Infrastructure.Entities.Canvass; using CPRNIMS.Infrastructure.Entities.Canvass;
using CPRNIMS.Infrastructure.Entities.Purchasing; using CPRNIMS.Infrastructure.Entities.Purchasing;
using CPRNIMS.Infrastructure.ViewModel.Canvass;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
@ -18,9 +15,9 @@ namespace CPRNIMS.Domain.Contracts.Canvass
public interface ICanvass : ISupplier public interface ICanvass : ISupplier
{ {
#region Post Put #region Post Put
Task<Result<StartCanvassResponse>> StartCanvass(CanvassVM canvass,CancellationToken ct); Task<RFQ> PostPerSupplierToken(CanvassDto CanvassDto);
Task<RFQ> PostPerSupplierToken(ForCanvassDto CanvassDto);
Task<ForCanvassFollowUp> PutSupplierCanvass(long canvassSupplierId); Task<ForCanvassFollowUp> PutSupplierCanvass(long canvassSupplierId);
Task<PRCanvassDetail> PostCanvass(CanvassDto CanvassDto);
Task<SupplierResponse> PostPutSupplier(CanvassDto CanvassDto); Task<SupplierResponse> PostPutSupplier(CanvassDto CanvassDto);
Task<SupplierResponse> PostTaggingSupplier(CanvassDto CanvassDto); Task<SupplierResponse> PostTaggingSupplier(CanvassDto CanvassDto);
Task<SupplierResponse> PostApprovedSupp(CanvassDto CanvassDto); Task<SupplierResponse> PostApprovedSupp(CanvassDto CanvassDto);
@ -35,17 +32,16 @@ namespace CPRNIMS.Domain.Contracts.Canvass
Task<List<PRCanvassDetail>> GetCanvassById(CanvassDto CanvassDto); Task<List<PRCanvassDetail>> GetCanvassById(CanvassDto CanvassDto);
Task<List<WOResponse>> GetCanvassWOResponse(CanvassDto CanvassDto); Task<List<WOResponse>> GetCanvassWOResponse(CanvassDto CanvassDto);
Task<List<WOResponseById>> GetWOResponseBySuppId(CanvassDto CanvassDto); Task<List<WOResponseById>> GetWOResponseBySuppId(CanvassDto CanvassDto);
Task<List<SupplierResponseDto>> GetSupplierById(CanvassDto CanvassDto); Task<List<SupplierResponse>> GetSupplierById(CanvassDto CanvassDto);
Task<List<RFQReference>> GetRFQ(ForCanvassDto CanvassDto); Task<List<RFQReference>> GetRFQ(CanvassDto CanvassDto);
Task<List<BiddingItem>> GetSupplierBid(CanvassDto CanvassDto); Task<List<BiddingItem>> GetSupplierBid(CanvassDto CanvassDto);
Task<List<RFQPerSupplier>> GetSupplierBidByItem(CanvassDto CanvassDto); Task<List<RFQPerSupplier>> GetSupplierBidByItem(CanvassDto CanvassDto);
Task<List<SupplierBidById>> GetSupplierBidById(CanvassDto CanvassDto); Task<List<SupplierBidById>> GetSupplierBidById(CanvassDto CanvassDto);
Task<PagedResult<PerSupplier>> GetCanvassPerSupplier(CanvassDto dto); Task<List<PerSupplier>> GetCanvassPerSupplier(CanvassDto CanvassDto);
Task<PagedResult<ItemsForTagging>> GetItemsForTagging(CanvassDto dto);
Task<List<PRCanvassDetail>> GetCanvassPerSupplierEmail(CanvassDto CanvassDto); Task<List<PRCanvassDetail>> GetCanvassPerSupplierEmail(CanvassDto CanvassDto);
Task<List<PRCanvassDetail>> GetCanvassPerSupplierId(CanvassDto itemCodeDto); Task<List<PRCanvassDetail>> GetCanvassPerSupplierId(CanvassDto itemCodeDto);
Task<List<ItemListWOEmail>> GetItemSupplierWOEmail(CanvassDto CanvassDto); Task<List<ItemListWOEmail>> GetItemSupplierWOEmail(CanvassDto CanvassDto);
Task<List<SupplierResponseDto>> GetSupplierItemWOEmail(CanvassDto CanvassDto); Task<List<SupplierResponse>> GetSupplierItemWOEmail(CanvassDto CanvassDto);
Task<List<PRCanvassDetail>> GetCanvassByPRNo(CanvassDto CanvassDto); Task<List<PRCanvassDetail>> GetCanvassByPRNo(CanvassDto CanvassDto);
Task<List<CanvassGroupByPRNo>> GetCanvassGroupByPRNo(CanvassDto CanvassDto); Task<List<CanvassGroupByPRNo>> GetCanvassGroupByPRNo(CanvassDto CanvassDto);
Task<List<PRCanvassDetail>> GetCanvassByItemNo(CanvassDto CanvassDto); Task<List<PRCanvassDetail>> GetCanvassByItemNo(CanvassDto CanvassDto);
@ -55,7 +51,7 @@ namespace CPRNIMS.Domain.Contracts.Canvass
Task<List<ForCanvass>> GetForCanvassPerItem(CanvassDto CanvassDto); Task<List<ForCanvass>> GetForCanvassPerItem(CanvassDto CanvassDto);
Task<int> GetCanvassNo(); Task<int> GetCanvassNo();
Task<List<ForCanvassFollowUp>> GetCanvassForFollowUp(CanvassDto itemDto); Task<List<ForCanvassFollowUp>> GetCanvassForFollowUp(CanvassDto itemDto);
Task<List<SupplierResponseDto>> GetMySuppliers(CanvassDto CanvassDto); Task<List<SupplierResponse>> GetMySuppliers(CanvassDto CanvassDto);
Task<List<MyPRWOCanvass>> GetMyPRWOCanvass(CanvassDto itemDto); Task<List<MyPRWOCanvass>> GetMyPRWOCanvass(CanvassDto itemDto);
Task<List<AlternativeOfferDetails>> GetAlternativeOfferByPRDetailId(CanvassDto itemDto); Task<List<AlternativeOfferDetails>> GetAlternativeOfferByPRDetailId(CanvassDto itemDto);
Task<List<AllForCanvass>> GetAllForCanvass(); Task<List<AllForCanvass>> GetAllForCanvass();

View File

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

View File

@ -1,14 +0,0 @@
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<ForPayment>> GetAllClosedPO(RRDetailsDto itemDto);
Task<List<ReceivingDetail>> GetRRDetailByPO(RRDetailsDto itemDto); Task<List<ReceivingDetail>> GetRRDetailByPO(RRDetailsDto itemDto);
Task<RRDetailDto> PostPutPayment(RRDetailsDto itemDto); Task<RRDetail> PostPutPayment(RRDetailsDto itemDto);
} }
} }

View File

@ -1,6 +1,4 @@
using CPRNIMS.Infrastructure.Dto.Inventory; 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.Inventory;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@ -13,15 +11,11 @@ namespace CPRNIMS.Domain.Contracts.Inventory
public interface IInventory public interface IInventory
{ {
Task<List<Lot>> GetLotNo(InventoryDto itemDto); 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<LotQtyByItem>> GetLotQtyByItem(InventoryDto itemDto);
Task<List<Infrastructure.Entities.Inventory.Inventory>> GetInventoryByUserId(InventoryDto itemDto); Task<List<Infrastructure.Entities.Inventory.Inventory>> GetInventoryByUserId(InventoryDto itemDto);
Task<List<RequestItemDetail>> GetRequestedItemByUserId(InventoryDto itemDto); Task<List<RequestItemDetail>> GetRequestedItemByUserId(InventoryDto itemDto);
Task<List<ItemDetail>> GetInventoryById(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<Infrastructure.Entities.Inventory.Inventory> PostPutReqApproval(InventoryDto itemDto);
Task<RequestItem> PostPutReqItems(InventoryDto itemDto); Task<RequestItem> PostPutReqItems(InventoryDto itemDto);
Task<Lot> PostPutLotNo(InventoryDto itemDto); Task<Lot> PostPutLotNo(InventoryDto itemDto);

View File

@ -1,17 +0,0 @@
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

@ -1,22 +0,0 @@
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

@ -1,22 +0,0 @@
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

@ -16,14 +16,14 @@ namespace CPRNIMS.Domain.Contracts.Items
Task<List<Departments>> GetDepartment(ItemCodeDto itemCode); Task<List<Departments>> GetDepartment(ItemCodeDto itemCode);
Task<PagedResult<ItemList>> GetItemList(ItemCodeDto itemCode); Task<PagedResult<ItemList>> GetItemList(ItemCodeDto itemCode);
Task<List<ItemCart>> GetItemCart(ItemDto itemDto); Task<List<ItemCart>> GetItemCart(ItemDto itemDto);
Task<List<ItemDtos>> GetItemDetail(ItemDto itemDto); Task<List<Item>> GetItemDetail(ItemDto itemDto);
Task<List<ItemLocalization>> GetItemLocalization(ItemDto itemDto); Task<List<ItemLocalization>> GetItemLocalization(ItemDto itemDto);
Task<List<ItemCategory>> GetItemCateg(ItemDto itemDto); Task<List<ItemCategory>> GetItemCateg(ItemDto itemDto);
Task<List<ItemColor>> GetItemColor(ItemDto itemDto); Task<List<ItemColor>> GetItemColor(ItemDto itemDto);
Task<List<UnitOfMessure>> GetItemUOM(ItemDto itemDto); Task<List<UnitOfMessure>> GetItemUOM(ItemDto itemDto);
Task<List<NotifUserKey>> GetNotifUserKey(ItemDto itemDto); Task<List<NotifUserKey>> GetNotifUserKey(ItemDto itemDto);
Task<IReadOnlyList<ProjectCodes>> GetProjectCode(); Task<List<ProjectCodes>> GetProjectCode();
Task<IReadOnlyList<ProjectCodes>> GetProjectCodeByTerm(string? fileName); Task<List<ProjectCodes>> GetProjectCodeByTerm(string? fileName);
Task<(long, long)> GetPRNo(); Task<(long, long)> GetPRNo();
Task<ResponseObject> PostPurchRequest(ItemDto itemDto); Task<ResponseObject> PostPurchRequest(ItemDto itemDto);
Task<ItemCodeDto> PostPutItem(ItemCodeDto itemDto); Task<ItemCodeDto> PostPutItem(ItemCodeDto itemDto);

View File

@ -1,5 +1,4 @@
using CPRNIMS.Infrastructure.Dto.Canvass.Response; using CPRNIMS.Infrastructure.Dto.PO;
using CPRNIMS.Infrastructure.Dto.PO;
using CPRNIMS.Infrastructure.Entities.Canvass; using CPRNIMS.Infrastructure.Entities.Canvass;
using CPRNIMS.Infrastructure.Entities.Common; using CPRNIMS.Infrastructure.Entities.Common;
using CPRNIMS.Infrastructure.Entities.LocalDb.NonInvent; using CPRNIMS.Infrastructure.Entities.LocalDb.NonInvent;
@ -38,7 +37,7 @@ namespace CPRNIMS.Domain.Contracts.PO
Task<List<SystemSettings>> GetLatestPO2(PODto pODto); Task<List<SystemSettings>> GetLatestPO2(PODto pODto);
Task<List<DocRequired>> GetDocRequired(PODto pODto); Task<List<DocRequired>> GetDocRequired(PODto pODto);
Task<List<OtherCharges>> GetOtherCharges(PODto itemDto); Task<List<OtherCharges>> GetOtherCharges(PODto itemDto);
Task<List<SupplierResponseDto>> GetSuppliers(PODto itemDto); Task<List<Suppliers>> GetSuppliers(PODto itemDto);
Task<List<CreatedPO>> GetCreatedPO(PODto pODto); Task<List<CreatedPO>> GetCreatedPO(PODto pODto);
Task<List<POItemDetail>> GetPOItemDetail(PODto pODto); Task<List<POItemDetail>> GetPOItemDetail(PODto pODto);
Task<List<CreatedPO>> GetMyCreatedPO(PODto pODto); Task<List<CreatedPO>> GetMyCreatedPO(PODto pODto);
@ -70,7 +69,6 @@ namespace CPRNIMS.Domain.Contracts.PO
Task<Incoterm> PostPutIncoterms(PODto pODto); Task<Incoterm> PostPutIncoterms(PODto pODto);
Task<bool> DeleteIncShip(PODto poDto); Task<bool> DeleteIncShip(PODto poDto);
Task<bool> PostIncShipFollowUp(PODto pODto); Task<bool> PostIncShipFollowUp(PODto pODto);
Task<IReadOnlyList<Currencies>> GetCurrencies(string currencyName, CancellationToken ct);
#endregion #endregion
} }
} }

View File

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

View File

@ -1,16 +0,0 @@
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

@ -1,16 +0,0 @@
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

@ -5,6 +5,8 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using AutoMapper;
using CPRNIMS.Infrastructure.ViewModel.Common;
using CPRNIMS.Infrastructure.Entities.Canvass; using CPRNIMS.Infrastructure.Entities.Canvass;
namespace CPRNIMS.Domain.Profile.Canvass namespace CPRNIMS.Domain.Profile.Canvass
@ -13,12 +15,14 @@ namespace CPRNIMS.Domain.Profile.Canvass
{ {
public SupplierRequestProfile() public SupplierRequestProfile()
{ {
// 1. THIS IS THE MISSING LINK: Request -> Entity
CreateMap<SupplierRequest, Suppliers>(); CreateMap<SupplierRequest, Suppliers>();
// 2. Entity -> Response
CreateMap<Suppliers, SupplierResponse>(); CreateMap<Suppliers, SupplierResponse>();
// 3. Response <-> Request (Use ReverseMap to handle both directions automatically)
CreateMap<SupplierResponse, SupplierRequest>().ReverseMap(); CreateMap<SupplierResponse, SupplierRequest>().ReverseMap();
CreateMap<StartCanvassRequest, ForAISearchingTagging>();
CreateMap<ForAISearchingTagging, StartCanvassResponse>().ReverseMap();
} }
} }
} }

View File

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

View File

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

View File

@ -1,17 +1,17 @@
using AutoMapper; using AutoMapper;
using Azure.Core;
using CPRNIMS.Domain.Services.ICanvass; using CPRNIMS.Domain.Services.ICanvass;
using CPRNIMS.Infrastructure.Database; using CPRNIMS.Infrastructure.Database;
using CPRNIMS.Infrastructure.Dto.Canvass; using CPRNIMS.Infrastructure.Dto.Canvass;
using CPRNIMS.Infrastructure.Dto.Canvass.Request; using CPRNIMS.Infrastructure.Dto.Canvass.Request;
using CPRNIMS.Infrastructure.Dto.Canvass.Response; using CPRNIMS.Infrastructure.Dto.Canvass.Response;
using CPRNIMS.Infrastructure.Dto.Common;
using CPRNIMS.Infrastructure.Entities.Canvass; using CPRNIMS.Infrastructure.Entities.Canvass;
using CPRNIMS.Infrastructure.Entities.Purchasing; using CPRNIMS.Infrastructure.Entities.Purchasing;
using CPRNIMS.Infrastructure.Helper; using CPRNIMS.Infrastructure.Helper;
using CPRNIMS.Infrastructure.ViewModel.Canvass;
using CPRNIMS.Infrastructure.ViewModel.Common; using CPRNIMS.Infrastructure.ViewModel.Common;
using Microsoft.Data.SqlClient; using Microsoft.Data.SqlClient;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using System.Data; using System.Data;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -31,14 +31,6 @@ namespace CPRNIMS.Domain.Services.Canvass
_mapper = mapper; _mapper = mapper;
} }
#region Get #region Get
public async Task<List<Suppliers>> GetSuppliers(CancellationToken ct)
{
return await _dbContext.Suppliers
.AsNoTracking()
.Where(s => s.IsActive)
.ToListAsync(ct);
}
public async Task<List<ItemListWOEmail>> GetItemSupplierWOEmail(CanvassDto CanvassDto) public async Task<List<ItemListWOEmail>> GetItemSupplierWOEmail(CanvassDto CanvassDto)
{ {
var allItems = await _dbContext.ItemListWOEmails var allItems = await _dbContext.ItemListWOEmails
@ -57,137 +49,14 @@ namespace CPRNIMS.Domain.Services.Canvass
return allItems ?? new List<BiddingItem>(); return allItems ?? new List<BiddingItem>();
} }
public async Task<PagedResult<ItemsForTagging>> GetItemsForTagging(CanvassDto dto) public async Task<List<PerSupplier>> GetCanvassPerSupplier(CanvassDto CanvassDto)
{ {
var parameters = new[] var allItems = await _dbContext.PerSuppliers
{ .FromSqlRaw($"EXEC GetCanvassPerSupplier @UserId",
new SqlParameter("@UserId", dto.UserId), new SqlParameter("@UserId", CanvassDto.UserId))
new SqlParameter("@SearchPRNo", dto.SearchPRNo ?? ""), .ToListAsync();
new SqlParameter("@SearchItemNo", dto.SearchItemNo ?? ""),
new SqlParameter("@SearchItemName", dto.SearchItemName ?? ""),
new SqlParameter("@SearchDepartment", dto.SearchDepartment ?? ""),
new SqlParameter("@PageNumber", dto.PageNumber),
new SqlParameter("@PageSize", dto.PageSize)
};
int totalCount = 0; return allItems ?? new List<PerSupplier>();
var departmentList = new List<string>();
var items = new List<ItemsForTagging>();
var conn = _dbContext.Database.GetDbConnection();
await conn.OpenAsync();
using var cmd = conn.CreateCommand();
cmd.CommandText = @"EXEC GetItemsForTagging @UserId,
@SearchPRNo,@SearchItemNo,@SearchItemName,@SearchDepartment,
@PageNumber, @PageSize";
foreach (var p in parameters) cmd.Parameters.Add(p);
cmd.CommandTimeout = 60;
using var reader = await cmd.ExecuteReaderAsync();
// Result set 1 — distinct supplier list
while (await reader.ReadAsync())
departmentList.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 ItemsForTagging
{
PRDetailsId = Convert.ToInt64(reader["PRDetailsId"]),
PRNo = Convert.ToInt64(reader["PRNo"]),
ItemNo = Convert.ToInt64(reader["ItemNo"]),
ItemName = reader["ItemName"]?.ToString(),
ItemDescription = reader["ItemDescription"]?.ToString(),
Qty = Convert.ToDecimal(reader["Qty"]),
Department = reader["Department"]?.ToString(),
CreatedBy = reader["CreatedBy"]?.ToString(),
CreatedDate =Convert.ToDateTime(reader["CreatedDate"]),
DateNeeded = Convert.ToDateTime(reader["DateNeeded"]),
});
}
await conn.CloseAsync();
return new PagedResult<ItemsForTagging>
{
Data = items,
TotalCount = totalCount,
PageNumber = dto.PageNumber,
PageSize = dto.PageSize,
DepartmentList = departmentList
};
}
public async Task<PagedResult<PerSupplier>> GetCanvassPerSupplier(CanvassDto 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("@SearchSupplier", dto.SearchSupplier ?? ""),
new SqlParameter("@PageNumber", dto.PageNumber),
new SqlParameter("@PageSize", dto.PageSize)
};
var supplierList = new List<string>();
int totalCount = 0;
var items = new List<PerSupplier>();
var conn = _dbContext.Database.GetDbConnection();
await conn.OpenAsync();
using var cmd = conn.CreateCommand();
cmd.CommandText = @"EXEC GetCanvassPerSupplier @UserId,
@SearchPRNo,@SearchItemNo,@SearchItemName,@SearchSupplier,
@PageNumber, @PageSize";
foreach (var p in parameters) cmd.Parameters.Add(p);
cmd.CommandTimeout = 60;
using var reader = await cmd.ExecuteReaderAsync();
// Result set 1 — distinct supplier list
while (await reader.ReadAsync())
supplierList.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 PerSupplier
{
SupplierId = reader["SupplierId"] as int? ?? 0,
SupplierName = reader["SupplierName"]?.ToString(),
EmailAddress = reader["EmailAddress"]?.ToString(),
AggreItemName = reader["AggreItemName"]?.ToString(),
AggreItemNo = reader["AggreItemNo"]?.ToString(),
AggrePRNo = reader["AggrePRNo"]?.ToString(),
});
}
await conn.CloseAsync();
return new PagedResult<PerSupplier>
{
Data = items,
TotalCount = totalCount,
PageNumber = dto.PageNumber,
PageSize = dto.PageSize,
SupplierList = supplierList
};
} }
public async Task<List<RFQPerSupplier>> GetSupplierBidByItem(CanvassDto CanvassDto) public async Task<List<RFQPerSupplier>> GetSupplierBidByItem(CanvassDto CanvassDto)
{ {
@ -244,26 +113,29 @@ namespace CPRNIMS.Domain.Services.Canvass
return allItems ?? new List<CanvassGroupByPRNo>(); return allItems ?? new List<CanvassGroupByPRNo>();
} }
public async Task<List<SupplierResponseDto>> GetSupplierItemWOEmail(CanvassDto canvassDto) public async Task<List<SupplierResponse>> GetSupplierItemWOEmail(CanvassDto canvassDto)
{ {
// 1. Use Interpolated string to prevent SQL injection and pass the parameter safely
var suppliers = await _dbContext.SupplierResponses var suppliers = await _dbContext.Suppliers
.FromSqlInterpolated($"EXEC GetSupplierItemWOEmail @ItemNo = {canvassDto.ItemNo}") .FromSqlInterpolated($"EXEC GetSupplierItemWOEmail @ItemNo = {canvassDto.ItemNo}")
.ToListAsync(); .ToListAsync();
return suppliers ?? new List<SupplierResponseDto>(); // 2. Map the List of entities to a List of Response objects
// AutoMapper handles collections automatically if the types are configured
return _mapper.Map<List<SupplierResponse>>(suppliers);
} }
public async Task<List<SupplierResponseDto>> GetSupplierById(CanvassDto CanvassDto) public async Task<List<SupplierResponse>> GetSupplierById(CanvassDto CanvassDto)
{ {
var items = await _dbContext.SupplierResponses var item = await _dbContext.Suppliers
.FromSqlRaw($"EXEC GetSupplierById @SupplierId", .FromSqlRaw($"EXEC GetSupplierById @SupplierId",
new SqlParameter("@SupplierId", CanvassDto.SupplierId)) new SqlParameter("@SupplierId", CanvassDto.SupplierId))
.ToListAsync(); .ToListAsync();
// 2. Map the List of entities to a List of Response objects
return items ?? new List<SupplierResponseDto>(); // AutoMapper handles collections automatically if the types are configured
return _mapper.Map<List<SupplierResponse>>(item);
} }
public async Task<List<RFQReference>> GetRFQ(ForCanvassDto CanvassDto) public async Task<List<RFQReference>> GetRFQ(CanvassDto CanvassDto)
{ {
var allItems = await _dbContext.RFQReferences var allItems = await _dbContext.RFQReferences
.FromSqlRaw($"EXEC GetRFQPerSupplier @SupplierId,@UserId", .FromSqlRaw($"EXEC GetRFQPerSupplier @SupplierId,@UserId",
@ -320,34 +192,14 @@ namespace CPRNIMS.Domain.Services.Canvass
return 0; return 0;
} }
} }
public async Task<List<ForAISearchingTagging>> GetForAISearchingTagging(CancellationToken ct) public async Task<List<ItemWithoutSupplier>> GetItemWithoutSupplier()
{
var allItems = await _dbContext.ForAISearchingTaggings
.AsNoTracking()
.Take(1)
.ToListAsync(ct);
return allItems ?? new List<ForAISearchingTagging>();
}
public async Task<List<ItemWithoutSupplier>> GetItemWithoutSupplier(CancellationToken ct)
{ {
var allItems = await _dbContext.ItemWithoutSuppliers var allItems = await _dbContext.ItemWithoutSuppliers
.FromSqlRaw("EXEC GetItemWithoutSupplier") .FromSqlRaw("EXEC GetItemWithoutSupplier")
.ToListAsync(ct); .ToListAsync();
return allItems ?? new List<ItemWithoutSupplier>(); return allItems ?? new List<ItemWithoutSupplier>();
} }
public async Task<List<SupplierForCanvass>> GetSupplierForCanvass(int supplierId,string userName,
CancellationToken ct)
{
var allItems = await _dbContext.SupplierForCanvass
.FromSqlRaw("EXEC GetSupplierForCanvass @UserName,@SupplierId",
new SqlParameter("@UserName", userName),
new SqlParameter("@SupplierId", supplierId)
).AsNoTracking().ToListAsync(ct);
return allItems ?? new List<SupplierForCanvass>();
}
public async Task<List<WOResponseById>> GetWOResponseBySuppId(CanvassDto CanvassDto) public async Task<List<WOResponseById>> GetWOResponseBySuppId(CanvassDto CanvassDto)
{ {
var allItems = await _dbContext.WOResponseByIds var allItems = await _dbContext.WOResponseByIds
@ -356,7 +208,7 @@ namespace CPRNIMS.Domain.Services.Canvass
return allItems ?? new List<WOResponseById>(); return allItems ?? new List<WOResponseById>();
} }
public async Task<RFQ> PostPerSupplierToken(ForCanvassDto CanvassDto) public async Task<RFQ> PostPerSupplierToken(CanvassDto CanvassDto)
{ {
await _dbContext.Database await _dbContext.Database
.ExecuteSqlRawAsync("EXEC PostPerSupplierToken @UserId,@SupplierId,@PRNo,@ItemNo,@CanvassNo,@PRDetailsId", .ExecuteSqlRawAsync("EXEC PostPerSupplierToken @UserId,@SupplierId,@PRNo,@ItemNo,@CanvassNo,@PRDetailsId",
@ -378,15 +230,15 @@ namespace CPRNIMS.Domain.Services.Canvass
return allItems ?? new List<SupplierBidById>(); return allItems ?? new List<SupplierBidById>();
} }
public async Task<List<SupplierResponseDto>> GetMySuppliers(CanvassDto CanvassDto) public async Task<List<SupplierResponse>> GetMySuppliers(CanvassDto CanvassDto)
{ {
var items = await _dbContext.SupplierResponses var items = await _dbContext.Suppliers
.FromSqlRaw($"EXEC GetMySuppliers @UserId,@SupplierId", .FromSqlRaw($"EXEC GetMySuppliers @UserId,@SupplierId",
new SqlParameter("@UserId", CanvassDto.UserId), new SqlParameter("@UserId", CanvassDto.UserId),
new SqlParameter("@SupplierId", CanvassDto.SupplierId)) new SqlParameter("@SupplierId", CanvassDto.SupplierId))
.ToListAsync(); .ToListAsync();
return items ?? new List<SupplierResponseDto>(); return _mapper.Map<List<SupplierResponse>>(items);
} }
public async Task<List<MyPRWOCanvass>> GetMyPRWOCanvass(CanvassDto itemDto) public async Task<List<MyPRWOCanvass>> GetMyPRWOCanvass(CanvassDto itemDto)
{ {
@ -459,7 +311,7 @@ namespace CPRNIMS.Domain.Services.Canvass
} }
#endregion #endregion
#region Post Put #region Post Put
public async Task<Result<SupplierResponse>> PostPutSupplierAsync(SupplierRequest request, CancellationToken ct) public async Task<Result<SupplierResponse>> PostSupplierAsync(SupplierRequest request, CancellationToken ct)
{ {
var strategy = _dbContext.Database.CreateExecutionStrategy(); var strategy = _dbContext.Database.CreateExecutionStrategy();
@ -470,7 +322,7 @@ namespace CPRNIMS.Domain.Services.Canvass
try try
{ {
var supplier = await _dbContext.Suppliers var supplier = await _dbContext.Suppliers
.FirstOrDefaultAsync(s => s.SupplierId == request.SupplierId, ct); .FirstOrDefaultAsync(s => s.SupplierName == request.SupplierName, ct);
if (supplier == null) if (supplier == null)
{ {
@ -490,6 +342,8 @@ namespace CPRNIMS.Domain.Services.Canvass
catch (DbUpdateException ex) catch (DbUpdateException ex)
{ {
await transaction.RollbackAsync(ct); await transaction.RollbackAsync(ct);
// handle unique constraint violation here if needed
throw; throw;
} }
}); });
@ -531,6 +385,16 @@ namespace CPRNIMS.Domain.Services.Canvass
new SqlParameter("@CanvassId", CanvassDto.CanvassId)); new SqlParameter("@CanvassId", CanvassDto.CanvassId));
return new CanvassDetail(); return new CanvassDetail();
} }
public async Task<PRCanvassDetail> PostCanvass(CanvassDto CanvassDto)
{
await _dbContext.Database
.ExecuteSqlRawAsync("EXEC PostCanvass @UserId, @SupplierId, @Status,@Remarks",
new SqlParameter("@SupplierId", CanvassDto.SupplierId != null ? CanvassDto.SupplierId : 0L),
new SqlParameter("@UserId", CanvassDto.UserId),
new SqlParameter("@Status", CanvassDto.Status),
new SqlParameter("@Remarks", CanvassDto.Remarks ?? "N/A"));
return new PRCanvassDetail();
}
public async Task<SupplierResponse> PostTaggingSupplier(CanvassDto CanvassDto) public async Task<SupplierResponse> PostTaggingSupplier(CanvassDto CanvassDto)
{ {
var (messCode, message) = CreateOutputParams(); var (messCode, message) = CreateOutputParams();
@ -683,7 +547,8 @@ namespace CPRNIMS.Domain.Services.Canvass
new SqlParameter("@CanvassSupplierId", canvassDto.CanvassSupplierId)); new SqlParameter("@CanvassSupplierId", canvassDto.CanvassSupplierId));
return new CanvassSupplier(); return new CanvassSupplier();
} }
public async Task<bool> SendRFQ(SupplierEmailRequest supplierEmailRequest)
public async Task SendRFQ(SupplierEmailRequest supplierEmailRequest)
{ {
var baseTemplate = EMailTemplate("Content\\SMTPEmailContent", "SendToSupplier.cshtml"); var baseTemplate = EMailTemplate("Content\\SMTPEmailContent", "SendToSupplier.cshtml");
@ -710,9 +575,7 @@ namespace CPRNIMS.Domain.Services.Canvass
AttachPath=supplierEmailRequest.AttachPath AttachPath=supplierEmailRequest.AttachPath
}; };
if (await _smptHelper.SendEmailAsync(messageDetails)) await _smptHelper.SendEmailAsync(messageDetails);
return true;
return false;
} }
public string EMailTemplate(string relativePath, string emailTemplate) public string EMailTemplate(string relativePath, string emailTemplate)
{ {
@ -730,61 +593,14 @@ namespace CPRNIMS.Domain.Services.Canvass
return "Template file not found"; return "Template file not found";
} }
} }
public async Task DeleteAsync(long pRDetailsId, CancellationToken ct)
public async Task<bool> SearchingUpdate(long pRDetailsId)
{ {
await _dbContext.ForAISearchingTaggings var rowsAffected = await _dbContext.PRDetails
.Where(p => p.PRDetailsId == pRDetailsId) .Where(p => p.PRDetailsId == pRDetailsId)
.ExecuteDeleteAsync(ct); .ExecuteUpdateAsync(s => s.SetProperty(p => p.IsSearched, true));
}
public async Task<Result<StartCanvassResponse>> StartCanvass(CanvassVM request, CancellationToken ct) return rowsAffected > 0;
{
var detailIds = request.ForSupplierSearchList?.PRDetailsId;
if (detailIds == null || !detailIds.Any())
return Result<StartCanvassResponse>.Failure("No items provided.");
// 1. Get IDs that already exist in one call to avoid the loop-check
var existingIds = await _dbContext.ForAISearchingTaggings
.Where(f => detailIds.Contains(f.PRDetailsId))
.Select(f => f.PRDetailsId)
.ToListAsync(ct);
var newTags = new List<ForAISearchingTagging>();
var idsToUpdate = new List<long>();
for (int i = 0; i < detailIds.Count; i++)
{
var currentId = detailIds[i];
if (existingIds.Contains(currentId)) continue;
newTags.Add(new ForAISearchingTagging
{
PRDetailsId = currentId,
PRNo = request.ForSupplierSearchList.PRNo[i],
ItemNo = request.ForSupplierSearchList.ItemNo[i],
ItemName = request.ForSupplierSearchList.ItemName[i],
ItemDescription = request.ForSupplierSearchList.ItemDescription[i],
IsInternational = request.IsInternational,
FullName = request.FullName,
UserId = request.UserId
});
idsToUpdate.Add(currentId);
}
if (newTags.Any())
{
// 2. Bulk Add
await _dbContext.ForAISearchingTaggings.AddRangeAsync(newTags, ct);
await _dbContext.SaveChangesAsync(ct);
// 3. Bulk Update the flags AFTER saving the tags
await _dbContext.PRDetails
.Where(p => idsToUpdate.Contains(p.PRDetailsId))
.ExecuteUpdateAsync(s => s.SetProperty(p => p.IsSearched, true), ct);
}
return Result<StartCanvassResponse>.Success(new StartCanvassResponse { });
} }
#endregion #endregion
} }

View File

@ -3,11 +3,9 @@ using CPRNIMS.Infrastructure.Dto.Canvass.Result;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Text.Json; using System.Text.Json;
using System.Text.Json.Serialization;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -21,125 +19,7 @@ namespace CPRNIMS.Domain.Services.Canvass
// Common contact page suffixes to try // Common contact page suffixes to try
private static readonly string[] ContactPaths = private static readonly string[] ContactPaths =
{ "/contact", "/contact-us", "/pages/contact-us", "/about/contact", "/about" }; { "/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) public SupplierSearchService(HttpClient httpClient, IConfiguration config)
{ {
_httpClient = httpClient; _httpClient = httpClient;
@ -147,90 +27,77 @@ namespace CPRNIMS.Domain.Services.Canvass
} }
public async Task<List<SupplierResponse>> SearchAndFilterSuppliersAsync( public async Task<List<SupplierResponse>> SearchAndFilterSuppliersAsync(
string itemName, string itemDescription, bool isInternational) string itemName, string itemDescription)
{ {
var locality = isInternational
? "all over Asia including Philippines"
: "Philippines";
// Step 1: Tavily — get supplier URLs // Step 1: Tavily — get supplier URLs
var (searchContent, supplierUrls) = await SearchTavilyAsync(itemName, itemDescription, locality); var (searchContent, supplierUrls) = await SearchTavilyAsync(itemName, itemDescription);
// Step 2: Fetch contact pages from discovered URLs // Step 2: Fetch contact pages from discovered URLs
var contactContent = await FetchContactPagesAsync(supplierUrls); var contactContent = await FetchContactPagesAsync(supplierUrls);
// Step 3: Combine search + contact content, send to Groq // Step 3: Combine search + contact content, send to Groq
var combined = searchContent + " CONTACT_PAGES_DATA: " + contactContent; var combined = searchContent + " CONTACT_PAGES_DATA: " + contactContent;
var suppliers = await FilterWithGroqAsync(itemName, itemDescription, combined,isInternational); var suppliers = await FilterWithGroqAsync(itemName, itemDescription, combined);
return suppliers; return suppliers;
} }
// ── Tavily ── // ── Tavily ──────────────────────────────────────────────────────────────
private async Task<(string content, List<string> urls)> SearchTavilyAsync( private async Task<(string content, List<string> urls)> SearchTavilyAsync(
string itemName, string itemDescription,string locality) string itemName, string itemDescription)
{ {
try var query = $"{itemName} {itemDescription} suppliers Philippines budget price contact email phone";
var payload = new
{ {
var query = $"{itemName} {itemDescription} suppliers {locality} budget price contact email phone"; query,
max_results = 10,
search_depth = "advanced",
include_answer = false
};
var payload = new 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
{ {
query, var uri = new Uri(r.Url);
max_results = 10, var baseUrl = $"{uri.Scheme}://{uri.Host}";
search_depth = "advanced", if (!urls.Contains(baseUrl)) urls.Add(baseUrl);
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++;
} }
catch { }
var fullText = sb.ToString(); i++;
if (fullText.Length > 2000) fullText = fullText[..2000];
return (fullText, urls);
} }
catch (Exception ex)
{ var fullText = sb.ToString();
ex.ToString(); if (fullText.Length > 2000) fullText = fullText[..2000];
throw;
} return (fullText, urls);
} }
// ── Fetch Contact Pages ─── // ── Fetch Contact Pages ──────────────────────────────────────────────────
private async Task<string> FetchContactPagesAsync(List<string> baseUrls) private async Task<string> FetchContactPagesAsync(List<string> baseUrls)
{ {
var sb = new StringBuilder(); var sb = new StringBuilder();
@ -281,173 +148,84 @@ namespace CPRNIMS.Domain.Services.Canvass
// ── Groq ───────────────────────────────────────────────────────────────── // ── Groq ─────────────────────────────────────────────────────────────────
private async Task<List<SupplierResponse>> FilterWithGroqAsync( private async Task<List<SupplierResponse>> FilterWithGroqAsync(
string itemName, string itemDescription, string searchContent, bool isInternational) string itemName, string itemDescription, string searchContent)
{ {
try var prompt = $"Extract top 10 unique suppliers for: {itemName} {itemDescription}. " +
"Prioritize Philippines suppliers first. " +
"IMPORTANT: Look carefully in CONTACT_PAGES_DATA section for real phone numbers and emails. " +
"Extract exact email addresses and phone numbers found. " +
"For domains without contact data found, infer email as sales@domain or info@domain. " +
"Prefer budget-friendly suppliers. No duplicates. " +
"Return ONLY a raw JSON array: company_name, country, phone_number, contact_email, website, estimated_price_usd, item_specifications. " +
$"Null for missing. JSON array only. Data: {searchContent}";
var payload = new
{ {
var localityRule = isInternational model = _config["Groq:Model"] ?? "llama-3.1-8b-instant",
? "1. Include suppliers from Philippines first, then other Asian countries (e.g. China, Japan, South Korea, Taiwan, India, Singapore).\n" stream = false,
: "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"; max_tokens = 2048,
temperature = 0.1,
var prompt = messages = new[]
$"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 = "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 } new { role = "user", content = prompt }
} }
}; };
var request = new HttpRequestMessage(HttpMethod.Post, _config["Groq:ApiUrl"]); var request = new HttpRequestMessage(HttpMethod.Post, _config["Groq:ApiUrl"]);
request.Headers.Add("Authorization", $"Bearer {_config["Groq:ApiKey"]}"); request.Headers.Add("Authorization", $"Bearer {_config["Groq:ApiKey"]}");
request.Content = new StringContent( request.Content = new StringContent(
JsonSerializer.Serialize(payload), Encoding.UTF8, "application/json"); JsonSerializer.Serialize(payload), Encoding.UTF8, "application/json");
var response = await _httpClient.SendAsync(request); var response = await _httpClient.SendAsync(request);
response.EnsureSuccessStatusCode(); response.EnsureSuccessStatusCode();
var body = await response.Content.ReadAsStringAsync(); var body = await response.Content.ReadAsStringAsync();
var groqResp = JsonSerializer.Deserialize<GroqResponse>(body, var groqResp = JsonSerializer.Deserialize<GroqResponse>(body,
new JsonSerializerOptions { PropertyNameCaseInsensitive = true }); new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
var rawText = groqResp?.Choices?[0]?.Message?.Content ?? string.Empty; var rawText = groqResp?.Choices?[0]?.Message?.Content ?? string.Empty;
var match = Regex.Match(rawText, @"\[[\s\S]*\]"); var match = Regex.Match(rawText, @"\[[\s\S]*\]");
if (!match.Success) return new List<SupplierResponse>(); if (!match.Success) return new List<SupplierResponse>();
// Add the converter to the shared options var groqList = JsonSerializer.Deserialize<List<GroqSupplierResult>>(match.Value,
var jsonOptions = new JsonSerializerOptions new JsonSerializerOptions { PropertyNameCaseInsensitive = true })
{ ?? new List<GroqSupplierResult>();
PropertyNameCaseInsensitive = true,
Converters = { new FlexibleDecimalConverter() }
};
var groqList = JsonSerializer.Deserialize<List<GroqSupplierResult>>(match.Value, jsonOptions) var seen = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
?? new List<GroqSupplierResult>(); var suppliers = new List<SupplierResponse>();
var seenNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase); foreach (var s in groqList)
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(); var key = (s.CompanyName ?? "").Trim().ToLower();
throw; if (string.IsNullOrEmpty(key) || seen.Contains(key)) continue;
seen.Add(key);
if (string.IsNullOrEmpty(s.ContactEmail)) continue;
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;
} }
}
private static string NormalizePhone(string phone)
{
if (string.IsNullOrWhiteSpace(phone)) return string.Empty;
// Strip everything except digits return suppliers;
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

@ -1,49 +0,0 @@
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

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

View File

@ -1,11 +1,9 @@
using CPRNIMS.Domain.Contracts.Inventory; using CPRNIMS.Domain.Contracts.Inventory;
using CPRNIMS.Infrastructure.Database; using CPRNIMS.Infrastructure.Database;
using CPRNIMS.Infrastructure.Dto.Inventory; using CPRNIMS.Infrastructure.Dto.Inventory;
using CPRNIMS.Infrastructure.Dto.Inventory.Request; using CPRNIMS.Infrastructure.Dto.Items;
using CPRNIMS.Infrastructure.Dto.Inventory.Response; using CPRNIMS.Infrastructure.Entities.Finance;
using CPRNIMS.Infrastructure.Entities.Account;
using CPRNIMS.Infrastructure.Entities.Inventory; using CPRNIMS.Infrastructure.Entities.Inventory;
using Microsoft.AspNetCore.Identity;
using Microsoft.Data.SqlClient; using Microsoft.Data.SqlClient;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using System; using System;
@ -19,224 +17,69 @@ namespace CPRNIMS.Domain.Services.Inventory
public class Inventory : IInventory public class Inventory : IInventory
{ {
private readonly NonInventoryDbContext _dbContext; private readonly NonInventoryDbContext _dbContext;
private readonly UserManager<ApplicationUser> _userManager; public Inventory(NonInventoryDbContext dbContext)
public Inventory(NonInventoryDbContext dbContext, UserManager<ApplicationUser> userManager)
{ {
_dbContext = dbContext; _dbContext = dbContext;
_userManager = userManager;
} }
public async Task<TransactContextDto?> GetTransactContextAsync(int inventoryId, CancellationToken ct) public async Task<List<Infrastructure.Entities.Inventory.ItemDetail>> GetInventoryById(InventoryDto itemDto)
{ {
var inv = await _dbContext.Inventories try
.Where(i => i.InventoryId == inventoryId && i.IsActive)
.Select(i => new
{
i.InventoryId,
i.QtyOnHand,
i.QtyIn,
i.QtyOut,
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
{ {
InventoryId = inv.InventoryId, var allItems = await _dbContext.ItemDetails
ItemName = inv.FirstDetail?.ItemName ?? "—", .FromSqlRaw($"EXEC GetInventoryById @UserId = '{itemDto.UserId}',@InventoryId = '{itemDto.InventoryId}'")
PRNo = inv.FirstDetail.PRNo, .ToListAsync();
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>(); 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"])
});
} }
catch (SqlException ex)
await conn.CloseAsync();
return new PagedResult<InventoryResponse>
{ {
Data = items, ex.ToString();
TotalCount = totalCount, throw;
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<Infrastructure.Entities.Inventory.Inventory>>
GetInventoryByUserId(InventoryDto itemDto)
{
try
{
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>();
}
catch (SqlException ex)
{
ex.ToString();
throw;
}
} }
public async Task<List<Lot>> GetLotNoById(InventoryDto itemDto) public async Task<List<Lot>> GetLotNoById(InventoryDto itemDto)
{ {
var allItems = await _dbContext.Lots try
.FromSqlRaw($"EXEC GetLotById @UserId = '{itemDto.UserId}'") {
.ToListAsync(); var allItems = await _dbContext.Lots
.FromSqlRaw($"EXEC GetLotById @UserId = '{itemDto.UserId}'")
.ToListAsync();
return allItems ?? new List<Lot>(); return allItems ?? new List<Lot>();
}
catch (SqlException ex)
{
ex.ToString();
throw;
}
} }
public async Task<List<Lot>> GetLotNo(InventoryDto itemDto) public async Task<List<Lot>> GetLotNo(InventoryDto itemDto)
@ -251,77 +94,125 @@ namespace CPRNIMS.Domain.Services.Inventory
public async Task<Lot> PostPutLotNo(InventoryDto itemDto) public async Task<Lot> PostPutLotNo(InventoryDto itemDto)
{ {
await _dbContext.Database try
.ExecuteSqlRawAsync("EXEC PostPutLotNo @UserId, @LotId, @LotTypeId,@LotName", {
new SqlParameter("@LotId", itemDto.LotId != null ? itemDto.LotId : 0L), await _dbContext.Database
new SqlParameter("@UserId", itemDto.UserId), .ExecuteSqlRawAsync("EXEC PostPutLotNo @UserId, @LotId, @LotTypeId,@LotName",
new SqlParameter("@LotTypeId", itemDto.LotTypeId), new SqlParameter("@LotId", itemDto.LotId != null ? itemDto.LotId : 0L),
new SqlParameter("@LotName", itemDto.LotName)); new SqlParameter("@UserId", itemDto.UserId),
return new Lot(); new SqlParameter("@LotTypeId", itemDto.LotTypeId),
new SqlParameter("@LotName", itemDto.LotName));
return new Lot();
}
catch (SqlException ex)
{
ex.ToString();
throw;
}
} }
public async Task<Infrastructure.Entities.Inventory.Inventory> PostPutReqApproval(InventoryDto itemDto) public async Task<Infrastructure.Entities.Inventory.Inventory> PostPutReqApproval(InventoryDto itemDto)
{ {
await _dbContext.Database try
.ExecuteSqlRawAsync("EXEC PostPutReqApproval @UserId, @ItemNo, @Status, @Remarks", {
new SqlParameter("@ItemNo", itemDto.InventoryId != null ? itemDto.InventoryId : 0L), await _dbContext.Database
new SqlParameter("@UserId", itemDto.UserId), .ExecuteSqlRawAsync("EXEC PostPutReqApproval @UserId, @ItemNo, @Status, @Remarks",
new SqlParameter("@Status", itemDto.Status), new SqlParameter("@ItemNo", itemDto.InventoryId != null ? itemDto.InventoryId : 0L),
new SqlParameter("@Remarks", itemDto.Remarks ?? "N/A")); new SqlParameter("@UserId", itemDto.UserId),
return new Infrastructure.Entities.Inventory.Inventory(); new SqlParameter("@Status", itemDto.Status),
new SqlParameter("@Remarks", itemDto.Remarks ?? "N/A"));
return new Infrastructure.Entities.Inventory.Inventory();
}
catch (SqlException ex)
{
ex.ToString();
throw;
}
} }
public async Task<ItemDetail> PostPutLotBin(InventoryDto itemDto) public async Task<ItemDetail> PostPutLotBin(InventoryDto itemDto)
{ {
await _dbContext.Database try
.ExecuteSqlRawAsync("EXEC PostPutLotBin @UserId, @LotId, @InventoryId", {
new SqlParameter("@InventoryId", itemDto.InventoryId), await _dbContext.Database
new SqlParameter("@UserId", itemDto.UserId), .ExecuteSqlRawAsync("EXEC PostPutLotBin @UserId, @LotId, @InventoryId",
new SqlParameter("@LotId", itemDto.LotId)); new SqlParameter("@InventoryId", itemDto.InventoryId),
return new ItemDetail(); new SqlParameter("@UserId", itemDto.UserId),
new SqlParameter("@LotId", itemDto.LotId));
return new ItemDetail();
}
catch (SqlException ex)
{
ex.ToString();
throw;
}
} }
public async Task<RequestItem> PostPutReqItems(InventoryDto itemDto) public async Task<RequestItem> PostPutReqItems(InventoryDto itemDto)
{ {
if (itemDto.QtyReceived == null || itemDto.QtyReceived == 0) try
{ {
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();
} }
if (itemDto.LotId == null || itemDto.LotId == 0) catch (SqlException ex)
{ {
itemDto.LotId = 0; ex.ToString();
throw;
} }
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) public async Task<List<RequestItemDetail>> GetRequestedItemByUserId(InventoryDto itemDto)
{ {
var allItems = await _dbContext.RequestItemDetails try
{
var allItems = await _dbContext.RequestItemDetails
.FromSqlRaw($"EXEC GetRequestedItemByUserId @UserId = '{itemDto.UserId}', " + .FromSqlRaw($"EXEC GetRequestedItemByUserId @UserId = '{itemDto.UserId}', " +
$"@RequestItemId = '{itemDto.RequestItemId}',@WithoutStocks = '{itemDto.WithoutStocks}'") $"@RequestItemId = '{itemDto.RequestItemId}',@WithoutStocks = '{itemDto.WithoutStocks}'")
.ToListAsync(); .ToListAsync();
return allItems ?? new List<RequestItemDetail>(); return allItems ?? new List<RequestItemDetail>();
}
catch (SqlException ex)
{
ex.ToString();
throw;
}
} }
public async Task<List<LotQtyByItem>> GetLotQtyByItem(InventoryDto itemDto) public async Task<List<LotQtyByItem>> GetLotQtyByItem(InventoryDto itemDto)
{ {
var allItems = await _dbContext.LotQtyByItems try
.FromSqlRaw($"EXEC GetLotQtyByItem @UserId = '{itemDto.UserId}', " + {
$"@ItemNo = '{itemDto.ItemNo}',@LotId = '{itemDto.LotId}'") var allItems = await _dbContext.LotQtyByItems
.ToListAsync(); .FromSqlRaw($"EXEC GetLotQtyByItem @UserId = '{itemDto.UserId}', " +
$"@ItemNo = '{itemDto.ItemNo}',@LotId = '{itemDto.LotId}'")
.ToListAsync();
return allItems ?? new List<LotQtyByItem>(); return allItems ?? new List<LotQtyByItem>();
}
catch (SqlException ex)
{
ex.ToString();
throw;
}
} }
} }
} }

View File

@ -1,307 +0,0 @@
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

@ -1,260 +0,0 @@
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

@ -1,331 +0,0 @@
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,5 +1,6 @@
using CPRNIMS.Domain.Contracts.Items; using CPRNIMS.Domain.Contracts.Items;
using CPRNIMS.Infrastructure.Database; using CPRNIMS.Infrastructure.Database;
using CPRNIMS.Infrastructure.Dto.Canvass;
using CPRNIMS.Infrastructure.Dto.Items; using CPRNIMS.Infrastructure.Dto.Items;
using CPRNIMS.Infrastructure.Entities.Account; using CPRNIMS.Infrastructure.Entities.Account;
using CPRNIMS.Infrastructure.Entities.Items; using CPRNIMS.Infrastructure.Entities.Items;
@ -63,6 +64,7 @@ namespace CPRNIMS.Domain.Services.Items
UserId = itemDto.UserId UserId = itemDto.UserId
}; };
} }
public async Task<Infrastructure.Entities.Items.Item> PutItemDetail(ItemDto itemDto) public async Task<Infrastructure.Entities.Items.Item> PutItemDetail(ItemDto itemDto)
{ {
await _dbContext.Database await _dbContext.Database
@ -91,6 +93,126 @@ namespace CPRNIMS.Domain.Services.Items
return new Infrastructure.Entities.Items.Item(); return new Infrastructure.Entities.Items.Item();
} }
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<Infrastructure.Entities.Items.Item>> GetItemDetail(ItemDto itemDto)
{
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>();
}
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<ItemAttachement> PostPutItemPath(ItemDto itemDto) public async Task<ItemAttachement> PostPutItemPath(ItemDto itemDto)
{ {
var isExist = await _dbContext.ItemAttachements var isExist = await _dbContext.ItemAttachements
@ -122,6 +244,19 @@ namespace CPRNIMS.Domain.Services.Items
new SqlParameter("@ItemLocalId", itemDto.ItemLocalId)); new SqlParameter("@ItemLocalId", itemDto.ItemLocalId));
return new ItemCart(); return new ItemCart();
} }
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();
return allItems ?? new List<ItemCart>();
}
public async Task<ResponseObject> PostPurchRequest(ItemDto itemDto) public async Task<ResponseObject> PostPurchRequest(ItemDto itemDto)
{ {
var (messCode, message) = OutputParamMessage.CreateOutputParams(); var (messCode, message) = OutputParamMessage.CreateOutputParams();
@ -187,23 +322,8 @@ namespace CPRNIMS.Domain.Services.Items
existing.FileName = attach.FileName; existing.FileName = attach.FileName;
} }
await _dbContext.SaveChangesAsync(); await _dbContext.SaveChangesAsync();
}
Task<ItemCart> IItem.PostPutItemPath(ItemDto itemDto)
{
throw new NotImplementedException();
} }
public async Task<List<ItemCart>> GetItemCart(ItemDto itemDto) public async Task<(long,long)> GetPRNo()
{
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>();
}
public async Task<(long, long)> GetPRNo()
{ {
try try
{ {
@ -213,9 +333,9 @@ namespace CPRNIMS.Domain.Services.Items
.FirstOrDefaultAsync(); .FirstOrDefaultAsync();
if (latestPR != null) if (latestPR != null)
return (latestPR.PRNo + 1, latestPR.PRId + 1); return (latestPR.PRNo + 1,latestPR.PRId + 1);
else else
return (0, 0); return (0,0);
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -224,122 +344,11 @@ namespace CPRNIMS.Domain.Services.Items
} }
} }
public async Task<List<ItemLocalization>> GetItemLocalization(ItemDto itemDto) Task<ItemCart> IItem.PostPutItemPath(ItemDto itemDto)
{ {
var localizations = await _dbContext.ItemLocalizations throw new NotImplementedException();
.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) public async Task <List<Departments>> GetDepartment(ItemCodeDto itemCode)
{ {
return await _dbContext.Departments return await _dbContext.Departments
@ -358,18 +367,18 @@ namespace CPRNIMS.Domain.Services.Items
return allItems ?? new List<NotifUserKey>(); return allItems ?? new List<NotifUserKey>();
} }
public async Task<IReadOnlyList<ProjectCodes>> GetProjectCode()
public async Task<List<ProjectCodes>> GetProjectCode()
{ {
return await _dbContext.ProjectCodes return await _dbContext.ProjectCodes
.AsNoTracking() .AsNoTracking()
.ToListAsync(); .ToListAsync();
} }
public async Task<IReadOnlyList<ProjectCodes>> GetProjectCodeByTerm(string? term) public async Task<List<ProjectCodes>> GetProjectCodeByTerm(string? term)
{ {
return await _dbContext.ProjectCodes return await _dbContext.ProjectCodes
.AsNoTracking() .AsNoTracking()
.Where(p => p.StatusName != "Completed" && p.IsActive .Where(p => EF.Functions.Like(p.ProjectCode, $"%{term}%"))
&& EF.Functions.Like(p.ProjectCode, $"%{term}%"))
.ToListAsync(); .ToListAsync();
} }
} }

View File

@ -1,7 +1,7 @@
using CPRNIMS.Domain.Contracts.PO; using CPRNIMS.Domain.Contracts.PO;
using CPRNIMS.Infrastructure.Database; using CPRNIMS.Infrastructure.Database;
using CPRNIMS.Infrastructure.Dto.Canvass.Response;
using CPRNIMS.Infrastructure.Dto.PO; using CPRNIMS.Infrastructure.Dto.PO;
using CPRNIMS.Infrastructure.Dto.PR;
using CPRNIMS.Infrastructure.Entities.Canvass; using CPRNIMS.Infrastructure.Entities.Canvass;
using CPRNIMS.Infrastructure.Entities.Common; using CPRNIMS.Infrastructure.Entities.Common;
using CPRNIMS.Infrastructure.Entities.LocalDb.NonInvent; using CPRNIMS.Infrastructure.Entities.LocalDb.NonInvent;
@ -30,14 +30,6 @@ namespace CPRNIMS.Domain.Services.PO
_smptHelper = smptHelper; _smptHelper = smptHelper;
} }
#region Get #region Get
public async Task<IReadOnlyList<Currencies>> GetCurrencies(string currencyName, CancellationToken ct)
{
return await _dbContext.Currencies.AsNoTracking()
.Where(c => c.IsActive==true &&
(string.IsNullOrEmpty(currencyName) || c.CurrencyName.Contains(currencyName)))
.ToListAsync(ct);
}
public async Task<POFormData> GetPOFormDataAsync(long? poId) public async Task<POFormData> GetPOFormDataAsync(long? poId)
{ {
// Reuse the connection from your existing DbContext // Reuse the connection from your existing DbContext
@ -81,15 +73,15 @@ namespace CPRNIMS.Domain.Services.PO
var charges = await _dbContext.OtherCharges.ToListAsync(); var charges = await _dbContext.OtherCharges.ToListAsync();
return charges; return charges;
} }
public async Task<List<SupplierResponseDto>> GetSuppliers(PODto itemDto) public async Task<List<Suppliers>> GetSuppliers(PODto itemDto)
{ {
var allItems = await _dbContext.SupplierResponses var allItems = await _dbContext.Suppliers
.FromSqlRaw($"EXEC GetSuppliers @UserId,@SupplierName", .FromSqlRaw($"EXEC GetSuppliers @UserId,@SupplierName",
new SqlParameter("@UserId", itemDto.UserId), new SqlParameter("@UserId", itemDto.UserId),
new SqlParameter("@SupplierName", itemDto.SupplierName)) new SqlParameter("@SupplierName", itemDto.SupplierName))
.ToListAsync(); .ToListAsync();
return allItems ?? new List<SupplierResponseDto>(); return allItems ?? new List<Suppliers>();
} }
public async Task<List<PRWOCanvass>> GetPRWOCanvass(PODto itemDto) public async Task<List<PRWOCanvass>> GetPRWOCanvass(PODto itemDto)
{ {
@ -501,7 +493,7 @@ namespace CPRNIMS.Domain.Services.PO
await _dbContext.Database await _dbContext.Database
.ExecuteSqlRawAsync("EXEC PostPutCustomPO @UserId,@POTypeId,@PONumber,@PRDetailsId,@Specification,@PRNo,@PORemarks,@IncoTermsId," + .ExecuteSqlRawAsync("EXEC PostPutCustomPO @UserId,@POTypeId,@PONumber,@PRDetailsId,@Specification,@PRNo,@PORemarks,@IncoTermsId," +
$"@PODId,@ProfInvoiceNo,@ProfInvoiceDate,@PaymentTermsId,@ShippingInstructionId,@SupplierId,@DeliveryDate,@Discount,@Amount," + $"@PODId,@ProfInvoiceNo,@ProfInvoiceDate,@PaymentTermsId,@ShippingInstructionId,@SupplierId,@DeliveryDate,@Discount,@Amount," +
$"@UnitPrice,@Quantity,@DeliverTo,@CountryOrigin,@CurrencyId, @MessCode OUTPUT, @Message OUTPUT", $"@UnitPrice,@Quantity,@DeliverTo, @MessCode OUTPUT, @Message OUTPUT",
new SqlParameter("@UserId", pODto.UserId), new SqlParameter("@UserId", pODto.UserId),
new SqlParameter("@POTypeId", pODto.POTypeId), new SqlParameter("@POTypeId", pODto.POTypeId),
new SqlParameter("@PONumber", formattedPONumber), new SqlParameter("@PONumber", formattedPONumber),
@ -523,8 +515,6 @@ namespace CPRNIMS.Domain.Services.PO
new SqlParameter("@UnitPrice", pODto.UnitPrice), new SqlParameter("@UnitPrice", pODto.UnitPrice),
new SqlParameter("@Quantity", pODto.Quantity), new SqlParameter("@Quantity", pODto.Quantity),
new SqlParameter("@DeliverTo", pODto.DeliverTo), new SqlParameter("@DeliverTo", pODto.DeliverTo),
new SqlParameter("@CountryOrigin", pODto.CountryOrigin ?? "N/A"),
new SqlParameter("@CurrencyId", pODto.CurrencyId),
messCode, messCode,
message); message);
@ -553,7 +543,7 @@ namespace CPRNIMS.Domain.Services.PO
await _dbContext.Database await _dbContext.Database
.ExecuteSqlRawAsync("EXEC PutExistingPO @UserId,@POTypeId,@PONumber,@PRDetailsId,@Specification,@PRNo,@PORemarks,@IncoTermsId," + .ExecuteSqlRawAsync("EXEC PutExistingPO @UserId,@POTypeId,@PONumber,@PRDetailsId,@Specification,@PRNo,@PORemarks,@IncoTermsId," +
$"@PODId,@ProfInvoiceNo,@ProfInvoiceDate,@PaymentTermsId,@ShippingInstructionId,@SupplierId,@DeliveryDate,@Discount,@Amount," + $"@PODId,@ProfInvoiceNo,@ProfInvoiceDate,@PaymentTermsId,@ShippingInstructionId,@SupplierId,@DeliveryDate,@Discount,@Amount," +
$"@UnitPrice,@Quantity,@DeliverTo,@IsRemoved,@CountryOrigin,@CurrencyId, @MessCode OUTPUT, @Message OUTPUT", $"@UnitPrice,@Quantity,@DeliverTo,@IsRemoved, @MessCode OUTPUT, @Message OUTPUT",
new SqlParameter("@UserId", pODto.UserId), new SqlParameter("@UserId", pODto.UserId),
new SqlParameter("@POTypeId", pODto.POTypeId), new SqlParameter("@POTypeId", pODto.POTypeId),
new SqlParameter("@PONumber", pODto.PONo), new SqlParameter("@PONumber", pODto.PONo),
@ -576,8 +566,6 @@ namespace CPRNIMS.Domain.Services.PO
new SqlParameter("@Quantity", pODto.Quantity), new SqlParameter("@Quantity", pODto.Quantity),
new SqlParameter("@DeliverTo", pODto.DeliverTo), new SqlParameter("@DeliverTo", pODto.DeliverTo),
new SqlParameter("@IsRemoved", isRemoved), new SqlParameter("@IsRemoved", isRemoved),
new SqlParameter("@CountryOrigin", pODto.CountryOrigin ?? "N/A"),
new SqlParameter("@CurrencyId", pODto.CurrencyId),
messCode, messCode,
message); message);
@ -644,9 +632,7 @@ namespace CPRNIMS.Domain.Services.PO
DeliveryDate = PODto.DeliveryDate, DeliveryDate = PODto.DeliveryDate,
DeliverTo = PODto.DeliverTo ?? "N/A", DeliverTo = PODto.DeliverTo ?? "N/A",
Specification = specification, Specification = specification,
IsUpdate = PODto.IsUpdate, IsUpdate = PODto.IsUpdate
CountryOrigin=PODto.CountryOrigin,
CurrencyId=PODto.CurrencyId
}; };
} }
public async Task<DocRequired> PostSuppDocRequirements(PODto poDto) public async Task<DocRequired> PostSuppDocRequirements(PODto poDto)

View File

@ -633,17 +633,6 @@ namespace CPRNIMS.Domain.Services.PR
&& pr.IsActive && pr.IsActive
select pr).AnyAsync(); 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) public async Task<MessageResponse> PRItemRemoval(PRDto prDto)
{ {
var (messCode, message) = CreateOutputParams(); var (messCode, message) = CreateOutputParams();
@ -664,6 +653,7 @@ namespace CPRNIMS.Domain.Services.PR
}; };
return response; return response;
} }
public async Task<ResponseObject> PostPutProjectCode(PRDto prDto) public async Task<ResponseObject> PostPutProjectCode(PRDto prDto)
{ {
if (prDto == null) throw new ArgumentNullException(nameof(prDto)); if (prDto == null) throw new ArgumentNullException(nameof(prDto));
@ -679,14 +669,13 @@ namespace CPRNIMS.Domain.Services.PR
ProjectName = prDto.ProjectName, ProjectName = prDto.ProjectName,
DeliveryAddress = prDto.DeliveryAddress, DeliveryAddress = prDto.DeliveryAddress,
MaxDays = prDto.MaxDays, MaxDays = prDto.MaxDays,
StatusName = prDto.StatusName,
IsActive = prDto.IsActive IsActive = prDto.IsActive
}; };
await _dbContext.ProjectCodes.AddAsync(project); await _dbContext.ProjectCodes.AddAsync(project);
} }
else else
{ {
if (await IsUsingAsync(prDto.ProjectCodeId) && await ProjectStatusChanges(prDto.ProjectCodeId,prDto.StatusName) == false) if (await IsUsingAsync(prDto.ProjectCodeId))
{ {
return new ResponseObject() return new ResponseObject()
{ {
@ -695,17 +684,12 @@ namespace CPRNIMS.Domain.Services.PR
success = false, success = false,
}; };
} }
if (await IsUsingAsync(prDto.ProjectCodeId))
{
existing.StatusName = prDto.StatusName;
}
else else
{ {
existing.ProjectCode = prDto.ProjectCode; existing.ProjectCode = prDto.ProjectCode;
existing.ProjectName = prDto.ProjectName; existing.ProjectName = prDto.ProjectName;
existing.DeliveryAddress = prDto.DeliveryAddress; existing.DeliveryAddress = prDto.DeliveryAddress;
existing.MaxDays = prDto.MaxDays; existing.MaxDays = prDto.MaxDays;
existing.StatusName = prDto.StatusName;
existing.IsActive = prDto.IsActive; existing.IsActive = prDto.IsActive;
} }
} }

View File

@ -73,7 +73,7 @@ namespace CPRNIMS.Domain.Services.Receiving
return allItems ?? new List<ReceivingDetail>(); return allItems ?? new List<ReceivingDetail>();
} }
public async Task<List<RRDetailDto>> GetRRDetail(ItemDto itemDto) public async Task<List<RRDetail>> GetRRDetail(ItemDto itemDto)
{ {
var allItems = await _dbContext.RRDetailss var allItems = await _dbContext.RRDetailss
.FromSqlRaw("EXEC GetRRDetail @RRNo,@UserId", .FromSqlRaw("EXEC GetRRDetail @RRNo,@UserId",
@ -81,7 +81,7 @@ namespace CPRNIMS.Domain.Services.Receiving
new SqlParameter("@UserId", itemDto.UserId)) new SqlParameter("@UserId", itemDto.UserId))
.ToListAsync(); .ToListAsync();
return allItems ?? new List<RRDetailDto>(); return allItems ?? new List<RRDetail>();
} }
#endregion #endregion
#region Post Put #region Post Put

View File

@ -1,80 +0,0 @@
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

@ -1,109 +0,0 @@
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

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

View File

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

View File

@ -1,18 +0,0 @@
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

@ -1,22 +0,0 @@
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

@ -1,20 +0,0 @@
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

@ -11,7 +11,6 @@ namespace CPRNIMS.Domain.UIContracts.PO
public interface IPurchaseOrder public interface IPurchaseOrder
{ {
#region Get #region Get
Task<List<POVM>> GetCurrencies(User user, POVM viewModels);
Task<List<POVM>> GetSupplierBidById(User user, POVM viewModel); Task<List<POVM>> GetSupplierBidById(User user, POVM viewModel);
Task<List<POVM>> GetSupplierBidByItem(User user, POVM viewModel); Task<List<POVM>> GetSupplierBidByItem(User user, POVM viewModel);
Task<List<POVM>> GetSupplierBid(User user, POVM viewModel); Task<List<POVM>> GetSupplierBid(User user, POVM viewModel);

View File

@ -1,6 +1,5 @@
using CPRNIMS.Domain.UIContracts.Canvass; using CPRNIMS.Domain.UIContracts.Canvass;
using CPRNIMS.Domain.UIContracts.Common; using CPRNIMS.Domain.UIContracts.Common;
using CPRNIMS.Infrastructure.Dto.Common;
using CPRNIMS.Infrastructure.Helper; using CPRNIMS.Infrastructure.Helper;
using CPRNIMS.Infrastructure.Models.Account; using CPRNIMS.Infrastructure.Models.Account;
using CPRNIMS.Infrastructure.Models.Common; using CPRNIMS.Infrastructure.Models.Common;
@ -124,54 +123,6 @@ namespace CPRNIMS.Domain.UIServices.Canvass
throw; 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 #endregion
#region Get #region Get
@ -184,7 +135,12 @@ namespace CPRNIMS.Domain.UIServices.Canvass
{ {
return await SendGetApiRequest(user, viewModel, return await SendGetApiRequest(user, viewModel,
_configuration["LLI:NonInvent:CanvassMgmt:GetSupplierBidByItem"]); _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) public async Task<List<CanvassVM>> GetCanvassPerSupplierEmail(User user, CanvassVM viewModel)
{ {
return await SendGetApiRequest(user, viewModel, return await SendGetApiRequest(user, viewModel,
@ -280,16 +236,6 @@ namespace CPRNIMS.Domain.UIServices.Canvass
return await SendGetApiRequest(user, viewModel, return await SendGetApiRequest(user, viewModel,
_configuration["LLI:NonInvent:CanvassMgmt:GetAlternativeOfferByPRDetailId"]); _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 #endregion
#region Post Put #region Post Put
public async Task<CanvassVM> PostCanvass(User user, CanvassVM viewModel) public async Task<CanvassVM> PostCanvass(User user, CanvassVM viewModel)
@ -342,19 +288,6 @@ namespace CPRNIMS.Domain.UIServices.Canvass
return await SendPostApiRequest(user, viewModel, return await SendPostApiRequest(user, viewModel,
_configuration["LLI:NonInvent:CanvassMgmt:UnlockFormLink"]); _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 #endregion
} }
} }

View File

@ -1,11 +1,9 @@
using CPRNIMS.Domain.UIContracts.Common; using CPRNIMS.Domain.UIContracts.Common;
using CPRNIMS.Domain.UIContracts.Inventory; 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.Helper;
using CPRNIMS.Infrastructure.Models.Account; using CPRNIMS.Infrastructure.Models.Account;
using CPRNIMS.Infrastructure.Models.Common; using CPRNIMS.Infrastructure.Models.Common;
using CPRNIMS.Infrastructure.ViewModel.Finance;
using CPRNIMS.Infrastructure.ViewModel.Inventory; using CPRNIMS.Infrastructure.ViewModel.Inventory;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using System; using System;
@ -125,73 +123,6 @@ namespace CPRNIMS.Domain.UIServices.Inventory
throw; 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 #endregion
#region Get #region Get
public async Task<List<InventoryVM>> GetInventoryById(User user, InventoryVM viewModel) public async Task<List<InventoryVM>> GetInventoryById(User user, InventoryVM viewModel)
@ -210,11 +141,7 @@ namespace CPRNIMS.Domain.UIServices.Inventory
return await SendGetApiRequest(user, viewModel, return await SendGetApiRequest(user, viewModel,
_configuration["LLI:NonInvent:InventoryMgmt:GetLotNoById"]); _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) public async Task<List<InventoryVM>> GetInventoryByUserId(User user, InventoryVM viewModel)
{ {
return await SendGetApiRequest(user, viewModel, return await SendGetApiRequest(user, viewModel,
@ -226,11 +153,7 @@ namespace CPRNIMS.Domain.UIServices.Inventory
return await SendGetApiRequest(user, viewModel, return await SendGetApiRequest(user, viewModel,
_configuration["LLI:NonInvent:InventoryMgmt:GetRequestedItemByUserId"]); _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 #endregion
#region Post Put #region Post Put
public async Task<InventoryVM> PostPutReqApproval(User user, InventoryVM viewModel) public async Task<InventoryVM> PostPutReqApproval(User user, InventoryVM viewModel)
@ -254,6 +177,12 @@ namespace CPRNIMS.Domain.UIServices.Inventory
return await SendPostApiRequest(user, viewModel, return await SendPostApiRequest(user, viewModel,
_configuration["LLI:NonInvent:InventoryMgmt:PostPutReqItems"]); _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 #endregion
} }
} }

View File

@ -1,126 +0,0 @@
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

@ -1,197 +0,0 @@
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

@ -1,157 +0,0 @@
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

@ -284,11 +284,6 @@ namespace CPRNIMS.Domain.UIServices.PO
return await SendGetApiRequest(user, viewModel, return await SendGetApiRequest(user, viewModel,
_configuration["LLI:NonInvent:POMgmt:GetPortOfDischarge"]); _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 #endregion
#region Post Put #region Post Put
public async Task<POVM> PostApprovedSupplier(User user, POVM viewModel) public async Task<POVM> PostApprovedSupplier(User user, POVM viewModel)

View File

@ -1,6 +1,4 @@
using CPRNIMS.Infrastructure.Dto.Canvass.Response; using CPRNIMS.Infrastructure.Entities.Account;
using CPRNIMS.Infrastructure.Dto.Inventory.Response;
using CPRNIMS.Infrastructure.Entities.Account;
using CPRNIMS.Infrastructure.Entities.Canvass; using CPRNIMS.Infrastructure.Entities.Canvass;
using CPRNIMS.Infrastructure.Entities.Common; using CPRNIMS.Infrastructure.Entities.Common;
using CPRNIMS.Infrastructure.Entities.Finance; using CPRNIMS.Infrastructure.Entities.Finance;
@ -23,7 +21,9 @@ namespace CPRNIMS.Infrastructure.Database
public class NonInventoryDbContext : IdentityDbContext<ApplicationUser> public class NonInventoryDbContext : IdentityDbContext<ApplicationUser>
{ {
public NonInventoryDbContext(DbContextOptions<NonInventoryDbContext> options) : base(options) { } public NonInventoryDbContext(DbContextOptions<NonInventoryDbContext> options) : base(options) { }
#region Common public virtual DbSet<ItemCode> ItemCodes { get; set; }
public virtual DbSet<ItemList> ItemList { get; set; }
public virtual DbSet<Item> Items { get; set; }
public DbSet<Departments> Departments { get; set; } public DbSet<Departments> Departments { get; set; }
public DbSet<IdentityRole> IdentityRoles { get; set; } public DbSet<IdentityRole> IdentityRoles { get; set; }
public DbSet<AuthorizeRoles> AuthorizeRoles { get; set; } public DbSet<AuthorizeRoles> AuthorizeRoles { get; set; }
@ -31,57 +31,41 @@ namespace CPRNIMS.Infrastructure.Database
public DbSet<IdentityUserRole<string>> IdentityUserRoles { get; set; } public DbSet<IdentityUserRole<string>> IdentityUserRoles { get; set; }
public DbSet<ForgotPassword> ForgotPasswords { get; set; } public DbSet<ForgotPassword> ForgotPasswords { get; set; }
public virtual DbSet<Otps> Otps { 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 DbSet<Attachment> Attachments { get; set; }
public virtual DbSet<AttachmentExtension> AttachmentExtensions { get; set; } public virtual DbSet<AttachmentExtension> AttachmentExtensions { get; set; }
public virtual DbSet<AttachmentFileType> AttachmentFileTypes { get; set; } public virtual DbSet<AttachmentFileType> AttachmentFileTypes { get; set; }
public virtual DbSet<ItemAttachement> ItemAttachements { 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<ItemCategory> ItemCategories { get; set; }
public virtual DbSet<UnitOfMessure> UnitOfMessures { get; set; } public virtual DbSet<UnitOfMessure> UnitOfMessures { get; set; }
public virtual DbSet<ItemColor> ItemColors { get; set; } public virtual DbSet<ItemColor> ItemColors { get; set; }
public virtual DbSet<ItemLocalization> ItemLocalizations { get; set; } public virtual DbSet<ItemLocalization> ItemLocalizations { get; set; }
public virtual DbSet<ItemCart> ItemCarts { 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<PR> PRs { get; set; }
public virtual DbSet<Approved> Approved { get; set; } public virtual DbSet<Approved> Approved { get; set; }
public virtual DbSet<ApprovedPR> ApprovedPrs { get; set; } public virtual DbSet<ApprovedPR> ApprovedPrs { get; set; }
public virtual DbSet<DeletedPR> DeletedPRs { get; set; } public virtual DbSet<DeletedPR> DeletedPRs { get; set; }
public virtual DbSet<SMTPCredential> SMTPCredentials { get; set; }
public virtual DbSet<PRDetails> PRDetails { get; set; } public virtual DbSet<PRDetails> PRDetails { get; set; }
public virtual DbSet<PRItemList> PRItemLists { get; set; } public virtual DbSet<PRItemList> PRItemLists { get; set; }
public DbSet<PRAttachments> PRAttachments { get; set; } public DbSet<PRAttachments> PRAttachments { get; set; }
public DbSet<ProjectCodes> ProjectCodes { 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<NotificationById> NotificationByIds { get; set; }
public virtual DbSet<AlternativeOffer> AlternativeOffers { get; set; } public virtual DbSet<AlternativeOffer> AlternativeOffers { get; set; }
public virtual DbSet<AlternativeOfferDetails> AlternativeOfferDetails { get; set; } public virtual DbSet<AlternativeOfferDetails> AlternativeOfferDetails { get; set; }
public virtual DbSet<MyPRWOCanvass> MyPRWOCanvass { 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 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<SupplierItems> SupplierItems { get; set; }
public DbSet<ItemsForTagging> ItemsForTaggings { get; set; }
public virtual DbSet<ForCanvassFollowUp> ForCanvassFollowUps { get; set; } public virtual DbSet<ForCanvassFollowUp> ForCanvassFollowUps { get; set; }
public virtual DbSet<WOResponse> WOResponses { get; set; } public virtual DbSet<WOResponse> WOResponses { get; set; }
public virtual DbSet<WOResponseById> WOResponseByIds { get; set; } public virtual DbSet<WOResponseById> WOResponseByIds { get; set; }
@ -96,20 +80,15 @@ namespace CPRNIMS.Infrastructure.Database
public virtual DbSet<RFQReference> RFQReferences { get; set; } public virtual DbSet<RFQReference> RFQReferences { get; set; }
public virtual DbSet<CanvassDetail> CanvassDetails { get; set; } public virtual DbSet<CanvassDetail> CanvassDetails { get; set; }
public virtual DbSet<PRCanvassDetail> PRCanvassDetails { 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<CanvassGroupByPRNo> CanvassGroupByPRNos { get; set; }
public virtual DbSet<ForCanvass> ForCanvasses { get; set; } public virtual DbSet<ForCanvass> ForCanvasses { get; set; }
#endregion
#region PO
public virtual DbSet<ForPO> ForPOs { get; set; } public virtual DbSet<ForPO> ForPOs { get; set; }
public virtual DbSet<CreatedPO> CreatedPOs { get; set; } public virtual DbSet<CreatedPO> CreatedPOs { get; set; }
public virtual DbSet<CustomPO> CustomPOs { get; set; } public virtual DbSet<CustomPO> CustomPOs { get; set; }
public virtual DbSet<IndexCard> IndexCards { get; set; } public virtual DbSet<IndexCard> IndexCards { get; set; }
public virtual DbSet<ForPOApproval> ForPOApprovals { get; set; } public virtual DbSet<ForPOApproval> ForPOApprovals { get; set; }
public virtual DbSet<ApprovedPO> ApprovedPOs { get; set; } public virtual DbSet<ApprovedPO> ApprovedPOs { get; set; }
public virtual DbSet<PurchaseOrder> PurchaseOrders { get; set; } public virtual DbSet<PurchaseOrder> PurchaseOrders { get; set; }
public virtual DbSet<ForPayment> ForPayments { get; set; }
public virtual DbSet<PO> POs { get; set; } public virtual DbSet<PO> POs { get; set; }
public DbSet<PODetails> PODetails { get; set; } public DbSet<PODetails> PODetails { get; set; }
public virtual DbSet<PRPOSummaryCount> PRPOSummaryCounts { get; set; } public virtual DbSet<PRPOSummaryCount> PRPOSummaryCounts { get; set; }
@ -119,44 +98,29 @@ namespace CPRNIMS.Infrastructure.Database
public virtual DbSet<PortOfDischarges> PortOfDischarges { get; set; } public virtual DbSet<PortOfDischarges> PortOfDischarges { get; set; }
public virtual DbSet<DocRequired> DocRequireds { get; set; } public virtual DbSet<DocRequired> DocRequireds { get; set; }
public virtual DbSet<BiddingApproval> BiddingApprovals { get; set; } public virtual DbSet<BiddingApproval> BiddingApprovals { get; set; }
public virtual DbSet<Entities.Receiving.RRDetail> RRDetailss { get; set; }
public virtual DbSet<NotifUserKey> NotifUserKeys { get; set; } public virtual DbSet<RRSeries> RRSeries { get; set; }
public virtual DbSet<ItemListForPO> ItemListForPOs { get; set; } public virtual DbSet<PRWOCanvass> PRWOCanvasses { get; set; }
public virtual DbSet<CreatedPOPerSupId> CreatedPOPerSupIds { get; set; } public virtual DbSet<ForPayment> ForPayments { 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 DbSet<Currencies> Currencies { get; set; }
#endregion
#region Inventory
public virtual DbSet<Inventory> Inventories { 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<Lot> Lots { get; set; }
public virtual DbSet<LotType> LotTypes { get; set; }
public virtual DbSet<LotQtyByItem> LotQtyByItems { get; set; } public virtual DbSet<LotQtyByItem> LotQtyByItems { get; set; }
public virtual DbSet<RequestItem> RequestItems { get; set; } public virtual DbSet<RequestItem> RequestItems { get; set; }
public virtual DbSet<RequestItemDetail> RequestItemDetails { get; set; } public virtual DbSet<RequestItemDetail> RequestItemDetails { get; set; }
public virtual DbSet<RIS> RIS { get; set; } public virtual DbSet<NotifUserKey> NotifUserKeys { get; set; }
public virtual DbSet<MRS> MRS { get; set; } public virtual DbSet<ItemListForPO> ItemListForPOs { get; set; }
public virtual DbSet<Discipline> Disciplines { get; set; } public virtual DbSet<CreatedPOPerSupId> CreatedPOPerSupIds { get; set; }
public virtual DbSet<InventTrans> InventTrans { get; set; } public virtual DbSet<PRTracking> PRTrackings { get; set; }
public virtual DbSet<InventTransDetail> InventTransDetails { get; set; } public virtual DbSet<Dashboard> Dashboards { get; set; }
public DbSet<InventoryByIdResponse> InventoryByIdResponses { get; set; } public virtual DbSet<PaymentTerm> PaymentTerms { get; set; }
#endregion public virtual DbSet<Incoterm> Incoterms { get; set; }
public virtual DbSet<CentralPONo> CentralPONos { get; set; }
#region RR public virtual DbSet<DetailedPRTracking> DetailedPRTrackings { get; set; }
public virtual DbSet<ForReceiving> ForReceivings { get; set; } public DbSet<IncomingShipment> IncomingShipments { get; set; }
public virtual DbSet<Infrastructure.Entities.Receiving.RRReport> RRReports { get; set; } public virtual DbSet<IncomingShipmentDto> IncomingShipmentDtos { 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 #region Automation Part
public virtual DbSet<AllForCanvass> AllForCanvasses { get; set; } public virtual DbSet<AllForCanvass> AllForCanvasses { get; set; }
@ -201,7 +165,7 @@ namespace CPRNIMS.Infrastructure.Database
b.HasOne(u => u.Attachment) b.HasOne(u => u.Attachment)
.WithOne(a => a.ApplicationUser) .WithOne(a => a.ApplicationUser)
.HasForeignKey<Attachment>(a => a.AttachmentId) .HasForeignKey<Attachment>(a => a.AttachmentId)
.IsRequired(false); .IsRequired(false); // Allow null if there is no attachment
}); });
modelBuilder.Entity<Attachment>(b => modelBuilder.Entity<Attachment>(b =>
{ {
@ -209,7 +173,7 @@ namespace CPRNIMS.Infrastructure.Database
b.HasOne(a => a.AttachmentExtention) b.HasOne(a => a.AttachmentExtention)
.WithOne() .WithOne()
.HasForeignKey<Attachment>(a => a.ExtensionId) .HasForeignKey<Attachment>(a => a.ExtensionId)
.IsRequired(false); .IsRequired(false); // Allow null if there is no extension
}); });
modelBuilder.Entity<ApplicationUser>(b => modelBuilder.Entity<ApplicationUser>(b =>
{ {
@ -267,74 +231,6 @@ namespace CPRNIMS.Infrastructure.Database
{ {
b.ToTable("UserRoles"); 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,7 +3,6 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using System.Linq; using System.Linq;
using System.Security.Claims;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -21,7 +20,6 @@ namespace CPRNIMS.Infrastructure.Dto.Account
public string URLAttachment { get; set; } = string.Empty; public string URLAttachment { get; set; } = string.Empty;
public string? token { get; set; } public string? token { get; set; }
public string? company { get; set; } public string? company { get; set; }
public int? departmentId { get; set; }
public string? refreshToken { get; set; } public string? refreshToken { get; set; }
public DateTime expiresAt { get; set; } public DateTime expiresAt { get; set; }
public int expiresInSeconds { get; set; } public int expiresInSeconds { get; set; }

View File

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

View File

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

View File

@ -1,17 +0,0 @@
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

@ -1,22 +0,0 @@
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

@ -1,19 +0,0 @@
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

@ -1,18 +0,0 @@
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

@ -1,18 +0,0 @@
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

@ -21,6 +21,5 @@ namespace CPRNIMS.Infrastructure.Dto.Canvass.Request
public string Address { get; set; } = string.Empty; public string Address { get; set; } = string.Empty;
public long ItemNo { get; set; } = 0; public long ItemNo { get; set; } = 0;
public string Website { get; set; } = string.Empty; public string Website { get; set; } = string.Empty;
public int SupplierId { get; set; }
} }
} }

View File

@ -1,16 +0,0 @@
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

@ -10,19 +10,18 @@ namespace CPRNIMS.Infrastructure.Dto.Canvass.Response
{ {
public int SupplierId { get; set; } public int SupplierId { get; set; }
public string SupplierName { get; set; } = string.Empty; public string SupplierName { get; set; } = string.Empty;
public string? EmailAddress { get; set; } public string EmailAddress { get; set; } = string.Empty;
public bool IsActive { get; set; } public bool IsActive { get; set; } = true;
public string? ContactNo { get; set; } public string ContactNo { get; set; } = string.Empty;
public string? ContactPerson { get; set; } public string ContactPerson { get; set; } = string.Empty;
public string? LeadTime { get; set; } public string LeadTime { get; set; } = string.Empty;
public bool? IsVatable { get; set; } public bool VatInc { get; set; } = false;
public byte? PaymentTermsId { get; set; } public string Currency { get; set; } = string.Empty;
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; public string PaymentTerms { get; set; } = string.Empty;
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 string Website { get; set; } = string.Empty;
} }
} }

View File

@ -1,27 +0,0 @@
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

@ -1,11 +1,9 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Text.Json; using System.Text.Json;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
using System.Text.RegularExpressions;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace CPRNIMS.Infrastructure.Dto.Canvass.Result namespace CPRNIMS.Infrastructure.Dto.Canvass.Result
@ -30,43 +28,12 @@ namespace CPRNIMS.Infrastructure.Dto.Canvass.Result
[JsonPropertyName("source")] [JsonPropertyName("source")]
public string? Source { get; set; } public string? Source { get; set; }
[JsonConverter(typeof(FlexibleDecimalConverter))] [JsonPropertyName("estimated_price_usd")]
public decimal? EstimatedPriceUsd { get; set; } public decimal? EstimatedPriceUsd { get; set; }
[JsonPropertyName("item_specifications")] [JsonPropertyName("item_specifications")]
public JsonElement? ItemSpecifications { get; set; } 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 class TavilySearchResult
{ {
public List<TavilyResult> Results { get; set; } = new(); public List<TavilyResult> Results { get; set; } = new();
@ -79,11 +46,7 @@ namespace CPRNIMS.Infrastructure.Dto.Canvass.Result
public string Content { get; set; } = string.Empty; public string Content { get; set; } = string.Empty;
public double Score { get; set; } public double Score { get; set; }
} }
public class GroqMatchResult
{
public bool Matched { get; set; }
public int? SupplierId { get; set; }
}
public class GroqResponse public class GroqResponse
{ {
public List<GroqChoice> Choices { get; set; } = new(); public List<GroqChoice> Choices { get; set; } = new();

View File

@ -1,15 +0,0 @@
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

@ -1,14 +0,0 @@
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

@ -1,20 +0,0 @@
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

@ -1,20 +0,0 @@
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

@ -1,20 +0,0 @@
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

@ -1,30 +0,0 @@
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

@ -1,20 +0,0 @@
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

@ -1,17 +0,0 @@
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

@ -1,20 +0,0 @@
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

@ -1,21 +0,0 @@
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

@ -1,17 +0,0 @@
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

@ -1,19 +0,0 @@
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

@ -1,26 +0,0 @@
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

@ -1,50 +0,0 @@
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

@ -1,160 +0,0 @@
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

@ -1,14 +0,0 @@
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

@ -1,13 +0,0 @@
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

@ -1,13 +0,0 @@
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

@ -1,10 +0,0 @@
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

@ -1,14 +0,0 @@
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

@ -1,14 +0,0 @@
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

@ -1,17 +0,0 @@
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

@ -1,18 +0,0 @@
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

@ -1,18 +0,0 @@
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; }
}
}

View File

@ -1,23 +0,0 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CPRNIMS.Infrastructure.Dto.Inventory.Request
{
public class InventoryRequest
{
public string? SearchPRNo { get; set; }
public string? SearchItemName { get; set; }
public string? SearchDept { get; set; }
public int PageNumber { get; set; } = 1;
public int PageSize { get; set; } = 10;
public byte MessCode { get; set; }
public string? SearchProjectCode { get; set; }
public string? SearchItemNo { get; set; }
public string? UserId { get; set; }
public int InventoryId { get; set; }
}
}

View File

@ -1,19 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CPRNIMS.Infrastructure.Dto.Inventory.Request
{
public class RISPagedRequest
{
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;
}
}

View File

@ -1,15 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CPRNIMS.Infrastructure.Dto.Inventory.Request
{
public class SearchRISProjectCodeRequest
{
public int? SearchProjectCodeId { get; set; }
public string? SearchRISNo { get; set; }
public string? SearchProjectCode { get; set; }
}
}

View File

@ -1,28 +0,0 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CPRNIMS.Infrastructure.Dto.Inventory.Response
{
public class InventoryByIdResponse
{
[Key]
public int InventoryId { get; set; }
public decimal QtyIn { get; set; }
public decimal QtyOut { get; set; }
public decimal QtyOnHand { get; set; }
public string? LotNo { get; set; }
public string? ProjectCode { get; set; }
public string? UserId { get; set; }
public string? ItemName { get; set; }
public string? ItemDescription { get; set; }
public string? ItemCategoryName { get; set; }
public string? Department { get; set; }
public DateTime CreatedDate { get; set; }
public long ItemNo { get; set; }
public long PRNo { get; set; }
}
}

View File

@ -1,28 +0,0 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CPRNIMS.Infrastructure.Dto.Inventory.Response
{
public class InventoryResponse
{
[Key]
public int InventoryId { get; set; }
public decimal QtyIn { get; set; }
public decimal QtyOut { get; set; }
public decimal QtyOnHand { get; set; }
public string? LotNo { get; set; }
public string? ProjectCode { get; set; }
public string? UserId { get; set; }
public string? ItemName { get; set; }
public string? ItemDescription { get; set; }
public string? ItemCategoryName { get; set; }
public string? Department { get; set; }
public DateTime CreatedDate { get; set; }
public long ItemNo { get; set; }
public long PRNo { get; set; }
}
}

View File

@ -1,34 +0,0 @@
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.Response
{
public class MRSPagedResponse
{
public List<MRSListItem> Data { get; set; } = [];
public int RecordsTotal { get; set; }
}
public class MRSListItem
{
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; }
}
}

View File

@ -1,17 +0,0 @@
using CPRNIMS.Infrastructure.Models.Inventory;
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.Response
{
public class MRSResponse
{
[JsonPropertyName("success")] public bool Success { get; set; }
[JsonPropertyName("message")] public string? Message { get; set; }
[JsonPropertyName("data")] public MRSData? Data { get; set; }
}
}

View File

@ -1,58 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CPRNIMS.Infrastructure.Dto.Inventory.Response
{
public class RISPagedResponse
{
public List<RISListItem> Data { get; set; } = [];
public int RecordsTotal { get; set; }
public List<string> DepartmentList { get; set; } = [];
public List<DisciplineItem> DisciplineList { get; set; } = [];
}
public class RISListItem
{
public long RISId { get; set; }
public string RISNo { get; set; } = string.Empty;
public int InventoryId { get; set; }
public string? ItemName { get; set; }
public long ItemNo { get; set; }
public string? ProjectCode { get; set; }
public string? ProjectName { get; set; }
public string? DisciplineName { get; set; }
public decimal QtyIssued { get; set; }
public decimal TotalReturned { 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 decimal MRSCount { get; set; }
}
public class DisciplineItem
{
public byte DisciplineId { get; set; }
public string DisciplineName { get; set; } = string.Empty;
}
}

View File

@ -1,15 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CPRNIMS.Infrastructure.Dto.Inventory.Response
{
public class RISProjectCodeResponse
{
public string ProjectCode { get; set; }=string.Empty;
public string ProjectName { get; set; } = string.Empty;
}
}

View File

@ -1,34 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CPRNIMS.Infrastructure.Dto.Inventory.Response
{
public class RISResponse
{
public long RISId { get; set; }
public string RISNo { get; set; } = string.Empty;
public int InventoryId { get; set; }
public string ItemName { get; set; } = string.Empty;
public long ItemNo { get; set; }
public string? LotNo { get; set; }
public int ProjectCodeId { get; set; }
public string DisciplineName { get; set; } = string.Empty;
public string? Message { get; set; }
public byte DisciplineId { get; set; }
public decimal QtyIssued { get; set; }
public string? Remarks { get; set; }
public short Status { get; set; }
public string StatusLabel => Status switch { 0 => "Draft", 1 => "Approved", 2 => "Cancelled", _ => "Unknown" };
public string CreatedBy { get; set; } = string.Empty;
public DateTime CreatedDate { get; set; }
public string? ApprovedBy { get; set; }
public DateTime? ApprovedDate { get; set; }
public decimal MRSCount { get; set; }
public decimal TotalReturned { get; set; }
public string? ProjectName { get; set; }
public string? ProjectCode { get; set; }
}
}

View File

@ -1,30 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CPRNIMS.Infrastructure.Dto.Inventory.Response
{
public class SearchApiResponse<T>
{
public bool Success { get; set; }
public List<T> data { get; set; } = new List<T>();
}
public class SearchRISProjectCodeResponse
{
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 ProjectCodeOptionResponse
{
public int ProjectCodeId { get; set; }
public string ProjectCode { get; set; } = string.Empty;
public string ProjectName { get; set; } = string.Empty;
}
}

View File

@ -1,24 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CPRNIMS.Infrastructure.Dto.Inventory
{
public class TransactContextDto
{
public int InventoryId { get; set; }
public string ItemName { get; set; } = string.Empty;
public long ItemNo { get; set; }
public long PRNo { get; set; }
public string? LotNo { get; set; }
public string? Department { get; set; }
public decimal QtyOnHand { get; set; }
public decimal QtyIn { get; set; }
public decimal QtyOut { get; set; }
public IEnumerable<ProjectCodeDto> ProjectCodes { get; set; } = [];
public IEnumerable<DisciplineDto> Disciplines { get; set; } = [];
public IEnumerable<RISReferenceDto> OpenRISList { get; set; } = [];
}
}

View File

@ -23,7 +23,7 @@ namespace CPRNIMS.Infrastructure.Dto.PO
public string? SupplierName { get; set; } public string? SupplierName { get; set; }
public string? Manufacturer { get; set; } public string? Manufacturer { get; set; }
public int ItemCount { get; set; } public int ItemCount { get; set; }
public byte CurrencyId { get; set; } public short CurrencyId { get; set; }
public string? Department { get; set; } public string? Department { get; set; }
public string? ItemCategoryName { get; set; } public string? ItemCategoryName { get; set; }
public DateTime CommitmentDate { get; set; } public DateTime CommitmentDate { get; set; }
@ -115,6 +115,5 @@ namespace CPRNIMS.Infrastructure.Dto.PO
public DateTime From { get; set; } public DateTime From { get; set; }
public string? OtherChargesName { get; set; } public string? OtherChargesName { get; set; }
public string? IncotermsName { get; set; } public string? IncotermsName { get; set; }
public string? CountryOrigin { get; set; }
} }
} }

View File

@ -23,7 +23,6 @@ namespace CPRNIMS.Infrastructure.Entities.Account
public DateTime UpdatedDate { get; set; } public DateTime UpdatedDate { get; set; }
public string? ProfilePicture { get; set; } public string? ProfilePicture { get; set; }
public string? Address { get; set; } public string? Address { get; set; }
public bool? IsActive { get; set; }
public Attachment? Attachment { get; set; } public Attachment? Attachment { get; set; }
} }
} }

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