# B2bFatturazione Documentation

Installation steps and everything you need to expose the B2B fields through your own storefront, including GraphQL/headless checkouts like React Checkout.

## Installation

### Requirements

Magento 2.4.x — tested on 2.4.9, compatible with previous 2.4.* releases. PHP 8.1–8.5. Compatible with both the default Luma theme and the Hyvä theme.

### Setup steps

1. Add the credentials you'll receive by email to `auth.json` in your Magento project root:
   ```json
   { "http-basic": { "repo.codingrow.com": { "username": "...", "password": "..." } } }
   ```
2. `composer config repositories.codingrow composer https://repo.codingrow.com`
3. `composer require codingrow/module-b2bfatturazione`
4. `bin/magento module:enable Codingrow_B2bFatturazione`
5. `bin/magento setup:upgrade && bin/magento setup:di:compile && bin/magento cache:flush`
6. Paste your license key into **Admin → Stores → Configuration → Codingrow Extensions → B2bFatturazione → License → License Key**, save, then `bin/magento cache:flush`. The key is bound to the domain declared at purchase — on any other domain the module stays installed but its fields stay disabled.
7. If the site runs in `production` mode, also redeploy static content: `bin/magento setup:static-content:deploy -f`. **Do not skip this step**: without it the browser cannot load the module files and the checkout only shows some of the fields.

### Uninstallation

`composer remove codingrow/module-b2bfatturazione` then `bin/magento setup:upgrade && bin/magento setup:di:compile && bin/magento cache:flush`.

## Admin configuration

There is **no behavioural configuration** — the only admin setting is the license key. Everything else (which fields show, when they're required) is automatic and driven by the customer's selections at checkout / in the address book.

![B2bFatturazione admin configuration: the module has a single License Key field under Codingrow Extensions](screenshot-config.png)

## What it does

A deliberately small, focused module: it adds the Italian e-invoicing fields to the customer address book and to checkout (billing and shipping), on both the default Luma theme and Hyvä. It just works once installed and licensed. The exact label shown to the customer is in **bold** below.

| Field | Shown when | Required when | Format / notes |
|---|---|---|---|
| **Tipo Account** (Customer Type) | always | always | Dropdown: *Persona Fisica (Privato)* / *Azienda / Libero Professionista*. Default: Private. Drives everything below. |
| **Ragione Sociale** (Company) | Business | Business | — |
| **Partita IVA** (VAT number) | Business | Business | Max 15 chars. 11 digits = Italian; **2 leading letters = foreign** (e.g. `DE123456789`) → SDI/PEC are hidden. |
| **Codice Univoco (SDI)** | Business + Italian VAT + invoice requested | at least one of SDI / PEC | Max 7 chars. |
| **PEC** (certified email) | Business + Italian VAT + invoice requested | at least one of SDI / PEC | Email format. Labelled *Indirizzo PEC* in checkout, *PEC* in the address book. |
| **Richiedi Fattura** (Invoice requested) | Private (checkbox) | — | For a Private customer, ticking it reveals & requires the Fiscal Code. |
| **Codice Fiscale** (Fiscal Code) | Business, or Private + invoice requested | Private + invoice requested | 16 chars (person) or 11 digits (company). |

![The B2B fiscal fields on the storefront address form, with Customer Type set to Business](screenshot-fields.png)

**Conditional logic** (identical in the address book and in checkout): a *Private* customer sees only the "Richiedi Fattura" checkbox (Company/VAT/SDI/PEC are hidden and cleared); ticking it requires the Fiscal Code. A *Business* customer must fill Company and VAT; for an Italian VAT with invoice requested, SDI **or** PEC is required (filling one drops the requirement on the other). A foreign VAT (2 leading letters) hides SDI/PEC entirely.

**Nothing to configure:** if a customer reports the B2B fields "disappeared", it's almost always the license (missing, expired, or the store changed domain) — not a setting.

## GraphQL / headless & React Checkout compatibility

The five B2B fields are exposed through Magento's own **core** GraphQL types and mutations — not a custom API. If your storefront is GraphQL-based (React Checkout, or any other headless/GraphQL frontend), you read and write these fields exactly like any other native address field, through the mutations you're already using.

### Reading the fields

`customer_type`, `sdi`, `pec`, `codice_fiscale` and `fattura_richiesta` are added directly onto Magento's own `BillingCartAddress`, `ShippingCartAddress` and `CustomerAddress` types:

```graphql
{
  customerCart {
    billing_address {
      customer_type
      sdi
      pec
      codice_fiscale
      fattura_richiesta
    }
  }
}
```

```graphql
{
  customer {
    addresses {
      customer_type
      sdi
      pec
      codice_fiscale
      fattura_richiesta
    }
  }
}
```

### Writing the fields

The same five fields are added to Magento's own core `CartAddressInput` type, so they're passed alongside the normal address fields in the standard cart mutations — no separate mutation to call:

```graphql
mutation {
  setShippingAddressesOnCart(
    input: {
      cart_id: "abc123"
      shipping_addresses: [
        {
          address: {
            firstname: "Mario"
            lastname: "Rossi"
            street: ["Via Roma 1"]
            city: "Milano"
            postcode: "20100"
            country_code: "IT"
            telephone: "+390000000"
            customer_type: "azienda"
            sdi: "ABC1234"
            pec: "mario.rossi@pec.it"
            codice_fiscale: "RSSMRA80A01F205X"
          }
        }
      ]
    }
  ) {
    cart { id }
  }
}
```

### Implementation notes

- All of this is done through official Magento extension points (`di.xml` plugins on core interfaces like `Magento\QuoteGraphQl\Model\Cart\QuoteAddressFactory` and `Magento\CustomerGraphQl\Model\Customer\Address\ExtractCustomerAddressData`) — nothing patches or copies core GraphQL resolver code.
- Server-side validation (e.g. "SDI or PEC is required for a business customer") runs the same way regardless of which storefront calls the mutation — REST, GraphQL, or the default Luma checkout.
- `fattura_richiesta` (invoice requested) only applies to private customers — business customers always receive an invoice by law, so the field is meaningful specifically for the "privato" case.

### Accurate address display in admin

The customer's default billing/shipping address summary in **Customers → All Customers → [customer] → Addresses**, and on the **Customer View** tab, now includes the B2B fields too — not just the base address:

```
Before                          After
------                          -----
Mario Rossi                     Mario Rossi
Mario Rossi S.r.l.              Mario Rossi S.r.l.
Via dei Test, 1                 Via dei Test, 1
Roma, RM, 00100                 Roma, RM, 00100
Italy                           Italy
T: 333 1122334                  T: 333 1122334
VAT: 01234567891                Customer Type: azienda
                                 VAT: 01234567891
                                 SDI: ABCDEFG
                                 PEC: mario.rossi@pec.it
                                 Fiscal Code: RSSMRA80A01H501V
```

## React Checkout: ready to use, out of the box

Codingrow also maintains **[codingrow/module-react-checkout](https://github.com/Snafruz/codingrow-react-checkout)**, a small companion package that adds the actual B2B billing form (customer type, VAT, SDI, PEC, fiscal code) to Hyvä's [React Checkout](https://github.com/friends-of-hyva/magento2-react-checkout) — the UI on top of the GraphQL fields documented above. Install both together and the billing form works immediately, no custom development required.

**It also includes our own compatibility patch that makes React Checkout actually run on PHP 8.4 and 8.5.** The upstream package predates PHP 8.4's stricter deprecation handling — implicit nullable parameters and an unescaped `str_getcsv()` call both throw *fatal errors* under Magento's error handler on 8.4+, not just warnings, which otherwise makes React Checkout unusable on a modern PHP stack. This patch is applied automatically as part of the installation below.

### Installing React Checkout with B2B support

1. Require both packages:
   ```bash
   composer require hyva-themes/magento2-react-checkout codingrow/module-react-checkout
   ```
2. Add the PHP 8.4/8.5 compatibility patch to your project's root `composer.json`, then run `composer update --lock` so it's recorded:
   ```json
   "extra": {
       "patches": {
           "hyva-themes/magento2-react-checkout": {
               "PHP 8.4/8.5 compat": "vendor/codingrow/module-react-checkout/patches/react-checkout-php84-compat.patch"
           }
       }
   }
   ```
   (Requires [`cweagans/composer-patches`](https://github.com/cweagans/composer-patches); `composer require cweagans/composer-patches` first if you don't already have it.)
3. Enable the modules:
   ```bash
   bin/magento module:enable Codingrow_ReactCheckout Hyva_ReactCheckout
   bin/magento setup:upgrade
   ```
4. Turn on React Checkout: `bin/magento config:set hyva_react_checkout/general/enable 1`
5. Build the React app:
   ```bash
   cd vendor/codingrow/module-react-checkout/reactapp
   npm install
   npm run build
   ```
6. Redeploy static content — **required every time**, even outside `production` mode; the browser can otherwise keep loading a stale bundle:
   ```bash
   bin/magento setup:static-content:deploy -f en_US --theme <your-theme>
   ```
7. `bin/magento cache:flush`

Requirements: Magento 2.4.9, PHP 8.1–8.5 (including 8.4/8.5, via the included patch).
