Skip to content

Contracts — from Quote to Closed

A Contract is the legal sales document — and the trigger for nearly every downstream workflow in SMART. A change to its ContractStatusID is never just a status update: a single proc call cascades into the Lot, the Contact, the ChosenOption rows, the Schedule, the Estimate, the Purchase Orders, the Commissions, the Transmissions queue, and the audit logs.

This page starts with the lifecycle and how the four spProcessContract* procs cascade — the deep field-by-field details for each transition are one click away.

At a glance

  • Every Contract belongs to exactly one Lot. The contract’s ContractStatusID drives the Lot’s status, the Schedule, the Estimate, POs, Commissions, and what gets sent to Business Central.
  • Four core operations: Accept (qte → acc), Ratify (acc → rat), Close (rat → clo), Cancel (any → can). Each is implemented by spProcessContract<Op> and has a “reverse” path used by CSR scripts.
  • Ratify is the big one — it locks the plan to the lot, sets ProcessEstimate=1, queues the schedule build, queues PO generation, and pushes deposits + closing dollars to the Business Central transmission tables.
  • A buyer cancellation on a built spec auto-creates a new inventory contract at rat so the lot doesn’t sit empty.
  • Every transition writes 3-character ProcessCodeID rows (S01, S02, F01, F11, C12, …) into ContractTransLog, LotTransLog, and ContactTransLog — the full audit trail of any contract.

94,485 contracts on Test (2026-06-02) · 45,884 deposits · 12,255 co-buyers · 79 columns on dbo.Contract.

A new Contract row is inserted from one of three places:

WhereWhen
SMART → Sales → Contract Management → NewThe standard sales path. A salesperson takes a Contact, a Lot, a Plan, and a price book and creates a row at qte.
SMART 1.0 (or thesmartbuilder.net) → Inventory releaseAn “inventory” contract has no ContactSysID — it’s the company’s spec home, started before a buyer is found.
Auto‑generated by spProcessContractCancelWhen a buyer cancels a previously‑ratified home, SMART automatically inserts a new inventory contract at rat so the lot doesn’t sit empty.

A Contract row is uniquely identified by ContractSysID (identity int) and always references one Lot via the composite key (ProjectID, BuildingID, UnitID). There can be multiple historical contracts on the same lot — but only one is “live” at any point.

1qteQuoted
Sales priced a Plan + Lot for the buyer. Nothing locked.
2lrLot Reserved
Buyer placed a small reservation deposit; the lot is held off the market.
3lcLot Reservation Cleared
Reservation expired or canceled. Lot returns to “For Sale”.
4accAccepted
Buyer signed. Earnest money posted. Lot moves to m Accepted (or stays in inventory flow).
5ratRatified
Build is authorized. Lot becomes f Sold (or i if contingent); Plan is locked onto the Lot; Estimate runs; Schedule is generated; POs are queued.
6sivSold Inventory
An inventory contract auto‑demoted from rat when a buyer’s contract takes over a spec already under construction.
7cloClosed
Closing happened. Lot locks at c. Buyer becomes a Homeowner. Bills can post; warranty starts.
8canCancelled
Sale fell through. Deposits and lot are unwound; if it was a built spec, an inventory contract takes its place.

See Contract Statuses for the literal lookup table.

The Contract table has 79 columns on Test. Day-to-day you only touch a handful — ContractStatusID, RatifiedDate, EstimatedClosedDate, PlansID, AssignedID. The rest exist to support specific workflows (loan tracking, closing logistics, commissions).

All 79 Contract columns, grouped by purpose
GroupFields
IdentityContractSysID, ContractStatusID, ProjectID + BuildingID + UnitID, ContactSysID
Plan & pricePlansID, PlanName, PlanPrice, Address
Buyer agentsAssignedID (sales rep), BuyerAgentID, BuyerAgentBrokerID, ListingBrokerID, OriginalContactSalesAgent, OriginalContractSalesAgent
Lifecycle datesAcceptedDate, RatifiedDate, CancelledDate, ClosedDate, EstimatedClosedDate, ScheduledClosing, RescissionDate, SchCompleteSaleDate
Lot reservationLotReserved, LotReservationExpDate, LotReservationRatifyDate
Loan / financingLoanPackageID, LoanTypeID, LoanNum, LenderID, FinanceLoanAmount, LoanAppliedDate, LoanApprovedDate, LockDate, LockExpiresDate, LockRate, MaximumInterestRate, ConditionalLoanApproval, FwdCommitID
Closing costsClosingCostAmt, ClosingCostPct, ClosingCostPaidBy, LenderPaidClosingCostAmt, FinanceCostAmt, FinanceCostPct, ConstrInterestAmt
CommissionsIntComAmt, IntComPct (internal sales rep), ExtComAmt, ExtComPct (external buyer’s agent)
Closing logisticsKeysInOffice, KeysOutOfOffice, KeysReceived, KeysSent, KeyID, MailboxNum, FinalSurveyReceived
Validation / postingAcceptValidationPassed, Printed, PrintedDate, RatifiedAssignedID, ClosedAssignedID
Cancel handlingRescissionReasonID, CancelledPreviousSoldDate

The four spProcess* procs each open a row in the Process table (visible in SMART → Administration → Process Monitor) and run inside a transaction. Every step writes audit rows into ContractTransLog and LotTransLog keyed by a 3‑character ProcessCodeID (full table: dbo.ProcessCode).

This is where most of the system’s behavior lives. Each transition has a high-level summary you’ll find here, with the full pre-checks, table changes, and reverse paths in the collapsibles below.

Driven by dbo.spProcessContractAccept. Triggered by Sales → Contract → Accept in SMART, and also by Inventory home releases. Validates that the lot is available and the options are still active, then moves chosen options from ContractOption onto the Lot’s ChosenOption rows, snapshots the price book, and flips the Contact from Prospect to Buyer.

Accept: full pre-checks, table cascade, and reverse path

Pre‑checks (sub‑procs, all must pass — see spProcessContractAccept_*):

  • _VerifyLotAvailable — the Lot is s For Sale or z Not Available
  • _LotNotInProcess — no other process holds the Lot
  • _LotReserved — the lot reservation, if any, belongs to this contract
  • _NoOtherAcceptedContracts — no other accepted/ratified contract on the same lot
  • _NoSalesAgentCommission — sales rep has commission setup
  • _OptionsNotDiscontinued — every chosen option is still active
  • _PriceBookDetailRecordExists (+2) — every chosen option has a price in the active price book
  • _VerifyBuyerAgentsCompany — buyer’s agent and broker are on the same company
  • _VerifyLimitPlan — the lot’s LimitPlanType allows this plan
  • _VerifyPurchaseOrder — there’s no PO blocker

What changes when it succeeds:

TableChange
ContractContractStatusID = 'acc', AcceptedDate = <user date>
ChosenOptionAll ContractOption rows are moved/inserted here. AcceptedQuantity = ContractOption.Quantity, SalesPrice = PriceBookDetail.SalesPrice (refreshed).
ContractOptionAll rows for this contract are deleted (the options now live on the lot).
ContractPriceAdjRows with Accepted=0, Ratified=0 are flipped to Accepted=1.
LotSale (has Contact): Status = 'm' Accepted. Inventory (no Contact): complex — see table below.
ContactContactStatusID = 'b' Buyer (was Prospect). ContactRank cleared and the previous rank is logged.
ContractLog / LotTransLogS01 (sale) or F06 (inventory). ContactTransLog C12 (status change) and C13 (rank reset).

Lot status table for inventory accept (@ContactSysID IS NULL):

Lot wasAvailabilityTypeBecomes
z Not Availablem Modelv Model Home
z Not Availabler R&Dw R&D Home
s For Salep Production Inventory
z Not Availableotherp Production Inventory

Reverse path (spProcessContractAccept called on an acc contract → qte):

  • Contract: ContractStatusID='qte', AcceptedDate=NULL
  • ChosenOption rows are unwound back into ContractOption
  • Lot: buyer → s (or p if a plan was already locked); inventory → v→z, w→z, p→s
  • Contact: ContactStatusID = 'p' (back to Prospect)
  • ContractPriceAdj: Accepted=0
  • Logs: S06 (sale) or F07 (inventory)

Driven by dbo.spProcessContractRatify. Triggered by Sales → Contract → Ratify — the single most consequential operation in the system. It locks the Plan onto the Lot, sets ProcessEstimate=1 so the next batch builds the schedule and POs, queues deposits and ratify lines into Transmission* tables for Business Central, and (if the buyer is on a previously-inventory home) demotes the original inventory contract to siv.

Ratify: full pre-checks, Lot field updates, and side effects on sister contracts

Pre‑checks:

  • _VerifyContractAccepted — must be currently acc
  • _VerifyPurchaseOrder — no blocker POs
  • All open ContractContingency rows must have ResolvedDate IS NOT NULL or the lot will be marked i Sold-Contingent instead of f Sold

What changes when it succeeds:

TableChange
ContractContractStatusID='rat', RatifiedDate, RatifiedAssignedID = AssignedID, SchCompleteSaleDate = Lot.SchComplete
ChosenOptionRatifiedQuantity = AcceptedQuantity, AcceptedQuantity = 0, RatifiedDate = now, ProjectedCost computed from StdBookResource.Total
ContractPriceAdjRows with Accepted=1, Ratified=0 flipped to Ratified=1
LotSee lot table below.
ChangeOrder (if change ratify)RatifiedDate = <change date>
ContractTransLog / LotTransLogS02 (sale) / F01 (initial inventory ratify) / F03 (subsequent inventory ratify) / S04 (change order ratify)
TransmissionMaster + TransmissionDepositOne row per un‑sent deposit, batched by company + bank account, status H Hold (legacy Solomon path; today the BC Worker drains these).
TransmissionContractRatifyOne row per Financial Template line — see Transmissions.

Lot updates on ratify (most important row in the system):

Lot fieldSet to
PlansIDContract.PlansID (the plan is now locked onto the lot)
planratified1 (signals the CAD team)
PlansCADVersionSysIDlatest PlansCADVersion for that plan category at the ratify date
SoldDateContract.RatifiedDate (only if buyer; null for inventory)
ProjectedCostPlanSUM(StdBookResource.Total) for the plan’s standard book
ProjectedCostOptionSUM(StdBookResource.Total × (EstimatedQuantity + RatifiedQuantity)) across chosen options
PendingStatus'sale' (buyer) / 'pstart' (initial inventory ratify) / 'pchng' (inventory change) / 'chgrat' (change order)
ProcessEstimate1 — flags the lot for the next Estimate batch
StatusBuyer: 'i' if any open contingency, else 'f' Sold. Inventory: unchanged.
ProdRatifiedDateRatifiedDate (only set the first time, only on inventory)

Side effects on sister inventory contracts (when a buyer ratifies on a previously‑inventory home):

[ buyer's contract ] rat ← this ratify
[ original inv contract ] rat → siv ← demoted: "Sold Inventory"
Log F11: "Lot has moved from Inventory to Sale"

If the inventory had no chosen options, the new sale’s lot is also flagged PendingStatus='', ProcessEstimate=0 (no estimate needed).

If the buyer was previously on a “doesn’t count” cancelled contract, Lot.SoldDate = Contract.CancelledPreviousSoldDate is preserved and an S02 'Sale Already Counted' log row is written so the sales bonus accounting isn’t double‑counted.

Driven by dbo.spProcessContractClose. Triggered at the closing table (typically by Accounting in SMART → Accounting → Closings or SMART 2.0 → accounting/). After close, the Lot is locked (Status='c'), the Contact becomes a Homeowner, change orders that never accepted are cleaned up, and closing rows are queued for Business Central.

Close: full pre-checks and table cascade

Pre‑checks:

  • _VerifyLotOwned — the Lot’s PurchaseDate must be set, and there can’t be unpaid land‑release POs (Permanentorderlog rows where OrderSource IN ('p','v') and InvoiceDate IS NULL and Amount <> 0 and CancelledDate IS NULL).
  • _VerifyNoOpenPOs — no open construction POs.

What changes when it succeeds:

TableChange
LotStatus = 'c' Closed, CloseDate = <closed date>
ContractContractStatusID='clo', ClosedDate, ClosedAssignedID = AssignedID
ContactHomeowner = 1, ContactStatusID = 'o' Owner
ContractDeposit, ContractPriceAdj, ChangeOrderAny rows on un‑accepted change orders are deleted
EstimateErrorLogAll rows for this lot are cleared
ContractTransLog / LotTransLogS09 Closing Posted
TransmissionLot (legacy Solomon) / TransmissionLotTransaction (legacy QuickBooks) / TransmissionContractPostClosing (BC)One row each per closing

After close, the lot is locked: most edits (plan changes, option changes) are blocked unless an admin explicitly runs the Unclose a contract customer‑support script.

Driven by dbo.spProcessContractCancel. Triggered by Sales → Contract → Cancel in SMART. Splits in two completely different paths depending on whether it’s a buyer’s contract or an inventory contract — the buyer path tries to keep the home alive as inventory; the inventory path zeros everything out.

Cancel buyer’s contract: full table cascade (the home stays alive as inventory)
TableChange
WorkLotProcessA “lock” row is inserted to block other processes (cleaned up at the end)
ContractOptionAll rows deleted
ContractDeposit / ContractPriceAdj / ChangeOrderRows on un‑accepted/un‑ratified change orders deleted
ChosenOptionNon‑ratified rows deleted; spProcessContractCancel_ClearOutChosenOptions consolidates the remainder
ContractContractStatusID = 'can', CancelledDate, RescissionReasonID
Contract (extra, if RescissionReason.CountCancellation = 0)CancelledPreviousSoldDate = RatifiedDate (so the sale isn’t double‑counted in metrics later)
Contract (extra, if FwdCommitID set)FwdCommitID = NULL, log S40 Forward Commitment removed
Sister inventory contractIf a siv contract exists for this lot → revert it to rat (and spInsertContractPriceAdjCopyWithLot re‑copies its price adjustments). Else if no other rat inventory contract exists → insert a brand‑new auto inventory contract at rat with default financial settings.
LotSoldDate = NULL, Status = 'p' Production Inventory, PendingStatus = '', ProdRatifiedDate = SoldDate, ProcessEstimate = 1
ContactContactStatusID = 'p' (back to Prospect), C12 log
ChosenOption (rollback)If options had been ratified, roll RatifiedQuantity → AcceptedQuantity and reset the sister inventory contract to acc so a CSR can review
ContractTransLog / LotTransLogS05 Recission
Cancel inventory contract: full table cascade (the home is fully torn down)
TableChange
ChosenOptionAll rows on the lot deleted
LotSelection, LotSelectionActivityAll rows deleted
ContractContractStatusID = 'can', CancelledDate, RescissionReasonID
LotPlansID = NULL, Status = 'z' Not Available (unless 'a' Job Cost), PendingStatus = '', PlansCADVersionSysID = 1, planratified = 0, ProdRatifiedDate = NULL, StatusAtStart = '', ProjectedCostPlan = 0, ProjectedCostOption = 0
Estimate*spUtilityDeleteEstimate clears the estimate (and its activities, resources, error logs)
ContractTransLog / LotTransLogF02 Prod Home Unratified

Status changes don’t just update one table — they ripple out into Lots, Schedules, Estimates, POs, Commissions, Transmissions, and Contacts.

The Lot’s Status is largely a function of the latest Contract operation on that lot.

Full Contract.Status → Lot.Status table
Contract statusLot.Status becomesOther Lot fields
qtes (or s + Reserved=1)unchanged
lrs with LotReservation* filledReserved=1
acc (sale)m AcceptedPendingStatus=''
acc (inventory)p / v / w (per AvailabilityType)unchanged
rat (sale, no contingency)f SoldPlansID, SoldDate, costs, ProcessEstimate=1
rat (sale, contingency)i Sold-Contingentsame
rat (inventory)unchangedProdRatifiedDate, PendingStatus='pstart'
sivunchangeddemoted; sale contract owns the lot now
cloc ClosedCloseDate
can (sale)p Production Inventorycosts zeroed, ProcessEstimate=1
can (inventory)z Not AvailablePlansID=NULL, all costs zeroed

A rat event sets Lot.ProcessEstimate=1. Once the next estimate batch runs, the Schedule (LotSelectionActivity) and Estimate (EstimateActivity / EstimateResource) are populated, and Type='y' activities turn into Permanentorderlog (PO) rows. Cancel deletes all of this; close locks all of this.

See Estimates, Schedules, Purchase Orders, and Variances.

acc saves the original sales agents (so commission stays attached even if reps change). rat stamps RatifiedAssignedID. clo is what actually creates Commission* rows and posts to BC. can either counts or doesn’t count against the rep’s bonus pool depending on RescissionReason.CountCancellation.

See Commissions.

Each contract operation queues specific Transmission* rows that the BC Integration Worker drains every 5 minutes.

Full Contract.Status → Transmission table
Status changeTransmission queuedDrained by
qteacc(none today; legacy Solomon used TransmissionContractAccept)
accratTransmissionContractRatify (one per Financial Template line) + TransmissionDeposit (one per unsent deposit, batched by company + bank account) + later TransmissionPOGenerate (one per generated PO) + TransmissionLot (lot info)BC Integration Worker, every 5 min
any → cloTransmissionContractPostClosing, TransmissionPostClosing, TransmissionLot (final lot info), TransmissionLotTransaction (legacy QB)BC Integration Worker
any → canTransmissionContractCancel (sale) — inventory cancel does not transmitBC Integration Worker
every PO releaseTransmissionPOGenerateBC Integration Worker

Each transmission is queued on TransmissionMaster with Status = 'N' (New) and moved to 'C' (Completed) or 'E' (Error) by the BC worker. See Transmissions and Transmission Statuses.

The buyer’s Contact.ContactStatusID is kept in lock‑step with the contract. acc → b Buyer; clo → o Owner with Homeowner=1; can → p back to Prospect. Each transition writes a C12 row to ContactTransLog.

Every state change writes a 3-character ProcessCodeID row to ContractTransLog, LotTransLog, and/or ContactTransLog. This is your replay log — if you want to know “what happened to this contract on Tuesday at 3 PM”, these tables tell you.

All ProcessCodes used by contracts (S/F/C codes)
CodeDescriptionWritten by
S01Buyer Acceptedsale accept
S02Sale Ratified (or “Sale Already Counted” subtitle)sale ratify
S04Change Request Ratifiedchange order ratify
S05Recissionsale cancel
S06Buyer Unacceptedsale unaccept
S09Closing Postedclose
S40Forward Commitmentcancel (FwdCommit cleared)
F01Prod Home Ratifiedinitial inventory ratify
F02Prod Home Unratifiedinventory cancel / unratify
F03Prod Home Change Ratifiedsubsequent inventory ratify
F06Inventory Acceptedinventory accept
F07Inventory Unacceptedinventory unaccept
F08Inventory Changes Acceptedchange order accept on inv
F09Inventory Changes Unacceptedchange order unaccept on inv
F11Inventory Soldsale takeover or revert
C12Status Changedevery Contact status flip
C13Rank Changedrank reset on accept
AppWhereWhat you can do
SMARTSales → Contract Management; Sales → Quote; Sales → Lot Reservation; Accounting → Closings; Administration → Process MonitorCreate, accept, ratify, cancel, close, change-order
SMART 2.0sales/, accounting/, landdev/Web dashboards; closing transmittal review; “TransmissionMasterErrorLog” review
Builder PortalSchedule.aspxReads Contract.RatifiedDate and EstimatedClosedDate to show the build calendar
Trade PortalDefault.aspx, PO.aspxTrades only see lots whose contract is rat or later
Home Owner PortalDefault.aspx, Schedule.aspx, Selections.aspxBuyers only see their lot once their contract is rat
BC Integration Workern/a (background)Drains every Transmission* row into Business Central

When something goes wrong (accidental cancel, plan needs to change after ratify, contract closed by mistake), the data team has hand-written .sql scripts that unwind specific scenarios. Every one of them bypasses the normal procs and validation. Use only with explicit approval.

Full list of CSR unwind scripts (SOURCECODE/SMART/Documentation/CustomerSupportDocumentation/)
ScriptWhat it does
UncancelContract.sqlResets a contract from can back to a chosen status (qte/acc/rat); clears CancelledDate, RescissionDate, RescissionReasonID.
Unratify.sqlReverses ratify back to acc (only safe if no estimate has been processed). Resets ChosenOption.RatifiedQuantity, Lot.PlansID, Lot.SoldDate, Lot.Status (m if buyer, p if not).
Unratify sale without inventory.sqlSame, but for a sale that didn’t have an underlying inventory contract.
Unclose a contract.sqlclo → rat; sets Lot.Status='f', clears Lot.CloseDate, sets Contact.Homeowner=0, Contact.ContactStatusID='b'.
ContractCancledAccidently.sqlReverses an accidental cancel back to rat/siv and re‑sets Lot.Status='F', SoldDate.
ChangePlanOnRatifiedContract.sqlUpdates Lot.PlansID and Contract.PlansID to a new plan after ratify (rare; requires re‑estimate).
AddBuyerAgentAndBrokertoContract.sqlBackfills missing buyer’s agent / broker on an already‑accepted contract.
UpdateCommissionContract.sqlReassign commission on an already‑closed contract.
Add Buyer to Contract.sqlAdds a ContractCoBuyer row for missing co‑buyers.

The four queries developers ask for most often:

Open contracts (not yet closed/cancelled/cleared)
SELECT c.ContractSysID, p.ProjectName, l.Address,
s.ContractStatusName, c.AcceptedDate, c.RatifiedDate, c.EstimatedClosedDate
FROM dbo.Contract c
JOIN dbo.ContractStatus s ON s.ContractStatusID = c.ContractStatusID
JOIN dbo.Lot l ON l.ProjectID = c.ProjectID
AND l.BuildingID = c.BuildingID
AND l.UnitID = c.UnitID
JOIN dbo.Project p ON p.ProjectID = c.ProjectID
WHERE c.ContractStatusID NOT IN ('clo','can','lc');
Contracts ratified this month, with what’s downstream
SELECT c.ContractSysID, l.Address, c.RatifiedDate,
l.Status AS lot_status,
l.PendingStatus AS lot_pending,
l.ProcessEstimate,
(SELECT COUNT(*) FROM dbo.ChosenOption co
WHERE co.ProjectID=l.ProjectID AND co.BuildingID=l.BuildingID AND co.UnitID=l.UnitID
AND co.RatifiedQuantity <> 0) AS ratified_options,
(SELECT COUNT(*) FROM dbo.TransmissionContractRatify tcr
WHERE tcr.ContractSysID = c.ContractSysID) AS bc_ratify_rows
FROM dbo.Contract c
JOIN dbo.Lot l ON l.ProjectID=c.ProjectID AND l.BuildingID=c.BuildingID AND l.UnitID=c.UnitID
WHERE c.RatifiedDate >= DATEADD(month, DATEDIFF(month, 0, GETDATE()), 0)
ORDER BY c.RatifiedDate DESC;
Replay a contract’s full audit trail
SELECT ctl.EntryDate, pc.ProcessCodeID, pc.ProcessCodeDesc, ctl.AdditionalDesc, ctl.UserID
FROM dbo.ContractTransLog ctl
JOIN dbo.ProcessCode pc ON pc.ProcessCodeID = ctl.ProcessCodeID
WHERE ctl.ContractSysID = @ContractSysID
ORDER BY ctl.EntryDate;
Stuck transmissions for a contract (“the closing isn’t in BC”)
SELECT tm.TransType, tm.Status, tm.DateAdded,
tcr.ContractSysID, tcr.AccountCode, tmel.ErrorDesc
FROM dbo.TransmissionMaster tm
LEFT JOIN dbo.TransmissionContractRatify tcr
ON tcr.TransmissionMasterSysID = tm.TransmissionMasterSysID
LEFT JOIN dbo.TransmissionMasterErrorLog tmel
ON tmel.TransmissionMasterSysID = tm.TransmissionMasterSysID
WHERE tcr.ContractSysID = @ContractSysID
AND tm.Status IN ('N','H','E');