Commit graph

104 commits

Author SHA1 Message Date
Adam Moussa
06bde26aff Wire FollowUp controller for real CRUD
Adds GetById and Delete; switches list filter from completed=bool to
status=string; expands list payload with FK ids, ScheduleStartTime, and
joined CreatedByName so the frontend edit form can prefill and the list
can show who created each item. Requires auth and stamps createdby from
the logged-in user on Create.
2026-04-20 13:49:45 -04:00
Adam Moussa
899ee7b83d Add NTE uplift workflow and vendor PO detail API
Introduces DispatchUpliftRequest entity and tier-gated approval flow:
vendors request a new NTE from the portal, dispatchers approve or deny
in SHOC, and requests above a configurable threshold require a higher
role. Adds DispatchController for PO-centric list/detail used by the
new Vendor POs page. Seeds Dispatcher and Manager roles.
2026-04-20 13:25:56 -04:00
Adam Moussa
b36ccd2758 Merge feature/vendor-portal into dev 2026-04-20 12:45:04 -04:00
Adam Moussa
73be673444 Add vendor portal with token-based authentication
- VendorAccessToken model + unique-index migration; TokenLifetimeDays config
- VendorPortalTokenService: CSPRNG token generation, rotation, revocation
- VendorPortalController: public portal API guarded by X-Vendor-Token header;
  dispatches list/detail, accept, vendor status transitions, cancel request,
  checklist updates, signoffs (vendor + customer), comments with dispatcher
  attribution via AspNetUsers join
- VendorController: portal-token admin endpoints (get / rotate / revoke)
- WorkOrderController: dispatch email now uses vendor portal URL and HTML-encodes
  user fields; AddDispatchComment now stores CommentType='dispatcher' with the
  SHOC user's name so portal can attribute the author
- DispatchPublicController: deprecated per-dispatch GET accept flow returns a
  static 'link no longer active' page (no state mutation)
2026-04-20 12:01:53 -04:00
Adam Moussa
6e0f891ca3 Update TODO with completed items and vendor portal next steps 2026-04-17 16:33:17 -04:00
Adam Moussa
3355df111f Add locationId filter to GetWorkOrderList
- Accept locationId query parameter for server-side location filtering
- Used by dispatch modal to find all WOs at the same site
2026-04-17 16:13:18 -04:00
Adam Moussa
575e8ab6fc Add dispatcher verification as final dispatch gate
- VerifiedBy and VerifiedAt fields on Dispatch model
- VerifyDispatch endpoint validates all checklist items complete + both signoffs present
- Returns missing items list if validation fails
- Sets status to Verified, logs to audit trail
- GetDispatchById includes verifiedBy and verifiedAt
- Migration for new fields
2026-04-17 16:03:34 -04:00
Adam Moussa
81472bf729 Add dispatch sign-offs with signature capture
- DispatchSignoff model (DispatchId, SignoffType, Name, Signature base64, SignatureMethod, SignedAt)
- AddDispatchSignoff endpoint — one per type per dispatch, validates no duplicate
- GetDispatchById includes signoffs in response
- Migration for DispatchSignoffs table
2026-04-17 15:51:20 -04:00
Adam Moussa
c482fa0558 Add vendor accept via email link
- DispatchPublicController with public GET /api/dispatch/accept/{token}
- Updates dispatch status to Acknowledged with timestamp
- Returns styled HTML confirmation page
- Dispatch email now includes green Accept Dispatch button
- Logs vendor acceptance to audit trail
2026-04-17 15:39:50 -04:00
Adam Moussa
3a25fa8559 Add dispatch checklist items with template support
- DispatchChecklistItem model (DispatchId, WorkOrderId, ItemText, IsCompleted, CompletedBy, CompletedAt)
- DispatchToVendor copies template items when TaskListTemplateId provided
- Supports custom checklist items alongside template items
- UpdateChecklistItem endpoint to toggle completion with user name
- AddChecklistItem endpoint for ad-hoc items
- GetDispatchById includes checklist items in response
- Migration for DispatchChecklistItems table
2026-04-17 15:28:52 -04:00
Adam Moussa
be190836a4 Add multi-WO dispatch support with junction table
- DispatchWorkOrder junction table for 1:N dispatch-to-WO relationship
- Make Dispatch.WorkOrderId nullable (backward compat)
- Add AcceptToken and AcknowledgedAt to Dispatch model
- Dispatch_DTO accepts WorkOrderIds array
- DispatchToVendor creates junction rows, email lists all WOs in table
- GetDispatches queries both junction table and direct FK
- GetDispatchById includes workOrders list from junction table
- Migration with DispatchWorkOrder table
2026-04-17 15:16:28 -04:00
Adam Moussa
1f4bd12cd7 Add Task List Templates with CRUD controller
- TaskListTemplate and TaskListTemplateItem models
- TaskListTemplateController: list, get by ID, create with items, update (replace items), soft delete
- Migration for new tables
2026-04-17 14:57:18 -04:00
Adam Moussa
63f76e9b2c Add dispatch detail modal backend + vendor reply sync
- Add DispatchNumber and CompletedDate to Dispatch model
- Add DispatchId to Comments for per-dispatch vendor threads
- GetDispatchById endpoint with vendor communication thread
- UpdateDispatch endpoint for status, NTE, dates, description
- AddDispatchComment endpoint — saves comment + sends email to vendor with sender name
- BackfillDispatchNumbers endpoint for existing dispatches
- SyncVendorReplies endpoint — pulls from DynamoDB VendorReplies table
- Fix reply-to address to include dispatch number
- Include sender name in dispatch and comment emails
2026-04-17 14:01:03 -04:00
Adam Moussa
17590daf9d Add project TODO tracking deferred work items
- Dispatch detail modal, Front API integration, vendor communication
- Missing pages (profile, settings, calendar)
- Dashboard analytics, PO enhancements, deployment migration
2026-04-17 13:08:12 -04:00
Adam Moussa
f89db3da52 Add server-side status and assignee filters to GetWorkOrderList
- Accept status and assignee query parameters
- Filter in SQL before counting and paginating
- Supports __unassigned for unassigned work orders
- Accurate totalCount reflects filtered results
2026-04-17 12:57:37 -04:00
Adam Moussa
7d764f966d Add server-side sorting to GetWorkOrderList
- Accept sortBy and sortDir query parameters
- Supports sorting by: number, title, location, priority, status,
  createdDate, assignedTo, lastUpdated
- Default sort: lastUpdated desc
- Sort applied in SQL before pagination
2026-04-17 12:50:23 -04:00
Adam Moussa
091390fcad Calculate lastUpdated from comments, audit log, and modification time
- Takes the max of: LastModificationTime, latest comment CreatedDate,
  latest audit log CreatedAt
- Reflects any comment (customer/vendor/internal) or status change
2026-04-17 12:35:14 -04:00
Adam Moussa
0a564499f5 Add lastUpdated field to work order list response 2026-04-17 12:33:30 -04:00
Adam Moussa
7ef7205681 Include InternalWONumber in work order list search
- Search now matches against internal WO number, customer WO number,
  title, and location name/title
2026-04-17 12:31:00 -04:00
Adam Moussa
b072d1fa2d Extract zip code from location address as fallback for distance calc
- Regex extracts 5-digit zip from address string when ZipCode field is empty
- Enables distance calculation for synced locations without structured zip data
2026-04-17 11:59:34 -04:00
Adam Moussa
521bb0fba2 Add zip-to-zip distance calculation for vendor dispatch
- ZipCodeDistance helper with Haversine formula on 33K US zip code centroids
- Loaded as singleton from wwwroot/zipcodes.csv on startup
- Vendor Dropdown endpoint accepts siteZip, returns address and distanceMiles
- Vendors sorted by distance when siteZip provided
- Include locationZip in GetWorkorderById response
2026-04-17 11:56:06 -04:00
Adam Moussa
ee69a1863a Add vendor scheduled date to dispatch workflow
- Add ScheduledDate field to Dispatch model and DTO
- Save scheduled date when dispatching to vendor
- Include ScheduledDate in dispatch response projections
2026-04-17 11:47:00 -04:00
Adam Moussa
d24c4643f5 Add vendor dispatch workflow backend
- Create Vendor model with company info, trade specialties, active flag
- Create Dispatch model (doubles as Vendor PO) with PO number, NTE, status, reply-to address
- VendorController: CRUD, paginated list, dropdown endpoint with trade filtering
- DispatchToVendor endpoint: multi-vendor dispatch, auto-generated PO numbers (VPO-00001),
  HTML email with full WO details via SendGrid, reply-to wo-{number}@int.seahaven.com
- GetDispatches endpoint for listing dispatches by WO
- Include dispatches in GetWorkorderById response
- SendMessage.SendDispatchEmail with reply-to support
- Audit log entry for each dispatch
2026-04-17 11:37:35 -04:00
Adam Moussa
05b36ef7dd Add configurable dropdowns, new WO fields, and seed data
- Create DropdownOption model with Category, Value, ParentValue for Trade/SubTrade/Problem
- Add DropdownOptionsController with CRUD + ByCategory endpoint with parent filtering
- Add Problem, Trade, SubTrade, VendorNTE, ScheduledDate, CompletedDate, Source to WorkOrder
- Update EditWorkorder_DTO and GetWorkorderById with new fields
- Audit log tracks changes to all new fields
- Seed default Trades (10), SubTrades (20), and Problems (11) on startup
2026-04-17 10:40:38 -04:00
Adam Moussa
78c7850fb2 Add DashboardController with Stats endpoint
- Returns total, open, notDispatched, completed work order counts
2026-04-16 19:25:42 -04:00
Adam Moussa
8959efc06b Add ChangeAssignment endpoint with audit logging
- POST /api/WorkOrder/ChangeAssignment?id=&assignTo=
- Logs old and new user names in audit trail
- Returns updated assignment name
2026-04-16 19:04:59 -04:00
Adam Moussa
d07e24e419 Add InternalWONumber field with auto-generation
- Add InternalWONumber to WorkOrder model
- Auto-generate 8-digit sequential numbers starting at 10000001
- Generate on new work order creation and DynamoDB sync
- Include in GetWorkorderById and GetWorkOrderList responses
- Add BackfillInternalWONumbers endpoint for existing records
- Add migration for new column
2026-04-16 18:42:58 -04:00
Adam Moussa
be70c84add Make Comments_DTO fields nullable for JSON endpoint compatibility
- Text, UserId, CreatedDate are set server-side, not required from client
2026-04-16 18:24:04 -04:00
Adam Moussa
18ca737307 Add JSON-based AddCommentJson endpoint
- Accepts JSON body instead of FormData for simple text comments
- Returns new comment with user name for immediate UI update
- Defaults to internal comment type
2026-04-16 18:22:34 -04:00
Adam Moussa
e1f57d3fb2 Add comment types, audit logging, and WorkOrderAuditLog table
- Add CommentType field to Comments (customer, vendor, internal)
- Add Status field to EditWorkorder_DTO
- Create WorkOrderAuditLog model tracking field-level changes
- Log all field changes on work order edit and status change
- Include commentType and auditLog in GetWorkorderById response
- Set CommentType=customer on synced comments from DynamoDB
- Add BackfillCommentTypes endpoint for existing data
2026-04-16 18:09:57 -04:00
Adam Moussa
c69cef7fa9 Add HttpPut route to EditWorkorder endpoint
- services/api.js sends PUT for updates, controller only accepted POST
- Add [HttpPut("{id:int}")] alongside existing [HttpPost]
2026-04-16 17:44:00 -04:00
Adam Moussa
cc87039a77 Include commenter and recordType in GetWorkorderById comments response 2026-04-16 17:41:11 -04:00
Adam Moussa
5a4d8e2240 Add description, createdDate, locationId to GetWorkorderById response 2026-04-16 17:37:21 -04:00
Adam Moussa
60fc933da7 Add lowercase route aliases for all controllers
- services/api.js uses lowercase routes (/api/workorders, /api/employees, etc.)
- Add matching [Route] attributes to WorkOrder, Employee, Contact, Account, FollowUp, PMSchedule controllers
- Add [HttpGet("{id:int}")] to WorkOrderController for REST-style get by ID
2026-04-16 17:32:28 -04:00
Adam Moussa
6f8f67735a Add DynamoDB sync bridge for workorder-ingest pipeline
- Add ExternalWorkOrderId, Customer, SiteCode, Building, Severity,
  DateReported, ScheduledStart, SourceEmailS3Key to WorkOrder model
- Add Commenter, RecordType, ExternalCommentId to Comments model
- Add AWSSDK.DynamoDBv2 package
- Create SyncController with endpoints:
  - POST /api/Sync/WorkOrders — scans DynamoDB WorkOrders table, upserts into SQL
  - POST /api/Sync/Comments — scans DynamoDB WorkOrderComments, creates Comments
  - POST /api/Sync/All — runs both
- Auto-creates Locations from site_code/building/address during sync
- Maps DynamoDB status values to SHOC status strings
- Maps severity to SHOC priority format (Sev N)
- Deduplicates on ExternalWorkOrderId / ExternalCommentId
2026-04-16 17:29:52 -04:00
Adam Moussa
93fa76a5aa Handle string-to-int AccountId conversion in Location DTOs
- Frontend sends accountId as empty string when not set
- Change DTO AccountId to string with GetAccountId() parser
- Prevents JSON deserialization error on empty/non-numeric values
2026-04-16 17:15:28 -04:00
Adam Moussa
5a20e55138 Add lowercase route alias for LocationController
- services/api.js uses /api/locations (lowercase), controller was only matching /api/Location
- Add [Route("api/locations")] to support both casings
2026-04-16 17:11:36 -04:00
Adam Moussa
534f97d6f1 Add LocationController with full CRUD and extended model
- Extend Locations model with Address, City, State, ZipCode, Phone, Contact, ContactEmail, Status, AccountId
- Update Location DTOs to match new fields
- Create LocationController with paged list, get by ID, create, update, delete
- Support both REST-style routes (/api/Location/{id}) and legacy query routes (/api/Location/DeleteLocation?id=)
- Add migration for new Location columns
2026-04-16 17:09:59 -04:00
Adam Moussa
51b52a7fb5 Add migration to sync Contacts table with model
- Generate SyncContactsAndModels migration for missing columns
- Adds AccountId, Address fields, social URLs, LocationId to Contacts table
2026-04-16 16:54:36 -04:00
Adam Moussa
dbb31ca7d7 Fix Contacts.Name references throughout Blazor project
- Replace all Contacts.Name with (FirstName + " " + LastName) pattern
- Fix ContactService, Index.razor, QuotesPDF, QuotesDetails, CreateQuotes
- Fix WorkOrderPDF, Viewworkorder, UserViewWordOrder, Addworkorders
- Fix ViewTemplate, AddTemplate, Templates settings pages
- Blazor project now builds successfully
2026-04-16 16:54:28 -04:00
Adam Moussa
493cff00fb Fix pagination to use database-side Skip/Take instead of loading all rows
- Move .ToList() after .Skip().Take() in ContactController, QuotesController, SettingsController
- Prevents loading entire tables into memory for paginated queries
2026-04-16 16:54:18 -04:00
Adam Moussa
483b765d69 Remove sample WeatherForecastController 2026-04-16 16:54:10 -04:00
Adam Moussa
e8c400a20a Add null safety checks across all API controllers
- Add null checks after FirstOrDefault() before property access
- Guard navigation property access (Locations, AssignToUser, ApplicationUser, POC, Contacts)
- Null-coalesce string properties in search/filter LINQ queries
- Protect Sum() on nullable LineItems collections
- Change FirstAsync to FirstOrDefaultAsync with null guard in UserController
- Add null check on model.Attachments iteration in EditWorkorder
2026-04-16 16:33:42 -04:00
Adam Moussa
128ae44a0d Fix login null check order and strengthen password reset code
- Reorder null check: check user != null before accessing user.IsDeleted
- Increase password reset code from 4 digits to 6 digits (10K to 1M combinations)
2026-04-16 16:33:09 -04:00
Adam Moussa
486233076c Replace hardcoded SMTP credentials with SendGrid service
- Remove inline SMTP method with codevoir.com credentials
- Inject existing SendMessage helper that uses SendGrid via config
- Clean up unused using directives
2026-04-16 16:25:11 -04:00
Adam Moussa
0e3cb761c9 Configure local development environment
- Generalize appsettings.json by removing hardcoded credentials
- Add local connection string and JWT config to appsettings.Development.json
- Add EF Core Design package for running migrations locally
- Seed admin user on startup in development
- Skip HTTPS redirect in development for proxy compatibility
- Gitignore appsettings.Development.json
2026-04-16 16:25:03 -04:00
npalOmega
a9fc4b8701 fix 2026-03-30 06:49:40 -05:00
npalOmega
cd78c93fa8 fix 2026-01-21 16:24:54 -06:00
npalOmega
9c78cd96fa added new controllers 2026-01-21 15:41:19 -06:00
npalOmega
2e9716fe34 fix 2025-03-09 19:39:28 -05:00