venturedrake/laravel-crm-filament
Filament plugin that brings VentureDrake's Laravel CRM into your admin panel. Provides ready-to-use Filament resources, forms, and tables for managing CRM contacts, companies, deals, and activities, so you can run your CRM from an existing Filament dashboard without building custom CRUD screens.
The panel now tracks core ~2.5.0 (was ~2.4.2). This is a coordinated upgrade, not a panel-only bump — variations only persist through core 2.5.0's services, and core 2.5.0 deletes the ProductAttribute model the panel's Product Attributes page was built on.
composer update venturedrake/laravel-crm venturedrake/laravel-crm-filament
php artisan laravelcrm:filament-update
laravelcrm:filament-update runs core's laravelcrm:update, which runs core 2.5.0's three migrations: variation columns, purchase-order line comments / order_product_id columns, and removal of the crm product attributes permissions.
First steps:
composer.json resolves venturedrake/laravel-crm to ~2.5.0. Do not leave core on 2.4.x — the panel will not install against it.php artisan laravelcrm:filament-update, then confirm laravelcrm:filament-upgrade is present in your post-autoload-dump composer hooks. That command now runs filament:assets too, which is what republishes the stylesheet after a Filament update.filament.*.resources.product-attributes.*. Replace with custom fields attached to Products.dcblogdev/laravel-xero is installed and shows the install notice rather than a broken Connect button.Where to look first:
ProductService::syncVariations() — the panel hands rows to it on save.Support\XeroIntegration if you need to gate your own Xero-related UI the same way the panel does.encrypt_db_fields, teams, and user interface mode.Upgrade core and panel as one unit, and keep Xero in the same deploy. Core 2.4.5 moved dcblogdev/laravel-xero from require to suggest. If you upgrade without adding the package yourself, Xero silently stops syncing — no error, no failed job. The pattern is unchanged:
composer require dcblogdev/laravel-xero:^1.1.3
Tokens and crm_xero_* rows are preserved, so reinstalling restores the connection without re-authorising. The panel still caps Guzzle at ^7.
Migrate product attributes to custom fields before you upgrade. Core 2.5.0 removes the crm product attributes permissions and the model; the panel removes ProductAttributeResource and its pages with it. If you store attribute data, export it and re-model it as custom fields on Products. Audit your seeders, Spatie permission lists, and any nav/footer links to those route names — route generation will throw once the resource is gone.
Let syncVariations() own variation lifecycle. The panel saves variations by handing rows to core's ProductService::syncVariations(). Key behaviours to preserve in any custom form:
Replicate the variation select in custom line-item forms. The select only appears for a product with active variations, or for a line already on one. Picking a variation prices the line from the variation's price in the document currency, falling back to the product price. Changing the product clears the variation — mirror that in any custom Livewire component or you'll persist a variation that belongs to a different product. Edit forms load each line's existing variation, so your form hydration must too.
Conversions carry the variation — rely on it, don't recompute. Quote → order, order → invoice, and order → purchase order all carry the variation. Order → purchase order uses the variation's own price row (cost_per_unit, then unit_price) when one exists. The delivery and purchase-order line pickers show Product — Variation, and PDFs, emails, and the portal print it through core's views. If you have custom conversion code, delete it and let core's services do the work.
Link the contact and organization yourself on custom pages. Saving a lead, deal, quote, order, invoice, or purchase order with both a contact person and an organization now makes them related contacts of each other via core's PersonService::linkToOrganization(). Core makes this call in its Livewire components rather than its services, so the panel's pages call it explicitly — your custom pages must too. An existing link is not duplicated, so the call is safe to repeat.
Fix the purchase-order line override. Core 2.5.0's PurchaseOrderService::update() reads the products rows the form submits. The panel's purchaseOrderLines shim is removed. Any custom code that pushed state through that property needs to submit products rows in the shape core expects.
Treat encryption as a search-mode switch. With encrypt_db_fields enabled, contact and organization names are ciphertext, Filament's SQL LIKE cannot match them, and the panel decrypts and matches in PHP for the lead, deal, quote, order, invoice, and purchase-order pickers, plus title search on lead, deal, and quote tables. With encryption off, pickers search in SQL. If you add custom pickers, reuse the panel's components or explicitly branch on the setting, and scope the candidate set before decrypting.
Preserve eager loads when overriding tables. The panel ports core's N+1 fixes into its index pages: People email/phone read eager-loaded collections (not getPrimaryEmail() / getPrimaryPhone()), "Next activity" uses one withMin() subselect, organizations eager load the Xero contact link, products read eager-loaded productPrices for the default price, deliveries read eager-loaded addresses, purchase orders check an eager-loaded Xero link for Edit/Delete, and the activity feed loads each row's causer and recordable. A custom accessor that calls getPrimaryEmail() or a tasks() relationship reintroduces the per-row queries the panel just removed.
Keep board filters server-side. The Owner filter lists up to 20 owners, keeps the selected owner visible even outside that window, and shows a search box beyond that. The bulk Assign owner action searches on the server. Follow that pattern for custom board actions instead of shipping every user as <option> tags.
Handle headless installs explicitly. When LARAVEL_CRM_USER_INTERFACE=false, core does not register the Connect and Disconnect routes. The panel hides those buttons; custom pages and actions should guard with Route::has() or the same config flag.
Use the panel's Xero gate for your own integration UI. The panel gates on Support\XeroIntegration, which probes the package's service provider the way core does. Core's own XeroIntegration class only exists from 2.4.5, so if you still support older cores anywhere in your fleet, use the panel's support class or your own feature probe.
This release requires core 2.5.0. The panel's constraint is ~2.5.0. Any deployment pipeline that pins core to ~2.4.x will fail to resolve. Roll both packages in one commit and one deploy — a panel-only update leaves you with a Product Attributes page whose model no longer exists.
ProductAttributeResource and its routes are gone. Hosts linking to filament.*.resources.product-attributes.* will throw. Grep your nav registrations, dashboards, email templates, and bookmarks.
The product-attributes permissions migration deletes rows. If you seeded or assigned crm product attributes permissions, roles referencing them lose that entry. Check admin roles after the update, and remove the permission from any seeder to avoid re-creating a now-meaningless record.
Sideways scrolling on tables was broken by a stale Filament stylesheet. A host whose composer hooks never ran filament:upgrade kept serving the stylesheet from its first install; on Filament v5 that copy sized the content area at 100vw beside the sidebar, so the right-hand side of every resource table — scrollbar included — sat off-screen. laravelcrm:filament-upgrade, added to post-autoload-dump by the installer, now runs filament:assets so every composer install republishes it. If you manage composer scripts yourself, verify the hook exists; otherwise run php artisan filament:assets once manually after the upgrade.
Purchase-order line edits silently failed before this release. If you patched around the purchaseOrderLines shim, remove the patch — the property is gone and core reads products rows now.
Quote → order conversion used to throw. The labels copy plucked crm_labelables.id, a column the pivot table doesn't have. If you have a workaround wrapped around conversion, unwrap it and re-test the label carry-through.
A variation with no price is not free. It sells at the product price. When converting order → purchase order, the variation's own price row (cost_per_unit, then unit_price) wins if one exists; otherwise the product cost applies. Check margin reports after migrating products that previously had a single price.
Changing the product clears the variation. If you have custom JS or Livewire line-item components, replicate that reset or you'll submit a mismatched variation/product pair.
Xero still fails silently after a core upgrade. Even on 2.5.0, if you don't require dcblogdev/laravel-xero yourself, nothing errors. The Integrations page shows an install command instead of "Connect Xero". Check that page after every core upgrade.
Watch the Guzzle constraint. The panel caps Guzzle at ^7. Composer reports the conflict at install time, but the interaction with the Xero package is easy to miss.
Contact ↔ organization links are not retroactive. Saving with both present links them going forward; records saved before this release keep whatever link state they had. Backfill with PersonService::linkToOrganization() if you need existing pairs related — it won't duplicate an existing link.
Multi-currency product pricing changed behaviour. The edit form now uses Product::getPrimaryPrice(), matching core 2.5.0. Previously, a product priced only in a currency other than the install's loaded blank and saving overwrote that price. Re-check any product you edited under the old form.
Headless mode has no Connect/Disconnect routes. The panel hides those buttons when LARAVEL_CRM_USER_INTERFACE=false, but custom links or redirects to those route names throw RouteNotFoundException.
Clearing a relationship is a real update. On quote, order, invoice, and purchase-order edit pages, submitting an empty contact or organization select unlinks it. A field absent from the request still keeps the link. Custom form logic treating an empty select as "leave unchanged" needs updating.
Debug N+1 regressions with your overrides in mind. Use Laravel Debugbar or Telescope on the People, Organizations, Products, Deliveries, and Purchase Orders index pages after customizing them — especially the Products index, which now resolves variation SKUs.
Extension points to prefer: override Filament resources and tables rather than duplicating panel pages; route variation writes through ProductService::syncVariations(); reuse Support\XeroIntegration for Xero availability checks; use the panel's picker components for encrypted-name search; and keep board filters server-side past 20 users.
How can I help you explore Laravel packages today?