# Cards and identity documents

Cards and identity documents are numbers a person holds: a card's brand
and last four digits, its expiry, a VAT number or tax id, a passport or a
driving licence. Each number is checked against its country's published
form, and the ones that identify a person are shown masked.

Here a shop keeps what it may of a customer's card once its payment
provider has the number, checks a supplier's VAT number by its country's
form, and records the passport a traveller shows:

```jadpo
type FormText = Text {}

type NotAVatNumber = Failure {
    kind: FailureKind.invalid_value
}

/// What the shop keeps of a card: its brand and last four.
function card_on_file(card: PaymentCardNumber) -> MaskedCardNumber {
    return money.mask(card)
}

/// A supplier's VAT number as its invoice prints it, with its country's
/// code.
function supplier_vat(raw: FormText) fails NotAVatNumber -> VatNumber {
    var number: VatNumber = attempt text.parse(raw, as: VatNumber) {
        malformed: NotAVatNumber
        number_of_country: NotAVatNumber
    }
    return number
}

/// A card on file as a receipt shows it.
function card_label(card: MaskedCardNumber, viewer: Locale) -> PresentationText {
    return text.format(card, locale: viewer)
}

/// A document as a booking shows it: its number's last four.
function document_label(held_document: IdentityDocument, viewer: Locale) -> PresentationText {
    return text.format(held_document, locale: viewer)
}
```

```jadpo
test "a card is kept as its brand and last four" {
    var stored_card: MaskedCardNumber = card_on_file(PaymentCardNumber("4242424242424242"))
    assert stored_card == MaskedCardNumber {
        brand: CardBrand.visa
        last_four: "4242"
    }
    assert card_label(stored_card, Locale.en_gb) == "Visa •••• 4242"
    var charge_card: MaskedCardNumber = card_on_file(PaymentCardNumber("378282246310005"))
    assert charge_card.brand == CardBrand.american_express
    var runs_until: CardExpiry = CardExpiry {
        year: 2028
        month: 12
    }
    assert text.from(runs_until) == "2028-12"
    assert text.format(runs_until, locale: Locale.en_gb) == "12/28"
}

test "a VAT number fits its country's form" {
    var supplier: VatNumber = attempt supplier_vat("DE143454214")
    assert supplier.country == Country.de
    assert supplier_vat("DE143454215") fails NotAVatNumber
    var greek_supplier: VatNumber = attempt supplier_vat("EL094259216")
    assert greek_supplier.country == Country.gr
    assert supplier_vat("GR094259216") fails NotAVatNumber
}

test "an identity document is shown by its number's last four" {
    var passport: IdentityDocument = IdentityDocument {
        kind: IdentityDocumentKind.passport
        country: Country.fr
        number: "12AB34567"
        expires: "2031-05-31"
    }
    assert document_label(passport, Locale.fr_fr) == "•••• 4567"
}
```

A number written out with its country is checked while compiling. A
French passport's number is two digits, two letters and five digits, so
this one is refused:

```jadpo
/// The passport a traveller showed at the desk.
function shown_at_desk() -> PassportNumber {
    return PassportNumber {
        country: Country.fr
        number: "123456789"
    }
}
```

```text
error: This `PassportNumber` breaks its rule `number_of_country`
 --> main.jadpo:5:17
  |
5 |         number: "123456789"
  |                 ^^^^^^^^^^^ not a number of the document's country
  reason: A `PassportNumber`'s `number` is in the form its `country`'s passport office writes. A literal is checked while compiling.
  next: Write a number in the country's form, or change `country` (agent)
  rule: type.invalid_literal
  help: https://jadpo.dev/docs/errors/type.invalid_literal

check failed: 1 error, 1 file
```

## Cards

- **`CardBrand`** is the eight schemes that issue cards under ranges of
  their own worldwide: American Express, Diners Club, Discover, JCB,
  Maestro, Mastercard, UnionPay and Visa. No authority gives them codes,
  so each variant's code is its own name, `american_express`, as a
  `Continent`'s is. It is shown by the scheme's own name in every locale,
  "American Express". It isn't personal data.
- **`MaskedCardNumber`** is what a shop may keep of a card once its
  payment provider has the number: its last four digits, `last_four`, and
  its `brand`, a `CardBrand` that is `none` for a card no listed scheme
  issued. It has no single text form. Its JSON is its parts, and it is
  stored as a column per part. It is shown as a receipt prints it,
  `Visa •••• 4242`, or `•••• 1234` with no brand. It is `financial`
  personal data, as the number is.
- **`money.mask(card)` makes one** from a `PaymentCardNumber`. It is an
  operation rather than `MaskedCardNumber(card)`, because a construction
  converts only between types with one representation
  ([Creating values](creating-values.md)). It takes
  the brand from the longest issuer range the number starts with:
  Discover Global Network's published ranges for Discover, Diners Club
  International, JCB and UnionPay; Mastercard's for its 2-series; and the
  long-known ranges for Visa, American Express and Maestro.
- **`CardExpiry`** is a `year` from 2000 to 2099 and a `month`, the year
  first so that it orders as a month does. Its canonical text is ISO
  8601's `2028-12`, and only that is read. It is shown as the card prints
  it, `12/28`, in every locale; the bounds on the year keep that to one
  month. It is sent as its text and stored as two `integer` columns. It is
  `financial` personal data, as PCI DSS counts it. No operation says
  whether a card has expired on a given day.

## Document numbers

A document's number is in upper case with no spaces or punctuation, as
the payment numbers are, and it fits its country's published form. The
named rule is `number_of_country`, or `number_of_kind_and_country` for an
`IdentityDocument`:

- where a literal writes the kind and the country, the rule is proved
  while compiling, as the passport example above shows;
- where the value is built from other values, it is built with
  `attempt`;
- in text and JSON, a number that doesn't fit breaks the rule by name.

A country that publishes no form takes any number within the type's
bounds: 1 to 25 capitals and digits, the longest a US state's licence
number may be by AAMVA's 2020 card standard, or 2 to 15 for a VAT number.
So a number is never refused for its country alone. A release adds
countries as their forms are published.

## VAT numbers and tax ids

**`VatNumber`** is a `Country` and its number. Its canonical text is the
one VIES, the EU's VAT checking service, uses: the country's code, then
the number, `GB980780684`.

- Greece's code is `EL`, so `GR...` is malformed.
- Northern Ireland's `XI` isn't a country code, so a trader there has its
  `GB` number.
- It is sent as that text, stored as a column per part, and shown as it
  is, because a business prints it on its invoices. It isn't personal
  data, as a US EIN isn't.

The forms come from VIES's table for the 27 member states; HMRC's for the
United Kingdom, with its mod-97 check and the 9755 variant for newer
numbers, a branch's three digits unchecked; Norway's and Switzerland's
mod-11 organisation numbers with their `MVA` and `MWST` suffixes; and,
outside Europe, Australia's ABN, whose check the ABR publishes.

The European Commission publishes no member state's check digit. So only
Germany's (ISO 7064 MOD 11,10), France's (a key of two digits; one with a
letter is unchecked) and Ireland's check letter are checked, since every
number those authorities issue passes them. Ireland's old numbers with
`+` or `*` aren't read.

**`TaxId`** is a `Country` and its number, with no scheme. The OECD's
common reporting standard records a jurisdiction and a tax
identification number (TIN), and code that needs one scheme has that
scheme's type: `UkUtr`, `UsSsn` or `UsEin`. A number fits any of its
country's forms, from the OECD's TIN page for each country and the EU's
TIN algorithms (DG TAXUD's functional specification 5.03, 2017-02-24):

- the United Kingdom's UTR, unchecked because HMRC publishes no check, or
  its National Insurance number;
- Germany's tax identification number, with its repetition rule;
- France's numéro fiscal;
- Ireland's PPS number;
- the US SSN, ITIN and EIN, by the prefixes the IRS assigns;
- India's PAN;
- Australia's tax file number, the older eight-digit form by its length
  only because its check isn't published;
- Canada's SIN, by its Luhn check.

## Passports, licences and identity documents

**`PassportNumber`** and **`DrivingLicenceNumber`** are a `Country` and a
number.

- Passports: the United Kingdom's nine digits (HMPO); Germany's nine
  characters of its 26 (the Federal Interior Ministry); the United
  States' nine digits, or a letter and eight (the State Department); and
  France's, Ireland's, India's, Canada's and Japan's forms as their
  offices state them.
- Licences: Great Britain's by the pattern DVLA's own API checks;
  Northern Ireland's eight digits; Germany's eleven characters, its check
  digit unchecked because its algorithm is published only second-hand;
  and India's fifteen. France and Ireland publish no form, and the United
  States has none nationally, so each takes the bounds.

**`IdentityDocument`** is its `kind`, its `country`, its `number`, and
the day it `expires`, which may be `none`, as Spain's DNI for someone
over 70 never expires. The part is called `kind` because `type` is a
reserved word. The kind is `IdentityDocumentKind`, a standard enum of
`passport`, `identity_card`, `driving_licence` and `residence_permit`,
each its own code, shown as its code.

The number fits its kind and country: a passport's or a licence's forms
above, Germany's identity card, Ireland's Passport Card, and India's
Aadhaar number by Verhoeff's check (UIDAI). No residence permit's form is
published, and the United Kingdom, the United States and France publish
no identity card's.

## Masking, test values and shapes

**Masked by `text.format`, to be safe.** A `TaxId`, a `PassportNumber`, a
`DrivingLicenceNumber` and an `IdentityDocument` are shown as their
number's last four, `•••• 6789`, as a card number and an SSN are. Each is
`government_id` personal data, which identifies its holder to the state.
Code that must show the whole number reads `number`.

**Test values are published ones** where an issuer publishes them: DVLA's
licence examples, the EU's TIN samples, the OECD's PAN, the ATO's own ABN
and Stripe's test cards. Some come from a company printing its own: SAP's,
TotalEnergies', Google Ireland's and Equinor's VAT numbers. Elsewhere they
are made up to the rules. `documents::DOCUMENT_EXAMPLES` holds a valid
and an invalid number for each rule, for GB, DE, FR, IE, US and one
country outside Europe (Australia, India or Japan), for each type.

**No shapes.** `type.standard_exists` matches none of these objects,
because `{ country, number }` is too common in applications' own types to
be a sign that a type is one.

The money group's records are under
[Money and payments](money-and-payments.md), and `BankAccount` under
[Bank accounts](bank-accounts.md).
