ORAFOL MDF Portal — Deep System Analysis

A senior-architect-grade migration analysis comparing the current heavily-customized Magento system to the Missio Commerce SaaS target. Maps every contracted scope item to existing Laravel code, flags technical debt, identifies integration risks, and lays out a phased migration plan with priority and effort.

Client: ORAFOL Americas Inc. Source: Magento (custom) Target: Missio Commerce Contract: $85K + $4K/mo Timeline: 14–16 weeks Generated: 2026-04-30

0Executive Summary

Big finding — ORAFOL scaffolding already exists. OrafolController.php, routes/orafol.php, and the menu in resources/views/sections/menus/store.blade.php already gate ORAFOL features behind GetCompanyId() == 100. There are 25+ orafol routes (group catalog, group assignments, parent accounts, integration hub, payment controls, regional reports, sales automation, KPI dashboard, 11 reports). Most are UI scaffolds without backend logic — views exist, models/migrations/business-logic do not. This is a major head-start.
9
Payment Gateways live
29
Frontend Themes
4
Auth Guards
1,091
Web routes total
25+
ORAFOL stub routes
7,000+
SKU target scale

Verdict

Missio is a mature multi-tenant Laravel SaaS with strong payments (Stripe, PayPal, Square, Authorize.Net, Razorpay, Mollie, Flutterwave, PayFast, Paystack), abandoned-cart recovery, multi-guard auth, and a theme engine. Three areas blocking ORAFOL UAT: (1) parent/child company hierarchy (only customer-groups have parent_id), (2) ORAFOL BE ERP connector (does not exist), (3) multi-location inventory (single stock field today). The 25+ ORAFOL skeleton routes need their backend logic written.

1Current System Architecture

1.1 Stack & Structure

LayerTechnologyNotes
FrameworkLaravel 10 (worksuite-saas fork)Multi-tenant via company_id scoping
DatabaseMySQLTables prefixed mixed: tbl_* for commerce, default Laravel for users/roles
AuthLaravel Sanctum + Socialite + custom 2FA4 guards: web/admin/customer/api
FrontendBlade + jQuery + Vue partials + 29 themesTheme manager: hexadog/laravel-themes-manager
Module systemnWidart/laravel-modulesModules: Event, RestAPI, Recruit (etc.)
QueueLaravel Queue (DB driver assumed)Jobs: ProcessInboundEmailJob, abandoned-cart reminders
PDFDOMPDF + barryvdh/laravel-dompdfInvoices, proposals
Excel I/Omaatwebsite/excelUsed; available for product/order import

1.2 Modules & Responsibilities

Commerce Core
app/Http/Controllers/ProductController, OrderController, ProductCategoryController, ProductAttributeController
  • Product CRUD + variants + attributes
  • Categories (recursive)
  • Orders + order items
  • Customer groups + tiered % discount
Frontend Shop
app/Http/Controllers/Front/* + Api/Shop/*
  • FrontProductController
  • MemberController (customer area)
  • Api/Shop: Catalog, Cart, Checkout, Payment
Payments (9 gateways)
app/Http/Controllers/Payment/*
  • Stripe, PayPal, Square, Authorize.Net
  • Razorpay, Mollie, Flutterwave
  • PayFast, Paystack
  • Per-company credentials in DB
CMS / Content
routes/content.php + CMS APIs
  • Pages, Menus, Post Types
  • Blogs, Settings
ORAFOL B2B Scaffold
app/Http/Controllers/OrafolController.php + routes/orafol.php
  • Group catalog/assignments
  • Parent accounts, customer rules
  • Integration hub, KPI dashboard
  • 11 stub reports
Donations / Events / RFP
routes/donations.php, event-pages.php, rfps.php
  • Non-commerce verticals (worksuite legacy)
  • Bloat — consider hiding for ORAFOL tenant

1.3 Tightly Coupled Components & Custom Logic

Coupling risks observed
  • GetCompanyId() == 100 hardcoded in store.blade.php — tenant-specific UI gating in views. Should be a feature flag.
  • Product::getPriceAttribute() queries Auth::guard('customer')->user()->customer_group_id inside the model accessor — couples model to auth/session and prevents background-job pricing.
  • Stripe modes read company.stripe_mode, company.test_stripe_secret, company.live_stripe_secret directly — should go through PaymentGatewayCredentials uniformly (other gateways do).
  • Theme switching tied to company config but no abstraction layer; theme upgrades require manual file copy across 29 directories.
  • OrderCart mixes type='item' and type='discount' rows — clever but fragile (forgetting where type=item in totals breaks math).

1.4 Data Flow — Current Order Lifecycle

[Browse] /shop → FrontProductController / Api/Shop/CatalogController ↓ (filters: category, price, attr) [Add to cart] Api/Shop/CartController::add() ↓ OrderCart row created (cart_id from session OR sanctum token) [Checkout] Api/Shop/CheckoutController::store() ↓ saves billing/shipping; creates Order draft [Payment] Api/Shop/PaymentController OR Payment/{Gateway}Controller ↓ Stripe PaymentIntent / PayPal redirect / etc. ↓ Webhook confirms (verify-webhook/{hash}) [Order] Order.status = paid; OrderItems created from cart [Email] Listener fires, Sendgrid template sent [Invoice] Invoice record created; DOMPDF generates PDF on request [Inventory] Product.stock decremented (single-field, no warehouses) [Fulfill] ??? — no fulfillment dashboard exists
Data flow gap The chain ends at the order record. There is no fulfillment / pick / pack / ship workflow, no carrier label generation, and no tracking-number lifecycle. Orders sit in “paid” status with no operational follow-through — fulfillment teams have no dashboard. This is the largest functional gap vs. Magento Commerce.

2Feature Mapping — Magento → Missio

2.1 Account & User

FeatureStatusWhereAction
Multi-user per companyEXISTS AS-ISusers.company_id + role_userReuse
Role-based permissions (Entrust)EXISTS AS-ISEntrustUserTrait, permission_roleReuse
Customer-group hierarchyEXISTS AS-IScustomer_groups.parent_id (mig 2025_09_10)Reuse
Parent / child company hierarchyMISSINGBUILD: companies.parent_company_id + scopes
Multi-role single loginNEEDS REFACTORPivot supports it; UI doesn'tAdd role-switcher dropdown
Self-service sub-account UISTUB ONLYorafol/parent_accounts.blade.phpImplement invite flow + middleware scoping
Sales rep visibility by regionMISSINGBUILD: sales_rep_regions table + dashboard scope
2FA / MFAEXISTS AS-ISLoginController::checkCode()Reuse for admin; extend to customer guard if requested
Social loginEXISTS AS-ISGoogle, Facebook, Twitter via SocialiteReuse (admin); extended to customer in MemberController
SSO / OKTA / SAMLMISSINGBUILD if ORAFOL needs employee SSO

2.2 Catalog & Pricing

FeatureStatusWhereAction
Simple productsEXISTS AS-ISProduct.typeReuse
Configurable products (variants)EXISTS AS-ISProductVariant + valuesReuse
Grouped / bundle productsMISSINGBUILD product_groups pivot
Downloadable / virtualPARTIALProductFilesWire to Issuu
Product attributes (size/color/series)EXISTS AS-ISFull schemaReuse
Group-based product visibilityEXISTS AS-IScustomer_group_product pivotReuse
Tiered pricing (qty breaks)PARTIALGroup % discount onlyBUILD price_tiers table
Catalog price rulesMISSINGCoupons cover cart-rules onlyBUILD rule engine
Cart price rules / couponsEXISTS AS-ISCoupons + CouponUsageReuse
7,000+ SKU scaleNEEDS REFACTORNo search indexAdd Meilisearch / Algolia / Scout
Layered / faceted navPARTIALFilter widgets existRefactor against search index
Product reviews & ratingsMISSINGBUILD module
WishlistsEXISTS AS-ISMemberController::store_wishlistReuse
Compare productsMISSINGBUILD (low priority)
Recently viewedMISSINGBUILD (low priority)
Quick order / SKU padPARTIALInquiry modal onlyBUILD true CSV-paste pad
Quote request / RFQPARTIALInquiry modalBUILD quote → order conversion + sales-rep approval
Requisition lists / saved cartsMISSINGBUILD (Magento B2B has it; high B2B value)
Issuu literaturePARTIALFiles existEmbed widget per product

2.3 Inventory

FeatureStatusWhereAction
Single-stock trackingEXISTS AS-ISProduct.stock, ProductVariant.stockReuse for fallback
Multi-warehouse inventoryMISSINGBUILD warehouses + inventory_locations
Stock reservations (during checkout)MISSINGBUILD (prevents over-sell)
Backorder / pre-orderMISSINGBUILD per-product flag
Low-stock alertsSTUB ONLYorafol/reports/low-stock viewWire query + email job
ORAFOL BE ERP sync (in/out)MISSINGBUILD — XL
Kathy's facility 2-way connectorMISSINGBUILD — spec TBD
Inventory audit trailMISSINGBUILD inventory_movements ledger

2.4 Payments & Credits

FeatureStatusWhereAction
Stripe / PayPal / 7 othersEXISTS AS-IS9 controllers in Payment/Reuse
Per-company gateway credentialsEXISTS AS-ISPaymentGatewayCredentialsReuse + standardize Stripe path
Webhook handling per gatewayEXISTS AS-ISverify-webhook/{hash}Reuse
PayPal subscriptions / recurringEXISTS AS-ISPaypalControllerReuse
Offline payment methodsEXISTS AS-ISOfflinePaymentMethodReuse
Purchase Order workflowPARTIALGeneric offline onlyBUILD: PO upload, PO #, approval state
Net-30 / Net-60 termsMISSINGInvoice has no terms fieldBUILD per-customer-group terms + AR aging
Credit limit enforcementMISSINGBUILD on customer group
Store creditsPARTIALCompanyAddonCredit + credit notes (invoice-side)BUILD customer-side ledger usable at checkout
Rewards / loyalty pointsMISSINGBUILD points ledger + earn/redeem rules
Gift cardsMISSINGBUILD (Magento parity)
Refunds & partial refundsSTUB ONLYorafol/reports/refunds viewWire to gateway refund APIs
Multi-currencyMISSINGBUILD if Canada operations need CAD

2.5 Shipping & Fulfillment

FeatureStatusWhereAction
Shippo (multi-carrier aggregator)EXISTS AS-ISapp/Helper/Shippo.phpReuse for rates/labels
UPS direct APIPARTIALShippingMethodCredentials + UPS viewImplement rate + label calls
USPS / FedEx directPARTIALEnums in credentials tableImplement; OR use Shippo umbrella
Freight (LTL) carriersMISSINGBUILD or use Shippo Freight
Group-based shipping rulesSTUB ONLYorafol/shipping_restrictions.blade.phpBUILD rule engine: zone, weight, group, total
Shipping zonesMISSINGBUILD (Magento has zones & methods OOTB)
Bulk UPS tracking importMISSINGBUILD CSV importer + queued attach
Customer-provided shipping labelsMISSINGBUILD checkout step + storage
Fulfillment dashboard (pick/pack/ship)MISSINGBUILD module — biggest fulfillment gap
Automated order routingMISSINGBUILD: by location, SKU, group → warehouse
Drop-ship workflowMISSINGBUILD if vendor drop-ship needed
Tax engine (Avalara / TaxJar)MISSINGBUILD: SOW silent; US+CA tax is non-trivial

2.6 Integrations & Operations

FeatureStatusWhereAction
ORAFOL BE (US & CA)MISSINGBUILD — XL connector
HubSpot CRMMISSINGBUILD contact/deal sync
Constant ContactMISSINGBUILD readiness hooks (SOW says “future”)
QuickBooksEXISTS AS-ISquickbooks/v3-php-sdkVerify wired up; available
SendGrid (email + webhook)EXISTS AS-ISapp/Helper/Sendgrid.phpReuse
Twilio SMSEXISTS AS-IScomposer depReuse
OpenAI / Mira AIEXISTS AS-ISapp/Helper/OpenAi.phpReuse for product descriptions, search suggestions
Zoom / Google CalendarEXISTS AS-ISComposer depsOut of scope for ORAFOL
IssuuMISSINGBUILD embed integration
Sentry error trackingEXISTS AS-ISconfig/sentry.phpVerify enabled in prod

3Frontend Features & Login Architecture

3.1 Frontend Shop — What customers see

Page / FeatureURL / ViewStatusNotes
Storefront home/shopfront/shop/index.blade.phpHAVETheme-driven
Product detail/shop/product/{slug}details.blade.phpHAVEVariant selector, wishlist, inquiry
Category browseCategory routes → _widget-store-categoryHAVERecursive nesting
Search + filterSidebar widgets (price, color, attribute)PARTIALNo search index; client-side filter only
Cartcart.blade.php + _sidebar-cartHAVEGuest + logged-in supported
Checkoutcheckout.blade.php (34 KB)HAVEComprehensive; all 9 gateways selectable
Order confirmationorder.blade.phpHAVE 
My ordersmy_orders.blade.phpSTUB297 bytes — needs full implementation
Customer dashboard/member/dashboardHAVEMemberController
Customer addressesMember areaHAVE 
WishlistMember areaHAVEproduct_wishlists table
Inquiry / quote modal_inquiry-modal.blade.phpPARTIALCaptures interest; no quote → order conversion
Abandoned cart recoveryBackground jobHAVEFull state machine: abandoned→email_sent→recovered
Quick reorderMISSINGBuild “reorder this” on order detail
Requisition listsMISSINGBuild (B2B essential)
SKU paste pad (bulk add)MISSINGBuild (B2B essential)
Sub-account self-serviceorafol scaffoldSTUBUI exists, no logic
Order approval queueorafol scaffoldSTUBUI exists, no logic
Reviews & ratingsMISSINGBuild module
Compare productsMISSINGBuild (low priority)

3.2 Login Types on Frontend — CRITICAL

The platform has 4 distinct authentication guards. Mapping them and clarifying the ORAFOL deployment use is essential before kickoff.

GuardLogin URLModel / TablePurposeStatus
web/loginUserAuth / usersInternal staff (NH employees, ORAFOL admins)ACTIVE
admin/loginUserAuth / usersSame as web — explicit admin guardACTIVE
customer/signinCustomer / tbl_customersStorefront / distributors / B2B — this is what ORAFOL distributors will useACTIVE
apiSanctum bearerRestAPI\UserAuth / usersHeadless API consumersACTIVE

What ORAFOL distributors will need

  • Single login URLportal.orafol.com/signin goes to customer guard
  • Username OR email login — already supported in MemberController::authentication()
  • 2FA on customer guard — currently only on web/admin guard. EXTEND
  • Email verification — supported via email_verified_at + token route
  • Password reset/member/forget-password exists
  • Magic link / OTP — not present, build if requested
  • SSO / OKTA — not present; ORAFOL employees may want this for admin login
  • Invite-only signup/invitation/{code} exists; needs sub-account flow on top
  • Role/account switcher after login — if a single user belongs to multiple ORAFOL distributors, they need a context picker. BUILD

3.3 Theme System

29 themes under themes/frontend/. ORAFOL will need either a custom theme or a fork of shop / radiant. Theme is selected per-company. Customizable: header, product cards, checkout form fields, color scheme, language files (54+ via laravel-lang/lang).

Theme proliferation is tech debt. 29 themes, many for unrelated verticals (recruitment, crypto, fundraising). Recommend pruning before ORAFOL launch — each theme is a maintenance surface for security patches and library upgrades.

4Payment Integrations — All Gateways

Missio already has 9 production-grade payment gateways, far more than most Magento installs run. The PDF requirement (PayPal + purchase orders + bank transfers) is fully covered by what exists.

GatewayControllerModesWebhooksRecurringSOW Match
StripePayment/StripeController.phplive / testYESIndirect (via cart)
PayPalPayment/PaypalController.phplive / sandboxYESYESRequired by SOW
SquarePayment/SquareController.phpsandbox / prodYES
Authorize.NetPayment/AuthorizeController.phpsandbox / live(direct)YES
RazorpayPayment/RazorPayController.phplive / testYESYESIndia only
MolliePayment/MollieController.phplive / testYESEU
FlutterwavePayment/FlutterwaveController.phplive / testYESAfrica
PayFastPayment/PayfastController.phplive / testYESSouth Africa
PaystackPayment/PaystackController.phplive / testYESAfrica
Offline (PO / bank transfer)OfflinePaymentMethodn/aRequired by SOW

4.1 Magento gateways NOT in Missio (parity check)

Magento gatewayStatus in MissioRecommendation
BraintreeMISSINGSkip — PayPal covers (Braintree owned by PayPal)
AdyenMISSINGSkip unless ORAFOL EU subsidiary requests
Klarna / Affirm (BNPL)MISSINGBUILD if consumer-facing; not needed for B2B distributors
Apple Pay / Google PayMISSINGStripe wrappers can add; low priority for B2B
Amazon PayMISSINGSkip
Worldpay / CyberSourceMISSINGSkip unless explicitly required
ACH / PlaidMISSINGBUILD if direct-debit needed for distributor net-terms collection

4.2 ORAFOL-specific payment requirements (from SOW)

SOW Section: Payments & Credits
  • Rewards point programs — BUILD
  • Store credits — EXTEND (have invoice-side, need customer-side)
  • PayPal payments — HAVE
  • Purchase orders / bank transfers — EXTEND (offline method exists; add PO upload + PO# + approval)
  • Charge-to-account invoicing with payment terms — BUILD (Net-30/60, credit limits, AR aging)

53rd-Party Integrations — Complete Inventory

5.1 What's installed (composer.json + helpers)

Email
SendGrid ✓MailgunPostmarkAWS SESSendgrid Inbound Parse ✓
Notifications
TelegramOneSignal (push)SlackTwilio (SMS)Vonage (SMS)
Shipping
Shippo ✓ReachShip (planned)UPS (creds)USPS (creds)FedEx (creds)
Payments (covered above)
StripePayPalSquareAuthorize.NetRazorpayMollieFlutterwavePayFastPaystack
CRM & Marketing
Google CalendarHubSpot — BUILDSalesforce — BUILDConstant Contact — BUILDKlaviyo — BUILD
AI / Content
OpenAI ✓Mira AI ✓Google TranslateDOMPDF (invoices)Intervention/Spatie Image
Auth / OAuth
Google ✓Facebook ✓Twitter ✓Microsoft — MISSINGOKTA / SAML — MISSING
Accounting / Tax
QuickBooks ✓Xero — MISSINGAvalara — MISSINGTaxJar — MISSING
Storage / Files
AWS S3 ✓DO Spaces (compatible)Issuu — BUILD
Conferencing / Calendar
Zoom ✓Google Calendar ✓
Analytics / Errors
Sentry ✓Google Analytics (JS)Mixpanel — MISSING
ERP / Connectors (ORAFOL critical)
ORAFOL BE — BUILD XLKathy's facility — BUILDGeneric ERP framework — BUILD

5.2 Integration risk profile

IntegrationTypeCouplingRisk
9 payment gatewaysAPI + webhookLoose — per-company credsLow
ShippoAPI onlyHelper classLow
SendGridAPI + inbound webhookHelperLow
ORAFOL BEBi-directional API + cronWill be tight (orders/inventory critical path)HIGH — spec unknown
Kathy's facilityBi-directionalTight (inventory truth source)HIGH — system unknown
HubSpotAPI + webhookNew buildMedium
QuickBooksOAuth + APILooseLow (already installed)

6Technical Debt Analysis

6.1 Fragile / hardcoded logic

IssueWhereImpact
Tenant-specific UI gatingstore.blade.phpGetCompanyId() == 100Hardcodes ORAFOL ID. Replace with features('orafol_b2b') flag.
Auth in model accessorsProduct::getPriceAttribute() — reads Auth::guard('customer')Breaks background jobs, API context, sales-rep impersonation. Refactor to pricing service.
Stripe creds split pathscompany.stripe_mode direct fields vs. PaymentGatewayCredentialsDual sources of truth. Standardize on credentials table.
Type-overloaded OrderCarttype='item' + type='discount' in same tableEasy to forget filter. Consider separate cart_adjustments table.
29 themesthemes/frontend/*Maintenance surface for security patches; many for unrelated verticals
Mixed table prefixestbl_customers vs usersIndicates fork merge history; cosmetic but confusing
Stub my_orders.blade.php297 bytesCustomer order history feature is missing on storefront

6.2 Performance bottlenecks & scaling risks

  • No search index. 7,000 SKU target needs Meilisearch or Algolia (Laravel Scout). Current LIKE-based queries will not scale.
  • No DB indexes confirmed on OrderCart.cart_id, products.sku, customer_groups.parent_id. Audit indexes during Phase 1.
  • Pricing accessor on every product render reads auth guard. Hydrating a 50-product page = 50 auth calls. Cache or batch.
  • No HTTP caching layer (Cloudflare / Varnish). Magento has built-in FPC. Plan CDN + cache for catalog pages.
  • Single-stock field = race conditions on concurrent checkout. Move to reservation pattern with row-level locks or Redis counters.
  • Job queue unclear. No Horizon visible; check if abandoned-cart job runs on supervisor or cron+work.

6.3 Duplicate logic

  • Pricing logic duplicated between Product::getPriceAttribute() and ProductVariant::getPriceAttribute().
  • Three contact-route files: contacts.php, contacts_old.php — legacy not yet removed.
  • Multiple mail providers configured (SendGrid, Mailgun, Postmark, SES) — pick one and remove others or document tenant choice.

7Migration Strategy — Magento → Missio

7.1 What we REUSE from Missio

Multi-guard auth, 2FA, social loginREUSE
Product / Variant / Attribute CRUDREUSE
Customer groups + group-product visibilityREUSE
Cart + Checkout API (CartController, CheckoutController)REUSE
9 payment gateways + webhook frameworkREUSE
Coupons + abandoned-cart recoveryREUSE
Wishlist, addresses, member dashboardREUSE
SendGrid, Twilio, OpenAI, Sentry, S3, QuickBooksREUSE
Theme system (one custom ORAFOL theme)REUSE + EXTEND
25+ ORAFOL stub routes/viewsUI READY — WIRE BACKEND

7.2 What we REBUILD (in Missio)

Parent/child company hierarchyBUILD
Multi-warehouse inventoryBUILD
Tiered pricing (qty breaks) + catalog price rulesBUILD
Net-terms invoicing + AR aging + credit limitsBUILD
Fulfillment dashboard + automated routingBUILD
Group-based shipping rulesBUILD
Quote / RFQ → Order conversionBUILD
Requisition lists / saved cartsBUILD
Quick-order SKU padBUILD
Rewards points + customer-side store creditBUILD
Bulk UPS tracking importBUILD
Customer-provided shipping label workflowBUILD
Sub-account self-service (invite, manage children)BUILD
Sales-rep regional dashboard scopingBUILD

7.3 What we REPLACE with SaaS / 3rd-party

CapabilityReplace withWhy
Magento searchMeilisearch (self-host) or Algolia7K SKU faceted search at scale; Laravel Scout integration
US + Canada sales taxAvalara or TaxJarMulti-state/province compliance — not worth building
Multi-carrier shippingShippo (already installed) or EasyPostOne API for UPS/USPS/FedEx/freight + label printing
Magento email templatesSendGrid Dynamic TemplatesEditable in SendGrid UI; no code deploy for copy changes
Magento CMS pagesExisting Missio CMS moduleAlready in code (CMS Pages API)
Magento product reviewsYotpo / TrustPilot widgetSaaS solves moderation, photo reviews, Google snippets
Issuu literatureIssuu embed widgetPer requirement
Error trackingSentry (already installed)

7.4 What we REMOVE / hide for ORAFOL tenant

  • Donations, donors, donation-pages, P2P, pledges, grants, RFPs, video interviews, donation events — HIDE via tenant module flags
  • Recruitment module, gallery, forum, channels — HIDE
  • 27 of 29 themes (keep ORAFOL custom + shop base) — PRUNE from tenant
  • contacts_old.php route file — DELETE

8Recommended Target Architecture

Per the SOW, Missio is delivered as three layers. Here's how to align the Laravel codebase to that model.

Layer 1 Experience Layer

Customer-facing storefront, admin UI, mobile API.

  • Storefront: One ORAFOL custom theme under themes/frontend/orafol/. Distributor portal, catalog browse, cart, checkout, account.
  • Admin: Existing Bootstrap admin under /account/*. Orders, products, customers, reports.
  • Mobile-ready: SOW says “mobile-first.” Reuse existing API/Shop endpoints for future native app.
  • Auth: customer guard for distributors, web/admin for ORAFOL staff. Add SSO if requested.

Layer 2 Core Business Logic Layer

Pricing, catalog, orders, inventory, customers — tenant-isolated services.

  • Pricing Service: Extract from Product accessors. Inputs: product, variant, customer, qty, group. Output: unit price + applied rules. Reusable from background jobs.
  • Catalog Service: Product, variant, attribute, category. Backed by Meilisearch index for facet search.
  • Order Service: Cart → Order → Fulfillment lifecycle. State machine. Hooks for ERP sync.
  • Inventory Service: Multi-location. warehouses, inventory_locations, inventory_movements. Reservation API.
  • Customer Hierarchy Service: Companies (parent/child), users, customer groups, role scoping. Single source of truth for “what can this user see?”
  • Pricing & Discount Engine: Group tiers + catalog price rules + cart price rules + coupons composed in defined order.
  • Fulfillment Service: Pick/pack/ship state machine. Order routing rules. Carrier label generation via Shippo.

Layer 3 Integration Layer

External system connectors. Idempotent, observable, retryable.

  • ERP Connector Framework: Generic base class. Concrete implementations: ORAFOL BE (US), ORAFOL BE (Canada), Kathy's facility.
  • Outbound: Order created, inventory adjusted, customer updated → queued job → ERP. With retries + dead-letter queue.
  • Inbound: Webhook + scheduled poll. Inventory deltas, invoice paid, shipment confirmed.
  • HubSpot Connector: Customer → Contact, Order → Deal sync. Webhook on contact updates.
  • Tax Connector: Avalara/TaxJar at cart total time.
  • Shipping Connector: Shippo for rates + labels + tracking.
  • Payment Connectors: 9 existing gateways. Standardize creds path.
  • Observability: Every external call logged to integration_logs table + Sentry breadcrumbs. Build a /account/integration-hub page (orafol stub already exists).

8.1 Event-driven design

Use Laravel events for cross-layer hooks. Examples:

OrderPlaced       → ERP outbound + HubSpot deal + email + inventory reserve
OrderShipped      → Customer email + ERP update + tracking webhook
InventoryAdjusted → ERP outbound + low-stock alert if threshold
CustomerCreated   → HubSpot contact + welcome email
PaymentCaptured   → QuickBooks invoice + gateway webhook log

8.2 Data ownership

EntityOwnerSync direction
Products (master)ORAFOL BEInbound to Missio
Products (storefront content: descriptions, images)Missio adminLocal only
Customers / DistributorsMissio (with HubSpot mirror)Bi-directional with HubSpot
OrdersMissioOutbound to ORAFOL BE
Inventory levelsORAFOL BE / Kathy's facilityInbound to Missio
Invoices & ARORAFOL BEInbound (status to Missio for AR display)
Reward pointsMissioLocal

9Gap Analysis — Master Table

FeatureCurrent StateTarget StateGapActionEffort
Parent/child companycustomer_groups have parent_id onlyFull company hierarchy with cascade scopescompanies.parent_company_id missingBuild migration + Eloquent scopes + dashboard rollupL
Self-service sub-accountsUI scaffold in orafol/parent_accountsParent invites & manages childrenNo backend logicWire invite flow + permissions middlewareL
Sales-rep regional scopingNoneReps see only assigned region/groupNo region model, no scopeBuild sales_rep_regions + dashboard scopeL
Tiered pricing (qty)Group % discountQty 1-9, 10-49, 50+ pricing per groupNo price_tiersNew table + price service hookM
Catalog search indexSQL LIKEFaceted, sub-100ms at 7K SKUsNo indexAdd Meilisearch + ScoutL
Grouped productsNoneBundle/grouped product typeNo modelBuild product_groups pivotM
Issuu literatureProductFiles onlyIssuu embed per productNo embedAdd field + render widgetS
Multi-warehouse inventorySingle stock fieldPer-location stock + reservationNo location tableswarehouses, inventory_locations, inventory_movementsL
ORAFOL BE ERP syncNoneBi-directional inventory/orders/invoicesNo connectorBuild connector framework + 2 implementations (US/CA)XL
Kathy's facility connectorNoneTwo-way inventory + ordersSpec unknownDiscovery call + custom connectorL
Net-30/60 invoicingInvoice has no termsPer-customer-group payment termsNo terms field, no AR agingSchema + AR dashboardL
Credit limitsNonePer-customer-group cap with checkout enforcementNo fieldSchema + checkout guardM
Customer-side store creditInvoice-side onlyApply at checkoutNo customer ledgercustomer_credits + checkout stepM
Rewards pointsNoneEarn / redeem with rulesNo ledgercustomer_points + earn rules + checkout redeemL
PO upload & workflowGeneric offline paymentPO #, file upload, approval stateNo PO fieldsExtend OfflinePaymentMethodM
Group-based shipping rulesUI scaffoldRule engine: zone+weight+group+totalNo engineshipping_rules table + evaluatorM
UPS / USPS / FedEx fullCredentials onlyLive rate quote + label printNo API callsUse Shippo umbrella OR direct APIsL
Bulk tracking importNoneCSV upload → attach to ordersNo importerMaatwebsite/excel jobS
Customer-provided labelsNoneCustomer uploads label/account at checkoutNo checkout stepAdd step + storageM
Fulfillment dashboardNonePending/picked/packed/shipped queueNo moduleBuild module with role-scoped viewsL
Automated order routingNoneRules: by SKU/group/location → warehouseNo rule enginerouting_rules + listener on OrderPlacedM
HubSpot CRMNoneContact + Deal bidirectionalNo connectorHubSpot SDK + sync jobs + webhooksM
Constant ContactNoneFuture-ready hooks (per SOW)No event hooksExpose customer-created event with API key fieldS
Tax engine (Avalara/TaxJar)NoneLive tax calc at checkoutNo connectorAdd at cart total stepM
Quote / RFQ workflowInquiry modalDistributor requests → rep approves → converts to orderNo state machinequotes table + approval UIM
Requisition listsNoneMultiple named saved carts per buyerNo modelrequisition_lists + itemsM
Quick-order SKU padNonePaste SKU+qty → cartNo UIPage + bulk-validate APIS
Reorder from past orderNone (my_orders is stub)One-click reorderStub viewImplement my_orders + reorder actionS
Product reviewsNoneReviews + ratings + moderationNo moduleBuild OR integrate YotpoM
2FA on customer guardAdmin onlyOptional 2FA for distributorsCustomer guard lacks 2FAPort from LoginController to MemberControllerS
SSO / OKTANoneOptional ORAFOL employee SSONo SAMLlaravel-saml2 if requestedM
Customer order historymy_orders.blade.php stubFull order history with reorder/trackStubBuild view + controllerS
Pruning unused modules29 themes, donation/event modules visibleClean ORAFOL tenant viewTenant feature flags looseModule visibility per companyS

10Risk Assessment

10.1 Migration risks

RiskSeverityLikelihoodMitigation
ORAFOL BE API spec poorly documentedCriticalHighRequest docs in kickoff week 1; build mock layer; budget contingency
Kathy's facility unknown systemCriticalHighDiscovery call week 1–2; bring connector spec back to scope
Magento data export qualityHighMediumSample 100 SKUs week 2; validate images, attributes, prices
Tax engine omitted from SOWHighHighConfirm Avalara/TaxJar with ORAFOL week 1; price as change order if needed
Catalog at 7K SKU scaleMediumMediumAdd Meilisearch by week 4; load-test with synthetic data
Theme/UI sign-off delayMediumHighLock design in week 2; iterate inside ORAFOL theme only
10% contingency too tightMediumHighStrict change-order discipline; weekly scope review

10.2 Data risks

  • Customer data dual-source. If HubSpot and Missio both let users edit a customer, conflict resolution rules must be defined.
  • Inventory truth source. ORAFOL BE is master, but during outage the portal must show last-known with timestamp + degraded indicator.
  • Pricing drift. If catalog prices are master in BE but admins also edit in Missio, customers see inconsistencies.
  • PII handling. Distributor company info, addresses, payment methods. Confirm SOC 2 / GDPR posture for ORAFOL legal review.

10.3 Integration risks

  • Cascading failures. ERP outage should not block checkout. Build queue-and-retry pattern; never sync orders inline.
  • Webhook replay attacks. Audit all 9 payment-gateway webhook signature verifications.
  • Rate limits. HubSpot, Shippo, Avalara all rate-limit. Design batch + backoff.

10.4 Business continuity

  • Cutover strategy. Hard cutover or parallel-run with Magento? Recommend 2-week parallel run with traffic split.
  • Rollback plan. Keep Magento read-only for 90 days post-launch.
  • SLA target 99.9% per SOW = 43 min downtime/month. Realistic with Sentry + uptime monitoring + Horizon.
  • Distributor training. 14–16 weeks is tight for a 7K SKU catalog launch. Schedule training weeks 12–14 with at least 2 sessions.

11Prioritized Execution Plan

11.1 First 2 weeks (foundation + de-risk)

  1. Day 1–3: Replace GetCompanyId() == 100 with feature flag features('orafol_b2b'). Hide unused modules for ORAFOL tenant. Standardize Stripe creds path.
  2. Day 3–5: Kickoff calls — ORAFOL BE API docs request, Kathy's facility discovery, tax engine decision (Avalara vs. TaxJar vs. zone), Magento export audit.
  3. Week 2: Add companies.parent_company_id migration. Build multi-warehouse schema. Spike Meilisearch + Scout with 100 SKUs. Build ERP connector base class with mock implementation.

11.2 Phased plan vs. SOW timeline

PhaseWeeksDeliverables
Foundation1–3Feature flag, parent/child company, multi-warehouse schema, payment-creds standardization, search index spike
ERP & Integrations3–7ORAFOL BE connector (US + CA), Kathy's facility, HubSpot, Avalara/TaxJar, Shippo full
Catalog & Portal6–10Meilisearch live with 7K SKUs, tiered pricing, Issuu, sub-account UI, sales-rep scoping, ORAFOL theme
Order & Fulfillment9–12Net-terms, PO workflow, fulfillment dashboard, group shipping rules, bulk tracking import, customer labels, automated routing
B2B Niceties10–13Quote/RFQ, requisition lists, quick-order pad, reorder, customer order history, store credits, rewards
Testing / UAT12–14Load test, ERP failure scenarios, security review, performance audit
Training & Launch14–16Admin training, distributor training, parallel run with Magento, hypercare

11.3 Highest-risk items (start earliest)

  1. ORAFOL BE connector — XL, spec unknown, blocks order flow
  2. Kathy's facility connector — L, spec entirely unknown
  3. Multi-warehouse inventory — L, blocks Kathy + BE inventory sync
  4. 7K SKU catalog import + search — L, performance unknown
  5. Tax engine decision — M, may need change order

11.4 Fastest ROI items (quick wins)

  1. Replace tenant ID hardcode with feature flag — S
  2. Implement my_orders.blade.php + reorder — S
  3. 2FA on customer guard — S
  4. Quick-order SKU pad — S — high distributor delight
  5. Bulk UPS tracking import — S — immediate ops time savings
  6. Issuu embed — S
Architecture principle for the team Treat every ORAFOL stub view in routes/orafol.php as a spec that the client has implicitly approved. Wiring the backend behind those scaffolds is the fastest visible-progress path. Don't refactor the views; build the services and controllers behind them.