katana_public_api_client.domain¶
katana_public_api_client.domain
¶
Pydantic domain models for Katana entities.
This package provides clean, ergonomic Pydantic models representing business entities from the Katana Manufacturing ERP system.
Domain models are separate from the generated API request/response models and are optimized for: - ETL and data processing - Business logic - Data validation - JSON schema generation
Example
from katana_public_api_client import KatanaClient
from katana_public_api_client.domain import KatanaVariant
async with KatanaClient() as client:
# Helpers return domain models
variants = await client.variants.search("fox fork", limit=10)
# Use business methods
for v in variants:
print(f"{v.get_display_name()}: ${v.sales_price}")
# Easy ETL export
csv_rows = [v.to_csv_row() for v in variants]
# JSON schema generation
schema = KatanaVariant.model_json_schema()
Classes¶
KatanaBaseModel
¶
Bases: BaseModel
Base class for all Pydantic domain models.
Provides: - Immutability by default (frozen=True) - Automatic validation - JSON schema generation - Easy serialization for ETL - Common timestamp fields
Example
Functions¶
model_dump_for_etl()
¶
Export to ETL-friendly format.
Removes None values and uses field aliases for cleaner output.
Returns:
Example
Source code in katana_public_api_client/domain/base.py
to_dict_with_computed()
¶
Export including computed fields.
Unlike model_dump(), this includes @computed_field properties.
Returns:
Source code in katana_public_api_client/domain/base.py
to_warehouse_json()
¶
Export as JSON for data warehouse.
Returns:
-
str–JSON string with all non-None fields
Example
Source code in katana_public_api_client/domain/base.py
KatanaMaterial
¶
Bases: KatanaBaseModel
Domain model for a Material.
A Material represents raw materials and components used in manufacturing, including inventory tracking, supplier information, and batch management. This is a Pydantic model optimized for: - ETL and data processing - Business logic - Data validation - JSON schema generation
Unlike the generated attrs model, this model: - Has no Unset sentinel values - Provides ETL-friendly methods - Is immutable by default - Clean Optional types
Example
material = KatanaMaterial(
id=3201,
name="Stainless Steel Sheet 304",
type="material",
uom="m²",
category_name="Raw Materials",
is_sellable=False,
batch_tracked=True,
)
# Business methods available
print(material.get_display_name()) # "Stainless Steel Sheet 304"
# ETL export
csv_row = material.to_csv_row()
schema = KatanaMaterial.model_json_schema()
Functions¶
get_display_name()
¶
Get formatted display name.
Returns:
-
str–Material name, or "Unnamed Material {id}" if no name
Example
Source code in katana_public_api_client/domain/material.py
matches_search(query)
¶
Check if material matches search query.
Searches across: - Material name - Category name
Parameters:
-
query(str) –Search query string (case-insensitive)
Returns:
-
bool–True if material matches query
Example
Source code in katana_public_api_client/domain/material.py
to_csv_row()
¶
Export as CSV-friendly row.
Returns:
Example
Source code in katana_public_api_client/domain/material.py
KatanaProduct
¶
Bases: KatanaBaseModel
Domain model for a Product.
A Product represents a finished good or component that can be sold, manufactured, or purchased, with support for variants and configurations. This is a Pydantic model optimized for: - ETL and data processing - Business logic - Data validation - JSON schema generation
Unlike the generated attrs model, this model: - Has no Unset sentinel values - Provides ETL-friendly methods - Is immutable by default - Clean Optional types
Example
product = KatanaProduct(
id=1,
name="Standard-hilt lightsaber",
type="product",
uom="pcs",
category_name="lightsaber",
is_sellable=True,
is_producible=True,
is_purchasable=True,
)
# Business methods available
print(product.get_display_name()) # "Standard-hilt lightsaber"
# ETL export
csv_row = product.to_csv_row()
schema = KatanaProduct.model_json_schema()
Functions¶
get_display_name()
¶
Get formatted display name.
Returns:
-
str–Product name, or "Unnamed Product {id}" if no name
Example
Source code in katana_public_api_client/domain/product.py
matches_search(query)
¶
Check if product matches search query.
Searches across: - Product name - Category name
Parameters:
-
query(str) –Search query string (case-insensitive)
Returns:
-
bool–True if product matches query
Example
Source code in katana_public_api_client/domain/product.py
to_csv_row()
¶
Export as CSV-friendly row.
Returns:
Example
Source code in katana_public_api_client/domain/product.py
KatanaService
¶
Bases: KatanaBaseModel
Domain model for a Service.
A Service represents an external service that can be used as part of manufacturing operations or business processes. This is a Pydantic model optimized for: - ETL and data processing - Business logic - Data validation - JSON schema generation
Unlike the generated attrs model, this model: - Has no Unset sentinel values - Provides ETL-friendly methods - Is immutable by default - Clean Optional types
Example
service = KatanaService(
id=1,
name="External Assembly Service",
type="service",
uom="pcs",
category_name="Assembly",
is_sellable=True,
)
# Business methods available
print(service.get_display_name()) # "External Assembly Service"
# ETL export
csv_row = service.to_csv_row()
schema = KatanaService.model_json_schema()
Functions¶
get_display_name()
¶
Get formatted display name.
Returns:
-
str–Service name, or "Unnamed Service {id}" if no name
Example
Source code in katana_public_api_client/domain/service.py
matches_search(query)
¶
Check if service matches search query.
Searches across: - Service name - Category name
Parameters:
-
query(str) –Search query string (case-insensitive)
Returns:
-
bool–True if service matches query
Example
Source code in katana_public_api_client/domain/service.py
to_csv_row()
¶
Export as CSV-friendly row.
Returns:
Example
Source code in katana_public_api_client/domain/service.py
KatanaVariant
¶
Bases: KatanaBaseModel
Domain model for a Product or Material Variant.
A Variant represents a specific SKU with unique pricing, configuration, and inventory tracking. This is a Pydantic model optimized for: - ETL and data processing - Business logic - Data validation - JSON schema generation
Unlike the generated attrs model, this model: - Has no Unset sentinel values - Provides ETL-friendly methods - Is immutable by default - Clean Optional types
Example
Functions¶
get_config_value(config_name)
¶
Get value of a configuration attribute by name.
Parameters:
-
config_name(str) –Name of the configuration attribute
Returns:
-
str | None–Config value or None if not found
Example
Source code in katana_public_api_client/domain/variant.py
get_custom_field(field_name)
¶
Get value of a custom field by name.
Parameters:
-
field_name(str) –Name of the custom field
Returns:
-
str | None–Field value or None if not found
Example
Source code in katana_public_api_client/domain/variant.py
get_display_name()
¶
Get formatted display name matching Katana UI format.
Format: "{Product/Material Name} / {Config Value 1} / {Config Value 2} / ..."
Returns:
-
str–Formatted variant name, or SKU if no name available
Example
Source code in katana_public_api_client/domain/variant.py
matches_search(query)
¶
Check if variant matches search query.
Searches across: - SKU - Product/material name - Supplier item codes - Config attribute values
Parameters:
-
query(str) –Search query string (case-insensitive)
Returns:
-
bool–True if variant matches query
Example
Source code in katana_public_api_client/domain/variant.py
to_csv_row()
¶
Export as CSV-friendly row.
Returns:
Example
Source code in katana_public_api_client/domain/variant.py
Functions¶
material_to_katana(material)
¶
Convert attrs Material model to Pydantic KatanaMaterial.
Handles: - Unwrapping Unset sentinel values - Extracting enum values - Converting nested variants/configs to counts
Parameters:
-
material(Material) –attrs Material model from API response
Returns:
-
KatanaMaterial–KatanaMaterial with all fields populated
Example
from katana_public_api_client.api.material import get_material
from katana_public_api_client.utils import unwrap
response = await get_material.asyncio_detailed(client=client, id=123)
material_attrs = unwrap(response)
material_domain = material_to_katana(material_attrs)
# Now use domain model features
print(material_domain.get_display_name())
print(material_domain.to_csv_row())
Source code in katana_public_api_client/domain/converters.py
materials_to_katana(materials)
¶
Convert list of attrs Material models to list of KatanaMaterial.
Parameters:
Returns:
-
list[KatanaMaterial]–List of KatanaMaterial models
Example
from katana_public_api_client.api.material import get_all_materials
from katana_public_api_client.utils import unwrap_data
response = await get_all_materials.asyncio_detailed(client=client)
materials_attrs = unwrap_data(response)
materials_domain = materials_to_katana(materials_attrs)
# Now use domain model features
batch_tracked = [m for m in materials_domain if m.batch_tracked]
Source code in katana_public_api_client/domain/converters.py
product_to_katana(product)
¶
Convert attrs Product model to Pydantic KatanaProduct.
Handles: - Unwrapping Unset sentinel values - Extracting enum values - Converting nested variants/configs to counts
Parameters:
-
product(Product) –attrs Product model from API response
Returns:
-
KatanaProduct–KatanaProduct with all fields populated
Example
from katana_public_api_client.api.product import get_product
from katana_public_api_client.utils import unwrap
response = await get_product.asyncio_detailed(client=client, id=123)
product_attrs = unwrap(response)
product_domain = product_to_katana(product_attrs)
# Now use domain model features
print(product_domain.get_display_name())
print(product_domain.to_csv_row())
Source code in katana_public_api_client/domain/converters.py
products_to_katana(products)
¶
Convert list of attrs Product models to list of KatanaProduct.
Parameters:
Returns:
-
list[KatanaProduct]–List of KatanaProduct models
Example
from katana_public_api_client.api.product import get_all_products
from katana_public_api_client.utils import unwrap_data
response = await get_all_products.asyncio_detailed(client=client)
products_attrs = unwrap_data(response)
products_domain = products_to_katana(products_attrs)
# Now use domain model features
sellable = [p for p in products_domain if p.is_sellable]
Source code in katana_public_api_client/domain/converters.py
service_to_katana(service)
¶
Convert attrs Service model to Pydantic KatanaService.
Handles: - Unwrapping Unset sentinel values - Extracting enum values - Converting nested variants to count
Parameters:
-
service(Service) –attrs Service model from API response
Returns:
-
KatanaService–KatanaService with all fields populated
Example
from katana_public_api_client.api.service import get_service
from katana_public_api_client.utils import unwrap
response = await get_service.asyncio_detailed(client=client, id=123)
service_attrs = unwrap(response)
service_domain = service_to_katana(service_attrs)
# Now use domain model features
print(service_domain.get_display_name())
print(service_domain.to_csv_row())
Source code in katana_public_api_client/domain/converters.py
services_to_katana(services)
¶
Convert list of attrs Service models to list of KatanaService.
Parameters:
Returns:
-
list[KatanaService]–List of KatanaService models
Example
from katana_public_api_client.api.service import get_all_services
from katana_public_api_client.utils import unwrap_data
response = await get_all_services.asyncio_detailed(client=client)
services_attrs = unwrap_data(response)
services_domain = services_to_katana(services_attrs)
# Now use domain model features
sellable = [s for s in services_domain if s.is_sellable]
Source code in katana_public_api_client/domain/converters.py
unwrap_unset(value, default=None)
¶
Unwrap an Unset sentinel value.
Parameters:
-
value(T | Unset) –Value that might be Unset
-
default(T | None, default:None) –Default value to return if Unset
Returns:
-
T | None–The unwrapped value, or default if value is Unset
Example
Source code in katana_public_api_client/domain/converters.py
variant_to_katana(variant)
¶
Convert attrs Variant model to Pydantic KatanaVariant.
Handles: - Unwrapping Unset sentinel values - Extracting nested product_or_material name - Converting config_attributes to dicts - Converting custom_fields to dicts
Parameters:
-
variant(Variant) –attrs Variant model from API response
Returns:
-
KatanaVariant–KatanaVariant with all fields populated
Example
from katana_public_api_client.api.variant import get_variant
from katana_public_api_client.utils import unwrap
response = await get_variant.asyncio_detailed(client=client, id=123)
variant_attrs = unwrap(response)
variant_domain = variant_to_katana(variant_attrs)
# Now use domain model features
print(variant_domain.profit_margin)
print(variant_domain.get_display_name())
Source code in katana_public_api_client/domain/converters.py
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 | |
variants_to_katana(variants)
¶
Convert list of attrs Variant models to list of KatanaVariant.
Parameters:
Returns:
-
list[KatanaVariant]–List of KatanaVariant models
Example
from katana_public_api_client.api.variant import get_all_variants
from katana_public_api_client.utils import unwrap_data
response = await get_all_variants.asyncio_detailed(client=client)
variants_attrs = unwrap_data(response)
variants_domain = variants_to_katana(variants_attrs)
# Now use domain model features
high_margin = [v for v in variants_domain if v.is_high_margin]