=== WC Store Manager Portal ===
Version 2.14.0 — Store/Sales Manager portal (frontend link + wp-admin menu) + payment-gated Pre-Booking system with a dedicated Booking Dashboard, one plugin.

== Changelog: 2.14.0 ==

NEW — Free/Premium licensing, via the shared sitss.in License Manager
  Server (same system used by School Management Suite, the Laundry
  Management Suite and the Celeste homestay booking plugin). A new
  "License" tab appears in the Store Portal (both the wp-admin page and
  the frontend /store-portal/ page), visible to Store Manager accounts
  only, for activating a license key (format LMS-XXXX-XXXX-XXXX-XXXX).
  License state (active/grace/free) is checked once daily via WP-Cron
  against the real activate/validate/deactivate REST contract, with a
  5-day offline buffer before a short server outage can downgrade status.

  Free plan limits (enforced server-side, not just hidden in the UI):
    - 1 active booking form (editing the existing one is unaffected)
    - No file-attachment field on booking forms
    - No CSV export of bookings
    - No product/quantity editing from the Booking Dashboard
    - Up to 2 staff accounts (Store Manager + Sales Manager combined)
    - Sales reports limited to Today/Yesterday/This Week/This Month
      (Quarter, Year and Custom ranges require Premium)
  Premium (any active or in-grace license) removes every limit above.

NEW — Automatic update delivery via the shared LMS_Plugin_Updater class,
  the same mechanism already used by the other plugins sold through
  sitss.in. Gives a normal wp-admin "Update available" notice and
  one-click update. This is not license-gated -- every install, free or
  premium, gets the same updates, since premium features are gated
  inside the plugin itself rather than by which version is installed.

== Changelog: 2.13.0 ==

NEW — Quantity per product. Customers can now specify how many of each
  product they're booking, defaulting to 1:
    - Single-product forms show a Quantity field next to the price, with a
      running total that appears once quantity is more than 1.
    - Multi-product forms show a small Qty field on each product card,
      factored into the running total alongside the checkbox selection.
  The quantity actually charged is always read from the real order line
  items at order-creation time (same as price always was), never trusted
  from the display alone -- server-side validation clamps every requested
  quantity to a sane 1-99 range regardless of what the browser sends.
  The Booking Dashboard now shows quantity per product too (e.g. "Product
  A ×2"), and the "Edit Products" picker lets staff adjust quantity per
  product, not just which products are included.
  Bookings made before this update are unaffected -- they're read as
  quantity 1 per product, same as they always effectively were.

== Changelog: 2.12.0 ==

NEW — Marking a booking form Inactive no longer hides it behind a plain
  "not currently available" message. Customers now still see the full
  product showcase (images, names, prices) exactly as when the form is
  active, but everything is dimmed and non-interactive -- no checkboxes,
  no customer detail fields, no submit button -- with a diagonal banner
  across the products reading your custom closed message (default: "This
  batch of booking is now closed"). Server-side submission is also
  rejected for a closed form regardless of the UI, as a safety net.
  The message is editable per form: open a booking form in Portal >
  Bookings > Booking Forms, set Status to Inactive, and a "Closed Message"
  field appears to customize the banner text for that specific form.

== Changelog: 2.11.0 ==

FIX — Booking form showing stale product prices/descriptions after they're
  updated in WooCommerce. Root cause: the page hosting the [wcsm_booking_
  form] shortcode is a normal themed page, so it's subject to full-page
  caching (WP Rocket etc.) the same way any other page is -- and a cache
  plugin has no way of knowing that a random custom shortcode's price data
  needs purging when a product changes, the way it does for standard
  shop/product pages. Two fixes, working together:
    1. AUTOMATIC: the booking form now fetches always-current price and
       description data via a small background request right after the
       page loads, and corrects anything stale in the displayed HTML --
       this request itself is never cached, so it's accurate no matter
       how old the surrounding cached page is. This needs no
       configuration and handles the problem on its own going forward.
    2. MANUAL: a "↻ Sync Now" button in Portal > Bookings > Booking Forms
       for an explicit refresh -- clears WooCommerce's own product data
       cache for every product across all booking forms, and purges WP
       Rocket/W3 Total Cache/WP Super Cache automatically if one is
       detected active.
  Either way, the actual amount charged at payment was always correct --
  this only affected what was displayed before checkout, but that's
  obviously still confusing and worth fixing properly.

== Changelog: 2.10.1 ==

FIX (important) — "Invalid credentials or your account does not have
  portal access" showing up on wp-login.php even with correct credentials,
  right after the redirect from /store-portal/. Root cause: a leftover
  filter from the old custom login form (retired in 2.9.0) was still
  hooked to WordPress's global 'login_errors' filter, which unconditionally
  replaced wp-login.php's actual error/message text with that generic
  line -- for every login attempt on the whole site, not just this
  plugin's own flows. That meant it was also overwriting Wordfence's own
  2FA prompt/messaging, which is exactly what made a legitimate 2FA step
  look like a failed login. This filter has been removed entirely --
  wp-login.php's native error handling (and Wordfence's on top of it) is
  what displays now. This should have been caught before 2.9.0 shipped;
  apologies for the extra round trip on this one.

== Changelog: 2.10.0 ==

FIX — 2FA not consistently triggering when logging in directly via
  /store-portal/ (worked fine when going through /wp-admin first). Root
  cause: the redirect used to send signed-out visitors to wp-login.php was
  a manually-built link (wp_login_url()). That reaches the same login
  screen, but doesn't fire the 'auth_redirect' action -- which is what
  Wordfence hooks into for its enforcement, and what wp-admin itself uses
  internally. Both /store-portal/ and /booking-dashboard/ now call
  WordPress's own auth_redirect() function directly (the exact mechanism
  wp-admin uses), so 2FA now triggers identically regardless of which URL
  you land there from, and returns you to the specific page you were
  trying to reach afterward.

NEW — Download bookings as CSV. On the Booking Dashboard:
  - A "★ All Bookings (every form)" option in the form dropdown shows/
    exports every booking regardless of which form it came through.
  - A "⬇ Download CSV" button next to the form selector exports whatever
    is currently in view (either the selected form's bookings, or all of
    them) -- Booking ID, Products, Customer Name, Email, Phone, Address,
    Note, Status, Order ID, Order Total, Has Attachment, Date.
  Editing a booking's products is only offered when viewing a specific
  form (not "All Bookings"), since there's no single bounded product list
  to scope that picker to when viewing everything at once.

== Changelog: 2.9.0 ==

CHANGE — The custom branded login form has been retired. Login now always
  goes through wp-login.php, where Wordfence's 2FA is enforced reliably --
  the custom form's 2FA handoff could not be guaranteed across every
  Wordfence version/configuration, and since MFA is a hard requirement for
  staff accounts, the safer move was to remove that endpoint entirely
  rather than leave it as a possible way to sign in without completing
  2FA. Visiting /store-portal/ or /booking-dashboard/ while signed out now
  redirects straight to wp-login.php and back again on success -- nothing
  else to configure.

NEW — Bookings are now only captured once payment actually succeeds. Prev-
  iously a booking record was written the moment the form was submitted
  (status "Pending Payment"), so an abandoned/unpaid attempt still showed
  up in the Booking Dashboard. Submitting the form now creates the
  WooCommerce order and stashes the booking details on it, but writes
  nothing to the bookings table -- the real booking record (status
  "Pending Verification") is only created the moment WooCommerce marks
  that order as paid. If a customer abandons payment, nothing shows up
  anywhere as a booking; it's just an unpaid WooCommerce order, same as
  any other abandoned order on the site.
  Note: bookings captured before this update that were already sitting in
  "Pending Payment" won't retroactively change -- this only affects new
  submissions going forward.

NEW — Booking orders are now marked in the native WooCommerce Orders
  screen (wp-admin > WooCommerce > Orders), not just in this plugin's own
  Booking Dashboard. A new "Booking" column shows a blue badge on any
  order that came from a booking form. This is deliberately a visible
  badge rather than a genuinely custom order status -- the order still
  needs to pass through the standard pending → processing/completed
  lifecycle for payment gateways, stock handling, and order emails to
  keep working correctly, and introducing a real custom status risks
  breaking that. The detailed booking-specific workflow (Pending
  Verification → Confirmed → Shipped → Completed) continues to live in
  the Booking Dashboard, same as before. If you'd still like a true custom
  order status after seeing this in action, let me know and we can look
  at it -- just flagging the tradeoff upfront.

== Changelog: 2.8.2 ==

FIX — Checkboxes rendering as full-width blue "toggle switch" bars, and
  buttons (Cancel, Save, etc.) showing with zero styling at all (no
  background, no border, just bare text) inside the portal's modals.
  Previous fixes only overrode colours, which isn't enough when a theme or
  page builder applies a much more aggressive global style -- e.g. turning
  every checkbox into a full-width toggle control, or a broad reset that
  strips buttons down to unstyled text. Every relevant CSS property for
  checkboxes and buttons inside this plugin's own containers is now
  explicitly re-declared with !important (including an "all: revert" reset
  on buttons before reapplying our own look), which defeats this kind of
  conflict regardless of its source or specificity. Scoped tightly so it
  can't affect anything outside this plugin's own markup.

== Changelog: 2.8.1 ==

FIX — Currency symbol showing as "&#8377;" (or similar) instead of the
  actual ₹ symbol in the booking form's running total and anywhere the
  Overview/Booking Dashboard stat cards display money via JavaScript.
  get_woocommerce_currency_symbol() returns an HTML entity meant for HTML
  rendering; when set via JS textContent (which doesn't decode entities),
  it showed up as literal garbled text. Now decoded server-side before
  being handed to JS everywhere this happens.

FIX — Fatal error when clicking "Proceed to Payment". Root cause: creating
  an order directly (added in 2.7.0) dropped a WooCommerce customer/session
  initialization step that WC_Order::calculate_totals() can quietly depend
  on internally (e.g. for location-based tax). admin-post.php requests
  don't get WooCommerce's normal frontend bootstrap, so WC()->customer was
  null, and calling a method on it fataled. Restored the lightweight
  initialization (without going back to the cart-based flow) and wrapped
  the whole order-creation step in a try/catch so any future edge case
  degrades to a clear on-page error message instead of a blank/fatal
  screen -- and cleans up the half-created order rather than leaving an
  orphaned draft behind.

FIX — "Proceed to Payment" button only visible on hover. The booking form
  renders inside your normal Woodmart-themed page (unlike the isolated
  Store Portal pages), so theme CSS can still contest ours there even with
  !important. Added an inline style directly on the button as a guaranteed
  fallback that wins regardless of any theme specificity/importance fight.

NEW — Configurable form width: [wcsm_booking_form id="3" width="400px"]
  (or width="100%", "70%", etc.) to fit whatever column/block you place it
  in. Defaults to 560px if omitted, same as before. The booking form
  builder's shortcode display now notes this option.

== Changelog: 2.8.0 ==

FIX — "This plugin is not compatible with your version of WooCommerce" /
  incompatibility warning. Root cause: WooCommerce only shows that warning
  for plugins that declare a "WC tested up to" version in their header (this
  one does) AND haven't explicitly declared compatibility with WooCommerce's
  High-Performance Order Storage (HPOS) feature. This plugin was already
  HPOS-safe in practice -- every order interaction goes through WC_Order /
  wc_get_order() / wc_create_order(), never direct database queries against
  post/postmeta -- it just never told WooCommerce that. Added the standard
  before_woocommerce_init compatibility declaration for both HPOS
  (custom_order_tables) and the Cart/Checkout blocks. The warning should be
  gone after this update.

UPDATED — Version headers refreshed against current releases: WordPress
  7.0 (latest core release, tested up to), WooCommerce 10.9 (latest stable
  as of this update; 11.0 was in beta at time of writing). "WC requires at
  least" raised to 8.0 as a sane modern floor.

FIX — wp-admin left menu registration order: the "Booking Dashboard"
  submenu was being registered before its own parent "Store Portal" menu
  in some cases due to plugin class load order. WordPress generally
  tolerates this, but it's now registered in the correct order (parent
  menu first, submenu second) to remove any doubt.

NOTE on "sidebar links not working": I've fixed everything I can verify
  and reproduce from here (the compatibility warning and the menu
  registration order). If links in the wp-admin left menu are still not
  behaving correctly after this update, please tell me exactly what
  happens when you click them (blank page? 404? "you don't have
  permission"? wrong URL in the address bar? the menu items don't appear
  at all?) so I can target the actual cause rather than guess further.

== Changelog: 2.7.1 ==

CHANGE — Reverted the out-of-stock blocking added in 2.7.0. Pre-booking is
  specifically meant for items that aren't in stock yet, so requiring stock
  to book was backwards for this feature -- any product on a booking form
  can now be selected and booked regardless of stock level, same as before
  2.7.0 introduced the restriction. This was already technically supported
  under the hood (orders are created directly rather than through the
  stock-gated cart), it just needed the UI/validation blocking it removed.

== Changelog: 2.7.0 ==

NEW — Payment is now taken directly from the booking flow, before the
  booking is treated as confirmed. Submitting the form no longer adds
  items to the general WooCommerce cart/checkout -- it creates a real
  order right away and sends the customer straight to WooCommerce's
  native "Pay for Order" page: order summary, choose a payment method
  (whatever gateways you already have installed -- Razorpay, PayU,
  Stripe, COD, etc. all work automatically, no extra setup needed), pay.
  Name/email/phone/address collected on the booking form are written
  straight onto the order, so there's no second billing form to fill in.
  The booking only moves to "Pending Verification" once that payment
  actually succeeds -- the same payment-complete hooks as before, just
  reached by a more direct path. This also sidesteps cart/session cookies
  entirely, which is inherently more reliable than the previous cart-based
  handoff.

FIX — Out-of-stock products could previously be selected, added toward a
  booking, and then silently fail to reach checkout with no items/price
  shown -- exactly the bug you reported. Two layers now prevent this:
    1. Out-of-stock products are visibly marked "Out of Stock" on the
       booking form with their checkbox disabled, so they can't be
       selected in the first place. A single-product form whose only
       product is out of stock shows a clear message and disables the
       Proceed button entirely.
    2. Server-side, if a stock level changes between page load and
       submission (or the disabled state is bypassed), the whole
       submission is rejected up front with a clear per-product message
       -- never partially processed.

== Changelog: 2.6.0 ==

NEW — Multi-product bookings: on forms with more than one product, customers
  now select via checkboxes instead of a single radio button, can pick as
  many as they like, and see a live running total ("Selected total: ₹X")
  update as they check/uncheck items. All selected products are added to
  the cart together under one shared booking reference, so checkout shows
  every item and the combined price -- not just one product.

FIX — Booking Dashboard now reflects what was actually booked: previously
  each booking stored (and could only ever store) a single product, so the
  dashboard's product dropdown could only represent one item even for a
  booking that should have covered several. Bookings now store their full
  product list. The dashboard shows the real list of booked products per
  row (not a single arbitrary dropdown), with an "Edit" action that opens a
  checklist -- scoped to that booking form's own products -- pre-checked
  with what the customer actually selected, in case a correction is needed.

NOTE: existing bookings made before this update only have their original
  single product on record (the legacy column is still read as a fallback),
  so they'll continue to display and behave correctly -- this only affects
  bookings made going forward, which can now cover multiple products.

== Changelog: 2.5.1 ==

FIX — Checkout showing no items / no price after clicking "Proceed to
  Checkout" from a booking form. Root cause: the booking form submits to
  admin-post.php, which WordPress always treats as an admin request
  (is_admin() is true there) even though it's being used to process a
  frontend form. WooCommerce only sets the cart/session tracking cookies
  during the normal frontend page lifecycle (the 'wp' action), which never
  fires on admin-post.php requests. So the booking product WAS being added
  to a cart, but the browser was never told which session to look up on
  its next request -- checkout landed on a brand new, empty session with
  nothing to pay. Fixed by explicitly forcing WooCommerce to persist the
  session and set those cookies before redirecting to checkout
  (WC()->cart->maybe_set_cart_cookies() + an explicit session save).
  Please re-test one full booking end to end after this update to confirm
  the product and price now appear correctly at checkout.

== Changelog: 2.5.0 ==

FIX — Modal buttons invisible except on hover: the "standalone" /store-portal/
  and /booking-dashboard/ pages were calling wp_print_styles() with no
  arguments, which prints every enqueued stylesheet on the site -- including
  your Woodmart theme's global CSS. Woodmart's own button styling was
  overriding ours. Both pages now print only this plugin's own stylesheet by
  handle, so the page is genuinely standalone as originally intended. Button
  colours are also now set with !important as a second line of defence.

FIX — A layout bug in the same area: the primary button style forced
  width:100%, which is right for the full-width login button but wrong for
  the Cancel/Save button pairs inside modals. Scoped that to the login card
  only.

NEW — Checkout booking note: when a customer proceeds to checkout from a
  booking form, two things now happen:
    1. A visible notice appears at the top of the checkout page stating what
       they're booking, its total cost, and a short booking reference.
    2. The checkout page's "Order notes" field is pre-filled with a full
       summary (product, total cost, name, phone, address, and any note they
       left) so it's visible right there for payment and processing -- and
       a private, staff-only order note with the same summary is also
       written permanently onto the order once it's created, so this
       information survives even if the customer edits or clears the
       notes field before paying.


== What this plugin does ==

1. Two new roles:
   - Store Manager (wcsm_store_manager): full store control — products (add/edit/delete),
     orders, shipping, coupons, staff accounts, bookings/settings. Cannot manage WordPress
     core (themes/plugins/other user roles) — that stays with Administrator.
   - Sales Manager (wcsm_sales_manager): add/update products (no delete), manage orders,
     shipping, bookings, and day-to-day operations. No staff account access.

2. A single fixed frontend link — https://yoursite.com/store-portal/ — that is the whole
   console (login + dashboard in one place, not a shortcode). See "Frontend Store Portal
   link" below for details.

3. Wordfence 2FA: enforced reliably because login only ever happens through
   wp-login.php itself -- visiting /store-portal/ or /booking-dashboard/ while
   signed out redirects straight there and back again on success. There is no
   custom login form any more (see the 2.9.0 changelog entry above for why).

4. The console itself (same content whether reached via /store-portal/ or the wp-admin
   "Store Portal" menu item) has:
   - Sales report: Today / Week / Month / Quarter / Year / custom date range, total
     sales, order count, items sold, average order value, a trend chart, and top products.
   - Products tab: list, search, add, edit. Delete button only shows for Store Manager.
   - Orders & Shipping tab: list/search/filter, view full order detail, change order
     status, set shipping carrier + tracking number (saved as an order note + order meta).
   - Bookings tab: see the Pre-Booking section below.
   - Staff tab (Store Manager only): create Sales Manager / Store Manager accounts
     (sends the standard WP "set your password" email) and remove staff accounts.

== Installation ==

1. If you installed an earlier version of this plugin, deactivate and delete it first
   (its roles/data are only removed on uninstall, not deactivate, so nothing is lost).
2. Upload this zip via Plugins > Add New > Upload Plugin, or unzip into
   wp-content/plugins/wc-store-manager/.
3. Activate. On activation the plugin automatically:
   - Creates the Store Manager and Sales Manager roles with the correct capabilities.
   - Creates the booking table and the "Pre-Book a Product" page (with [wcsm_booking_form]).
   - Registers the /store-portal/ link.
4. Go to wp-admin > Settings > Permalinks and click "Save Changes" once (no need to
   change anything) — this is a standard WordPress step after any plugin adds a new URL,
   and guarantees /store-portal/ resolves correctly.
5. Go to Users > Add New (or the portal's own Staff tab once you have one Store Manager
   account) and assign the "Store Manager" or "Sales Manager" role.
6. Send staff to https://yoursite.com/store-portal/ — or they can log in via the normal
   wp-login.php and they'll land there automatically.
7. If you use Wordfence 2FA, enable it on a test Sales Manager account and confirm the
   login flow works end to end before rolling this out to real staff.


== Changelog: 2.4.0 ==

FIX — Booking forms silently failing to save: two things were happening.
  1. Failed AJAX requests had no error handler anywhere in the JS, so a
     rejected request (expired nonce, missing permission) did nothing
     visible at all -- it just looked like the Save button didn't work.
     Every AJAX call now surfaces a clear error message if this happens.
  2. More importantly: this plugin has picked up new capabilities
     (like wcsm_manage_booking_products) across updates, but capabilities
     only get (re)applied to your roles when the plugin is *activated* --
     not on a simple file overwrite. If you updated by re-uploading the
     zip without deactivating/reactivating in between, your live
     Store Manager / Sales Manager roles could have been missing a
     capability the code had started checking for, causing a silent
     permission failure. This is now self-healing: the plugin checks its
     capability set against your database on every page load and quietly
     re-syncs if anything's out of date, so this can't happen again even
     if you forget to reactivate on a future update.

NEW — Editable booking form fields: each Booking Form now has a "Customer
  Fields" section in the builder (Portal > Bookings > Booking Forms) where
  you choose whether Phone, Address, Note, and Attachment are shown at all,
  and whether each is required. Name and Email are always shown and
  required. The public booking form and its server-side validation both
  respect this per form.

NEW — Editable product per booking: on the new Booking Dashboard (see
  below), each booking's product is a dropdown, not a fixed value -- if a
  customer's booking needs to be corrected to a different product from the
  same form, change it right there.

NEW — Dedicated Booking Dashboard page, separate from the main Store
  Portal tabs:
    - Frontend link: https://yoursite.com/booking-dashboard/
    - wp-admin: Store Portal > Booking Dashboard (submenu)
  Pick a Booking Form from the dropdown at the top and see every booking
  made through it -- customer name, email, phone, address, attachment,
  linked order, and status -- with soft-coloured stat cards (total
  bookings, pending verification, confirmed+shipped, completed, total
  value) above the table. The main Store Portal's Bookings tab now just
  manages Booking Forms and the upload limit, with a button through to
  this dashboard.

NEW — Soft colour treatment across the dashboard: the four Overview stat
  cards (Total Sales, Orders, Items Sold, AOV) and the new booking stat
  cards each get a distinct soft pastel accent (blue/green/purple/orange/
  amber) instead of flat white, and status dropdowns are colour-coded
  (amber for pending, blue for confirmed, purple for shipped, green for
  completed, red for cancelled) so table state is readable at a glance.


The Store Manager / Sales Manager frontend is now a single, fixed link -- NOT a
shortcode you paste into a page:

    https://yoursite.com/store-portal/

This is a custom rewrite endpoint, not a normal WordPress page. It renders a
fully standalone document (its own head/body, no Woodmart header/footer/sidebar,
no theme styling bleeding in) so the console looks and behaves like its own app.
The same link adapts automatically:

- Not logged in            -> redirected to wp-login.php (Wordfence 2FA aware) and back
- Logged in, not authorized-> a plain "no access" notice
- Logged in, authorized    -> the full Overview / Products / Orders & Shipping /
  Bookings / Staff console

Bookmark or menu-link that single URL for your staff. If you'd rather it live at
a different slug (e.g. /portal/ instead of /store-portal/), add this to a small
mu-plugin or your theme's functions.php:

    add_filter( 'wcsm_portal_slug', function() { return 'portal'; } );

Then re-save Settings > Permalinks once (or deactivate/reactivate this plugin)
so WordPress picks up the new rewrite rule.

IMPORTANT: after installing/updating this plugin, visit wp-admin > Settings >
Permalinks and just click "Save Changes" once (no need to change anything) --
this forces WordPress to register the new /store-portal/ URL. Activation does
this automatically, but if the link ever 404s after a server migration or
permalink change, this is the fix.

The wp-admin "Store Portal" left-menu page still exists as a second, equivalent
entry point for anyone who prefers working from inside wp-admin -- both point
at the exact same AJAX endpoints and data, just with different chrome around
them.

The [wcsm_booking_form] shortcode is unchanged and still meant to be pasted on
any page, since customers (not staff) use it and it needs to sit inside your
normal site pages/theme.

== wp-admin left menu (new) ==

There's now a "Store Portal" item in the wp-admin left menu (with the store icon),
visible to Store Manager, Sales Manager and Administrator. It opens the exact same
app as the [wcsm_dashboard] shortcode -- Overview/Reports, Products, Orders &
Shipping, Bookings, Staff -- just inside wp-admin.

Store/Sales Managers are no longer blocked from wp-admin outright. WordPress's own
capability system already hides anything they don't have rights to (Plugins,
Themes, core Users, Tools, Settings, Comments are removed from their menu, and
attempting to open those screens directly is refused by WordPress itself). What
they land on:

- Logging in via wp-login.php drops them straight onto the Store Portal page
  instead of the default WP Dashboard widgets screen (or onto the Booking
  Dashboard specifically, if that's what they were trying to reach).
- Visiting wp-admin's default Dashboard (index.php) auto-redirects them to the
  Store Portal page too, so they never see the standard widgets screen.

Because they now use wp-admin, Store Manager retains native WooCommerce product/
order screens as a fallback for anything the simplified portal UI doesn't cover
(variations, attributes, complex shipping zones, etc.) -- matching "store manager
will have all access to change anything" from your spec.

== Notes for your setup ==

- This plugin is theme-independent, so it will work the same way on radiohub.in
  (Woodmart theme) as on any other WooCommerce install.
- It's HPOS-safe (works whether WooCommerce's new order storage is on or the legacy
  post-based storage is on) since all order queries go through wc_get_orders()/WC_Order.
- Reporting only counts orders in status processing/completed/on-hold by default;
  adjust with the `wcsm_report_order_statuses` filter if you also want e.g. "shipped"
  or a custom status included.
- Product delete capability is intentionally withheld from Sales Manager per your spec
  ("store manager will have all access to change anything but sales manager should
  have access to add or update product").

== Pre-Booking system ==

1. Booking Forms, not one fixed shortcode: Portal > Bookings tab > "Booking Forms" >
   "+ Create Booking Form". Both Store Manager and Sales Manager can create/edit these
   (per your spec that sales staff should control which products are open for booking).
   Each form has:
     - A title (e.g. "Diwali Pre-Orders", "iPhone 17 Waitlist")
     - One or more products, picked via a live search-and-check picker
     - An Active/Inactive toggle
   Saving gives you a shortcode like [wcsm_booking_form id="3"] — copy it onto any
   page. You can create as many forms as you like, each covering different products,
   so you can run several pre-booking campaigns at once on different pages.

2. Product cover photo + details on the form itself:
     - If a form has one product, the form shows that product's cover photo, name,
       price, and short description right at the top before the customer fills
       anything in.
     - If a form has several products, each one appears as a selectable card with
       its own photo, name and price in a grid; clicking a card shows that
       product's description and marks it as the one being booked.

3. Upload limit: Portal > Bookings tab > "Upload Size Limit" — configurable between
   100 KB and 1024 KB (1MB), enforced both client-side (instant feedback) and
   server-side (real check, not just trusting the browser). Only JPG/PNG/WEBP/PDF
   are accepted, and the real file content is checked (not just the extension).

4. Checkout handoff: submitting the form creates a booking record (status
   "Pending Payment"), adds the chosen product to the WooCommerce cart with the
   booking reference attached, and sends the customer straight to your normal
   WooCommerce checkout to pay by whatever gateways you already have configured
   — no separate payment integration needed.

5. Once WooCommerce marks the order as processing/completed (payment received),
   the booking automatically flips to "Pending Verification" and shows up in
   Portal > Bookings with customer details, order link, and the attachment (if any).

6. Status flow: Sales/Store Manager update each booking through Pending
   Verification → Confirmed → Shipped → Completed via a dropdown in the table
   (a Cancelled option is also available).

7. Attachments are stored in a private, non-web-accessible folder
   (wp-content/uploads/wcsm-bookings/, blocked via .htaccess) and are only ever
   served through a signed, capability-checked link from inside the portal — no
   customer's uploaded file/ID/photo is guessable or publicly reachable.

8. A product only accepts bookings if it's included in at least one Active booking
   form — there's no separate global "enable for booking" switch any more, the
   forms themselves define what's bookable. Deleting a form (or setting it
   Inactive) immediately stops new bookings for the products only reachable
   through that form.
