Work Orders
The Work Orders module (CrestApps.OrchardCore.WorkOrders, with WorkOrders.Abstractions and WorkOrders.Core) keeps the jobs done for customers. A work order is made from a type, which gives it its duration, priority, checklists, lines, service level and billing; it then moves through its statuses until it is completed, invoiced and closed.
The admin screens are described in the User Manual: Work Orders.
Features
| Feature | Id | Depends on |
|---|---|---|
| Work Orders | CrestApps.OrchardCore.WorkOrders | — |
| Service Agreements | CrestApps.OrchardCore.WorkOrders.Agreements | Work Orders |
The module works with other features when they are on:
| Feature on | What it adds |
|---|---|
| Inventory | Lines can name a stock item; parts used come off a stock location, such as a van's, with IInventoryService.ConsumeAsync and the work order as the reference. Counted parts are used in whole units. |
| Transactions | Completing a billed work order makes an outstanding invoice (ReferenceType WorkOrder, source WorkOrders, due in 30 days) with an invoice number. |
| Geo | A new or changed service address gets the territory it is in, and is queued for geocoding (WorkOrderServiceAddress). |
| Assets | A work order can be for assets; the asset page links to the asset's work orders. |
| Workflows | The five work order events. |
| Skills | A type's required skills (with the lowest level) and certifications are edited on its page, for Dispatch. |
| Dispatch | Visits for each work order, shown in a panel on its page. |
Records
All live in the WorkOrders YesSql collection.
WorkOrderType:Name,Color,DefaultDurationMinutes,RequiredSkills,RequiredCertificationIds,CrewSize,RequiredEquipmentTypeIds,ChecklistTemplateIds,DefaultLines,ServiceLevelPolicyId,BillingMode(NotBillable,FixedPrice,TimeAndMaterials),Currency,FixedPrice,DefaultPriority,RequiresSignatureandRequiredPhotos.WorkOrder:Number(WO-000001and on, from theWorkOrders.WorkOrderseries of the shared lockedINumberSequence, which a site with earlier work orders starts after its highest number),TypeId,Priority(Low,Normal,High,Urgent),Status(New,Ready,Scheduled,InProgress,OnHold,Completed,Closed,Canceled),SubStatusId,Summary,Description, the customer (CustomerId,CompanyId,ContactId) andContact(name, phone, email),ServiceAddress(anAddress),AccessNotes,TerritoryId,AssetIds, the window (EarliestUtc,LatestUtc),Sla,RequiredSkills,EstimatedMinutes, preferred and excluded workers,Lines,Checklists(each a copy of its template's questions with the answers),Attachments,Signatures,Notes(the history),SourcewithSourceId,ParentWorkOrderId(follow-ups),InvoiceTransactionIdand when and by whom it was completed and closed.WorkOrderLine:Kind(Product,Service,Labor,Expense),ProductId,StockItemId,Description,QuantityEstimated,QuantityUsed,UnitPrice,LocationId(where the parts came from) andBillable.ChecklistTemplate:NameandQuestions:Section,Text,Kind(YesNo,PassFailNA,Text,Number,Choice,MultiChoice,Photo,Signature,MeterReading,Date),Required,Help,MinandMax,Unit,Choices,MinPhotos,MeterandShowWhen(shown only when an earlier answer is a value; the editor's Shown when column picks an earlier saved question and the answer, and refuses one that depends on itself or a later question).ServiceLevelPolicy:Targets(per priority, minutes to respond and to resolve),WeeklyHours(the days and hours the clock runs in) orHoursCalendarId(hours from anIServiceHoursProvider),TimeZoneId,PauseStatuses(on hold for a new policy) andWarningPercent(80).WorkOrderSubStatus:Name,ParentStatus,ColorandPausesSla.
Each settings record has its own index table (WorkOrderTypeIndex, ChecklistTemplateIndex, ServiceLevelPolicyIndex, WorkOrderSubStatusIndex). WorkOrderIndex keeps the number, type, status, whether it is open, priority, summary, customer, territory, due times, creation time and source; WorkOrderAssetIndex has a row per asset.
Behavior
WorkOrderService does everything to a work order, and the pages, API and tools go through it.
- Places. With Geo on, the editor places the job with a pin on the map; a pinned place is kept (
GeocodeSourcePin) and gives the territory, and an address without one is geocoded in the background. - New work orders.
NewAsync(typeId)makes a work order with the type's defaults and copies of its checklists.CreateAsyncgives it its number and due times, runs theIWorkOrderHandlers and starts the Created event.UpdateAsyncruns them again, so a changed address is placed again. - Statuses.
ChangeStatusAsyncallows only the usual moves (WorkOrderStatusRules): a closed or canceled work order doesn't move, a completed one can be closed or reopened, and canceling needs a reason. A sub-status must belong to the status. - Service levels.
SlaClockcounts a target in the policy's weekly hours in its time zone, in the hours anIServiceHoursProvidergives for its calendar, or around the clock. The Work Orders module registersOpenHoursServiceHoursProvider, which reads the shared Business Hours (IOpenHoursService); with the Contact Center Business Hours feature enabled,HoursCalendarIdnames a business hours calendar: the clock counts its open hours in the calendar's own time zone and skips its holidays, and a missing or disabled calendar counts around the clock. Opening and closing times that a daylight-saving change skips move forward by the gap. The clock stops in a pause status or a sub-status that pauses it, and the due times move out by the time stopped. Moving it to Ready, Scheduled or In progress is the first response.SlaMonitor, run every minute by a background task, starts the Service Level Warning event at the warning share of a target and the Service Level Breached event when it is missed, once each. - Parts.
UsePartAsyncrecords what was used on a line; for a counted part it takes the units off the chosen location through everyIWorkOrderPartsService, refusing more than the location has. - Checklists.
AnswerAsyncchecks an answer fits its question: yes or no, pass, fail or N/A, a number in range, one of the choices, or a date. - Completing.
CompleteAsyncrefuses a work order with a required question unanswered (one shown by its condition), without a signature its type requires, or with fewer photos than it needs. It then invoices the billable amount throughIWorkOrderBilling: the fixed price, or the billable lines at their used quantities (or planned ones for services not yet recorded), and starts the Completed event. - Follow-ups.
FollowUpAsyncmakes a new work order of the same type for the same customer, contact, place and assets.
Service agreements
The Service Agreements feature keeps recurring visits, such as preventive maintenance, for a customer over a period.
ServiceAgreement(in theWorkOrderscollection, indexed byServiceAgreementIndex):Number(SA-00001and on),Name,Status(Draft,Active,Expired,Canceled), the customer andContact,ServiceAddress,AccessNotes,AssetIds,StartDate,EndDate,TimeZoneId,Schedules,Pricing(IncludedorPerVisit) withPricePerVisit,ExpiringNoticeDays(30) andExpiringNotifiedUtc.AgreementSchedule:Name,TypeId,Rule(an RFC 5545 rule, expanded from the start date with the Calendars recurrence engine),LeadDays(14) andAssetIds(picked on the schedule's row; none means the agreement's assets).
ServiceAgreementScheduler runs every active agreement each hour (and from the agreement's page). For each schedule, it makes the work order of every visit day within the lead time that has none yet: the source is Agreement and the source id is the agreement, schedule and day, so each visit gets one work order however often it runs. The work order's window is the visit day in the agreement's time zone, across daylight saving changes; it copies the customer, place and assets, and its AgreedPrice (zero when included, the price per visit otherwise) replaces its type's billing. An agreement past its end date expires, and an active one within its notice of the end starts the Service Agreement Expiring event once (IServiceAgreementObserver). The ManageServiceAgreements permission covers the agreement pages.
Workflow events
| Event | Starts when | Input |
|---|---|---|
| Work Order Created | A work order is created. | |
| Work Order Status Changed | Its status or sub-status changes. | PreviousStatus |
| Work Order Service Level Warning | It is close to missing a target. | Target |
| Work Order Service Level Breached | It misses a target. | Target |
| Work Order Completed | It is completed. | |
| Service Agreement Expiring | An agreement comes within its notice of its end date. | AgreementId, Number, Name, EndDate |
Each can be limited to some work order types. Every event's input has WorkOrderId, Number, TypeId, Status, Priority, Summary, CustomerId and TerritoryId.
Bookings, dispositions and contacts
Work Orders links up with three other features when they are on.
-
Scheduling (
CrestApps.OrchardCore.Scheduling). A work order type lists, under Bookings, the appointment types whose bookings make work orders of it (WorkOrderType.AppointmentTypeIds). AnIAppointmentObserver(AppointmentWorkOrderObserver) acts on each confirmed booking of one of those types, after it is saved:- it makes a work order with the appointment type's name as its summary, the customer's name, phone and email as the contact, and the booking's notes as the description (source
Appointment, the booking's id), once per booking. The booked time is when the technician arrives: the window starts at the booking's start and ends at its end plus the job's length, so dispatch can fit the whole job; - rescheduling moves the work order's window the same way and adds a note;
- canceling cancels the work order, with the booking's reason.
The type editor lists the appointment types through
IWorkOrderLookup.AppointmentTypesAsync. With Dispatch on, those appointment types offer only the times a technician can take the job (see Dispatch). - it makes a work order with the appointment type's name as its summary, the customer's name, phone and email as the contact, and the booking's notes as the description (source
-
Omnichannel Management (
CrestApps.OrchardCore.Omnichannel.Managements). The Create Work Order subject action (CreateWorkOrder) makes a work order of the chosen type, and optionally priority, when its disposition is chosen. The work order has the activity's contact, the notes' first line as its summary, the whole notes as the description, and the number the activity reached as the contact phone. It is made once per activity (sourceActivity, the activity's id); Dispatch then gives it a visit. -
Contacts. A CRM contact's page (any content item with
OmnichannelContactPart) shows a Work orders card with the contact's latest ten work orders and a New work order menu of types. A work order started there keeps the contact (ContactIdand the contact's name). -
Customers, accounts and contacts in the editor. The company a work order or service agreement is for is an account of the Accounts module (
AccountId), the same record the CRM and Commerce B2B use, so everything kept on the account is there for field service too. With Assets on, the editors pick the customer (CustomerId, a user id: party kindUser, not a Customers record id), the account and, for work orders, the CRM contact (ContactId) by name, through the same party sources as the asset owners (IPartyDirectory, inWorkOrderCustomers); only the kinds with a source show. A work order with no account chosen takes the account of its contact (the account's list the contact is in) or, with Account Members on, the account its customer is a member of (IAccountMemberService): from the editor, the contact's New work order, or the Create Work Order subject action. With no service address typed, a work order or agreement takes the address of the account's first location (Account Locations,AccountLocationsPart). -
Accounts. With the Accounts feature on, an account's page (
DetailAdmin) shows Work orders (with New work order), Assets and, with Service Agreements on, Service agreements (with New agreement) in its Service tab (AccountPageTabs.Location(AccountPageTabs.Service, ...)), each started with the account chosen. Other agreements, such as billing, can be added the same way: a record with anAccountIdand a display driver forAccountPart. The account picker searches through the Accounts module (AccountsConstants.RouteNames.Search), which lists only the accounts the user may view; the customer and contact pickers searchAdmin/api/crestapps/work-orders/customers/search?kind=&query=(Manage work orders). A contact picked with no contact name typed gives the work order its name, and the work order's page shows the names, with a link to the contact.
Extending
IWorkOrderHandler: change a work order before it is created or saved.IWorkOrderObserver: hear about the events after they happen.IWorkOrderPartsServiceandIWorkOrderBilling: take parts off stock and invoice, in place of Inventory and Transactions.IServiceHoursProvider: give the open hours of a policy's calendar, and list the calendars you know (ListCalendarsAsync, returningServiceHoursCalendar(Id, Name)records) so the service level editor offers them in its Hours calendar picker. The picker appears when a provider lists a calendar; WorkOrders merges every provider's calendars throughServiceHoursCalendars.ListAsyncand never uses the provider's own types.WorkOrderPanels: a display driver for it adds a panel, placed in the Content zone, to the work order's page.DisplayDriver<WorkOrder>: adds a section to the work order editor (New work order and Edit), which is built withIDisplayManager<WorkOrder>. The built-in fields are one driver,WorkOrderFields_EditatContent:1. Register yours withservices.AddDisplayDriver<WorkOrder, TDriver>(), place it after (Content:5), bind your own view model with the driver'sPrefix, and report errors under it ($"{Prefix}.Field"): any error keeps the work order from being saved, and the editor cancels the session, so records your driver wrote while the editor was updated are not kept either.
Recipes and deployment
The WorkOrders recipe step creates or updates, by ItemId, checklists (Checklists), service levels (ServiceLevels), sub-statuses (SubStatuses), types (Types, which name their checklists and service level by id) and, with Service Agreements on, agreements (Agreements). The Work order settings deployment step exports them, the agreements only when asked, since their customers, places and assets must be on the other site too. Work orders themselves aren't exported: they carry numbers and service level clocks of the site they belong to.
Permissions
| Permission | Allows |
|---|---|
ManageWorkOrderSettings (Manage work order settings) | Types, checklists, service levels and sub-statuses. |
ManageWorkOrders (Manage work orders) | Creating and working work orders. |
ViewWorkOrders (View work orders) | The work order list and pages. Implied by Manage work orders. |