From c092b3e4f1da7c8873cdb9db1f434b78f6b5d540 Mon Sep 17 00:00:00 2001 From: Jason Sylvestre Date: Wed, 1 Jul 2026 07:38:37 -0700 Subject: [PATCH 1/6] Show parent organization on details view --- Purchasing.Mvc/Views/Organization/Details.cshtml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Purchasing.Mvc/Views/Organization/Details.cshtml b/Purchasing.Mvc/Views/Organization/Details.cshtml index 18363323b..bc084d736 100644 --- a/Purchasing.Mvc/Views/Organization/Details.cshtml +++ b/Purchasing.Mvc/Views/Organization/Details.cshtml @@ -37,6 +37,19 @@
Type Name
@Model.TypeName
+
  • +
    Parent Org
    +
    + @if (Model.Parent != null) + { + @Html.ActionLink($"{Model.Parent.Name} ({Model.Parent.Id})", "Details", "Organization", new { id = Model.Parent.Id }, new { }) + } + else + { + @:n/a + } +
    +
  • Is Active
    @Model.IsActive
    From 441b5bb34bb7b700c9f1775b15e0549ef44b9aac Mon Sep 17 00:00:00 2001 From: Jason Sylvestre Date: Mon, 3 Aug 2026 14:55:22 -0700 Subject: [PATCH 2/6] Auto-populate PO number for eligible Aggie Enterprise orders When an Aggie Enterprise order is in 'Complete' status, has a reference number, and is missing a PO number, attempt to retrieve the PO number from Aggie Enterprise during the order review process. --- Purchasing.Mvc/Controllers/OrderController.cs | 2 + Purchasing.Mvc/Services/OrderService.cs | 25 ++++++ .../OrderServiceTestsMisc01.cs | 80 +++++++++++++++++++ 3 files changed, 107 insertions(+) diff --git a/Purchasing.Mvc/Controllers/OrderController.cs b/Purchasing.Mvc/Controllers/OrderController.cs index 5f0626ca6..a1ec13af9 100644 --- a/Purchasing.Mvc/Controllers/OrderController.cs +++ b/Purchasing.Mvc/Controllers/OrderController.cs @@ -620,6 +620,8 @@ public async Task Review(int id) { return ViewHelper.NotAuthorized(Resources.Authorization_PermissionDenied); } + + await _orderService.TryPopulatePoNumberFromAggieEnterprise(model.Order); model.Vendor = _repositoryFactory.OrderRepository.Queryable.Where(x=>x.Id == id).Select(x=>x.Vendor).Single(); if(model.Vendor != null && !string.IsNullOrWhiteSpace( model.Vendor.AeSupplierNumber )) diff --git a/Purchasing.Mvc/Services/OrderService.cs b/Purchasing.Mvc/Services/OrderService.cs index 44e568e17..ca1fb9ff0 100644 --- a/Purchasing.Mvc/Services/OrderService.cs +++ b/Purchasing.Mvc/Services/OrderService.cs @@ -71,6 +71,8 @@ public interface IOrderService /// String array of error messages, non-empty if completion didn't succeed Task Complete(Order order, OrderType newOrderType, string kfsDocType = null); + Task TryPopulatePoNumberFromAggieEnterprise(Order order); + /// /// Get the current user's list of orders. /// @@ -648,6 +650,29 @@ public async Task Complete(Order order, OrderType newOrderType, string return new string[0]; //return no errors } + public async Task TryPopulatePoNumberFromAggieEnterprise(Order order) + { + if (order.StatusCode?.Id != OrderStatusCode.Codes.Complete || + order.OrderType?.Id?.Trim() != OrderType.Types.AggieEnterprise || + string.IsNullOrWhiteSpace(order.ReferenceNumber) || + !string.IsNullOrWhiteSpace(order.PoNumber)) + { + return false; + } + + var status = await _aggieEnterpriseService.LookupOrderStatus(order.ReferenceNumber.Trim()); + if (string.IsNullOrWhiteSpace(status?.PoNumber)) + { + return false; + } + + order.PoNumber = status.PoNumber.Trim(); + _eventService.OrderUpdated(order, $"PO # automatically populated from Aggie Enterprise: {order.PoNumber}"); + _orderRepository.EnsurePersistent(order); + + return true; + } + /// /// Duplicates the given order info a new order, one that doesn't include the splits, approvals, or history of the given order /// diff --git a/Purchasing.Tests/ServiceTests/OrderServiceTests/OrderServiceTestsMisc01.cs b/Purchasing.Tests/ServiceTests/OrderServiceTests/OrderServiceTestsMisc01.cs index aeac523e6..76883ab03 100644 --- a/Purchasing.Tests/ServiceTests/OrderServiceTests/OrderServiceTestsMisc01.cs +++ b/Purchasing.Tests/ServiceTests/OrderServiceTests/OrderServiceTestsMisc01.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using Microsoft.VisualStudio.TestTools.UnitTesting; using Purchasing.Core.Domain; +using Purchasing.Core.Models.AggieEnterprise; using Purchasing.Tests.Core; using UCDArch.Testing; using UCDArch.Testing.Extensions; @@ -49,5 +50,84 @@ public void TestReRouteSingleApprovalForExistingOrder() #endregion Assert } #endregion ReRouteSingleApprovalForExistingOrder Tests + + #region TryPopulatePoNumberFromAggieEnterprise Tests + + [TestMethod] + public async System.Threading.Tasks.Task TestTryPopulatePoNumberFromAggieEnterprisePopulatesPoAndAddsHistory() + { + var order = CreateValidEntities.Order(1); + order.StatusCode.Id = OrderStatusCode.Codes.Complete; + order.OrderType = new OrderType(OrderType.Types.AggieEnterprise); + order.ReferenceNumber = " 184e9d20-f759-413e-8f42-06db62bf1e59 "; + order.PoNumber = " "; + + Mock.Get(AggieEnterpriseService) + .Setup(a => a.LookupOrderStatus("184e9d20-f759-413e-8f42-06db62bf1e59")) + .ReturnsAsync(new AeResultStatus { PoNumber = " PO123456 " }); + + var result = await OrderService.TryPopulatePoNumberFromAggieEnterprise(order); + + Assert.IsTrue(result); + Assert.AreEqual("PO123456", order.PoNumber); + Mock.Get(EventService).Verify(a => a.OrderUpdated( + order, + "PO # automatically populated from Aggie Enterprise: PO123456")); + Mock.Get(OrderRepository).Verify(a => a.EnsurePersistent(order)); + } + + [TestMethod] + public async System.Threading.Tasks.Task TestTryPopulatePoNumberFromAggieEnterpriseDoesNothingWhenLookupHasNoPo() + { + var order = CreateValidEntities.Order(1); + order.StatusCode.Id = OrderStatusCode.Codes.Complete; + order.OrderType = new OrderType(OrderType.Types.AggieEnterprise); + order.ReferenceNumber = "184e9d20-f759-413e-8f42-06db62bf1e59"; + order.PoNumber = null; + + Mock.Get(AggieEnterpriseService) + .Setup(a => a.LookupOrderStatus(order.ReferenceNumber)) + .ReturnsAsync(new AeResultStatus { PoNumber = " " }); + + var result = await OrderService.TryPopulatePoNumberFromAggieEnterprise(order); + + Assert.IsFalse(result); + Assert.IsNull(order.PoNumber); + Mock.Get(EventService).Verify( + a => a.OrderUpdated(It.IsAny(), It.IsAny()), + Times.Never()); + Mock.Get(OrderRepository).Verify(a => a.EnsurePersistent(It.IsAny()), Times.Never()); + } + + [DataTestMethod] + [DataRow(OrderStatusCode.Codes.Purchaser, OrderType.Types.AggieEnterprise, "184e9d20-f759-413e-8f42-06db62bf1e59", null)] + [DataRow(OrderStatusCode.Codes.Complete, OrderType.Types.KfsDocument, "184e9d20-f759-413e-8f42-06db62bf1e59", null)] + [DataRow(OrderStatusCode.Codes.Complete, OrderType.Types.AggieEnterprise, " ", null)] + [DataRow(OrderStatusCode.Codes.Complete, OrderType.Types.AggieEnterprise, "184e9d20-f759-413e-8f42-06db62bf1e59", "PO123456")] + public async System.Threading.Tasks.Task TestTryPopulatePoNumberFromAggieEnterpriseOnlyLooksUpEligibleOrders( + string statusCode, + string orderType, + string referenceNumber, + string poNumber) + { + var order = CreateValidEntities.Order(1); + order.StatusCode.Id = statusCode; + order.OrderType = new OrderType(orderType); + order.ReferenceNumber = referenceNumber; + order.PoNumber = poNumber; + + var result = await OrderService.TryPopulatePoNumberFromAggieEnterprise(order); + + Assert.IsFalse(result); + Mock.Get(AggieEnterpriseService).Verify( + a => a.LookupOrderStatus(It.IsAny()), + Times.Never()); + Mock.Get(EventService).Verify( + a => a.OrderUpdated(It.IsAny(), It.IsAny()), + Times.Never()); + Mock.Get(OrderRepository).Verify(a => a.EnsurePersistent(It.IsAny()), Times.Never()); + } + + #endregion TryPopulatePoNumberFromAggieEnterprise Tests } } From 90c0bcf1c963e2145d3a4155cf3d5e0329f86429 Mon Sep 17 00:00:00 2001 From: Jason Sylvestre Date: Mon, 3 Aug 2026 14:59:39 -0700 Subject: [PATCH 3/6] Add exception handling to Aggie Enterprise PO auto-population Wrap the PO number auto-population logic in a try-catch block to gracefully handle potential exceptions. If an error occurs during the Aggie Enterprise service lookup or order persistence, the process will fail silently by returning false, preventing unhandled exceptions from disrupting the application. --- Purchasing.Mvc/Services/OrderService.cs | 36 +++++++++++++++---------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/Purchasing.Mvc/Services/OrderService.cs b/Purchasing.Mvc/Services/OrderService.cs index ca1fb9ff0..3990c711f 100644 --- a/Purchasing.Mvc/Services/OrderService.cs +++ b/Purchasing.Mvc/Services/OrderService.cs @@ -652,25 +652,33 @@ public async Task Complete(Order order, OrderType newOrderType, string public async Task TryPopulatePoNumberFromAggieEnterprise(Order order) { - if (order.StatusCode?.Id != OrderStatusCode.Codes.Complete || - order.OrderType?.Id?.Trim() != OrderType.Types.AggieEnterprise || - string.IsNullOrWhiteSpace(order.ReferenceNumber) || - !string.IsNullOrWhiteSpace(order.PoNumber)) + try { - return false; - } + if (order.StatusCode?.Id != OrderStatusCode.Codes.Complete || + order.OrderType?.Id?.Trim() != OrderType.Types.AggieEnterprise || + string.IsNullOrWhiteSpace(order.ReferenceNumber) || + !string.IsNullOrWhiteSpace(order.PoNumber)) + { + return false; + } + + var status = await _aggieEnterpriseService.LookupOrderStatus(order.ReferenceNumber.Trim()); + if (string.IsNullOrWhiteSpace(status?.PoNumber)) + { + return false; + } + + order.PoNumber = status.PoNumber.Trim(); + _eventService.OrderUpdated(order, $"PO # automatically populated from Aggie Enterprise: {order.PoNumber}"); + _orderRepository.EnsurePersistent(order); - var status = await _aggieEnterpriseService.LookupOrderStatus(order.ReferenceNumber.Trim()); - if (string.IsNullOrWhiteSpace(status?.PoNumber)) + return true; + } + catch (Exception ex) { + //swallow it. return false; } - - order.PoNumber = status.PoNumber.Trim(); - _eventService.OrderUpdated(order, $"PO # automatically populated from Aggie Enterprise: {order.PoNumber}"); - _orderRepository.EnsurePersistent(order); - - return true; } /// From 48a8f6739d17608884fcb96a3b915b20819e3873 Mon Sep 17 00:00:00 2001 From: Jason Sylvestre Date: Tue, 4 Aug 2026 07:02:36 -0700 Subject: [PATCH 4/6] Update Aggie Enterprise related UI messages Remove the outdated Aggie Enterprise announcement from the homepage. Update the purchaser status message on the order review page to reflect the August 2026 timeline for editing uploaded orders within Aggie Enterprise. --- Purchasing.Mvc/Views/Home/Index.cshtml | 4 ++-- Purchasing.Mvc/Views/Order/_ReviewSubmit.cshtml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Purchasing.Mvc/Views/Home/Index.cshtml b/Purchasing.Mvc/Views/Home/Index.cshtml index bb5753894..a644c7f8b 100644 --- a/Purchasing.Mvc/Views/Home/Index.cshtml +++ b/Purchasing.Mvc/Views/Home/Index.cshtml @@ -185,7 +185,7 @@ -
    +@*

    Aggie Enterprise Announcement!

    @@ -197,7 +197,7 @@

    This FAQ has some updates and useful information.

    -
    +
    *@
    diff --git a/Purchasing.Mvc/Views/Order/_ReviewSubmit.cshtml b/Purchasing.Mvc/Views/Order/_ReviewSubmit.cshtml index d9469b8bb..a277390dd 100644 --- a/Purchasing.Mvc/Views/Order/_ReviewSubmit.cshtml +++ b/Purchasing.Mvc/Views/Order/_ReviewSubmit.cshtml @@ -26,7 +26,7 @@ if (Model.IsPurchaser) {
    - You may now complete orders in Aggie Enterprise! + August 2026: Aggie Enterprise now supports editing orders uploaded from PrePurchasing. Complete this as Aggie Enterprise to use this feature.
    } } From e3bf97e59dfb9f91f8d22f47fdee8d5168783057 Mon Sep 17 00:00:00 2001 From: Jason Sylvestre Date: Tue, 4 Aug 2026 07:32:32 -0700 Subject: [PATCH 5/6] fix KB button in help --- Purchasing.Mvc/Views/Help/Index.cshtml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Purchasing.Mvc/Views/Help/Index.cshtml b/Purchasing.Mvc/Views/Help/Index.cshtml index 33e2620c9..d700d7926 100644 --- a/Purchasing.Mvc/Views/Help/Index.cshtml +++ b/Purchasing.Mvc/Views/Help/Index.cshtml @@ -67,8 +67,8 @@
    - - Knowledge Base + + knowledge base
    From 572b3790d5cf9d03f96e1bb457df7cc2bfc6990b Mon Sep 17 00:00:00 2001 From: Jason Sylvestre Date: Tue, 4 Aug 2026 07:59:21 -0700 Subject: [PATCH 6/6] Refine help page content and styling Simplify help section descriptions and update styling for improved clarity and user experience. --- Purchasing.Mvc/Views/Help/Index.cshtml | 31 ++++++++------------------ 1 file changed, 9 insertions(+), 22 deletions(-) diff --git a/Purchasing.Mvc/Views/Help/Index.cshtml b/Purchasing.Mvc/Views/Help/Index.cshtml index d700d7926..8bb79b73e 100644 --- a/Purchasing.Mvc/Views/Help/Index.cshtml +++ b/Purchasing.Mvc/Views/Help/Index.cshtml @@ -22,12 +22,7 @@
    - -

    Help make PrePurchasing better with your ideas

    -
      -
    • See a suggestion you like? Vote for it!
    • -
    • Make your own suggestions
    • -
    +

    Share ideas and vote for improvements suggested by other users.

    @@ -39,9 +34,7 @@
    - -

    Need some help? Try submitting a ticket to our help desk.

    - +

    Submit a help ticket for technical problems or unexpected behavior.

    @@ -54,14 +47,7 @@
    - -

    Who should I contact?

    -
      -
    • What Workgroups do you belong to?
    • -
    • Who are the Departmental Admins for those workgroups?
    • -
    • Have a technical questions instead? Try the other help button.
    • -
    - +

    Find your workgroups and the departmental admins who support them.

    @@ -73,9 +59,7 @@
    - -

    Try our knowledge base.

    - +

    Browse guides and answers to common PrePurchasing questions.

    @@ -86,7 +70,10 @@ } \ No newline at end of file