45 lines
1.3 KiB
Python
45 lines
1.3 KiB
Python
"""
|
|
Base interface for anything that can fetch orders.
|
|
|
|
To add a new source later (ShipStation, Odoo, ...):
|
|
1. Create app/services/shipstation_service.py
|
|
2. Subclass OrderService, implement fetch_orders()
|
|
3. Register it in app/services/__init__.py's SERVICE_REGISTRY
|
|
4. Add its settings to app/config.py's SETTINGS_SCHEMA
|
|
The UI and database layers don't need to change at all.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
from abc import ABC, abstractmethod
|
|
from typing import List, TypedDict, Optional
|
|
import datetime as dt
|
|
|
|
|
|
class NormalizedOrder(TypedDict):
|
|
"""The common shape every service must translate its data into."""
|
|
source: str
|
|
external_id: str
|
|
ticket_number: Optional[str]
|
|
company: str
|
|
skus: List[str]
|
|
summary: str
|
|
status: str
|
|
source_created_at: Optional[dt.datetime]
|
|
raw_data: dict
|
|
|
|
|
|
class OrderService(ABC):
|
|
"""Common interface for every order source."""
|
|
|
|
#: short machine-friendly name, e.g. "jira", "shipstation", "odoo"
|
|
name: str = "base"
|
|
|
|
@abstractmethod
|
|
def fetch_orders(self) -> List[NormalizedOrder]:
|
|
"""Fetch and return today's orders, normalized to NormalizedOrder."""
|
|
raise NotImplementedError
|
|
|
|
def is_configured(self) -> bool:
|
|
"""Override to check that required settings are present."""
|
|
return True
|