Get Plugin

Document Types

Document Types

Easy PDF Invoices for WooCommerce generates four document types and decides which one to render based on order status. This page explains each type, when it appears, and how to override the default behaviour.

The four types

Invoice

Used for orders awaiting payment.

  • Title: Invoice
  • No status badge
  • Shows Amount Due
  • Includes terms and conditions text (configurable on the Legal tab)
  • Triggered by: pending, on-hold, processing (when payment hasn't been confirmed by the gateway)

Receipt

Used for completed orders that have been paid.

  • Title: Receipt
  • PAID badge in green, top right
  • Caption: "Paid on [date] via [gateway]"
  • Shows the payment date and method below the badge
  • No terms section
  • Triggered by: completed, processing (when $order->is_paid() returns true)

Credit Note

Used for full or partial refunds.

  • Title: Credit Note
  • REFUNDED badge in red, top right
  • References the original invoice number
  • Shows refund total as a line item
  • Separate sequential numbering (e.g., CN-2026-000001)
  • Triggered by: refunded status, partial refund event

Packing Slip

Used for fulfilment.

  • Title: Packing Slip
  • No prices, no tax, no payment information
  • Includes: product name, SKU, quantity, weight (if available), order notes
  • Ship-to address prominently displayed
  • Optional QR code with order number for warehouse scanning (off by default)
  • Not auto-generated — created on demand from the admin

How the plugin decides

The plugin reads order status and uses this resolution order:

Order statusDocument typeNotes
PendingInvoiceAwaiting payment
On HoldInvoiceAwaiting confirmation
Processing (payment not confirmed)InvoiceOrder received but payment pending
Processing (payment confirmed)Receipt$order->is_paid() returned true
CompletedReceiptAlways shows PAID badge
RefundedCredit NoteREFUNDED badge, references original
Partial refundReceiptWith a refund line item shown in totals
FailedNo documentPlugin skips generation
CancelledNo documentPlugin skips generation
Scroll to see all columns →
Internally this lives in DocumentFactory::resolve_type(). Refunded → credit-note, paid → receipt, otherwise invoice. Failed and cancelled orders are skipped entirely.

Overriding the resolution

You can override the resolution per-order with the epdi_document_type filter:

add_filter( 'epdi_document_type', function( $type, $order ) {
    // Always render proforma-style invoices for B2B orders
    if ( $order->get_meta( '_b2b_proforma' ) === 'yes' ) {
        return 'invoice';
    }
    return $type;
}, 10, 2 );

You can also force a global default in WooCommerce > Settings > Invoices > General > Document type mode:

  • Auto (recommended) — uses the resolution table above.
  • Always Invoice — every order generates an Invoice, regardless of payment status.
  • Always Receipt — every order generates a Receipt with PAID badge.
The Auto mode is recommended for almost every store. The override modes exist for edge cases like B2B stores that always send invoices, or POS-style stores that always send receipts.

When documents are generated

PDFs are generated lazily — the plugin doesn't burn CPU rendering documents that no one will read.

TriggerWhat happens
Order status changesIf type changed, regenerate. Otherwise reuse.
WooCommerce sends an email with attachGenerate if missing, attach.
Customer downloads from My AccountGenerate if missing, stream the file.
Customer downloads from Thank You pageSame as My Account.
Admin clicks Download in the metaboxStream existing or regenerate if forced.
Admin clicks RegenerateAlways regenerate, replacing the previous file.
Bulk action on the order listRegenerate each order, inline up to 50, queued above.
Scroll to see all columns →
The status change handler (StatusListener) only regenerates when the resolved type differs from what's already stored. If an order moves from Processing to Completed and both resolve to Receipt, the existing PDF is reused. If it moves from Processing (Invoice) to Completed (Receipt), a fresh PDF is generated.

Number persistence across transitions

Once an invoice number is assigned to an order, it stays. If the order's document type changes (Invoice → Receipt → Credit Note), the same number is reused so your records stay clean.

For credit notes specifically, a separate sequential counter is used so credit note numbers don't collide with invoice numbers.

Refunds and partial refunds

When you process a refund through WooCommerce:

  • Full refund (status moves to "Refunded") → Credit Note is generated automatically.
  • Partial refund (refund recorded, status stays the same) → The current document (usually Receipt) regenerates with a refund line item shown in the totals section.
The plugin listens to both the customer_refunded_order and customer_partially_refunded_order email IDs so the right attachment goes out.

Packing slips on demand

Packing slips don't follow the auto-generation flow. They're created manually:

  • From the order edit screen, click Generate packing slip in the metabox.
  • From the order list, select multiple orders and use the Generate packing slips (ZIP) bulk action.
  • Optionally, enable Auto-attach packing slip to Customer Completed Order email in the Emails tab.
Use the Thermal template variant for 80mm POS printers if you're printing pick lists in the warehouse.

Hooks for developers

// Fires when document type is resolved (good for logging or analytics)
do_action( 'epdi_document_type_resolved', $order, $document_type );

// Filter the resolved type (per-order override)
apply_filters( 'epdi_document_type', $type, $order );

// Prevent generation entirely for specific orders
apply_filters( 'epdi_should_generate', $should_generate, $order );

// Fires before PDF generation
do_action( 'epdi_before_generate', $order, $document_type );

// Fires after PDF generation
do_action( 'epdi_after_generate', $order, $document_type, $pdf_path );

See the Developer Guide for the full list of hooks and filters.