View Source QRNBU.FieldLock (NBU payment QR v0.3.3)
Human-readable field lock bitmask builder for NBU QR Code V003.
Field lock controls which fields can be edited by the payer when processing a QR code payment. Setting a bit to 1 prevents the payer from modifying that field.
Quick Start
# Lock all fields except amount
iex> alias QRNBU.FieldLock
iex> FieldLock.all_except([:amount]) |> FieldLock.to_integer()
65279
# Get preset for fixed-amount payments
iex> alias QRNBU.FieldLock
iex> FieldLock.preset(:fixed_payment) |> FieldLock.to_integer()
65535
# Build custom lock
iex> alias QRNBU.FieldLock
iex> FieldLock.new() |> FieldLock.lock([:recipient, :iban]) |> FieldLock.to_integer()
51455NBU Requirement
Per NBU specification (Додаток 4, розділ IV, пункт 14), fields 1-5, 11, 14-17 must ALWAYS be locked. This module automatically enforces this requirement.
Field Reference
| Field # | Name | Editable | Description |
|---|---|---|---|
| 1 | service_mark | No | BCD marker |
| 2 | format_version | No | Version (003) |
| 3 | encoding | No | Character encoding |
| 4 | function | No | UCT/ICT/XCT |
| 5 | unique_recipient_id | No | Reserved |
| 6 | recipient | Yes | Recipient name |
| 7 | iban | Yes | Account number |
| 8 | amount | Yes | Payment amount |
| 9 | recipient_code | Yes | EDRPOU/Tax ID |
| 10 | category_purpose | Yes | ISO 20022 category |
| 11 | reference | No | Invoice reference |
| 12 | purpose | Yes | Payment purpose text |
| 13 | display | Yes | Display text |
| 14 | field_lock | No | This field |
| 15 | invoice_validity | No | Expiration datetime |
| 16 | invoice_creation | No | Creation datetime |
Summary
Functions
Creates a FieldLock with ALL fields locked.
Creates a FieldLock with all fields locked EXCEPT the specified ones.
Returns the bit position for a given field name.
Returns a human-readable description of the field lock.
Returns list of editable field names.
Returns list of all available field names.
Creates a FieldLock from an existing integer value.
Creates a FieldLock from an existing integer value, raising on error.
Locks the specified field(s) (adds to existing locks).
Checks if a specific field is locked.
Returns list of all currently locked fields.
Returns list of mandatory (always-locked) field names.
Creates a new FieldLock with only mandatory fields locked.
Creates a FieldLock with only mandatory fields locked, then adds the specified ones.
Returns a preset FieldLock for common payment scenarios.
Converts FieldLock to uppercase hex string (without 0x prefix).
Converts FieldLock to integer for use in QR data.
Unlocks the specified field(s) (removes from locks).
Checks if a specific field is unlocked (editable).
Returns list of all currently unlocked (editable) fields.
Types
@type field() ::
:service_mark
| :format_version
| :encoding
| :function
| :unique_recipient_id
| :recipient
| :iban
| :amount
| :recipient_code
| :category_purpose
| :reference
| :purpose
| :display
| :field_lock
| :invoice_validity
| :invoice_creation
@type preset_name() ::
:minimal | :fixed_payment | :editable_amount | :editable_purpose | :flexible
@type t() :: %QRNBU.FieldLock{value: non_neg_integer()}
Functions
@spec all() :: t()
Creates a FieldLock with ALL fields locked.
Equivalent to 0xFFFF. The payer cannot modify any field.
Examples
iex> alias QRNBU.FieldLock
iex> FieldLock.all() |> FieldLock.to_integer()
65535
iex> alias QRNBU.FieldLock
iex> FieldLock.all() |> FieldLock.to_hex()
"FFFF"
Creates a FieldLock with all fields locked EXCEPT the specified ones.
Mandatory fields remain locked regardless of the input. This is the most common way to create a field lock for payments where you want to allow the payer to edit specific fields.
Examples
# Allow only amount to be edited
iex> alias QRNBU.FieldLock
iex> FieldLock.all_except([:amount]) |> FieldLock.to_integer()
65279
# Allow amount and purpose to be edited
iex> alias QRNBU.FieldLock
iex> FieldLock.all_except([:amount, :purpose]) |> FieldLock.to_integer()
61183
# Attempting to unlock mandatory fields has no effect
iex> alias QRNBU.FieldLock
iex> FieldLock.all_except([:service_mark]) |> FieldLock.to_integer()
65535
@spec bit_position(field()) :: non_neg_integer() | nil
Returns the bit position for a given field name.
Examples
iex> alias QRNBU.FieldLock
iex> FieldLock.bit_position(:amount)
8
iex> alias QRNBU.FieldLock
iex> FieldLock.bit_position(:service_mark)
1
iex> alias QRNBU.FieldLock
iex> FieldLock.bit_position(:unknown)
nil
Returns a human-readable description of the field lock.
Examples
iex> alias QRNBU.FieldLock
iex> FieldLock.all() |> FieldLock.describe()
"0xFFFF: All fields locked"
iex> alias QRNBU.FieldLock
iex> FieldLock.new() |> FieldLock.describe()
"0xC83F: Editable fields: recipient, iban, amount, recipient_code, category_purpose, purpose, display"
iex> alias QRNBU.FieldLock
iex> FieldLock.all_except([:amount]) |> FieldLock.describe()
"0xFEFF: Editable fields: amount"
@spec editable_fields() :: [field()]
Returns list of editable field names.
Examples
iex> alias QRNBU.FieldLock
iex> FieldLock.editable_fields()
[:recipient, :iban, :amount, :recipient_code, :category_purpose, :purpose, :display]
@spec fields() :: [field()]
Returns list of all available field names.
Examples
iex> alias QRNBU.FieldLock
iex> FieldLock.fields() |> length()
16
Creates a FieldLock from an existing integer value.
Returns {:ok, field_lock} if valid, or {:error, reason} if invalid.
The value must be between 0 and 65535, and mandatory fields will be
automatically locked if not already set.
Examples
iex> alias QRNBU.FieldLock
iex> {:ok, fl} = FieldLock.from_integer(0xFEFF)
iex> FieldLock.to_integer(fl)
65279
iex> alias QRNBU.FieldLock
iex> FieldLock.from_integer(70000)
{:error, "Value must be between 0 and 65535"}
iex> alias QRNBU.FieldLock
iex> {:ok, fl} = FieldLock.from_integer(0)
iex> FieldLock.to_integer(fl)
51263
Creates a FieldLock from an existing integer value, raising on error.
Examples
iex> alias QRNBU.FieldLock
iex> FieldLock.from_integer!(0xFEFF) |> FieldLock.to_hex()
"FEFF"
Locks the specified field(s) (adds to existing locks).
Examples
iex> alias QRNBU.FieldLock
iex> FieldLock.new() |> FieldLock.lock(:amount) |> FieldLock.to_integer()
51519
iex> alias QRNBU.FieldLock
iex> FieldLock.new() |> FieldLock.lock([:amount, :recipient]) |> FieldLock.to_integer()
51583
Checks if a specific field is locked.
Examples
iex> alias QRNBU.FieldLock
iex> FieldLock.new() |> FieldLock.locked?(:amount)
false
iex> alias QRNBU.FieldLock
iex> FieldLock.new() |> FieldLock.locked?(:service_mark)
true
iex> alias QRNBU.FieldLock
iex> FieldLock.all() |> FieldLock.locked?(:amount)
true
Returns list of all currently locked fields.
Examples
iex> alias QRNBU.FieldLock
iex> FieldLock.new() |> FieldLock.locked_fields()
[:invoice_creation, :service_mark, :format_version, :encoding, :function, :unique_recipient_id, :reference, :field_lock, :invoice_validity]
iex> alias QRNBU.FieldLock
iex> FieldLock.all() |> FieldLock.locked_fields() |> length()
16
@spec mandatory_fields() :: [field()]
Returns list of mandatory (always-locked) field names.
Examples
iex> alias QRNBU.FieldLock
iex> FieldLock.mandatory_fields()
[:invoice_creation, :service_mark, :format_version, :encoding, :function, :unique_recipient_id, :reference, :field_lock, :invoice_validity]
@spec new() :: t()
Creates a new FieldLock with only mandatory fields locked.
This is the most permissive valid configuration - all editable fields can be modified by the payer.
Examples
iex> alias QRNBU.FieldLock
iex> fl = FieldLock.new()
iex> FieldLock.to_integer(fl)
51263
iex> alias QRNBU.FieldLock
iex> fl = FieldLock.new()
iex> FieldLock.to_hex(fl)
"C83F"
Creates a FieldLock with only mandatory fields locked, then adds the specified ones.
Use this when you want maximum payer flexibility but need to lock specific additional fields.
Examples
iex> alias QRNBU.FieldLock
iex> FieldLock.only([:recipient, :iban]) |> FieldLock.to_integer()
51455
iex> alias QRNBU.FieldLock
iex> FieldLock.only([]) |> FieldLock.to_integer()
51263
@spec preset(preset_name()) :: t()
Returns a preset FieldLock for common payment scenarios.
Available Presets
:minimal- Only mandatory fields locked (maximum payer flexibility):fixed_payment- All fields locked (fixed invoice, no changes allowed):editable_amount- All except amount locked (common for variable payments):editable_purpose- All except purpose locked:flexible- Mandatory + recipient info locked; amount, purpose, display editable
Examples
iex> alias QRNBU.FieldLock
iex> FieldLock.preset(:fixed_payment) |> FieldLock.to_hex()
"FFFF"
iex> alias QRNBU.FieldLock
iex> FieldLock.preset(:editable_amount) |> FieldLock.to_hex()
"FEFF"
iex> alias QRNBU.FieldLock
iex> FieldLock.preset(:minimal) |> FieldLock.to_hex()
"C83F"
Converts FieldLock to uppercase hex string (without 0x prefix).
Examples
iex> alias QRNBU.FieldLock
iex> FieldLock.all() |> FieldLock.to_hex()
"FFFF"
iex> alias QRNBU.FieldLock
iex> FieldLock.new() |> FieldLock.to_hex()
"C83F"
iex> alias QRNBU.FieldLock
iex> FieldLock.all_except([:amount]) |> FieldLock.to_hex()
"FEFF"
@spec to_integer(t()) :: non_neg_integer()
Converts FieldLock to integer for use in QR data.
Examples
iex> alias QRNBU.FieldLock
iex> FieldLock.all() |> FieldLock.to_integer()
65535
iex> alias QRNBU.FieldLock
iex> FieldLock.new() |> FieldLock.to_integer()
51263
Unlocks the specified field(s) (removes from locks).
Cannot unlock mandatory fields - they remain locked regardless.
Examples
iex> alias QRNBU.FieldLock
iex> FieldLock.all() |> FieldLock.unlock(:amount) |> FieldLock.to_integer()
65279
iex> alias QRNBU.FieldLock
iex> FieldLock.all() |> FieldLock.unlock([:amount, :purpose]) |> FieldLock.to_integer()
61183
# Cannot unlock mandatory fields
iex> alias QRNBU.FieldLock
iex> FieldLock.all() |> FieldLock.unlock(:service_mark) |> FieldLock.to_integer()
65535
Checks if a specific field is unlocked (editable).
Examples
iex> alias QRNBU.FieldLock
iex> FieldLock.new() |> FieldLock.unlocked?(:amount)
true
iex> alias QRNBU.FieldLock
iex> FieldLock.all() |> FieldLock.unlocked?(:amount)
false
Returns list of all currently unlocked (editable) fields.
Examples
iex> alias QRNBU.FieldLock
iex> FieldLock.new() |> FieldLock.unlocked_fields()
[:recipient, :iban, :amount, :recipient_code, :category_purpose, :purpose, :display]
iex> alias QRNBU.FieldLock
iex> FieldLock.all() |> FieldLock.unlocked_fields()
[]
iex> alias QRNBU.FieldLock
iex> FieldLock.all_except([:amount]) |> FieldLock.unlocked_fields()
[:amount]