The Python Merchant model must mirror the Shade backend's Prisma schema exactly. Field names are converted from camelCase (Prisma/JSON) to snake_case (Python). The merchant_id field (from merchantId: Int) is the numeric identifier stored by the Soroban contract on every invoice, making it the bridge between the backend and the on-chain world.
Proposed Steps:
- Create
src/shade/models/merchant.py.
- Define
Merchant(ShadeObject) with Pydantic Field(alias=...) for camelCase ↔ snake_case mapping.
- Fields:
id: str, merchant_id: int, address: str, account: Optional[str], email: Optional[str], first_name: Optional[str], last_name: Optional[str], business_name: Optional[str], category: Optional[str], description: Optional[str], logo: Optional[str], webhook: Optional[str], active: bool, verified: bool.
- Add
display_name computed property: returns business_name if set, else "{first_name} {last_name}".strip(), else email.
- Validate
address is a valid Stellar public key (starts with G, 56 chars).
Acceptance Criteria:
Merchant.from_dict(api_response) correctly maps camelCase fields to snake_case attributes.
merchant.merchant_id is an int.
- A non-Stellar
address raises InvalidRequestError on construction.
merchant.display_name returns the most informative available name.
- The model has no generic
settings dict — all fields are explicitly typed.
The Python
Merchantmodel must mirror the Shade backend's Prisma schema exactly. Field names are converted fromcamelCase(Prisma/JSON) tosnake_case(Python). Themerchant_idfield (frommerchantId: Int) is the numeric identifier stored by the Soroban contract on every invoice, making it the bridge between the backend and the on-chain world.Proposed Steps:
src/shade/models/merchant.py.Merchant(ShadeObject)with PydanticField(alias=...)for camelCase ↔ snake_case mapping.id: str,merchant_id: int,address: str,account: Optional[str],email: Optional[str],first_name: Optional[str],last_name: Optional[str],business_name: Optional[str],category: Optional[str],description: Optional[str],logo: Optional[str],webhook: Optional[str],active: bool,verified: bool.display_namecomputed property: returnsbusiness_nameif set, else"{first_name} {last_name}".strip(), elseemail.addressis a valid Stellar public key (starts withG, 56 chars).Acceptance Criteria:
Merchant.from_dict(api_response)correctly maps camelCase fields to snake_case attributes.merchant.merchant_idis anint.addressraisesInvalidRequestErroron construction.merchant.display_namereturns the most informative available name.settingsdict — all fields are explicitly typed.