Skip to content

Oman broker renewal & resubmission

The Oman broker pre-registration flow ends the moment the CRM callback mints a real Broker and the application lands in ACTIVE with broker_id set. This page picks up from there. An onboarded Oman broker still owns the same OmanPreRegistrationBrokerApplication row, and that row keeps living: a company broker’s contract expires once a year, the broker resubmits signed contracts to renew, and any single document an admin rejects can be re-uploaded for a fresh review. Everything here is verified against the current backend (develop @ 8434e475).

The onboarding spine parks the row in ACTIVE. From there, three of the twelve OmanBrokerApplicationStatusEnums states (OmanBrokerApplicationStatusEnums.php:11-22) run the lifecycle: PENDING_RENEWAL (:20), CONTRACT_EXPIRED (:21), and PENDING_DOCUMENT_REVIEW (:22). All three are in the Voyager dashboard filter (getValidStatusForDashboard, :47-60), so they surface as admin tasks just like the onboarding review states do.

stateDiagram-v2
[*] --> ACTIVE: onboarded (CRM callback minted the Broker)
ACTIVE --> CONTRACT_EXPIRED: scheduled daily job when contract_end_date is past (company brokers only)
ACTIVE --> PENDING_RENEWAL: broker resubmit-contract with both signed contracts present
ACTIVE --> PENDING_DOCUMENT_REVIEW: broker resubmit-document (a rejected non-contract doc)
CONTRACT_EXPIRED --> PENDING_RENEWAL: broker resubmit-contract with both signed contracts present
CONTRACT_EXPIRED --> PENDING_DOCUMENT_REVIEW: broker resubmit-document
PENDING_RENEWAL --> ACTIVE: admin approve-renewal when every document is accepted then CRM update job
PENDING_RENEWAL --> CONTRACT_SENT: admin reject-renewal when a signed contract is rejected
CONTRACT_SENT --> PENDING_RENEWAL: broker re-uploads both signed contracts
PENDING_DOCUMENT_REVIEW --> ACTIVE: admin approve-documents-after-review
PENDING_DOCUMENT_REVIEW --> MISSING_INFORMATION: admin reject-documents-after-review
MISSING_INFORMATION --> PENDING_DOCUMENT_REVIEW: broker resubmit-document
Oman broker — post-approval lifecycle (verified)

Contract expiry — a scheduled job, company brokers only

Section titled “Contract expiry — a scheduled job, company brokers only”

Expiry is not a user action. App\Console\Kernel.php:45 schedules oman-broker-with-contract-expired:notify daily; the command (NotifyOmanContractExpired.php:10,17) dispatches NotifyOmanBrokerWithContractExpiredJob, which does the transition.

  1. Who it selects. Only applications that are ACTIVE, have a non-null contract_end_date strictly before today, and whose broker is a company type (local_company / international_company) — getBrokerApplicationsQuery, NotifyOmanBrokerWithContractExpiredJob.php:89-104. Individual ambassadors have no contract, so this job never touches them — an ambassador’s row simply stays ACTIVE.

  2. The atomic flip. Per broker it runs a single guarded update — it only fires when last_notified_at is null or older than today, and in that one statement it sets last_notified_at = now and status = CONTRACT_EXPIRED (:57-71). That last_notified_at guard is what makes the daily run idempotent and race-safe: a second worker on the same row gets 0 rows updated and returns.

  3. Documents expire too. The signed-contract documents (Salalah-Beach + Jebel-Sifah) are bulk-set to document_status = EXPIRED (:73-78), so the broker must upload fresh signed contracts to renew.

  4. Notifications. The broker gets BrokerContractExpiredNotification; each configured admin gets AdminBrokerContractExpiredEmail (:80-86). Admin recipients come from omanBrokerApplicationNotification.admin_emails (env OMAN_CONTRACT_EXPIRED_ADMIN_EMAILS); if it’s empty the job logs a warning but still expires the row and still notifies the broker (:36-39).

Both resubmit endpoints save the uploaded file first (via SaveDocument, with markPendingAndClearReview = true, so the touched document is reset to PENDING with its rejection reason and admin comment cleared — SaveDocument.php:19-43, UpdateBrokerPreRegistrationDocument.php:40-46), then run their status action. If the broker has no application row, both return 404 pre_registration_application_not_found.

  1. Renew the contract — POST oman-application/resubmit-contract (OmanRegistrationApplicationController@resubmitApplication, routes/api/broker.php:280). Accepts jebel_sifah_signed_contract_file and/or salalah_beach_signed_contract_file (each nullable, max:5120 KB, mimes:jpg,jpeg,png,pdf,doc,docxResubmitBrokerApplicationRequest). The action ResubmitApplication.handle is valid from CONTRACT_EXPIRED, CONTRACT_SENT, ACTIVE, PENDING_RENEWAL, or PENDING_DOCUMENT_REVIEW (else 422 resubmit_application_wrong_status, ResubmitApplication.php:18-35). It moves the row to PENDING_RENEWAL only when both signed contracts now exist with status PENDING or ACCEPTED (count() === 2, :37-45). Upload only one and it silently stays put.

  2. Resubmit a rejected document — POST oman-application/resubmit-document (@resubmitDocument, routes/api/broker.php:281). Accepts a single file + document_type, where document_type must be in valuesExceptSignedContract() — i.e. any document except the two signed contracts (ResubmitBrokerApplicationDocumentRequest; signed contracts go through step 1). The action ResubmitDocument.handle is valid from MISSING_INFORMATION, CONTRACT_EXPIRED, CONTRACT_SENT, PENDING_DOCUMENT_REVIEW, ACTIVE, or PENDING_RENEWAL (else 422 resubmit_documents_wrong_status, ResubmitDocument.php:16-35). It moves the row to PENDING_DOCUMENT_REVIEW and emails the admins (AdminBrokerDocumentsResubmittedEmail, :46-64) — unless the row is already PENDING_DOCUMENT_REVIEW or PENDING_RENEWAL, in which case the file is replaced but no status change and no admin email happen (:38-44).

  3. Read / upload supporting documents. GET oman-application/documents lists the row’s documents (OmanApplicationDocumentController@index, broker.php:275); POST oman-application/documents uploads one (@save, broker.php:279); GET oman-application/documents/{document} streams a file, guarded so a broker can only download their own application’s documents (else 403/404, OmanApplicationDocumentController.php:80-98).

The renewal and document-review decisions are admin actions under routes/web/dashboard.php (behind admin.user), handled by OmanPreRegistrationBrokerApplicationController.

Admin action (route) Guard Effect Action class
approve-renewal (dashboard.php:92) only from PENDING_RENEWAL, requires signed docs present and every document accepted ACTIVE, sets contract_start_date = now + contract_end_date = now + 1yr, clears comment/reason, dispatches the CRM update job ApproveApplicationRenewal.php:17-54
reject-renewal (dashboard.php:97) only from PENDING_RENEWAL, requires at least one rejected signed contract CONTRACT_SENT, notifies BrokerRejectedContractRenewalNotification RejectApplicationRenewal.php:17-49
approve-documents-after-review (dashboard.php:102) no status guard ACTIVE, clears comment/reason, notifies BrokerDocumentsAcceptedAfterReviewNotification ApproveDocumentsAfterDocumentReview.php:11-25
reject-documents-after-review (dashboard.php:107) MISSING_INFORMATION + admin_comment, notifies BrokerApplicationDocumentReviewMissingInformationNotification RejectDocumentsAfterDocumentReview.php:11-27
per-doc status / bulk-accept / download (dashboard.php:112-124) set an individual document to accepted / rejected / expired OmanPreRegistrationBrokerDocumentController
sequenceDiagram
participant BR as Broker (real broker token)
participant APP as Application row
participant AD as ODH admin (Voyager)
participant JOB as UpdateOmanPreRegistrationBrokerInCrmJob
participant MW as crms-middleware then CRM
BR->>APP: resubmit-contract (upload both signed contracts)
Note over APP: both signed docs PENDING or ACCEPTED so status becomes PENDING_RENEWAL
AD->>APP: approve-renewal (needs every document accepted)
Note over APP: status ACTIVE, contract_start now, contract_end now plus one year
APP->>JOB: dispatch (idempotent per application via WithoutOverlapping)
JOB->>MW: PATCH oman-pre-registration brokers with header country oman
MW-->>JOB: 200
JOB->>BR: BrokerContractRenewedNotification
Renewal approval → CRM update round-trip (verified)

Status reference — the renewal & expiry states

Section titled “Status reference — the renewal & expiry states”

From OmanBrokerApplicationStatusEnums.php:11-22 (the three onboarding-only draft states are covered on the pre-registration page).

Status (value) What it means How you get here How you leave
active Fully onboarded / renewed. A company broker’s contract_end_date is in the future CRM callback (onboarding), approve-renewal, or approve-documents-after-review Contract expires, or the broker resubmits a contract/document
pending_renewal Fresh signed contracts uploaded, awaiting admin renewal decision Broker resubmit-contract with both signed contracts present approve-renewalactive, or reject-renewalcontract_sent
contract_expired Yearly agreement lapsed. Signed-contract docs are set to expired Scheduled daily job when contract_end_date is past (company brokers only) Broker resubmit-contractpending_renewal, or resubmit-documentpending_document_review
pending_document_review A resubmitted non-contract document is awaiting admin review Broker resubmit-document approve-documents-after-reviewactive, or reject-documents-after-reviewmissing_information
contract_sent Renewal rejected — broker must upload fresh signed contracts (also an onboarding state) reject-renewal (renewal path) Broker resubmit-contractpending_renewal
missing_information Document review found problems — broker must fix a document (also an onboarding state) reject-documents-after-review Broker resubmit-documentpending_document_review

Each OmanPreRegistrationBrokerDocument.document_status is one of four values (OmanBrokerApplicationDocumentStatusEnums.php:11-14). The last three are the admin-settable ones (getUpdateStatusActions, :16-23).

Document status Meaning
pending Uploaded / resubmitted, awaiting an admin decision. A resubmit resets the document to this and clears its prior rejection reason + admin comment
accepted Admin approved this document. Renewal approval requires every document to be accepted
rejected Admin rejected it (with a reason + optional comment). The broker re-uploads via resubmit-contract or resubmit-document
expired Set on the signed-contract documents when the yearly job flips the application to contract_expired