Skip to content

[Products]: Upload one or more Product Images for invoice/quote display #388

Closed as duplicate

Description

@pouyiouk

Duplicate of #63 — which has a full SMART spec and acceptance criteria for product image uploads visible on quotes and invoices.

Please follow #63 for updates and contribute discussion there.

Activity

  1. changed the title [-][Feature request] Product Images[/-] [+][Feature request] bring able to upload ine or more Product Images and attach it to quotes[/+] on Feb 9, 2023
  2. changed the title [-][Feature request] bring able to upload ine or more Product Images and attach it to quotes[/-] [+][Feature request] bring able to upload ine or more Product Images and attach it to quotes and invoices[/+] on Feb 9, 2023
  3. changed the title [-][Feature request] bring able to upload ine or more Product Images and attach it to quotes and invoices[/-] [+][Feature request] being able to upload ine or more Product Images and attach it to quotes and invoices[/+] on Feb 9, 2023
  4. changed the title [-][Feature request] being able to upload ine or more Product Images and attach it to quotes and invoices[/-] [+][Feature request] being able to upload one or more Product Images and attach it to quotes and invoices[/+] on Feb 9, 2023
  5. nielsdrost7 commented on Feb 9, 2023

    @nielsdrost7
    Collaborator

    Great job with the Feature Request.

    This would be a candidate for a new feature in v2

  6. nielsdrost7 commented on Jan 19, 2026

    @nielsdrost7
    Collaborator
  7. coderabbitai commented on Jan 19, 2026

    @coderabbitai
    Contributor

    Coding Plan

    Approach

    Add the ability to upload one or more images when creating/editing a product, and display those images in both Quote and Invoice PDF templates so clients can see visual representations of products being quoted or invoiced.

    Observations

    The application uses a modular Laravel architecture with Filament for admin interfaces. Products are managed in Modules/Products/ with a model, Filament resource, and schema-based forms. Products link to Quotes and Invoices through line item tables (quote_items, invoice_items) with product_id foreign keys. File uploads use Filament's FileUpload component with local storage at storage/app/private. PDF generation uses DomPDF/wkhtmltopdf with Blade templates in custom/templates/ directories, falling back to default templates. The Quote and Invoice PDF templates iterate through line items to render product details.

    Assumptions
    Assumption 1: Single Image vs Multiple Images

    Options Considered:

    • Single image field (image string) - Simpler but less flexible
    • Multiple images field (images JSON array) - More flexible, matches title requirement

    Chosen Option: 2

    Rationale: Implement multiple image support using a JSON array field, as the title explicitly requests "one or more" images and Filament's FileUpload component handles this natively with ->multiple().

    Assumption 2: Image Storage Approach

    Options Considered:

    • JSON array field on products table - Simple, no additional tables
    • Separate product_images table - More normalized, adds complexity
    • Spatie Media Library - Feature-rich but adds dependency

    Chosen Option: 1

    Rationale: Use a JSON array field (images) on the products table. This follows the existing pattern used by Filament FileUpload for multiple files, requires no additional dependencies, and keeps the implementation straightforward.

    💡 User Tips

    Regenerate the plan with different choices with @coderabbitai <feedback>.

    Implementation Steps

    Phase 1: Product Image Storage and Upload

    This phase adds the infrastructure for storing and uploading product images, including database schema changes, model updates, and the Filament form component.

    Task 1: Add Database Migration for Product Images

    Add a migration to store product images in the products table.

    • Create new migration in Modules/Products/Database/Migrations/ to add images column
    • Use JSON/text column type to store array of image paths
    • Column should be nullable since existing products won't have images
    Task 2: Update Product Model

    Extend the Product model to handle the new images field.

    • Update Modules/Products/Models/Product.php to add images to the $fillable array
    • Add cast for images field to array type so JSON is automatically serialized/deserialized
    • Add a helper method or accessor to retrieve full storage URLs for images if needed for template rendering
    Task 3: Add Image Upload to Product Form

    Add the FileUpload component to the product creation/edit form.

    • Update Modules/Products/Filament/Company/Resources/Products/Schemas/ProductForm.php
    • Add FileUpload::make('images') component following existing patterns from Settings.php logo upload
    • Configure with ->multiple(), ->image(), ->directory('products'), ->maxSize(2048), ->reorderable()
    • Enable image preview with ->previewable() and ->imagePreviewHeight('100')
    • Add appropriate label using translation key (add to language files if needed)
    • Position the field appropriately within the existing form layout
    🤖 Prompt for AI agents
    Add database support and UI for uploading multiple product images. The goal is
    to enable users to attach one or more images to products through the admin
    interface.
    
    - Create migration to add nullable `images` JSON column to products table
    - Update Product model: add `images` to fillable, cast to array, add helper
    method for full storage URLs
    - Add FileUpload component to ProductForm.php with multiple image support,
    preview, reordering, directory set to 'products', and max size 2048
    

    Phase 2: Display Product Images in PDF Templates

    This phase updates the Quote and Invoice PDF templates to render product images within line items, providing visual context for clients.

    Task 1: Update Quote PDF Template

    Modify the Quote PDF template to display product images alongside line items.

    • Update custom/templates/quote_templates/custom.blade.php
    • Within the line items loop (@foreach ($quote->items as $item)), add conditional image display
    • Check if $item->product exists and has images before attempting to render
    • Add an image column or inline image display within the product/description cell
    • Use appropriate sizing (thumbnails) to maintain PDF layout integrity
    • Handle multiple images by showing first image or a small gallery representation
    • Ensure backwards compatibility - items without products or products without images should render normally
    Task 2: Update Invoice PDF Template

    Modify the Invoice PDF template to display product images, mirroring the Quote template approach.

    • Update custom/templates/invoice_templates/custom.blade.php
    • Apply the same image display pattern implemented for Quote templates
    • Within the line items loop (@foreach ($invoice->items as $item)), add conditional image display
    • Maintain consistent styling and sizing with the Quote template
    • Ensure the product relationship is available (may need eager loading in Modules/Core/Support/HTML.php invoice method)
    Task 3: Ensure Product Relationship is Loaded for PDF Rendering

    Verify and update PDF rendering services to eager load product relationships with images.

    • Review Modules/Core/Support/HTML.php methods for quote and invoice rendering
    • Ensure items relationship eager loads the product: ->with('items.product')
    • This ensures product images are available without N+1 queries when rendering PDFs
    • Check both quote() and invoice() methods in the HTML support class
    🤖 Prompt for AI agents
    Display product images in Quote and Invoice PDF templates. The goal is to render
    product images within line items so clients see visual representations of
    products.
    
    - Update Quote PDF template: add conditional image display in line items loop,
    check for product and images, show thumbnails (first image or gallery), maintain
    layout and backwards compatibility
    - Update Invoice PDF template: apply same image display pattern as Quote
    template with consistent styling
    - Update HTML.php PDF rendering methods: eager load product relationship with
    `->with('items.product')` to avoid N+1 queries
    

    🚀 Next Steps

    🤖 All AI agent prompts combined
    Task: 1
    
    Add database support and UI for uploading multiple product images. The goal is
    to enable users to attach one or more images to products through the admin
    interface.
    
    - Create migration to add nullable `images` JSON column to products table
    - Update Product model: add `images` to fillable, cast to array, add helper
    method for full storage URLs
    - Add FileUpload component to ProductForm.php with multiple image support,
    preview, reordering, directory set to 'products', and max size 2048
    ===============================================================================
    
    Task: 2
    
    Display product images in Quote and Invoice PDF templates. The goal is to render
    product images within line items so clients see visual representations of
    products.
    
    - Update Quote PDF template: add conditional image display in line items loop,
    check for product and images, show thumbnails (first image or gallery), maintain
    layout and backwards compatibility
    - Update Invoice PDF template: apply same image display pattern as Quote
    template with consistent styling
    - Update HTML.php PDF rendering methods: eager load product relationship with
    `->with('items.product')` to avoid N+1 queries
    
    💡 Iterate on the plan with: @coderabbitai <feedback>
    Example Feedback
    - `@coderabbitai` You can skip phase 3. Add a simple unit test case for phase 2.
    - `@coderabbitai` For assumption 1 go ahead with option 3 and replan.
    

    💬 Have feedback or questions? Drop into our discord!

  8. nielsdrost7 commented on Jun 13, 2026

    @nielsdrost7
    Collaborator

    Planning Note — v2 Implementation

    Story: As a company admin, I want to upload a product image when creating or editing a product, so that the image appears on quotes and invoices to help clients identify exactly what they are purchasing.

    v2 context: The Product model is in Modules/Products/. v2 has an Upload model in Core. The product image should be stored via UploadService and the image URL made available to the invoice/quote PDF blade template.

    Acceptance Criteria:

    • Product create/edit form has an Image file upload field (accepted types: JPEG, PNG, WebP; max 2 MB).
    • The uploaded image is stored in storage/company/{company_id}/products/ and linked via an Upload polymorphic record.
    • The product image URL is available as $product->image_url (accessor).
    • On invoice/quote PDF templates, if a product has an image, it is rendered as a thumbnail (<img>) in the line item row.
    • Image display on the PDF is optional (configurable via a "Show product images on PDF" setting).
    • If no image is uploaded, no broken image placeholder appears.

    Implementation:

    • Add FileUpload::make('image') to Modules/Products/Filament/Company/Resources/Products/Schemas/ProductSchema.php.
    • Product::getImageUrlAttribute(): look up $this->uploads()->first()?->file_path and return Storage::url($path).
    • In the invoice PDF blade: @if($item->product?->image_url && $settings->show_product_images) ``&lt;img src="{{ $item-&gt;product-&gt;image_url }}" ...&gt;`` @endif.

    Test Scenarios (PHPUnit + Livewire):

    // Product image uploads and saves
    /* Arrange */ $product = Product::factory()->for($this->company)->create();
                  $file = UploadedFile::fake()->image('widget.jpg', 200, 200);
    /* Act */     app(UploadService::class)->attachToModel($file, $product);
    /* Assert */  $this->assertDatabaseHas('uploads',
                      ['uploadable_type' => Product::class, 'uploadable_id' => $product->id]);
    // image_url accessor returns correct URL
    /* Arrange */ $product = Product::factory()->for($this->company)->create();
                  app(UploadService::class)->attachToModel(UploadedFile::fake()->image('p.png'), $product);
    /* Act */     $url = $product->fresh()->image_url;
    /* Assert */  $this->assertStringContainsString('p.png', $url);
    // image_url returns null when no image uploaded
    /* Arrange */ $product = Product::factory()->for($this->company)->create();
    /* Assert */  $this->assertNull($product->image_url);

    Generated by Claude Code

  9. changed the title [-][Feature request] being able to upload one or more Product Images and attach it to quotes and invoices[/-] [+][Products]: Upload one or more Product Images for invoice/quote display[/+] on Jun 13, 2026
  10. added this to the v2.0.0-alpha milestone on Jun 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions