tryton_helpers.py — Docstrings

Generated: 2026-02-05 — Summary of Google-style docstrings for helper functions.


find_party_by_name

def find_party_by_name(party_name)
Find a party (typically a supplier, client, service provider...) by its name.

Attempts an exact name match first. If no exact match is found, performs a
case-insensitive 'ilike' lookup. If still not found, a warning is printed
and the function returns None.

Args:
    party_name (str): The name of the party to search for. Leading/trailing
        whitespace is ignored and empty values return None.

Returns:
    object or None: The first matching Tryton `party.party` record if found,
    otherwise `None` when no match exists or the input is invalid.

Notes:
    - If multiple matches exist the first record returned by Tryton is used.
    - This function prints a warning when no party is found.
    

find_product_by_code

def find_product_by_code(product_code)
Find a product by its code.

Attempts an exact code match first. If no exact match is found, performs a
case-insensitive 'ilike' lookup. If still not found, a warning is printed
and the function returns None.

Args:
    product_code (str): The code of the product to search for. Leading and
        trailing whitespace is ignored and empty values return None.

Returns:
    object or None: The first matching Tryton `product.product` record if
    found; otherwise `None` when no match exists or the input is invalid.

Notes:
    - If multiple matches exist the first record returned by Tryton is used.
    - This function prints a warning when no product is found.
    

find_currency_by_code

def find_currency_by_code(currency_code)
Find a currency by its ISO code or name.

Performs a case-sensitive search by currency name after uppercasing the
input. Returns the first matching `currency.currency` record. If the input
is empty or no match is found, a warning is printed and the function
returns `None`.

Args:
    currency_code (str): The currency code or name to search for. Leading
        and trailing whitespace is ignored; empty values return `None`.

Returns:
    object or None: The first matching Tryton `currency.currency` record
    if found; otherwise `None` when no match exists or the input is
    invalid.

Notes:
    - This function searches by the `name` field using an uppercased exact
      match. Consider expanding to include ISO code or `ilike` searches if
      needed in the future.
    - If multiple matches exist the first record returned by Tryton is used.
    

find_contract_line_by_sequence

def find_contract_line_by_sequence(contract, line_sequence)
Find a contract line within a purchase contract by its sequence number.

Validates the provided contract and attempts to convert the provided
`line_sequence` to an integer. Searches the `lines` iterable on the
contract for a line object whose `sequence` attribute matches the
integer sequence number. Returns the first matching line, or `None` if the
contract is invalid, the sequence cannot be parsed, or no matching line is
found.

Args:
    contract (object): A `purchase.purchase` record (or similar) expected
        to have a `lines` iterable attribute containing line objects.
    line_sequence (int | str): Sequence number to search for. Can be an
        integer or a string representation of an integer.

Returns:
    object or None: The matching contract line object if found; otherwise
    `None`.

Notes:
    - Prints a warning when the provided `line_sequence` is invalid or when
      no matching line is found.
    

find_purchase_contract_by_ref

def find_purchase_contract_by_ref(contract_ref)
Find a purchase contract by its reference identifier.

Performs an exact match lookup on the `reference` field of the
`purchase.purchase` model. If the input is empty or no contract is found,
the function prints a warning and returns `None`.

Args:
    contract_ref (str): The reference string of the purchase contract.
        Leading/trailing whitespace is ignored and empty values return None.

Returns:
    object or None: The first matching Tryton `purchase.purchase` record if
    found; otherwise `None` when no match exists or the input is invalid.

Notes:
    - If multiple matches exist the first record returned by Tryton is used.
    - This function prints a warning when no contract is found.
    

find_supplier_category

def find_supplier_category()
Retrieve the 'SUPPLIER' party category from the system.

First attempts an exact match on the `name` field for 'SUPPLIER'. If an
exact match is not found, the function falls back to iterating all party
categories and returns the first one whose uppercased `name` equals
'SUPPLIER'. If no matching category is found, a warning is printed and
`None` is returned.

Args:
    None

Returns:
    object or None: The matching `party.category` record if found; otherwise
    `None`.

Notes:
    - This helper helps ensure that parties can be categorized as suppliers
      without relying on exact case-sensitive persistence of the category
      name.
    

ensure_party_is_supplier

def ensure_party_is_supplier(party, auto_enable=True)
Ensure a party has the SUPPLIER category, optionally adding it.

Checks whether the provided `party` record contains the SUPPLIER
category. If the category is missing and `auto_enable` is True, the
function attempts to append the category to the party and save the
record. On success it returns the updated party and True. If
`auto_enable` is False the function leaves the party unchanged and
returns (party, False), printing guidance for manual action.

Args:
    party (object): A `party.party` record expected to have a
        `categories` collection attribute.
    auto_enable (bool): If True (default) attempt to add the SUPPLIER
        category when missing; if False do not modify the party and
        prompt the user to add the category manually.

Returns:
    tuple: (party, bool) where bool is True if the party has the
    SUPPLIER category after the call, otherwise False.

Notes:
    - Prints informative messages for missing category, permission
      issues, and other exceptions. Use `find_supplier_category()` to
      retrieve the category object directly if needed.
    

find_fee_mode_by_name

def find_fee_mode_by_name(mode_name)
Map a human-readable fee mode name to the system's internal mode code.

Normalizes the input (trims whitespace and uppercases) and returns a
short code used internally. Known mappings are:
  - 'PER QT' -> 'perqt'
  - '% COST PRICE' -> 'pcost'
  - '% PRICE' -> 'pprice'
  - 'LUMP SUM' -> 'lumpsum'

Args:
    mode_name (str): Fee mode display name. Leading/trailing whitespace is
        ignored and comparison is case-insensitive.

Returns:
    str or None: The mapped internal mode string if recognized, otherwise
    `None` for unknown or empty inputs.

Notes:
    - Prints a warning when an unknown mode is encountered.
    

find_payable_receivable_by_name

def find_payable_receivable_by_name(p_r_value)
Determine whether a fee is payable or receivable from a P_R-style value.

Normalizes the input by trimming whitespace and uppercasing it, then maps
common variants to either 'pay' or 'rec'. Recognised payable values include
'PAY', 'PAYABLE', and 'P'; recognised receivable values include 'REC',
'RECEIVABLE', and 'R'. An empty or falsy input returns `None`. Unknown
values print a warning and default to 'pay'.

Args:
    p_r_value (str): Raw value from the P_R column (e.g., 'PAY', 'REC').

Returns:
    str or None: 'pay' for payable, 'rec' for receivable, or `None` for
    empty/invalid inputs.

Notes:
    - Prints a warning when encountering an unrecognised value and
      defaults to 'pay' to maintain backward compatibility.
    

get_existing_fees_for_line

def get_existing_fees_for_line(contract_line)
Retrieve the existing fees associated with a contract line.

Validates the provided `contract_line` and returns its `fees` collection
if present. If the contract line is missing or does not expose a `fees`
attribute, the function returns an empty list to simplify downstream
duplicate checks and iteration.

Args:
    contract_line (object): A contract line object expected to have a
        `fees` iterable attribute (may be None or empty).

Returns:
    list: The fees associated with the contract line, or an empty list if
    none exist or the input is invalid.
    

fee_already_exists

def fee_already_exists(existing_fees, product, supplier, price)
Check whether a fee with the same product, supplier and price already exists.

Iterates `existing_fees` and compares each fee's `product.id`, `party.id`,
and `price` to the provided `product`, `supplier`, and `price` respectively.
The function performs attribute presence checks to avoid AttributeError and
uses exact equality for price comparison.

Args:
    existing_fees (iterable): Iterable of fee objects (may be a list or
        None). Each fee is expected to expose `product`, `party`, and
        `price` attributes.
    product (object): Product record with an `id` attribute.
    supplier (object): Supplier/party record with an `id` attribute.
    price (Decimal | number): Price value to match against fee.price.

Returns:
    bool: True if a matching fee exists; False otherwise.

Notes:
    - Exact equality is used for price comparison; consider tolerances when
      comparing floating point values.
    

parse_decimal

def parse_decimal(value, field_name)
Parse and validate a numeric value into a Decimal.

Converts `value` to a Decimal using `Decimal(str(value))`. Returns `None`
for empty inputs, common string null markers (e.g. 'NULL', 'NONE', 'N/A'),
or when the value cannot be parsed as a decimal (in which case a warning
is printed referencing `field_name`).

Args:
    value (str|int|Decimal|None): The raw value to parse into a Decimal.
    field_name (str): Name of the field (used to provide contextual
        information in warning messages).

Returns:
    Decimal or None: A Decimal instance when parsing succeeds; otherwise
    `None` for empty/invalid inputs.

Notes:
    - Uses `Decimal(str(value))` to avoid floating-point precision issues.
    - Catching `ValueError` and `TypeError` ensures the function is safe to
      call on arbitrary input values encountered while importing data.