Compare commits

..

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

170 changed files with 6346 additions and 10747 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="CaptchaGen.NetCore" Version="1.1.2" />
<PackageReference Include="Dapper" Version="2.1.66" />
<PackageReference Include="FastReport.OpenSource" Version="2026.2.3" />
<PackageReference Include="FastReport.OpenSource.Export.PdfSimple" Version="2026.2.3" />
<PackageReference Include="FastReport.OpenSource.Web" Version="2026.2.3" />
<PackageReference Include="Google.Apis.Drive.v3" Version="1.67.0.3373" />
<PackageReference Include="Microsoft.AspNet.Identity.Core" Version="2.2.4" />
<PackageReference Include="Microsoft.AspNetCore.SignalR.Core" Version="1.2.0" />

View File

@ -1,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<ReceivingDetail>> GetRRDetailByPO(RRDetailsDto itemDto);
Task<RRDetailDto> PostPutPayment(RRDetailsDto itemDto);
Task<RRDetail> PostPutPayment(RRDetailsDto itemDto);
}
}

View File

@ -21,7 +21,7 @@ namespace CPRNIMS.Domain.Contracts.Inventory
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<IEnumerable<DisciplineDto>> GetDisciplinesAsync(CancellationToken ct);
Task<Infrastructure.Entities.Inventory.Inventory> PostPutReqApproval(InventoryDto itemDto);
Task<RequestItem> PostPutReqItems(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

@ -11,12 +11,9 @@ 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);
Task<MRSPagedResult> GetPagedAsync(MRSFilterDto filter);
Task<MRS?> GetByIdAsync(long mrsId);
Task<MRS> CreateAsync(CreateMRSRequest dto, string createdBy);
Task ApproveAsync(long mrsId, string approvedBy);
}
}

View File

@ -13,10 +13,10 @@ namespace CPRNIMS.Domain.Contracts.Inventory
{
public interface IRIS
{
Task<RISPagedResult> GetPagedAsync(RISFilterDto filter, CancellationToken ct, int? departmentId = null, string? userName = "");
Task<RISPagedResult> GetPagedAsync(RISFilterDto filter, CancellationToken ct);
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);
Task CancelAsync(CancelRISRequest request, CancellationToken ct);
}
}

View File

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

View File

@ -70,7 +70,6 @@ namespace CPRNIMS.Domain.Contracts.PO
Task<Incoterm> PostPutIncoterms(PODto pODto);
Task<bool> DeleteIncShip(PODto poDto);
Task<bool> PostIncShipFollowUp(PODto pODto);
Task<IReadOnlyList<Currencies>> GetCurrencies(string currencyName, CancellationToken ct);
#endregion
}
}

View File

@ -12,7 +12,7 @@ namespace CPRNIMS.Domain.Contracts.Receiving
public interface IReceiving
{
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<RR>> GetRR(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

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

View File

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

View File

@ -3,9 +3,7 @@ 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.Account;
using CPRNIMS.Infrastructure.Entities.Inventory;
using Microsoft.AspNetCore.Identity;
using Microsoft.Data.SqlClient;
using Microsoft.EntityFrameworkCore;
using System;
@ -19,11 +17,9 @@ namespace CPRNIMS.Domain.Services.Inventory
public class Inventory : IInventory
{
private readonly NonInventoryDbContext _dbContext;
private readonly UserManager<ApplicationUser> _userManager;
public Inventory(NonInventoryDbContext dbContext, UserManager<ApplicationUser> userManager)
public Inventory(NonInventoryDbContext dbContext)
{
_dbContext = dbContext;
_userManager = userManager;
}
public async Task<TransactContextDto?> GetTransactContextAsync(int inventoryId, CancellationToken ct)
{
@ -83,7 +79,7 @@ namespace CPRNIMS.Domain.Services.Inventory
.ToListAsync(ct);
var disciplines = await GetDisciplinesAsync(ct);
var projectCodes = await GetProjectCodesAsync(ct);
return new TransactContextDto
{
InventoryId = inv.InventoryId,
@ -95,15 +91,13 @@ namespace CPRNIMS.Domain.Services.Inventory
QtyOnHand = inv.QtyOnHand,
QtyIn = inv.QtyIn,
QtyOut = inv.QtyOut,
ProjectCodes = projectCodes,
Disciplines = disciplines,
OpenRISList = openRIS
};
}
public async Task<IReadOnlyList<DisciplineDto>> GetDisciplinesAsync(CancellationToken ct)
public async Task<IEnumerable<DisciplineDto>> GetDisciplinesAsync(CancellationToken ct)
{
return await _dbContext.Disciplines
.AsNoTracking()
.OrderBy(d => d.DisciplineName)
.Select(d => new DisciplineDto
{
@ -112,19 +106,6 @@ namespace CPRNIMS.Domain.Services.Inventory
})
.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

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,35 +1,25 @@
using CPRNIMS.Domain.Contracts.Common;
using CPRNIMS.Domain.Contracts.Inventory;
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 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.");
// }
//}
public MRS(NonInventoryDbContext db) => _db = db;
public async Task ApproveAsync(long mrsId, string approvedBy)
{
var rms = await _db.MRS.FindAsync(mrsId)
?? throw new InvalidOperationException("MRS not found.");
@ -40,119 +30,73 @@ namespace CPRNIMS.Domain.Services.Inventory
rms.ApprovedBy = approvedBy;
rms.ApprovedDate = DateTime.Now;
await _db.SaveChangesAsync(ct);
await _db.SaveChangesAsync();
}
public async Task CancelAsync(CancelMRSRequest request,string canceledBy, CancellationToken ct)
public async Task<Infrastructure.Entities.Inventory.MRS> CreateAsync(CreateMRSRequest dto, string createdBy)
{
//var user = await _userManager.FindByNameAsync(canceledBy);
//if (user != null)
//{
// bool isApprover2 = await _userManager.IsInRoleAsync(user, "APPROVER2");
var ris = await _db.RIS
.Include(r => r.Inventory)
.FirstOrDefaultAsync(r => r.RISId == dto.RISId)
?? throw new InvalidOperationException("Referenced RIS not found.");
// if (!isApprover2)
// {
// throw new Exception("You have no permission to cancel this item.");
// }
//}
if (dto.QtyReturned > ris.QtyIssued)
throw new InvalidOperationException(
$"Cannot return more than issued. Issued: {ris.QtyIssued}.");
await _transactionFacade.ExecuteAsync(async () =>
var mrsNo = await GenerateMRSNoAsync();
var mrs = new Infrastructure.Entities.Inventory.MRS
{
var mrs = await _db.MRS
.Include(m => m.Inventory)
.FirstOrDefaultAsync(m => m.MRSId == request.MRSId)
?? throw new InvalidOperationException("MRS not found.");
MRSNo = mrsNo,
RISId = dto.RISId,
InventoryId = ris.InventoryId,
ReturnedBy = dto.ReturnedBy,
QtyReturned = dto.QtyReturned,
Condition = dto.Condition,
Remarks = dto.Remarks,
Status = 0,
CreatedBy = createdBy,
CreatedDate = DateTime.Now
};
_db.MRS.Add(mrs);
if (mrs.Status == 2)
throw new InvalidOperationException("MRS is already cancelled.");
var inventory = ris.Inventory;
inventory.QtyOut = Math.Max(0m, inventory.QtyOut - dto.QtyReturned);
// 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);
inventory.QtyOnHand = inventory.QtyIn - inventory.QtyOut;
var trans = await _db.InventTrans
.FirstOrDefaultAsync(t => t.InventoryId == ris.InventoryId && t.IsActive == true)!;
_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
});
await _db.SaveChangesAsync();
return mrs;
}
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)
public async Task<Infrastructure.Entities.Inventory.MRS?> GetByIdAsync(long mrsId)
=> await _db.MRS
.Include(r => r.Inventory)
.Include(r => r.RIS)
.FirstOrDefaultAsync(r => r.RISId == mrsId, ct);
.FirstOrDefaultAsync(r => r.RISId == mrsId);
public async Task<MRSPagedResult> GetPagedAsync(MRSFilterDto filter, CancellationToken ct,
int? departmentId = null, string? userName = "")
public async Task<MRSPagedResult> GetPagedAsync(MRSFilterDto filter)
{
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));
@ -168,13 +112,13 @@ namespace CPRNIMS.Domain.Services.Inventory
if (filter.DateTo.HasValue)
q = q.Where(m => m.CreatedDate <= filter.DateTo.Value.AddDays(1));
var total = await q.CountAsync(ct);
var total = await q.CountAsync();
var data = await q
.OrderByDescending(m => m.CreatedDate)
.Skip((filter.PageNumber - 1) * filter.PageSize)
.Skip((filter.Page - 1) * filter.PageSize)
.Take(filter.PageSize)
.Select(m => new MRSPagedDto
.Select(m => new MRSResponse
{
MRSId = m.MRSId,
MRSNo = m.MRSNo,
@ -195,10 +139,11 @@ namespace CPRNIMS.Domain.Services.Inventory
ApprovedBy = m.ApprovedBy,
ApprovedDate = m.ApprovedDate
})
.ToListAsync(ct);
.ToListAsync();
return new MRSPagedResult { Data = data, RecordsTotal = total };
}
private async Task<string> GenerateMRSNoAsync()
{
var year = DateTime.Now.Year;
@ -206,55 +151,5 @@ namespace CPRNIMS.Domain.Services.Inventory
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,5 +1,5 @@
using CPRNIMS.Domain.Contracts.Common;
using CPRNIMS.Domain.Contracts.Inventory;
using CPRNIMS.Domain.Contracts.Inventory;
using CPRNIMS.Domain.UIServices.Inventory;
using CPRNIMS.Infrastructure.Database;
using CPRNIMS.Infrastructure.Dto.Inventory;
using CPRNIMS.Infrastructure.Dto.Inventory.Request;
@ -17,78 +17,79 @@ 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 RIS(NonInventoryDbContext db) => _db = db;
public async Task<Infrastructure.Entities.Inventory.RIS> CreateAsync(CreateRISRequest dto, string createdBy, CancellationToken ct)
{
return await _transactionFacade.ExecuteAsync(async () =>
var strategy = _db.Database.CreateExecutionStrategy();
return await strategy.ExecuteAsync(async () =>
{
var inventory = await _db.Inventories
await using var tx = await _db.Database.BeginTransactionAsync(ct);
try
{
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}.");
if (inventory.QtyOnHand < dto.QtyIssued)
throw new InvalidOperationException(
$"Insufficient stock. On hand: {inventory.QtyOnHand}, requested: {dto.QtyIssued}.");
var risNo = await GenerateRISNoAsync(ct);
var risNo = await GenerateRISNoAsync(ct);
var ris = new Infrastructure.Entities.Inventory.RIS
var ris = new Infrastructure.Entities.Inventory.RIS
{
RISNo = risNo,
InventoryId = dto.InventoryId,
PRDetailId = dto.PRDetailId,
IssuedTo = dto.IssuedTo,
DisciplineId = dto.DisciplineId,
QtyIssued = dto.QtyIssued,
Remarks = dto.Remarks,
Status = 0,
CreatedBy = createdBy,
CreatedDate = DateTime.Now
};
_db.RIS.Add(ris);
await _db.SaveChangesAsync(ct);
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;
await _db.SaveChangesAsync(ct);
await tx.CommitAsync(ct);
return ris;
}
catch
{
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);
await tx.RollbackAsync(ct);
throw;
}
});
}
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.");
@ -102,22 +103,16 @@ namespace CPRNIMS.Domain.Services.Inventory
await _db.SaveChangesAsync(ct);
}
public async Task CancelAsync(CancelRISRequest request,string canceledBy, CancellationToken ct)
public async Task CancelAsync(CancelRISRequest request, CancellationToken ct)
{
//var user = await _userManager.FindByNameAsync(canceledBy);
//if (user != null)
//{
// bool isApprover2 = await _userManager.IsInRoleAsync(user, "APPROVER2");
var strategy = _db.Database.CreateExecutionStrategy();
// if (!isApprover2)
// {
// throw new Exception("You have no permission to cancel this item.");
// }
//}
await _transactionFacade.ExecuteAsync(async () =>
await strategy.ExecuteAsync(async () =>
{
var ris = await _db.RIS
await using var tx = await _db.Database.BeginTransactionAsync(ct);
try
{
var ris = await _db.RIS
.Include(r => r.Inventory)
.FirstOrDefaultAsync(r => r.RISId == request.RISId, ct)
?? throw new InvalidOperationException("RIS not found.");
@ -125,23 +120,6 @@ namespace CPRNIMS.Domain.Services.Inventory
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;
@ -163,7 +141,31 @@ namespace CPRNIMS.Domain.Services.Inventory
Remarks = request.Reason,
IsActive = true
});
}, ct);
//var inventory = await _db.Inventories
// .FirstOrDefaultAsync(i => i.InventoryId == ris.InventoryId, ct)
// ?? throw new InvalidOperationException("Inventory record not found.");
//if (inventory.QtyOnHand < ris.QtyIssued)
// throw new InvalidOperationException(
// $"Insufficient stock. On hand: {inventory.QtyOnHand}, requested: {ris.QtyIssued}.");
////restore the QtyOnHand using ris.QtyIssued
//inventory.QtyOnHand = Math.Max(0m, inventory.QtyOnHand) + ris.QtyIssued;
////reduce the QtyOut using ris.QtyIssued as we cancel the return isuance slip
//inventory.QtyOut = Math.Max(0m, inventory.QtyOut) - ris.QtyIssued;
await _db.SaveChangesAsync(ct);
await tx.CommitAsync(ct);
return ris;
}
catch
{
await tx.RollbackAsync(ct);
throw;
}
});
}
private async Task<string> GenerateRISNoAsync(CancellationToken ct)
@ -175,30 +177,19 @@ namespace CPRNIMS.Domain.Services.Inventory
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 = "")
public async Task<RISPagedResult> GetPagedAsync(RISFilterDto filter, CancellationToken ct)
{
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);
else
q = q.Where(r => r.Status == 0);
// RIS No
if (!string.IsNullOrWhiteSpace(filter.SearchRISNo))
@ -211,10 +202,9 @@ namespace CPRNIMS.Domain.Services.Inventory
.Any(d => d.PRDetails != null &&
d.PRDetails.ItemName.Contains(filter.SearchItemName)));
// Issued To is Project code/name
// Issued To
if (!string.IsNullOrWhiteSpace(filter.SearchIssuedTo))
q = q.Where(r => r.ProjectCodes.ProjectCode.Contains(filter.SearchIssuedTo)
|| r.ProjectCodes.ProjectName.Contains(filter.SearchIssuedTo));
q = q.Where(r => r.IssuedTo.Contains(filter.SearchIssuedTo));
// Discipline
if (!string.IsNullOrWhiteSpace(filter.Discipline))
@ -243,8 +233,7 @@ namespace CPRNIMS.Domain.Services.Inventory
.FirstOrDefault() ?? "—",
ItemNo = r.Inventory.ItemNo,
LotNo = r.Inventory.Lot != null ? r.Inventory.Lot.LotName : null,
ProjectName = r.ProjectCodes.ProjectName,
ProjectCode = r.ProjectCodes.ProjectCode,
IssuedTo = r.IssuedTo,
DisciplineName = r.Discipline.DisciplineName,
DisciplineId = r.DisciplineId,
QtyIssued = r.QtyIssued,
@ -277,7 +266,7 @@ namespace CPRNIMS.Domain.Services.Inventory
DisciplineList = disciplines
};
}
public async Task<IReadOnlyList<DisciplineDto>> GetDisciplinesAsync(CancellationToken ct)
public async Task<IEnumerable<DisciplineDto>> GetDisciplinesAsync(CancellationToken ct)
{
return await _db.Disciplines
.OrderBy(d => d.DisciplineName)
@ -288,19 +277,6 @@ namespace CPRNIMS.Domain.Services.Inventory
})
.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
@ -310,7 +286,7 @@ namespace CPRNIMS.Domain.Services.Inventory
RISId = r.RISId,
RISNo = r.RISNo,
InventoryId = r.InventoryId,
ProjectCodeId = r.ProjectCodeId,
IssuedTo = r.IssuedTo,
DisciplineName = r.Discipline.DisciplineName,
DisciplineId = r.DisciplineId,
QtyIssued = r.QtyIssued,

View File

@ -63,6 +63,7 @@ namespace CPRNIMS.Domain.Services.Items
UserId = itemDto.UserId
};
}
public async Task<Infrastructure.Entities.Items.Item> PutItemDetail(ItemDto itemDto)
{
await _dbContext.Database
@ -91,6 +92,126 @@ namespace CPRNIMS.Domain.Services.Items
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)
{
var isExist = await _dbContext.ItemAttachements
@ -122,6 +243,19 @@ namespace CPRNIMS.Domain.Services.Items
new SqlParameter("@ItemLocalId", itemDto.ItemLocalId));
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)
{
var (messCode, message) = OutputParamMessage.CreateOutputParams();
@ -188,22 +322,7 @@ namespace CPRNIMS.Domain.Services.Items
}
await _dbContext.SaveChangesAsync();
}
Task<ItemCart> IItem.PostPutItemPath(ItemDto itemDto)
{
throw new NotImplementedException();
}
public async Task<List<ItemCart>> GetItemCart(ItemDto itemDto)
{
var allItems = await _dbContext.ItemCarts
.FromSqlRaw($"EXEC GetItemCart @UserId,@RequestTypeId,@IsCount",
new SqlParameter("@UserId", itemDto.UserId),
new SqlParameter("@RequestTypeId", itemDto.RequestTypeId),
new SqlParameter("@IsCount", itemDto.IsCount))
.ToListAsync();
return allItems ?? new List<ItemCart>();
}
public async Task<(long, long)> GetPRNo()
public async Task<(long,long)> GetPRNo()
{
try
{
@ -213,9 +332,9 @@ namespace CPRNIMS.Domain.Services.Items
.FirstOrDefaultAsync();
if (latestPR != null)
return (latestPR.PRNo + 1, latestPR.PRId + 1);
return (latestPR.PRNo + 1,latestPR.PRId + 1);
else
return (0, 0);
return (0,0);
}
catch (Exception ex)
{
@ -224,122 +343,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
.Where(ic => ic.IsActive == true &&
EF.Functions.Like(ic.ItemLocalName, $"%{itemDto.ItemLocalName}%"))
.Take(15)
.ToListAsync();
return localizations ?? new List<ItemLocalization>();
throw new NotImplementedException();
}
public async Task<List<ItemCategory>> GetItemCateg(ItemDto itemDto)
{
if (itemDto.ItemCategoryId == 0 || itemDto.ItemCategoryId == null)
{
var categories = await _dbContext.ItemCategories
.Where(ic => ic.IsActive == true)
.ToListAsync();
return categories ?? new List<ItemCategory>();
}
else
{
var categories = await _dbContext.ItemCategories
.Where(ic => ic.IsActive == true && ic.ItemCategoryId == itemDto.ItemCategoryId)
.ToListAsync();
return categories ?? new List<ItemCategory>();
}
}
public async Task<List<ItemDtos>> GetItemDetail(ItemDto itemDto)
{
var allItems = await _dbContext.ItemDtos
.FromSqlRaw($"EXEC GetItemDetail @ItemCodeId,@UserId",
new SqlParameter("@ItemCodeId", itemDto.ItemCodeId),
new SqlParameter("@UserId", itemDto.UserId))
.ToListAsync();
return allItems ?? new List<ItemDtos>();
}
public async Task<PagedResult<ItemList>> GetItemList(ItemCodeDto dto)
{
var parameters = new[]
{
new SqlParameter("@UserId", dto.UserId),
new SqlParameter("@SearchItemNo", dto.SearchItemNo ?? ""),
new SqlParameter("@SearchItemName", dto.SearchItemName ?? ""),
new SqlParameter("@SearchCategory", dto.SearchCategory ?? ""),
new SqlParameter("@PageNumber", dto.PageNumber),
new SqlParameter("@PageSize", dto.PageSize)
};
int totalCount = 0;
var items = new List<ItemList>();
var categoryList = new List<string>();
// Use ADO.NET to read two result sets
var conn = _dbContext.Database.GetDbConnection();
await conn.OpenAsync();
using var cmd = conn.CreateCommand();
cmd.CommandText = "EXEC GetItemList @UserId, @SearchItemNo,@SearchItemName,@SearchCategory, @PageNumber, @PageSize";
foreach (var p in parameters) cmd.Parameters.Add(p);
cmd.CommandTimeout = 60;
using var reader = await cmd.ExecuteReaderAsync();
while (await reader.ReadAsync())
categoryList.Add(reader.GetString(0));
await reader.NextResultAsync();
if (await reader.ReadAsync())
totalCount = reader.GetInt32(0);
await reader.NextResultAsync();
while (await reader.ReadAsync())
{
items.Add(new ItemList
{
ItemCodeId = Convert.ToInt64(reader["ItemCodeId"]),
ItemNo = Convert.ToInt64(reader["ItemNo"]),
ItemName = reader["ItemName"]?.ToString(),
ItemDescription = reader["ItemDescription"]?.ToString(),
ItemCategoryName = reader["ItemCategoryName"]?.ToString(),
CartItemCount = Convert.ToInt32(reader["CartItemCount"])
});
}
await conn.CloseAsync();
return new PagedResult<ItemList>
{
Data = items,
TotalCount = totalCount,
CategoryList = categoryList,
PageNumber = dto.PageNumber,
PageSize = dto.PageSize
};
}
public async Task<List<ItemColor>> GetItemColor(ItemDto itemDto)
{
var colors = await _dbContext.ItemColors
.Where(ic => EF.Functions.Like(ic.ItemColorName, $"%{itemDto.ItemColorName}%"))
.Take(5)
.ToListAsync();
return colors ?? new List<ItemColor>();
}
public async Task<List<UnitOfMessure>> GetItemUOM(ItemDto itemDto)
{
var uoms = await _dbContext.UnitOfMessures
.Where(ic => ic.IsActive == true &&
EF.Functions.Like(ic.UOMName, $"%{itemDto.UOMName}%"))
.Take(150)
.ToListAsync();
return uoms ?? new List<UnitOfMessure>();
}
public async Task <List<Departments>> GetDepartment(ItemCodeDto itemCode)
{
return await _dbContext.Departments
@ -358,18 +366,18 @@ namespace CPRNIMS.Domain.Services.Items
return allItems ?? new List<NotifUserKey>();
}
public async Task<IReadOnlyList<ProjectCodes>> GetProjectCode()
public async Task<List<ProjectCodes>> GetProjectCode()
{
return await _dbContext.ProjectCodes
.AsNoTracking()
.ToListAsync();
}
public async Task<IReadOnlyList<ProjectCodes>> GetProjectCodeByTerm(string? term)
public async Task<List<ProjectCodes>> GetProjectCodeByTerm(string? term)
{
return await _dbContext.ProjectCodes
.AsNoTracking()
.Where(p => p.StatusName != "Completed" && p.IsActive
&& EF.Functions.Like(p.ProjectCode, $"%{term}%"))
.Where(p => EF.Functions.Like(p.ProjectCode, $"%{term}%"))
.ToListAsync();
}
}

View File

@ -30,14 +30,6 @@ namespace CPRNIMS.Domain.Services.PO
_smptHelper = smptHelper;
}
#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)
{
// Reuse the connection from your existing DbContext
@ -501,7 +493,7 @@ namespace CPRNIMS.Domain.Services.PO
await _dbContext.Database
.ExecuteSqlRawAsync("EXEC PostPutCustomPO @UserId,@POTypeId,@PONumber,@PRDetailsId,@Specification,@PRNo,@PORemarks,@IncoTermsId," +
$"@PODId,@ProfInvoiceNo,@ProfInvoiceDate,@PaymentTermsId,@ShippingInstructionId,@SupplierId,@DeliveryDate,@Discount,@Amount," +
$"@UnitPrice,@Quantity,@DeliverTo,@CountryOrigin,@CurrencyId, @MessCode OUTPUT, @Message OUTPUT",
$"@UnitPrice,@Quantity,@DeliverTo,@CountryOrigin, @MessCode OUTPUT, @Message OUTPUT",
new SqlParameter("@UserId", pODto.UserId),
new SqlParameter("@POTypeId", pODto.POTypeId),
new SqlParameter("@PONumber", formattedPONumber),
@ -524,7 +516,6 @@ namespace CPRNIMS.Domain.Services.PO
new SqlParameter("@Quantity", pODto.Quantity),
new SqlParameter("@DeliverTo", pODto.DeliverTo),
new SqlParameter("@CountryOrigin", pODto.CountryOrigin ?? "N/A"),
new SqlParameter("@CurrencyId", pODto.CurrencyId),
messCode,
message);
@ -553,7 +544,7 @@ namespace CPRNIMS.Domain.Services.PO
await _dbContext.Database
.ExecuteSqlRawAsync("EXEC PutExistingPO @UserId,@POTypeId,@PONumber,@PRDetailsId,@Specification,@PRNo,@PORemarks,@IncoTermsId," +
$"@PODId,@ProfInvoiceNo,@ProfInvoiceDate,@PaymentTermsId,@ShippingInstructionId,@SupplierId,@DeliveryDate,@Discount,@Amount," +
$"@UnitPrice,@Quantity,@DeliverTo,@IsRemoved,@CountryOrigin,@CurrencyId, @MessCode OUTPUT, @Message OUTPUT",
$"@UnitPrice,@Quantity,@DeliverTo,@IsRemoved,@CountryOrigin, @MessCode OUTPUT, @Message OUTPUT",
new SqlParameter("@UserId", pODto.UserId),
new SqlParameter("@POTypeId", pODto.POTypeId),
new SqlParameter("@PONumber", pODto.PONo),
@ -577,7 +568,6 @@ namespace CPRNIMS.Domain.Services.PO
new SqlParameter("@DeliverTo", pODto.DeliverTo),
new SqlParameter("@IsRemoved", isRemoved),
new SqlParameter("@CountryOrigin", pODto.CountryOrigin ?? "N/A"),
new SqlParameter("@CurrencyId", pODto.CurrencyId),
messCode,
message);
@ -645,8 +635,7 @@ namespace CPRNIMS.Domain.Services.PO
DeliverTo = PODto.DeliverTo ?? "N/A",
Specification = specification,
IsUpdate = PODto.IsUpdate,
CountryOrigin=PODto.CountryOrigin,
CurrencyId=PODto.CurrencyId
CountryOrigin=PODto.CountryOrigin
};
}
public async Task<DocRequired> PostSuppDocRequirements(PODto poDto)

View File

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

View File

@ -73,7 +73,7 @@ namespace CPRNIMS.Domain.Services.Receiving
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
.FromSqlRaw("EXEC GetRRDetail @RRNo,@UserId",
@ -81,7 +81,7 @@ namespace CPRNIMS.Domain.Services.Receiving
new SqlParameter("@UserId", itemDto.UserId))
.ToListAsync();
return allItems ?? new List<RRDetailDto>();
return allItems ?? new List<RRDetail>();
}
#endregion
#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,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,5 +1,4 @@
using CPRNIMS.Infrastructure.Dto.Common;
using CPRNIMS.Infrastructure.Dto.Inventory.Request;
using CPRNIMS.Infrastructure.Dto.Inventory.Request;
using CPRNIMS.Infrastructure.Dto.Inventory.Response;
using CPRNIMS.Infrastructure.ViewModel.Inventory;
using System;
@ -12,9 +11,10 @@ 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<bool> ApproveRIS(ApproveRISRequest request, CancellationToken ct);
Task<bool> CancelRIS(CancelRISRequest request, CancellationToken ct);
Task<RISResponse> CreateRIS(CreateRISRequest request, CancellationToken ct);
Task<RISPagedResponse> GetRISById(int risId, CancellationToken ct);
Task<RISPagedResponse> GetRISPaged(RISPagedRequest request, CancellationToken ct);
}
}

View File

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

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

@ -3,7 +3,6 @@ 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;
@ -31,51 +30,60 @@ namespace CPRNIMS.Domain.UIServices.Inventory
#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)
try
{
Console.WriteLine($"[GetRISPaged] Error {(int)response.StatusCode}: {json}");
return new RISPagedResponse { Data = [], RecordsTotal = 0 };
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();
}
catch (Exception ex)
{
ex.ToString();
throw;
}
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)
public async Task<bool> ApproveRIS(ApproveRISRequest request, CancellationToken ct)
{
var token = await _tokenHelper.GetValidTokenAsync();
if (string.IsNullOrEmpty(token))
@ -89,16 +97,15 @@ namespace CPRNIMS.Domain.UIServices.Inventory
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;
{
return false;
}
return true;
}
public async Task<ApiResponse<object>> CancelRIS(CancelRISRequest request, CancellationToken ct)
public async Task<bool> CancelRIS(CancelRISRequest request, CancellationToken ct)
{
var token = await _tokenHelper.GetValidTokenAsync();
if (string.IsNullOrEmpty(token))
@ -108,21 +115,19 @@ namespace CPRNIMS.Domain.UIServices.Inventory
?? 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");
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;
{
return false;
}
return true;
}
public async Task<ApiResponse<object>> CreateRIS(CreateRISRequest request, CancellationToken ct)
public async Task<RISResponse> CreateRIS(CreateRISRequest request, CancellationToken ct)
{
var token = await _tokenHelper.GetValidTokenAsync();
if (string.IsNullOrEmpty(token))
@ -133,19 +138,27 @@ namespace CPRNIMS.Domain.UIServices.Inventory
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");
using var content = new StringContent(
JsonSerializer.Serialize(request),
Encoding.UTF8,
"application/json");
var response = await httpClient.PostAsync(endpoint, content,ct);
if (!response.IsSuccessStatusCode)
{
return new RISResponse();
}
var json = await response.Content.ReadAsStringAsync();
var result = JsonSerializer.Deserialize<ApiResponse<object>>(json, _jsonOptions)
?? new ApiResponse<object> { success = false, message = $"HTTP {(int)response.StatusCode}" };
var result = JsonSerializer.Deserialize<ApiResponse<RISResponse>>(json, _jsonOptions);
return result?.data ?? new RISResponse();
}
if (!response.IsSuccessStatusCode)
result.success = false;
return result;
public Task<RISPagedResponse> GetRISById(int risId, CancellationToken ct)
{
throw new NotImplementedException();
}
private static readonly JsonSerializerOptions _jsonOptions = new()

View File

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

View File

@ -40,7 +40,6 @@ namespace CPRNIMS.Infrastructure.Database
public virtual DbSet<ItemCode> ItemCodes { get; set; }
public virtual DbSet<ItemList> ItemList { get; set; }
public virtual DbSet<Item> Items { get; set; }
public DbSet<ItemDtos> ItemDtos { get; set; }
public DbSet<Attachment> Attachments { get; set; }
public virtual DbSet<AttachmentExtension> AttachmentExtensions { get; set; }
public virtual DbSet<AttachmentFileType> AttachmentFileTypes { get; set; }
@ -128,7 +127,6 @@ namespace CPRNIMS.Infrastructure.Database
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
@ -150,11 +148,10 @@ namespace CPRNIMS.Infrastructure.Database
public virtual DbSet<ForReceiving> ForReceivings { get; set; }
public virtual DbSet<Infrastructure.Entities.Receiving.RRReport> RRReports { get; set; }
public virtual DbSet<ReceivingDetail> ReceivingDetails { get; set; }
public virtual DbSet<RRDetailDto> RRDetailDtos { get; set; }
public virtual DbSet<RRDetail> RRDetails { 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<Entities.Receiving.RRDetail> RRDetailss { get; set; }
public virtual DbSet<RRSeries> RRSeries { get; set; }
#endregion
@ -201,7 +198,7 @@ namespace CPRNIMS.Infrastructure.Database
b.HasOne(u => u.Attachment)
.WithOne(a => a.ApplicationUser)
.HasForeignKey<Attachment>(a => a.AttachmentId)
.IsRequired(false);
.IsRequired(false); // Allow null if there is no attachment
});
modelBuilder.Entity<Attachment>(b =>
{
@ -209,7 +206,7 @@ namespace CPRNIMS.Infrastructure.Database
b.HasOne(a => a.AttachmentExtention)
.WithOne()
.HasForeignKey<Attachment>(a => a.ExtensionId)
.IsRequired(false);
.IsRequired(false); // Allow null if there is no extension
});
modelBuilder.Entity<ApplicationUser>(b =>
{
@ -273,23 +270,13 @@ namespace CPRNIMS.Infrastructure.Database
.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<InventTrans>(e =>
{
e.HasMany(r => r.InventTransDetails)
.WithOne()
.HasForeignKey(t => t.InventTransId)
.OnDelete(DeleteBehavior.Restrict);
});
modelBuilder.Entity<InventTransDetail>(e =>
{
@ -297,15 +284,7 @@ namespace CPRNIMS.Infrastructure.Database
.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)
@ -323,10 +302,6 @@ namespace CPRNIMS.Infrastructure.Database
e.HasOne(r => r.Discipline)
.WithMany()
.HasForeignKey(r => r.DisciplineId);
e.HasOne(r => r.ProjectCodes)
.WithMany()
.HasForeignKey(r => r.ProjectCodeId);
});
modelBuilder.Entity<MRS>(e => {

View File

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

View File

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

View File

@ -11,10 +11,4 @@ namespace CPRNIMS.Infrastructure.Dto.Inventory
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

@ -8,7 +8,7 @@ namespace CPRNIMS.Infrastructure.Dto.Inventory
{
public class MRSFilterDto
{
public int PageNumber { get; set; } = 1;
public int Page { get; set; } = 1;
public int PageSize { get; set; } = 12;
public string? SearchMRSNo { get; set; }
public long? RISId { 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

@ -9,7 +9,7 @@ namespace CPRNIMS.Infrastructure.Dto.Inventory
{
public class MRSPagedResult
{
public IEnumerable<MRSPagedDto> Data { get; set; } = [];
public IEnumerable<MRSResponse> 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,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

@ -10,7 +10,7 @@ namespace CPRNIMS.Infrastructure.Dto.Inventory.Request
{
public int InventoryId { get; set; }
public long PRDetailId { get; set; }
public int ProjectCodeId { get; set; }
public string IssuedTo { get; set; } = string.Empty;
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,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,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 +1,28 @@
using CPRNIMS.Infrastructure.Models.Inventory;
using System;
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; }
public long MRSId { get; set; }
public string MRSNo { get; set; } = string.Empty;
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 string ReturnedBy { get; set; } = string.Empty;
public decimal QtyReturned { get; set; }
public string? Condition { 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; }
}
}

View File

@ -27,9 +27,7 @@ namespace CPRNIMS.Infrastructure.Dto.Inventory.Response
public long ItemNo { get; set; }
public string? ProjectCode { get; set; }
public string? ProjectName { get; set; }
public string? IssuedTo { get; set; }
public string? DisciplineName { get; set; }

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

@ -14,7 +14,7 @@ namespace CPRNIMS.Infrastructure.Dto.Inventory.Response
public string ItemName { get; set; } = string.Empty;
public long ItemNo { get; set; }
public string? LotNo { get; set; }
public int ProjectCodeId { get; set; }
public string IssuedTo { get; set; } = string.Empty;
public string DisciplineName { get; set; } = string.Empty;
public string? Message { get; set; }
public byte DisciplineId { get; set; }
@ -28,7 +28,5 @@ namespace CPRNIMS.Infrastructure.Dto.Inventory.Response
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

@ -17,7 +17,6 @@ namespace CPRNIMS.Infrastructure.Dto.Inventory
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? Manufacturer { get; set; }
public int ItemCount { get; set; }
public byte CurrencyId { get; set; }
public short CurrencyId { get; set; }
public string? Department { get; set; }
public string? ItemCategoryName { get; set; }
public DateTime CommitmentDate { get; set; }

View File

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

View File

@ -8,7 +8,7 @@ using System.Threading.Tasks;
namespace CPRNIMS.Infrastructure.Entities.Finance
{
public class RRDetailDto : CommonProperties
public class RRDetail : CommonProperties
{
[Key]
public long RRDetailId { get; set; }

View File

@ -17,7 +17,6 @@ namespace CPRNIMS.Infrastructure.Entities.Inventory
public long RRNo { get; set; }
public string CreatedBy { get; set; }=string.Empty;
public bool IsActive { get; set; }
public Inventory? Inventory { get; set; }
public ICollection<InventTransDetail> InventTransDetails { get; set; } = [];
}
}

View File

@ -1,6 +1,4 @@
using CPRNIMS.Infrastructure.Entities.Items;
using CPRNIMS.Infrastructure.Entities.Purchasing;
using CPRNIMS.Infrastructure.Entities.Receiving;
using CPRNIMS.Infrastructure.Entities.Purchasing;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
@ -18,15 +16,13 @@ namespace CPRNIMS.Infrastructure.Entities.Inventory
public long InventTransDetailId { get; set; }
public int InventTransId { get; set; }
public byte TransTypeId { get; set; }
public long RRDetailId { get; set; }
public decimal QtyIn { get; set; }
public decimal QtyOut { get; set; }
public DateTime CreatedDate { get; set; }
public string? Remarks { get; set; }
public bool IsActive { get; set; }
public long PRDetailId { get; set; }
public long? RRDetailId { get; set; }
public PRDetails? PRDetails { get; set; }
public RRDetails? RRDetails { get; set; }
public InventTrans? InventTrans { get; set; }
}
}

View File

@ -1,5 +1,4 @@
using CPRNIMS.Infrastructure.Entities.Account;
using CPRNIMS.Infrastructure.Entities.Items;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
@ -25,6 +24,5 @@ namespace CPRNIMS.Infrastructure.Entities.Inventory
public Lot? Lot { get; set; }
public ICollection<InventTrans> InventTrans { get; set; } = [];
public ApplicationUser? User { get; set; }
public Item? Item { get; set; }
}
}

View File

@ -42,4 +42,5 @@ namespace CPRNIMS.Infrastructure.Entities.Inventory
public RIS RIS { get; set; } = null!;
public Inventory Inventory { get; set; } = null!;
}
}

View File

@ -20,6 +20,10 @@ namespace CPRNIMS.Infrastructure.Entities.Inventory
public int InventoryId { get; set; }
public long PRDetailId { get; set; }
[Required, MaxLength(450)]
public string IssuedTo { get; set; } = string.Empty;
public byte DisciplineId { get; set; }
public decimal QtyIssued { get; set; }
@ -36,8 +40,6 @@ namespace CPRNIMS.Infrastructure.Entities.Inventory
public string? CanceledBy { get; set; }
public DateTime? CanceledDate { get; set; }
public string? Reason { get; set; }
public int ProjectCodeId { get; set; }
public ProjectCodes ProjectCodes { get; set; } = null!;
public Inventory Inventory { get; set; } = null!;
public PRDetails PRDetail { get; set; } = null!;
public Discipline Discipline { get; set; } = null!;

View File

@ -1,7 +1,13 @@
using CPRNIMS.Infrastructure.Entities.Common;
using CPRNIMS.Infrastructure.Entities.Account;
using CPRNIMS.Infrastructure.Entities.Common;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static System.Runtime.InteropServices.JavaScript.JSType;
namespace CPRNIMS.Infrastructure.Entities.Items
{
@ -36,6 +42,5 @@ namespace CPRNIMS.Infrastructure.Entities.Items
public string? ItemAttachPath { get; set; }
public bool IsMDLD { get; set; }
public bool CheckBox { get; set; }
public ItemCode? ItemCode { get; set; }
}
}

View File

@ -23,7 +23,5 @@ namespace CPRNIMS.Infrastructure.Entities.Items
public byte RequestTypeId { get; set; }
public bool IsActive { get; set; }
public int CartItemCount { get; set; }
public short ItemCategoryId { get; set; }
public ItemCategory? ItemCategory { get; set; }
}
}

View File

@ -1,41 +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.Entities.Items
{
public class ItemDtos
{
[Key]
public long ItemNo { get; set; }
public long ItemCodeId { get; set; }
public string? Department { get; set; }
public string? ItemCategoryName { get; set; }
public string? UserId { get; set; }
public string? ItemName { get; set; }
public string? ItemDescription { get; set; }
public string? StatusName { get; set; }
public bool IsActive { get; set; }
public bool IsCommon { get; set; }
public byte RequestTypeId { get; set; }
public string? ItemLocalName { get; set; }
public string? ItemTypeName { get; set; }
public string? PRTypeName { get; set; }
public decimal Qty { get; set; }
public int ItemColorId { get; set; }
public short ItemLocalId { get; set; }
public int UOMId { get; set; }
public short ItemCategoryId { get; set; }
public string? PackagingTypeName { get; set; }
public short ItemClassId { get; set; }
public string? UOMName { get; set; }
public string? ItemColorName { get; set; }
public long ItemAttachId { get; set; }
public string? ItemAttachPath { get; set; }
public bool IsMDLD { get; set; }
public bool CheckBox { get; set; }
}
}

View File

@ -1,22 +0,0 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CPRNIMS.Infrastructure.Entities.PO
{
[Table("Currencies")]
public class Currencies
{
[Key]
public byte CurrencyId { get; set; }
public string CurrencyName { get; set; }=string.Empty;
public decimal VatRate { get; set; }
public decimal CER { get; set; }
public string? AmountWords { get; set; }
public bool? IsActive { get; set; }
}
}

View File

@ -34,7 +34,6 @@ namespace CPRNIMS.Infrastructure.Entities.PO
public byte PODId { get; set; }
public byte POTypeId { get; set; }
public byte IncoTermsId { get; set; }
public byte CurrencyId { get; set; }
public string? IncotermsName { get; set; }
public string? CountryOrigin { get; set; }
}

View File

@ -6,7 +6,7 @@ using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static System.Runtime.InteropServices.JavaScript.JSType;
namespace CPRNIMS.Infrastructure.Entities.Purchasing
{

View File

@ -1,5 +1,4 @@
using CPRNIMS.Infrastructure.Entities.Common;
using CPRNIMS.Infrastructure.Entities.Items;
using CPRNIMS.Infrastructure.ViewModel.Items;
using System;
using System.Collections.Generic;
@ -25,6 +24,5 @@ namespace CPRNIMS.Infrastructure.Entities.Purchasing
public decimal Qty { get; set; }
public bool IsSearched { get; set; }
public PR? PRs { get; set; }
public ItemCategory? ItemCategory { get; set; }
}
}

View File

@ -17,7 +17,6 @@ namespace CPRNIMS.Infrastructure.Entities.Purchasing
public string? ProjectName { get; set; }
public int MaxDays { get; set; }
public string? DeliveryAddress { get; set; }
public string? StatusName { get; set; }
public bool IsActive { get; set; }
}
}

View File

@ -8,7 +8,7 @@ using System.Threading.Tasks;
namespace CPRNIMS.Infrastructure.Entities.Receiving
{
public class RRDetailDto
public class RRDetail
{
[Key]
public long PRDetailsId { get; set; }

View File

@ -1,25 +0,0 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CPRNIMS.Infrastructure.Entities.Receiving
{
[Table("RRDetails")]
public class RRDetails
{
[Key]
public long RRDetailId { get; set; }
public long PRDetailId { get; set; }
public long RRId { get; set; }
public long PODetailId { get; set; }
public decimal Quantity { get; set; }
public decimal QuantityReceived { get; set; }
public decimal QtyRemaining { get; set; }
public decimal UnitPrice { get; set; }
public bool IsActive { get; set; }
}
}

View File

@ -23,6 +23,5 @@ namespace CPRNIMS.Infrastructure.Models.Account
public string? Token { get; set; }
public string? Company { get; set; }
public string? MyAccess { get; set; }
public int DepartmentId { get; set; }
}
}

View File

@ -1,26 +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.Models.Inventory
{
public class MRSData
{
[JsonPropertyName("mrsId")] public long MRSId { get; set; }
[JsonPropertyName("mrsNo")] public string? MRSNo { get; set; }
[JsonPropertyName("risId")] public long RISId { get; set; }
[JsonPropertyName("inventoryId")] public int InventoryId { get; set; }
[JsonPropertyName("returnedBy")] public string? ReturnedBy { get; set; }
[JsonPropertyName("qtyReturned")] public decimal QtyReturned { get; set; }
[JsonPropertyName("condition")] public string? Condition { get; set; }
[JsonPropertyName("remarks")] public string? Remarks { get; set; }
[JsonPropertyName("status")] public short Status { get; set; }
[JsonPropertyName("createdBy")] public string? CreatedBy { get; set; }
[JsonPropertyName("createdDate")] public DateTime CreatedDate { get; set; }
[JsonPropertyName("approvedBy")] public string? ApprovedBy { get; set; }
[JsonPropertyName("approvedDate")] public DateTime? ApprovedDate { get; set; }
}
}

View File

@ -24,7 +24,7 @@ namespace CPRNIMS.Infrastructure.ViewModel.PO
public string? ContactPerson { get; set; }
public string? Manufacturer { get; set; }
public int ItemCount { get; set; }
public byte CurrencyId { get; set; }
public short CurrencyId { get; set; }
public string? Department { get; set; }
public string? ItemCategoryName { get; set; }
public DateTime CommitmentDate { get; set; }

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ActiveDebugProfile>https</ActiveDebugProfile>
<Controller_SelectedScaffolderID>MvcControllerEmptyScaffolder</Controller_SelectedScaffolderID>
<Controller_SelectedScaffolderCategoryPath>root/Common/MVC/Controller</Controller_SelectedScaffolderCategoryPath>
<NameOfLastUsedPublishProfile>D:\sourcecode\NonInventPurchasing\CPRNIMS.WebApi\Properties\PublishProfiles\FolderProfile1.pubxml</NameOfLastUsedPublishProfile>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DebuggerFlavor>ProjectDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<DebuggerFlavor>ProjectDebugger</DebuggerFlavor>
</PropertyGroup>
</Project>

View File

@ -1,18 +1,15 @@
using CPRNIMS.Domain.Contracts.Account;
using CPRNIMS.Domain.Contracts.Canvass;
using CPRNIMS.Domain.Contracts.Common;
using CPRNIMS.Domain.Contracts.Finance;
using CPRNIMS.Domain.Contracts.Inventory;
using CPRNIMS.Domain.Contracts.Items;
using CPRNIMS.Domain.Contracts.PO;
using CPRNIMS.Domain.Contracts.PR;
using CPRNIMS.Domain.Contracts.Receiving;
using CPRNIMS.Domain.Contracts.Reports;
using CPRNIMS.Domain.Contracts.SMTP;
using CPRNIMS.Domain.Services;
using CPRNIMS.Domain.Services.Account;
using CPRNIMS.Domain.Services.Canvass;
using CPRNIMS.Domain.Services.Common;
using CPRNIMS.Domain.Services.Finance;
using CPRNIMS.Domain.Services.Inventory;
using CPRNIMS.Domain.Services.PO;
@ -21,7 +18,6 @@ using CPRNIMS.Domain.Services.SMTP;
using CPRNIMS.Infrastructure.Database;
using CPRNIMS.Infrastructure.Entities.Account;
using CPRNIMS.Infrastructure.Helper;
using CPRNIMS.Infrastructure.Reports;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
@ -93,6 +89,7 @@ namespace CPRNIMS.WebApi.Common
sql.EnableRetryOnFailure(5, TimeSpan.FromHours(2), null);
sql.CommandTimeout(20);
}));
services.AddDbContext<PurchLocalDbContext>(options =>
options.UseSqlServer(localConn, sql =>
{
@ -150,7 +147,6 @@ namespace CPRNIMS.WebApi.Common
{
services.AddMemoryCache();
services.AddScoped<IRoleAuthorizationCache, RoleAuthorizationCache>();
services.AddScoped<ITransactionFacade, TransactionFacade>();
services.AddScoped<IDepartment, Department>();
services.AddScoped<IAttachment, Domain.Services.Account.Attachment>();
services.AddScoped<IItem, Domain.Services.Items.Item>();
@ -158,8 +154,7 @@ namespace CPRNIMS.WebApi.Common
services.AddScoped<ICanvass, Canvass>();
services.AddScoped<IRIS, RIS>();
services.AddScoped<IMRS, MRS>();
services.AddScoped<IReportDataService, ReportDataService>();
services.AddScoped<IInventoryReports, InventoryReports>();
#region Automation using LLM
services.AddHttpClient<SupplierSearchService>();
#endregion

View File

@ -67,7 +67,6 @@ namespace CPRNIMS.WebApi.Controllers.Account
userId = user.Id,
userName = user.UserName,
fullName = user.FullName,
departmentId = user.DepartmentId,
email = user.Email,
phoneNumber = user.PhoneNumber,
company = user.Company,

View File

@ -2,6 +2,7 @@
using CPRNIMS.Domain.Services;
using CPRNIMS.Infrastructure.Dto.Inventory;
using CPRNIMS.Infrastructure.Dto.Inventory.Request;
using CPRNIMS.Infrastructure.Dto.PR;
using CPRNIMS.WebApi.Controllers.Base;
using Microsoft.AspNetCore.Mvc;

View File

@ -1,68 +0,0 @@
using Azure.Core;
using CPRNIMS.Domain.Contracts.Inventory;
using CPRNIMS.Domain.Contracts.Reports;
using CPRNIMS.Infrastructure.Dto.Inventory.Reports;
using CPRNIMS.Infrastructure.Dto.Inventory.Request;
using CPRNIMS.WebApi.Security;
using Microsoft.AspNetCore.Mvc;
namespace CPRNIMS.WebApi.Controllers.Inventory
{
[Route("api/[controller]")]
[ApiController]
public class InventoryReportsController : ControllerBase
{
private readonly IReportDataService _data;
private readonly IInventoryReports _reports;
public InventoryReportsController(IReportDataService data, IInventoryReports reports)
{
_data = data;
_reports = reports;
}
[HttpGet("GetRISReport")]
public async Task<IActionResult> GetRISReport([FromQuery] InventoryReportsRequest request, CancellationToken ct)
{
var currentUser = User.ToUserClaims();
if (currentUser == null)
return BadRequest();
var data = await _reports.GetRISReportAsync(request, currentUser.UserName,currentUser.DepartmentId, ct);
return Ok(data);
}
[HttpGet("GetMRSReport")]
public async Task<IActionResult> GetMRSReport([FromQuery] InventoryReportsRequest request, CancellationToken ct)
{
var currentUser = User.ToUserClaims();
if (currentUser == null)
return BadRequest();
var data = await _reports.GetMRSReportAsync(request, currentUser.UserName, currentUser.DepartmentId, ct);
return Ok(data);
}
[HttpGet("GetInventoryReport")]
public async Task<IActionResult> GetInventoryReport([FromQuery] InventoryReportsRequest request, CancellationToken ct)
{
var currentUser = User.ToUserClaims();
if (currentUser == null)
return BadRequest();
var data = await _reports.GetInventoryReportAsync(request, currentUser.UserName, currentUser.DepartmentId, ct);
return Ok(data);
}
[HttpGet("GetRISData")]
public IActionResult GetData([FromQuery] DateTime dateFrom, [FromQuery] DateTime dateTo,CancellationToken ct)
{
var result = new RISReportDataDto
{
Rows = _data.GetMain(dateFrom, dateTo),
Disciplines = _data.GetDisciplines(dateFrom, dateTo),
Recipients = _data.GetRecipients(dateFrom, dateTo)
};
return Ok(result);
}
}
}

View File

@ -1,76 +1,12 @@
using CPRNIMS.Domain.Contracts.Inventory;
using CPRNIMS.Infrastructure.Dto.Inventory;
using CPRNIMS.Infrastructure.Dto.Inventory.Request;
using CPRNIMS.WebApi.Security;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc;
namespace CPRNIMS.WebApi.Controllers.Inventory
{
[Route("api/[controller]")]
[ApiController]
public partial class MRSMgmtController : ControllerBase
public class MRSMgmtController : Controller
{
private readonly IMRS _mrs;
public MRSMgmtController(IMRS mrs) => _mrs = mrs;
[HttpGet]
public async Task<IActionResult> GetMRS([FromQuery] MRSFilterDto filter, CancellationToken ct)
public IActionResult Index()
{
var currentUser = User.ToUserClaims();
if (currentUser == null)
return BadRequest();
var result = await _mrs.GetPagedAsync(filter, ct, currentUser.DepartmentId, currentUser.UserName);
return Ok(result);
}
[HttpGet("SearchRIS")]
public async Task<IActionResult> SearchRIS([FromQuery] string? searchRISNo, int? projectCodeId, CancellationToken ct)
{
var results = await _mrs.SearchRISForReturnAsync(searchRISNo, projectCodeId, ct);
return Ok(new { success = true, data = results });
}
[HttpGet("SearchProjects")]
public async Task<IActionResult> SearchProjects([FromQuery] string? searchProjectCode, CancellationToken ct)
{
var results = await _mrs.GetProjectsWithOpenRISAsync(searchProjectCode, ct);
return Ok(new { success = true, data = results });
}
[HttpPost]
public async Task<IActionResult> CreateMRS([FromBody] CreateMRSRequest request, CancellationToken ct)
{
var currentUser = User.ToUserClaims();
if (currentUser == null)
return BadRequest();
var result = await _mrs.CreateAsync(request, currentUser.UserName, ct);
return Ok(new { success = true, message = $"MRS# {result.MRSNo} created successfully." });
}
[HttpPost("Approve")]
public async Task<IActionResult> ApproveMRS([FromBody] ApproveMRSRequest request, CancellationToken ct)
{
var currentUser = User.ToUserClaims();
if (currentUser == null)
return BadRequest();
await _mrs.ApproveAsync(request.MRSId, currentUser.UserName, ct);
return Ok(new { success = true, message = "MRS approved successfully." });
}
[HttpPost("Cancel")]
public async Task<IActionResult> CancelMRS([FromBody] CancelMRSRequest request, CancellationToken ct)
{
if (string.IsNullOrWhiteSpace(request.Reason))
return BadRequest(new { success = false, message = "A reason for cancellation is required." });
var currentUser = User.ToUserClaims();
if (currentUser == null)
return BadRequest();
await _mrs.CancelAsync(request, currentUser.UserName, ct);
return Ok(new {success = true,message = "MRS cancelled and inventory adjusted."});
return View();
}
}
}

View File

@ -4,6 +4,7 @@ using CPRNIMS.Infrastructure.Dto.Inventory;
using CPRNIMS.Infrastructure.Dto.Inventory.Request;
using CPRNIMS.WebApi.Security;
using Microsoft.AspNetCore.Mvc;
using System.Security.Claims;
namespace CPRNIMS.WebApi.Controllers.Inventory
{
@ -19,11 +20,7 @@ namespace CPRNIMS.WebApi.Controllers.Inventory
[HttpGet("GetRIS")]
public async Task<IActionResult> GetRIS([FromQuery] RISFilterDto filter, CancellationToken ct)
{
var currentUser = User.ToUserClaims();
if (currentUser == null)
return BadRequest();
var result = await _risRepo.GetPagedAsync(filter,ct, currentUser.DepartmentId, currentUser.UserName);
var result = await _risRepo.GetPagedAsync(filter,ct);
return Ok(result);
}
@ -51,7 +48,12 @@ namespace CPRNIMS.WebApi.Controllers.Inventory
});
var ris = await _risRepo.CreateAsync(request, currentUser.UserName,ct);
return Ok(new { success = true, message = $"RIS# {ris.RISNo} created successfully." });
return Ok(new
{
success = true,
message = $"RIS {ris.RISNo} created successfully.",
data= ris
});
}
[HttpPut("ApproveRIS")]
@ -67,11 +69,7 @@ namespace CPRNIMS.WebApi.Controllers.Inventory
[HttpPut("CancelRIS")]
public async Task<IActionResult> CancelRIS([FromBody] CancelRISRequest request, CancellationToken ct)
{
var currentUser = User.ToUserClaims();
if (currentUser == null)
return BadRequest();
await _risRepo.CancelAsync(request, currentUser.UserName, ct);
await _risRepo.CancelAsync(request, ct);
return Ok(new { success = true, message = "RIS cancelled and inventory restored." });
}
}

View File

@ -284,12 +284,6 @@ namespace CPRNIMS.WebApi.Controllers.PO
}
#endregion
#region Get
[HttpPost("GetCurrencies")]
public async Task<IActionResult> GetCurrencies(Currencies request, CancellationToken ct)
{
var data = await _purchaseOrder.GetCurrencies(request.CurrencyName,ct);
return Ok(data);
}
[HttpGet("GetPOFormData")]
public async Task<IActionResult> GetPOFormData(int? poId = null)
{

View File

@ -5,7 +5,6 @@ using CPRNIMS.WebApi.Common;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddApplicationServices(builder);
builder.Services.AddFastReport();
builder.Services.AddAutoMapper(cfg => { }, typeof(SupplierRequestProfile));
@ -17,22 +16,20 @@ if (app.Environment.IsDevelopment())
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("./v2/swagger.json", "LLOYD API V2");
c.SwaggerEndpoint("./v2/swagger.json", "LLOYD API V2"); //originally "./swagger/v1/swagger.json"
});
}
app.UseMiddleware<GlobalExceptionMiddleware>();
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("./v2/swagger.json", "LLOYD API V2");
c.SwaggerEndpoint("./v2/swagger.json", "LLOYD API V2"); //originally "./swagger/v1/swagger.json"
});
app.UseCors("AllowAnyOrigin");
app.UseHttpsRedirection();
app.UseFastReport();
app.UseAuthentication();
app.UseAuthorization();

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
https://go.microsoft.com/fwlink/?LinkID=208121.
-->
<Project>
<PropertyGroup>
<_PublishTargetUrl>D:\sourcecode\CPRNIMS\CPRNIMS.WebApi\bin\Release\net8.0\publish\</_PublishTargetUrl>
<History>True|2025-12-17T23:10:35.4921808Z||;True|2025-12-16T14:53:58.3743182+08:00||;True|2025-12-16T14:53:53.8528078+08:00||;True|2025-11-27T09:07:09.5404338+08:00||;True|2025-11-27T09:07:02.8345022+08:00||;True|2025-11-26T16:01:43.2068083+08:00||;True|2025-11-26T13:18:23.6103149+08:00||;True|2025-11-26T13:06:57.8584612+08:00||;True|2025-11-05T07:21:05.3959433+08:00||;True|2025-10-24T13:44:41.2876894+08:00||;True|2025-10-24T09:10:03.6232364+08:00||;True|2025-10-24T09:09:56.5522930+08:00||;True|2025-09-16T09:32:01.0906622+08:00||;True|2025-09-12T08:54:29.9542476+08:00||;True|2025-09-11T12:06:12.9357427+08:00||;True|2025-09-09T15:12:53.5036032+08:00||;True|2025-09-08T16:13:57.6489788+08:00||;True|2025-09-08T15:49:13.2220596+08:00||;True|2025-09-08T15:49:09.1175544+08:00||;True|2025-09-08T14:16:49.9685540+08:00||;True|2025-09-04T17:16:30.6365380+08:00||;True|2025-09-04T16:11:55.1923650+08:00||;True|2025-09-04T15:59:54.3131225+08:00||;True|2025-09-04T13:04:52.2805520+08:00||;True|2025-09-04T13:04:43.9603490+08:00||;True|2025-09-03T17:16:57.9153347+08:00||;True|2025-09-03T16:05:34.6735848+08:00||;True|2025-09-02T16:31:41.1104433+08:00||;True|2025-09-02T16:31:28.9543370+08:00||;True|2025-09-02T11:02:07.6244438+08:00||;True|2025-09-01T07:06:55.2325589+08:00||;True|2025-08-28T07:46:30.3699102+08:00||;True|2025-08-28T07:04:09.9075273+08:00||;True|2025-08-26T09:48:46.3663800+08:00||;True|2025-08-21T07:20:24.1925540+08:00||;True|2025-08-20T07:13:03.4186833+08:00||;True|2025-08-19T10:43:26.3618437+08:00||;True|2025-08-14T17:07:08.7644641+08:00||;True|2025-08-14T11:52:57.3626470+08:00||;True|2025-08-13T10:04:24.2646290+08:00||;True|2025-08-13T09:52:02.8860494+08:00||;True|2025-08-12T13:30:44.9278812+08:00||;True|2025-08-12T07:14:01.7635891+08:00||;True|2025-08-12T07:13:37.8273450+08:00||;True|2025-08-08T11:00:25.8006408+08:00||;True|2025-08-08T08:33:19.7826504+08:00||;True|2025-08-08T08:33:17.0210998+08:00||;True|2025-08-05T09:52:56.3618071+08:00||;True|2025-07-31T15:04:11.5021618+08:00||;True|2025-07-21T17:16:42.5825002+08:00||;True|2025-07-21T17:16:31.3000014+08:00||;True|2025-06-20T10:19:19.8573068+08:00||;True|2025-05-28T08:14:52.0497965+08:00||;True|2025-05-28T08:14:32.1379767+08:00||;True|2025-05-15T16:20:18.0632480+08:00||;True|2025-05-15T16:19:48.4614805+08:00||;True|2025-05-15T10:52:08.4012348+08:00||;True|2025-05-15T10:52:01.9277880+08:00||;True|2025-05-13T09:35:30.2002459+08:00||;True|2025-04-22T09:44:31.3997970+08:00||;True|2025-04-22T09:44:25.6317531+08:00||;True|2025-04-14T08:03:15.9455375+08:00||;True|2025-04-11T09:30:57.1064901+08:00||;True|2025-04-09T13:43:42.7362198+08:00||;True|2025-04-09T13:43:39.6044873+08:00||;True|2025-04-09T13:36:06.1196237+08:00||;True|2025-04-09T13:35:58.4320424+08:00||;True|2025-04-04T09:43:18.5933871+08:00||;True|2025-04-04T09:42:34.9498924+08:00||;True|2025-04-03T07:02:46.7077629+08:00||;True|2025-04-03T06:58:02.0551766+08:00||;True|2025-03-21T09:52:18.3925005+08:00||;True|2025-03-20T14:39:10.7153863+08:00||;True|2025-03-20T14:38:01.6285942+08:00||;True|2025-03-20T14:37:56.4692955+08:00||;True|2025-03-20T12:17:55.1302908+08:00||;True|2025-03-18T17:04:40.7861848+08:00||;True|2025-03-18T17:04:37.3907842+08:00||;True|2025-03-14T15:52:44.9073796+08:00||;True|2025-03-07T14:12:45.0977693+08:00||;True|2025-03-07T14:12:42.5277665+08:00||;True|2025-02-27T09:40:55.2110821+08:00||;True|2025-02-26T10:06:26.6616955+08:00||;True|2025-02-25T13:52:14.0774519+08:00||;True|2025-02-25T12:12:58.5452123+08:00||;True|2025-02-21T14:21:27.8721893+08:00||;True|2025-02-21T14:21:17.5025040+08:00||;True|2025-02-18T13:28:26.1030353+08:00||;True|2025-02-14T09:30:08.9595204+08:00||;True|2025-02-13T08:42:38.0359073+08:00||;True|2025-02-03T17:18:34.9028789+08:00||;True|2025-01-27T14:37:48.6993964+08:00||;True|2025-01-21T09:04:15.0865384+08:00||;True|2025-01-16T07:41:47.1616176+08:00||;False|2025-01-16T07:40:14.1951891+08:00||;True|2025-01-16T07:03:41.6806457+08:00||;True|2025-01-16T07:03:31.4460188+08:00||;True|2025-01-15T10:23:23.7811134+08:00||;False|2025-01-15T10:22:54.8331554+08:00||;True|2025-01-15T10:02:24.4815760+08:00||;</History>
<LastFailureDetails />
</PropertyGroup>
</Project>

View File

@ -1,19 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- https://go.microsoft.com/fwlink/?LinkID=208121. -->
<Project>
<PropertyGroup>
<DeleteExistingFiles>true</DeleteExistingFiles>
<ExcludeApp_Data>false</ExcludeApp_Data>
<LaunchSiteAfterPublish>true</LaunchSiteAfterPublish>
<LastUsedBuildConfiguration>Release</LastUsedBuildConfiguration>
<LastUsedPlatform>Any CPU</LastUsedPlatform>
<PublishProvider>FileSystem</PublishProvider>
<PublishUrl>bin\Release\net8.0\publish\</PublishUrl>
<WebPublishMethod>FileSystem</WebPublishMethod>
<_TargetId>Folder</_TargetId>
<SiteUrlToLaunchAfterPublish />
<TargetFramework>net8.0</TargetFramework>
<ProjectGuid>8ab7b541-48dc-4dbf-84e0-05b161c32965</ProjectGuid>
<SelfContained>false</SelfContained>
</PropertyGroup>
</Project>

View File

@ -16,7 +16,6 @@ namespace CPRNIMS.WebApi.Security
UserName = user.FindFirstValue(ClaimTypes.Name) ?? "",
FullName = user.FindFirstValue("FullName") ?? "",
Company = user.FindFirstValue("Company") ?? "",
DepartmentId = Convert.ToInt32(user.FindFirstValue("DepartmentId")),
Roles = user.FindAll(ClaimTypes.Role)
.Select(r => r.Value)
.ToList()

View File

@ -1,13 +1,13 @@
USE [CPRNIMS]
GO
/****** Object: StoredProcedure [dbo].[GetInventory] Script Date: 6/18/2026 3:09:49 PM ******/
/****** Object: StoredProcedure [dbo].[GetInventory] Script Date: 6/11/2026 9:29:29 AM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[GetInventory]
(
@UserId VARCHAR(450)='16b37c00-131f-4205-b8f6-ad4d0f9f3a32',
@UserId VARCHAR(450)='89da2977-c70f-4df9-94d4-9a610aa999ea',
@SearchPRNo VARCHAR(50) = '',
@SearchItemNo VARCHAR(50) = '',
@SearchItemName VARCHAR(100) = '',
@ -20,18 +20,6 @@ AS
BEGIN
SET NOCOUNT ON;
DECLARE @Offset INT = (@PageNumber - 1) * @PageSize;
DECLARE @HasFullAccess BIT = 0;
DECLARE @UserDepartmentId INT,@UserName VARCHAR(50);
SELECT @UserDepartmentId = DepartmentId,@UserName=UserName
FROM dbo.Users
WHERE Id = @UserId;
IF @UserName IN ('LSKRISUR24','LSCYNDIZ25','LSJONTAN25','LHRIOCAS24')
SET @HasFullAccess = 1;
IF @UserDepartmentId = 6
SET @HasFullAccess = 1;
-- ── 1. Full department list — unaffected by any filter ──────────────
SELECT DISTINCT D.Department
@ -61,30 +49,42 @@ BEGIN
, ICAT.ItemCategoryName
, RRD.RemainingQty
, ITD.CreatedDate
,COALESCE(PC.ProjectCode,'N/A') ProjectCode
,COALESCE(PCD.ProjectCode,'N/A') ProjectCode
INTO #Inventory
FROM dbo.Inventory IV
INNER JOIN dbo.InventTrans IT ON IV.InventoryId = IT.InventoryId
INNER JOIN dbo.InventTransDetail ITD ON IT.InventTransId = ITD.InventTransId
INNER JOIN dbo.PRDetails PRD ON ITD.PRDetailId = PRD.PRDetailsId AND PRD.IsActive = 1
INNER JOIN dbo.PR ON PR.PRId=PRD.PRId AND PR.IsActive = 1
INNER JOIN dbo.RRDetails RRD ON PRD.PRDetailsId = RRD.PRDetailId AND RRD.IsActive = 1
INNER JOIN dbo.ItemCategories ICAT ON PRD.ItemCategoryId = ICAT.ItemCategoryId
LEFT JOIN dbo.Lot L ON IV.LotId = L.LotId
LEFT JOIN dbo.LotType LT ON L.LotTypeId = LT.LotTypeId
LEFT JOIN dbo.ProjectCodes PC ON PR.ProjectCodeId = PC.ProjectCodeId
INNER JOIN dbo.Users U ON IV.UserId = U.Id
INNER JOIN dbo.Departments D ON U.DepartmentId = D.DepartmentId
WHERE ITD.TransTypeId = 2 AND IV.IsActive = 1 AND ITD.IsActive = 1
AND (
@HasFullAccess = 1
OR D.DepartmentId = @UserDepartmentId
)
AND (@SearchPRNo = '' OR PR.PRNo = @SearchPRNo)
AND (@SearchItemNo = '' OR PRD.ItemNo = @SearchItemNo)
AND (@SearchItemName = '' OR PRD.ItemName LIKE '%' + @SearchItemName + '%')
AND (@SearchDept = '' OR D.Department LIKE '%' + @SearchDept + '%')
AND (@SearchProjectCode = '' OR PC.ProjectCode LIKE '%' + @SearchProjectCode + '%')
INNER JOIN dbo.InventTrans IT
ON IV.InventoryId = IT.InventoryId
INNER JOIN dbo.InventTransDetail ITD
ON IT.InventTransId = ITD.InventTransId
INNER JOIN dbo.PRDetails PRD
ON ITD.PRDetailId = PRD.PRDetailsId
AND PRD.IsActive = 1
INNER JOIN dbo.RRDetails RRD
ON PRD.PRDetailsId = RRD.PRDetailId
AND RRD.IsActive = 1
INNER JOIN dbo.ItemCategories ICAT
ON PRD.ItemCategoryId = ICAT.ItemCategoryId
INNER JOIN dbo.Lot L
ON IV.LotId = L.LotId
INNER JOIN dbo.LotType LT
ON L.LotTypeId = LT.LotTypeId
INNER JOIN dbo.PR PR
ON PR.UserId = IV.UserId
AND PR.IsActive = 1
INNER JOIN dbo.ProjectCodes PC
ON PR.ProjectCodeId = PC.ProjectCodeId
INNER JOIN dbo.Users U
ON IV.UserId = U.Id
INNER JOIN dbo.Departments D
ON U.DepartmentId = D.DepartmentId
INNER JOIN dbo.ProjectCodes PCD
ON PR.ProjectCodeId = PCD.ProjectCodeId
WHERE ITD.TransTypeId=2 AND IV.IsActive=1 AND ITD.IsActive=1 AND
(@SearchPRNo = '' OR PR.PRNo = @SearchPRNo)
AND (@SearchItemNo = '' OR PRD.ItemNo = @SearchItemNo)
AND (@SearchItemName = '' OR PRD.ItemName LIKE '%' + @SearchItemName + '%')
AND (@SearchDept = '' OR D.Department LIKE '%' + @SearchDept + '%')
AND (@SearchProjectCode = '' OR PC.ProjectCode LIKE '%' + @SearchProjectCode + '%')
GROUP BY
IV.InventoryId
, IV.ItemNo
@ -100,7 +100,7 @@ BEGIN
, ICAT.ItemCategoryName
, RRD.RemainingQty
, ITD.CreatedDate
,PC.ProjectCode;
,PCD.ProjectCode;
-- ── 3. Total count of filtered results ──────────────────────────────
SELECT COUNT(*) AS TotalCount

View File

@ -16,7 +16,7 @@ CREATE TABLE [dbo].[RIS] (
[RISNo] VARCHAR(50) NOT NULL, -- generated slip number
[InventoryId] INT NOT NULL,
[PRDetailId] BIGINT NOT NULL,
[ProjectCodeId] INT NOT NULL, -- UserId receiving items
[IssuedTo] VARCHAR(450) NOT NULL, -- UserId receiving items
[DisciplineId] TINYINT NOT NULL, -- Trade/Matrix/Structural/Architectural
[QtyIssued] DECIMAL(14,2) NOT NULL,
[Remarks] VARCHAR(500) NULL,
@ -30,8 +30,7 @@ CREATE TABLE [dbo].[RIS] (
Reason VARCHAR(150) NULL,
FOREIGN KEY ([InventoryId]) REFERENCES [Inventory]([InventoryId]),
FOREIGN KEY ([PRDetailId]) REFERENCES [PRDetails]([PRDetailsId]),
FOREIGN KEY ([DisciplineId]) REFERENCES [Disciplines]([DisciplineId]),
FOREIGN KEY ([ProjectCodeId]) REFERENCES ProjectCodes([ProjectCodeId])
FOREIGN KEY ([DisciplineId]) REFERENCES [Disciplines]([DisciplineId])
);
-- ── MRS: Material Return Slip ─────────────────────────────────────

View File

@ -0,0 +1,56 @@
{
"JWT": {
"ValidAudience": "https://lloydwebapi.lloydlab.com:2021",
"ValidIssuer": "https://lloydwebapi.lloydlab.com:2021",
"Secret": "JWTAuthenticationHIGHsecuredPasswordVVVp1OH7Xasd707"
},
"Tavily": {
"ApiKey": "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",
"SearchUrl": "https://api.tavily.com/search"
},
"Groq": {
"ApiKey": "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",
"ApiUrl": "https://api.groq.com/openai/v1/chat/completions",
"Model": "llama-3.1-8b-instant"
},
"WebEndPoint": {
"ForgotPassword": "https://llipurchasingnoninventory.com:8080/",
"SupplierForm": "https://llipurchasingnoninventory.com:8083/"
},
"ConnectionStrings": {
"DefaultConnection": "Server=212.47.72.54;Database=CPRNIMS;User Id=LRMS26;Password=P@ssw0rd26;Encrypt=False;",
"LocalPurchConn": "Server=DESKTOP-RQGHQQN;Database=PurchasingSystem;User Id=LRMS25;Password=P@ssw0rd26;Encrypt=False;"
},
"SMTP": {
"DisplayName": "no-reply-cwms@lloydlab.com",
"ToReceiver": "NA",
"OutgoingPort": "587",
"IncomingPort": "110",
"SenderEmail": "lli.mis2025@gmail.com",
"Password": "vcwq nesk rsqb zxbf",
"Server": "smtp.gmail.com",
"SenderName": "CWMS",
"UserName": "lli.mis2025@gmail.com",
"CC": "rmsoriano@lloydlab.com;",
"PurchasingCC": ";rmsoriano@lloydlab.com;iigajasan@lloydlab.com;laoreo@lloydlab.com;avaustria@lloydlab.com;hdbautista@lloydlab.com;pur_canvasser2@lloydlab.com;pur_canvasser4@lloydlab.com;purchasing@lloydlab.com;jmmaulawin@lloydlab.com"
},
"Canvass": {
"CC": "iigajasan@lloydlab.com;rmsoriano@lloydlab.com;laoreo@lloydlab.com;avaustria@lloydlab.com;hdbautista@lloydlab.com;pur_canvasser2@lloydlab.com;pur_canvasser4@lloydlab.com;purchasing@lloydlab.com;jmmaulawin@lloydlab.com",
"EmailSettings": {
"ExcludedEmails": [
"jmcariaga@lloydlab.com",
"projctrl@lloydlab.com",
"test@test.com",
"admin@internal.com"
]
}
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}

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