Projects Service
Overview
The Projects Service handles purchase order (PO) creation and tracking for active construction projects. It supports six PO types with vendor-specific workflows and approval chains.
Base URL
- Development
- Production
http://localhost:5002/api
https://projects.precisionsiteservices.com/api
Authentication
Cookie: sAccessToken=...; sRefreshToken=...
Purchase Order Types
Concrete
Mix design, cubic yards, delivery schedule
Material
General materials and supplies
Rental
Equipment rentals with duration
Subcontract
External services and labor
Pump
Concrete pumping services
Miscellaneous
General costs and fees
PO Workflow
Base Operations
List Purchase Orders
- Request
- Response
GET /api/purchase-orders
Cookie: sAccessToken=...; sRefreshToken=...
[
{
"id": "uuid",
"poNumber": "PO-2025-001",
"projectId": "uuid",
"type": "CONCRETE",
"status": "WITH_RECEIPT",
"scopeId": "uuid",
"vendorId": "uuid",
"createdBy": "user@example.com",
"createdAt": "2025-11-12T10:00:00.000Z",
"project": {
"jobNumber": "J-2025-001",
"jobName": "Shopping Center Foundation"
},
"vendor": {
"name": "ABC Concrete Supply"
}
},
...
]
Roles: OPS, PM, ACCOUNTING, ADMIN
Query Parameters:
projectId- Filter by projectstatus- Filter by statustype- Filter by PO typevendorId- Filter by vendor
Get Purchase Order
- Request
- Response
GET /api/purchase-orders/:id
Cookie: sAccessToken=...; sRefreshToken=...
{
"id": "uuid",
"poNumber": "PO-2025-001",
"type": "CONCRETE",
"status": "WITH_RECEIPT",
"receiptUrl": "https://storage.googleapis.com/...",
"concreteData": {
"concreteType": "3000 PSI",
"mixIds": "MIX-001",
"cubicYards": 45.5,
"slumpSize": 4,
"spacing": "Continuous",
"desiredDelivery": "2025-11-20T08:00:00.000Z",
"notes": "Foundation pour"
}
}
Roles: OPS, PM, ACCOUNTING, ADMIN
Update Purchase Order
- Request
- Response
PUT /api/purchase-orders/:id
Cookie: sAccessToken=...; sRefreshToken=...
Content-Type: application/json
{
"scopeId": "new-uuid",
"notes": "Updated notes"
}
{
"id": "uuid",
"message": "Purchase order updated successfully"
}
Roles: OPS, ADMIN
Delete Purchase Order
- Request
- Response
DELETE /api/purchase-orders/:id
Cookie: sAccessToken=...; sRefreshToken=...
{
"message": "Purchase order deleted successfully"
}
Roles: OPS, ADMIN
Only POs with status PENDING_RECEIPT can be deleted.
PO Type Endpoints
Concrete PO
- Create
- Update
POST /api/purchase-orders/concrete
Cookie: sAccessToken=...; sRefreshToken=...
Content-Type: application/json
{
"projectId": "uuid",
"vendorId": "uuid",
"scopeId": "uuid",
"concreteType": "3000 PSI",
"mixIds": "MIX-001",
"cubicYards": 45.5,
"slumpSize": 4,
"spacing": "Continuous",
"desiredDelivery": "2025-11-20T08:00:00Z",
"notes": "Foundation pour"
}
PUT /api/purchase-orders/concrete/:id
Cookie: sAccessToken=...; sRefreshToken=...
Content-Type: application/json
{
"cubicYards": 50.0,
"notes": "Updated quantity"
}
Required Fields:
concreteType,mixIds,cubicYards,slumpSize,spacing,desiredDelivery
Vendor Type: CONCRETE
Material PO
- Create
POST /api/purchase-orders/material
Cookie: sAccessToken=...; sRefreshToken=...
Content-Type: application/json
{
"projectId": "uuid",
"vendorId": "uuid",
"scopeId": "uuid",
"desiredDelivery": "2025-11-20T08:00:00Z",
"notes": "Lumber delivery"
}
Required Fields:
desiredDelivery
Vendor Type: MATERIAL
Rental PO
- Create
POST /api/purchase-orders/rental
Cookie: sAccessToken=...; sRefreshToken=...
Content-Type: application/json
{
"projectId": "uuid",
"vendorId": "uuid",
"scopeId": "uuid",
"equipmentType": "Skid Steer - Daily",
"duration": 5,
"desiredDelivery": "2025-11-20T08:00:00Z",
"notes": "Site work"
}
Required Fields:
equipmentType,duration,desiredDelivery
Vendor Type: EQUIPMENT
Subcontract PO
- Create
POST /api/purchase-orders/subcontract
Cookie: sAccessToken=...; sRefreshToken=...
Content-Type: application/json
{
"projectId": "uuid",
"vendorId": "uuid",
"scopeId": "uuid",
"subType": "Pier Drilling",
"quantity": 100,
"uom": "LF",
"desiredDelivery": "2025-11-20T08:00:00Z",
"notes": "Drilled piers"
}
Required Fields:
subType,quantity,uom,desiredDelivery
Vendor Type: SUBCONTRACTOR
Units: EA, LF, SF, CY, HR, DAY, etc.
Pump PO
- Create
POST /api/purchase-orders/pump
Cookie: sAccessToken=...; sRefreshToken=...
Content-Type: application/json
{
"projectId": "uuid",
"vendorId": "uuid",
"scopeId": "uuid",
"pumpType": "Alamo City - 32 Meter",
"desiredDelivery": "2025-11-20T08:00:00Z",
"notes": "Foundation pour"
}
Required Fields:
pumpType,desiredDelivery
Vendor Type: PUMP
Miscellaneous PO
- Create
POST /api/purchase-orders/misc
Cookie: sAccessToken=...; sRefreshToken=...
Content-Type: application/json
{
"projectId": "uuid",
"vendorId": "uuid",
"specifyScope": "Foundation, Grade Beam",
"notes": "General project costs"
}
Optional Fields:
specifyScope- Multi-select from project scopesnotes
Vendor Type: MISC
Receipt Management
Upload Receipt
- Request
- Response
POST /api/purchase-orders/:id/receipt
Cookie: sAccessToken=...; sRefreshToken=...
Content-Type: multipart/form-data
[Upload image file]
{
"receiptUrl": "https://storage.googleapis.com/...",
"message": "Receipt uploaded successfully"
}
Roles: OPS, ADMIN
Requirements:
- Max size: 10MB
- Formats: JPEG, PNG
- Storage: Google Cloud Storage
Updates status from PENDING_RECEIPT to WITH_RECEIPT.
Get Receipt
- Request
- Response
GET /api/purchase-orders/:id/receipt
Cookie: sAccessToken=...; sRefreshToken=...
{
"receiptUrl": "https://storage.googleapis.com/..."
}
Roles: OPS, PM, ACCOUNTING, ADMIN
Delete Receipt
- Request
- Response
DELETE /api/purchase-orders/:id/receipt
Cookie: sAccessToken=...; sRefreshToken=...
{
"message": "Receipt deleted successfully"
}
Roles: OPS, ADMIN
Updates status back to PENDING_RECEIPT.
Bids Integration
Get Equipment Types
- Request
- Response
GET /api/purchase-orders/integration/equipment-types
Cookie: sAccessToken=...; sRefreshToken=...
[
"Skid Steer - Daily",
"Skid Steer - Weekly",
"Concrete Mixer - Daily",
...
]
Cached: 1 hour
Get Subcontractor Types
- Request
- Response
GET /api/purchase-orders/integration/subcontractor-types
Cookie: sAccessToken=...; sRefreshToken=...
[
"Pier Drilling",
"Sub Labor",
"Crane Rental",
"Surveying",
"Pumping",
"Rodbusting",
...
]
Cached: 1 hour
Get Pump Catalog
- Request
- Response
GET /api/purchase-orders/integration/pump-catalog
Cookie: sAccessToken=...; sRefreshToken=...
[
{
"vendor": "Alamo City Concrete Pumping",
"pumps": [
{
"name": "32 Meter",
"volumeRate": 8.5,
"hourRate": 225,
"travelFee": 225,
"minimumHours": 4,
"reach": 32
},
...
]
},
...
]
Cached: 1 hour
Status Transitions
| Current Status | Allowed Actions | Next Status |
|---|---|---|
| PENDING_RECEIPT | Upload receipt, Update, Delete | WITH_RECEIPT |
| WITH_RECEIPT | PM assign cost codes | ALLOCATED |
| WITH_RECEIPT | PM reject | REJECTED_BY_PM |
| ALLOCATED | Accounting approve | COMPLETE |
| ALLOCATED | Accounting reject | REJECTED_BY_ACCT |
| REJECTED_BY_PM | OPS fix and re-upload | WITH_RECEIPT |
| REJECTED_BY_ACCT | PM review and fix | ALLOCATED |
Vendor Type Validation
Each PO type requires specific vendor types:
| PO Type | Required Vendor Type |
|---|---|
| CONCRETE | CONCRETE |
| MATERIAL | MATERIAL |
| RENTAL | EQUIPMENT |
| SUBCONTRACT | SUBCONTRACTOR |
| PUMP | PUMP |
| MISC | MISC |
Creating a PO with wrong vendor type returns error: "Selected vendor is not a [type] supplier"
Role-Based Access
| Role | Permissions |
|---|---|
| OPS | Create, update, upload receipts |
| PM | Approve/reject, assign cost codes |
| ACCOUNTING | Reconcile, approve/reject |
| ADMIN | Full access |