Architecture¶
AirDoo is an Odoo 18 module that extends the Odoo core with short-term rental management features.
Overview¶
Main Models¶
airdoo.accommodation¶
The accommodation is the central pivot. Each accommodation contains: - Its metadata (name, address, times, color) - Its specific communication rules - Its pricelist for direct bookings - Cleaning provider information - Social media and branding
File: models/airdoo_accommodation.py
sale.order (extended)¶
Bookings are Odoo sales orders enriched with:
- PMS fields: checkin_date, checkout_date, nights, guest_count
- Guest composition: adults_count, children_count, babies_count
- Airbnb fields: airbnb_confirmation_code, airbnb_payout_amount, airbnb_status
- Direct Booking fields: booking_source, booking_reference, stripe_payment_intent_id
- Occupancy: occupancy_state (upcoming / in_stay / completed)
File: models/sale_order.py
airdoo.comm.rule¶
Communication rules define send timing:
- event_type: confirmation / welcome / checkin_reminder / thank_you / loyalty
- delay + delay_unit + delay_reference: send datetime calculation
- accommodation_id: optional (empty = default rule)
- Priority: specific rule > default rule
File: models/communication_rule.py
airdoo.communication.log¶
Communication logs are scheduled instances:
- Idempotency key: {order_id}_{event_type}_{rule_id} (UNIQUE constraint)
- Statuses: scheduled → sent / failed / cancelled
File: models/airdoo_communication_log.py
airdoo.communication.template¶
Wrapper around Odoo mail.template, adding:
- channel: email / whatsapp
- language: fr / en / es / de / it / pt
File: models/airdoo_communication_template.py
Email Parser (airdoo_parser.py)¶
The parser extracts data from Airbnb HTML emails:
HTML Email → AirDooParser.parse_email() → dict {
confirmation_code, guest_name, arrival_date, departure_date,
payout_amount, cleaning_fee, nights, guest_count,
adults_count, children_count, babies_count,
property_name, booking_status
}
Accommodation → email matching is done via airbnb_listing_name (exact match, case-insensitive).
REST API (controllers/)¶
| File | Contents |
|---|---|
airdoo_v1_api.py |
All /api/v1/airdoo/* endpoints (Bearer auth) |
webhook_api.py |
/airdoo/webhook/* endpoints (HMAC auth) |
booking_api_deprecated.py |
Old endpoints (return 410 Gone) |
oauth_callback.py |
Google OAuth2 callback |
tracking.py |
Email open/click tracking (in development) |
API v1 Authentication¶
Routes use auth='bearer' — Odoo verifies the Bearer token against the airdoo_api_user system user and its native API key.
Crons¶
| Cron | Frequency | Method |
|---|---|---|
| Gmail Sync | 30 min | airdoo.accommodation._cron_gmail_sync() |
| Generate Communications | 4h | sale.order._cron_generate_communications() |
| Send Due Communications | 10 min | airdoo.communication.log._cron_send_due_communications() |
Direct Booking Pricing Engine¶
For direct bookings, sale_order._compute_direct_booking_price():
1. Retrieves the accommodation's pricelist
2. For each night of the stay, calls pricelist._get_product_price(product, quantity=total_nights, date=night)
3. Returns {total, detail: [{date, price}], avg_price}
The quantity passed is the total number of nights (not 1) so that minimum night rules are respected.
Direct Booking Flow (API + Stripe)¶
1. Next.js → POST /api/v1/airdoo/availability (check availability + price)
2. Next.js → Stripe API (create PaymentIntent)
3. Guest → Stripe Elements (pay)
4. Next.js → POST /api/v1/airdoo/bookings (create booking)
└─ Odoo creates sale.order (status=confirmed)
└─ Trigger: cleaning email + comm scheduling
5. Next.js → GET /api/v1/airdoo/bookings/<id> (confirm on UI side)
Technical Stack¶
| Component | Version |
|---|---|
| Odoo | 18.0 |
| Python | 3.12 |
| PostgreSQL | 16 |
| Google API (Gmail) | OAuth2 / REST |
| iCalendar | RFC 5545 format |