FCHubFCHub.co

NIP at Checkout

How the "I want a company invoice" toggle and NIP field work at FluentCart checkout, including Polish NIP validation and data storage.

FCHub Fakturownia adds an optional "I want a company invoice" checkbox to the FluentCart checkout. When customers check it, a NIP (tax identification number) field appears. This is how Polish businesses provide their tax ID for a proper B2B VAT invoice.

How It Works

When the Checkout NIP Field setting is enabled (it is by default), the plugin adds two fields to the FluentCart checkout personal information section:

  1. Checkbox -- "I want a company invoice" (billing_wants_company_invoice)
  2. NIP input -- a text field for the Polish tax ID (billing_nip), hidden by default

Customer Sees the Toggle

During checkout, a "I want a company invoice" checkbox appears in the billing section. By default, it's unchecked and the NIP field is hidden.

Customer Checks the Box

When the customer checks the toggle, the NIP field slides into view. If they uncheck it, the NIP field disappears and its value is cleared.

Customer Enters NIP

The customer types their 10-digit Polish NIP. The field accepts the NIP in any common format -- with or without dashes.

Order Submitted

When the order is placed, the NIP and the "wants company invoice" flag are stored in the billing address metadata. The invoice handler picks up this data when creating the Fakturownia invoice.

Dynamic Rendering with MutationObserver

FluentCart renders its checkout form dynamically using JavaScript (Vue.js). This means the checkout fields don't exist in the DOM when the page first loads -- they're injected by FluentCart's JavaScript after initialization.

The plugin handles this by using a MutationObserver to watch for DOM changes:

var observer = new MutationObserver(function(mutations) {
    for (var i = 0; i < mutations.length; i++) {
        if (mutations[i].addedNodes.length) {
            initNipToggle();
            break;
        }
    }
});
observer.observe(document.body, { childList: true, subtree: true });

Every time FluentCart adds new nodes to the DOM (such as rendering or re-rendering the checkout form), the plugin re-initializes the NIP toggle behavior. This ensures the toggle/show functionality works regardless of when or how FluentCart renders the form.

The initNipToggle() function:

  1. Finds the checkbox by its ID (billing_wants_company_invoice)
  2. Finds the NIP wrapper using the [data-nip-field] attribute
  3. Attaches a change event listener to show/hide the NIP field
  4. Clears the NIP value when the toggle is unchecked

NIP Validation

The plugin validates NIP at checkout via the fluent_cart/checkout/validate_data filter. Invalid NIPs are rejected with a clear error message before the order is placed. The validation uses the official Polish mod-11 checksum algorithm.

The Algorithm

Validation Scope

The validateNip() method is available as a static method on the CheckoutFields class. It validates the checksum format only -- it does not verify whether the NIP is currently registered with the Polish tax office (GUS/VIES lookup is not included).

Data Storage

The NIP and company invoice preference are stored in the billing address metadata within FluentCart's order system.

Storage Location

The data is stored in the fct_order_addresses table, specifically in the meta JSON column under other_data:

{
  "other_data": {
    "wants_company_invoice": true,
    "nip": "1234563218"
  }
}

How the Invoice Handler Reads It

When creating an invoice, the InvoiceHandler reads the NIP from the billing address:

$nip = $billingAddress
    ? Arr::get($billingAddress->meta ?? [], 'other_data.nip', '')
    : '';

If nip is non-empty, a B2B invoice is created. Otherwise, it's a B2C invoice.

The checkbox state (wants_company_invoice) is not used for B2B detection — it's injected via raw DOM outside Vue's reactive system and its state is never persisted to POST data. The NIP value alone determines the invoice type. The checkbox exists purely as a UX toggle to show/hide the NIP field.

Checkout Field Schema

The plugin registers two fields through FluentCart's checkout field schema system.

PropertyValue
namebilling_wants_company_invoice
typecheckbox
label"I want a company invoice"
requiredNo
wrapper_classfchub-nip-toggle-wrapper

The NIP field is also registered in FluentCart's address field system (fluent_cart/fields/address_base_fields) so it appears correctly in saved address displays. This registration is limited to billing addresses only.

GDPR Considerations

Personal Data

The NIP (tax identification number) is considered personal data under GDPR when it can identify a natural person. If you collect NIP numbers, make sure your privacy policy covers this data processing.

Key points for GDPR compliance:

  • Purpose -- NIP is collected specifically for invoice generation as required by Polish tax law. This is a legitimate interest / legal obligation basis.
  • Storage -- NIP is stored in FluentCart's order address metadata. It persists as long as the order record exists.
  • Deletion -- when you delete an order in FluentCart, the associated address metadata (including NIP) is deleted. Uninstalling the plugin also removes Fakturownia-related order metadata.
  • Disclosure -- inform customers in your privacy policy that their NIP may be shared with Fakturownia for invoice generation and (if applicable) submitted to KSeF.

Disabling the NIP Field

If you don't need the NIP checkout field (for example, if you only sell to consumers or handle NIP collection through other means), you can disable it:

  1. Go to FluentCart > Settings > Integrations > Fakturownia
  2. Set Checkout NIP Field to No
  3. Save settings

When disabled, the CheckoutFields::register() method returns early without registering any hooks. No checkbox or NIP field will appear at checkout, and all invoices will be created as B2C.

On this page