# NocoDB Orders Table Schema ## Proposed Schema (Updated 2025-11-03) ### Core Identification | Field | Type | Required | Description | |-------|------|----------|-------------| | `Id` | Number | Yes (auto) | NocoDB record ID | | `CreatedAt` | DateTime | Yes (auto) | Record creation timestamp | | `UpdatedAt` | DateTime | Yes (auto) | Record last update timestamp | | `orderId` | String | Yes | Unique order identifier (UUID) | | `status` | Enum | Yes | Order status: `pending`, `paid`, `fulfilled`, `cancelled` | | `source` | String | No | Order source: `web`, `mobile-app`, `manual`, `api` | ### Payment Information | Field | Type | Required | Description | |-------|------|----------|-------------| | `stripeSessionId` | String | No | Stripe Checkout Session ID | | `stripePaymentIntent` | String | No | Stripe Payment Intent ID (for refunds) | | `baseAmount` | String | Yes | Pre-fee amount in cents (e.g., "160174") | | `processingFee` | String | Yes | Stripe processing fee in cents (e.g., "4805") | | `totalAmount` | String | Yes | Total charged amount in cents (baseAmount + processingFee) | | `currency` | String | Yes | Currency code: `USD`, `EUR`, `GBP`, `CHF` | | `amountUSD` | String | No | Amount converted to USD for reporting | | `paymentMethod` | String | No | Payment method type (e.g., "card", "bank_transfer") | ### Carbon Offset Details | Field | Type | Required | Description | |-------|------|----------|-------------| | `co2Tons` | String | Yes | Tons of CO2 offset (e.g., "6.73") | | `portfolioId` | String | Yes | Wren portfolio ID (e.g., "37") | | `portfolioName` | String | No | Human-readable portfolio name | | `wrenOrderId` | String | No | Wren API order ID (populated after fulfillment) | | `certificateUrl` | String | No | URL to offset certificate | | `fulfilledAt` | DateTime | No | Timestamp when order was fulfilled with Wren | ### Customer Information | Field | Type | Required | Description | |-------|------|----------|-------------| | `customerName` | String | Yes | Customer display name (business or individual) | | `customerEmail` | String | Yes | Customer email address | | `customerPhone` | String | No | Customer phone (if phone collection enabled in Stripe) | | `businessName` | String | No | Business name for B2B purchases | | `stripeCustomerId` | String | No | Stripe Customer ID (for recurring customers) | | `taxIdType` | String | No | Tax ID type (e.g., "eu_vat", "us_ein", "gb_vat") | | `taxIdValue` | String | No | Tax identification number | | `billingCity` | String | No | Billing address city | | `billingCountry` | String | No | Billing address country code (e.g., "FR") | | `billingLine1` | String | No | Billing address line 1 | | `billingLine2` | String | No | Billing address line 2 | | `billingPostalCode` | String | No | Billing address postal/zip code | | `billingState` | String | No | Billing address state/region | ### Vessel Information (Optional - for yacht calculations) | Field | Type | Required | Description | |-------|------|----------|-------------| | `vesselName` | String | No | Name of vessel | | `imoNumber` | String | No | IMO vessel identification number | | `vesselType` | String | No | Type of vessel (e.g., "Motor Yacht") | | `vesselLength` | String | No | Vessel length in meters | ### Trip Details (Optional - for trip-based calculations) | Field | Type | Required | Description | |-------|------|----------|-------------| | `departurePort` | String | No | Departure port name | | `arrivalPort` | String | No | Arrival port name | | `distance` | String | No | Distance in nautical miles | | `avgSpeed` | String | No | Average speed in knots | | `duration` | String | No | Trip duration in hours | | `enginePower` | String | No | Engine power in horsepower | ### Administrative | Field | Type | Required | Description | |-------|------|----------|-------------| | `notes` | LongText | No | Internal admin notes | --- ## Changes from Original Schema ### ✅ Added Fields **Payment & Stripe Integration:** - `stripeSessionId` - Link to Stripe Checkout Session - `stripePaymentIntent` - Link to Stripe Payment Intent - `stripeCustomerId` - Reusable Stripe Customer ID - `baseAmount` - Pre-fee amount from Stripe metadata - `processingFee` - Stripe fee from metadata **Billing Address:** - `billingCity` - From Stripe address - `billingCountry` - From Stripe address - `billingLine1` - From Stripe address - `billingLine2` - From Stripe address - `billingPostalCode` - From Stripe address - `billingState` - From Stripe address **B2B Customer Support:** - `businessName` - Business name for B2B purchases - `taxIdType` - Tax ID type (eu_vat, us_ein, gb_vat, etc.) - `taxIdValue` - Tax identification number ### ⚠️ Modified Fields - `customerPhone` - Now optional, populated from Stripe if phone collection is enabled - `customerName` - Now serves as display name (either business_name or individual_name) ### ❌ Removed Fields - `customerCompany` - Not provided by Stripe, can be added manually if needed - `paymentReference` - Redundant with `stripePaymentIntent` ### ⚠️ Made Optional All vessel and trip fields are now optional since they only apply to specific order types (not all orders are for vessel trips). --- ## Stripe Webhook Mapping When receiving Stripe webhook `checkout.session.completed`: ```typescript { // Payment Information stripeSessionId: session.id, stripePaymentIntent: session.payment_intent, baseAmount: session.metadata.baseAmount, // in cents processingFee: session.metadata.processingFee, // in cents totalAmount: session.amount_total.toString(), // in cents currency: session.currency, paymentMethod: session.payment_method_types[0], // 'card', 'us_bank_account', etc. // Carbon Offset Details co2Tons: session.metadata.tons, portfolioId: session.metadata.portfolioId, // Customer Information customerName: session.customer_details.name, // Display name (business or individual) customerEmail: session.customer_details.email, customerPhone: session.customer_details.phone, // if phone collection enabled // Business Customer Fields (B2B) businessName: session.customer_details.business_name, // For B2B purchases stripeCustomerId: session.customer, // Reusable customer ID // Tax Collection (if enabled) taxIdType: session.customer_details.tax_ids?.[0]?.type, // 'eu_vat', 'us_ein', etc. taxIdValue: session.customer_details.tax_ids?.[0]?.value, // Tax number // Billing Address billingCity: session.customer_details.address?.city, billingCountry: session.customer_details.address?.country, billingLine1: session.customer_details.address?.line1, billingLine2: session.customer_details.address?.line2, billingPostalCode: session.customer_details.address?.postal_code, billingState: session.customer_details.address?.state, // Order Status status: 'paid' } ``` ### Real-World Example (Business Purchase) From actual Stripe payload `evt_1SPPa3Pdj1mnVT5kscrqB21t`: ```typescript { stripeSessionId: "cs_test_b1HSYDGs73Ail2Vumu0qC3yu96ce9X4qnozsDr5hDwRndpZOsq8H47flLc", stripePaymentIntent: "pi_3SPPa2Pdj1mnVT5k2qsmDiV1", stripeCustomerId: "cus_TM7pU6vRGh0N5N", baseAmount: "16023588", // $160,235.88 processingFee: "480708", // $4,807.08 totalAmount: "16504296", // $165,042.96 currency: "usd", co2Tons: "673.26", portfolioId: "37", customerName: "LetsBe Solutions LLC", // Business name used as display name customerEmail: "matt@letsbe.solutions", customerPhone: "+33633219796", businessName: "LetsBe Solutions LLC", taxIdType: "eu_vat", taxIdValue: "FRAB123456789", billingLine1: "108 Avenue du Trois Septembre", billingLine2: null, billingCity: "Cap-d'Ail", billingState: null, billingPostalCode: "06320", billingCountry: "FR", paymentMethod: "card", status: "paid" } ``` --- ## Field Type Notes **Why String for numeric fields?** NocoDB stores all custom fields as strings by default. Numeric calculations should be done in application code by parsing these strings. This prevents precision issues with currency and decimal values. **Date/DateTime fields:** - `CreatedAt`, `UpdatedAt`, `fulfilledAt` use NocoDB's DateTime type - ISO 8601 format: `2025-11-03T14:30:00.000Z` **Enum constraints:** - `status`: Must be one of `pending`, `paid`, `fulfilled`, `cancelled` - `currency`: Must be one of `USD`, `EUR`, `GBP`, `CHF` - `source`: Typically `web`, `mobile-app`, `manual`, or `api`