# SaaS hosting setup

Sell subscriptions to separate company workspaces with the optional SaaS module.

The optional **SaaS** module lets you sell subscriptions to separate company workspaces. Each customer has its own users, HR records, settings and files within one shared database. One workspace has one subscription. Without this module, Open Core HR remains a standalone installation.

## Prepare the service

1. Enable SaaS through module management and apply the supplied migrations. Enable **SaaS PayPal** or **SaaS Razorpay** only if you need that payment provider.
2. Configure outgoing email and keep the queue worker and scheduler running as described in [Services](https://czappstudio.com/ar/docs/installation/services). Customers must receive and open their signup verification email.
3. Sign in as the installation super administrator. In **Settings → General**, enter the seller's billing details and currency. Choose the currency before creating plans or orders. Creating the first plan or order locks the currency. For offline payments, configure **Settings → Bank transfer**.
4. Set the payment grace period and your terms and privacy links. Once either link is set, visitors must accept the linked terms to sign up. The acceptance and links are recorded in the customer's billing audit when they verify their email. To protect signup from automated submissions, enable **Workspace signup** under **Settings → Security** (see [Google reCAPTCHA](https://czappstudio.com/ar/docs/installation/configuration#section-3)). Keep public signup disabled until you have checked the complete signup and payment flow.
5. Create and publish plans. Set monthly and/or yearly pricing, trial days, user and storage limits, and included modules. Only installed, enabled modules can be offered; include their dependencies too.

Changing a plan does not rewrite accepted subscription terms or old invoices. Archive a plan when it should no longer be offered to new customers. A customer's existing subscription keeps its saved terms.

Visitors can compare published offers at `/plans` and choose a billing interval before signing up. With Landing Page enabled, **Pricing** appears in the public navigation, and visitors can return to the published landing sections from pricing or signup. To feature pricing in your landing page’s main call to action, set its destination to `/plans`. The operator edits the landing page, its pages, enquiries and subscribers from **Landing page** in the console menu, and its site settings under **Settings → Landing page**.

## Explore the demo

On a local or testing installation with SaaS enabled and migrations applied, populate sample workspaces from `backend/`:

```sh
php artisan db:seed --class='Modules\SaaS\Database\Seeders\Demo\SaaSDemoSeeder'
```

Set `APP_DEMO=true` for the demo installation to show **Platform admin demo**, **Customer admin demo** and **Employee demo** on the sign-in page. The buttons select the appropriate workspace and use normal authentication, including CAPTCHA when configured. Keep demo mode off on a real customer deployment.

The sample companies cover active monthly and annual subscriptions, a trial, an overdue subscription and a suspension. Review the sample bank transfer, inspect order and refund history, or open Northstar's HR workspace and billing page. These are fictional records; no payment provider is charged. Re-running the seeder preserves existing demo records and your changes.

## Bank transfers

In **Settings → Bank transfer**, enter your payment instructions, turn on **Accept bank transfers**, and save. Customers can then create an order, make the transfer outside Open Core HR, and submit a reference and optional proof.

To pause new bank transfer orders, turn off **Accept bank transfers** and save. The instructions are kept for when you enable it again. Customers can still submit proof for existing, unexpired orders, and you can review those transfers.

Review the actual bank receipt before approving a submission in **Orders**. Approval activates its paid period. Reject incorrect submissions with a reason so the customer can correct them. A bank refund must first be completed outside the application; **Record refund** records the amount and reference in the order history.

## Online payments

Gateway configuration is available only to the installation super administrator. Open **Settings → PayPal** or **Settings → Razorpay**, store provider credentials, select the test or live environment, and configure the webhook URL shown there. Each provider appears only when its module is enabled. Preserve the application encryption key in your backup process.

PayPal and Razorpay payments use the provider's hosted checkout. An approval or return page alone does not activate a subscription: the server verifies payment through provider events or reconciliation. Test both the checkout and webhook delivery with the provider before accepting live customers.

PayPal returns the customer to billing. After Razorpay hosted checkout, customers return to **Subscription** and use **Refresh status**. An online renewal that needs a new mandate starts when the current period ends; bank transfer can be prepaid for the next period.

An unpaid online order expires after three days, and its checkout is withdrawn at the provider. If the customer completes that checkout later anyway, the payment is still recorded and applied. If PayPal suspends a subscription after a failed renewal, or Razorpay halts one after its retries, Open Core HR cancels that mandate. The owner can then pay again from billing during the grace period. Overdue reminders wait three days after the period ends while an automatic renewal can still be collected.

PayPal supports a coupon on the first paid cycle. Razorpay coupon checkout is currently unavailable; use a supported payment method for discounted orders. Online refunds are initiated in the provider dashboard and reflected in Open Core HR after verification.

The scheduler reconciles subscriptions and expiry. For troubleshooting, run `php artisan saas:reconcile` from `backend/` and investigate reported failures. A successful credentials test confirms authentication, not the full recurring-payment flow.

## Customers and limits

Use **Dashboard** to compare monthly collections and refunds. The chart covers the current calendar month and the preceding five; a refund appears in the month it was recorded. **Net collections (all time)** subtracts refunds from successful payments in the billing currency. **Monthly recurring revenue** uses the plan price for active and past-due subscriptions, divides annual prices by twelve, and excludes trials. It is an estimate of recurring billings, not a payment balance.

The customer owner manages employees and ordinary workspace permissions. Platform administration remains restricted to the installation super administrator. Customers sign in with their workspace identifier; the installation administrator leaves this field blank.

User limits count non-system accounts that have not been deleted, including inactive accounts. Storage limits count managed files. Reaching a limit blocks additional users or uploads; existing records are retained. Billing stays available after access expires so the customer can renew.

Use a suspension to block ordinary workspace access. Suspending also cancels the customer's automatic payments at PayPal or Razorpay, so the provider stops charging them. After you reactivate the customer, the owner authorizes payment again from billing when the next period is due. Employees using the mobile app in a suspended or expired workspace are told to contact their administrator. A trial extension requires a reason and is recorded. A refund does not automatically cancel a subscription; handle the access decision separately.

Do not disable SaaS while subscriptions exist. Gateway modules also prevent disabling while they manage active payment mandates. Cancel or migrate the affected subscriptions first. Back up the entire shared database and managed file storage together; see [Backups & updates](https://czappstudio.com/ar/docs/installation/backups-and-updates).
