diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..ab3f8db --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,53 @@ +name: Build and Push Docker Image to GHCR + +on: + release: + types: [published] + +env: + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }} + +jobs: + build-and-push: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Log in to the Container registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + tags: | + type=ref,event=tag + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=semver,pattern={{major}} + type=raw,value=latest,enable={{is_default_branch}} + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Build and push Docker image + uses: docker/build-push-action@v6 + with: + context: . + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + platforms: linux/amd64,linux/arm64 + cache-from: type=gha + cache-to: type=gha,mode=max diff --git a/docs/API_ENDPOINTS_SUMMARY.md b/docs/API_ENDPOINTS_SUMMARY.md new file mode 100644 index 0000000..bc1b39f --- /dev/null +++ b/docs/API_ENDPOINTS_SUMMARY.md @@ -0,0 +1,197 @@ +# API Endpoints Summary + +This document provides a quick overview of all available API endpoints in the Commercify system. + +## Base URL + +``` +/api +``` + +## Public Endpoints + +### Health Check + +- `GET /health` - Health check endpoint + +### Authentication + +- `POST /api/auth/register` - Register new user +- `POST /api/auth/signin` - User login + +### Products + +- `GET /api/products/{productId}` - Get product by ID +- `GET /api/products/search` - Search products + +### Categories + +- `GET /api/categories` - List all categories +- `GET /api/categories/{id}` - Get category by ID +- `GET /api/categories/{id}/children` - Get child categories + +### Payment Providers + +- `GET /api/payment/providers` - Get available payment providers + +### Discounts + +- `POST /api/discounts/validate` - Validate discount code + +### Currencies + +- `GET /api/currencies` - List enabled currencies +- `GET /api/currencies/default` - Get default currency +- `POST /api/currencies/convert` - Convert amount between currencies + +### Shipping + +- `POST /api/shipping/options` - Calculate shipping options + +### Checkout (Guest) + +- `GET /api/checkout` - Get current checkout +- `POST /api/checkout/items` - Add item to checkout +- `PUT /api/checkout/items/{sku}` - Update checkout item +- `DELETE /api/checkout/items/{sku}` - Remove item from checkout +- `DELETE /api/checkout` - Clear checkout +- `PUT /api/checkout/shipping-address` - Set shipping address +- `PUT /api/checkout/billing-address` - Set billing address +- `PUT /api/checkout/customer-details` - Set customer details +- `PUT /api/checkout/shipping-method` - Set shipping method +- `PUT /api/checkout/currency` - Set checkout currency +- `POST /api/checkout/discount` - Apply discount +- `DELETE /api/checkout/discount` - Remove discount +- `POST /api/checkout/complete` - Complete checkout + +## Authenticated User Endpoints + +### User Profile + +- `GET /api/users/me` - Get user profile +- `PUT /api/users/me` - Update user profile +- `PUT /api/users/me/password` - Change password + +### Orders + +- `GET /api/orders` - List user orders +- `GET /api/orders/{orderId}` - Get order by ID (also accessible via checkout session) + +## Admin Endpoints + +All admin endpoints require authentication and admin role. + +### User Management + +- `GET /api/admin/users` - List all users + +### Order Management + +- `GET /api/admin/orders` - List all orders +- `PUT /api/admin/orders/{orderId}/status` - Update order status + +### Checkout Management + +- `GET /api/admin/checkouts` - List all checkouts +- `GET /api/admin/checkouts/{checkoutId}` - Get checkout by ID +- `DELETE /api/admin/checkouts/{checkoutId}` - Delete checkout + +### Currency Management + +- `GET /api/admin/currencies/all` - List all currencies +- `POST /api/admin/currencies` - Create currency +- `PUT /api/admin/currencies` - Update currency +- `DELETE /api/admin/currencies` - Delete currency +- `PUT /api/admin/currencies/default` - Set default currency + +### Category Management + +- `POST /api/admin/categories` - Create category +- `PUT /api/admin/categories/{id}` - Update category +- `DELETE /api/admin/categories/{id}` - Delete category + +### Product Management + +- `GET /api/admin/products` - List all products +- `POST /api/admin/products` - Create product +- `PUT /api/admin/products/{productId}` - Update product +- `DELETE /api/admin/products/{productId}` - Delete product + +### Product Variant Management + +- `POST /api/admin/products/{productId}/variants` - Add product variant +- `PUT /api/admin/products/{productId}/variants/{variantId}` - Update variant +- `DELETE /api/admin/products/{productId}/variants/{variantId}` - Delete variant + +### Shipping Management + +- `POST /api/admin/shipping/methods` - Create shipping method +- `POST /api/admin/shipping/zones` - Create shipping zone +- `POST /api/admin/shipping/rates` - Create shipping rate +- `POST /api/admin/shipping/rates/weight` - Create weight-based rate +- `POST /api/admin/shipping/rates/value` - Create value-based rate + +### Discount Management + +- `POST /api/admin/discounts` - Create discount +- `GET /api/admin/discounts/{discountId}` - Get discount +- `PUT /api/admin/discounts/{discountId}` - Update discount +- `DELETE /api/admin/discounts/{discountId}` - Delete discount +- `GET /api/admin/discounts` - List all discounts +- `GET /api/admin/discounts/active` - List active discounts +- `POST /api/admin/discounts/apply/{orderId}` - Apply discount to order +- `DELETE /api/admin/discounts/remove/{orderId}` - Remove discount from order + +### Payment Management + +- `POST /api/admin/payments/{paymentId}/capture` - Capture payment +- `POST /api/admin/payments/{paymentId}/cancel` - Cancel payment +- `POST /api/admin/payments/{paymentId}/refund` - Refund payment +- `POST /api/admin/payments/{paymentId}/force-approve` - Force approve MobilePay payment + +### Payment Provider Management + +- `GET /api/admin/payment-providers` - Get all payment providers +- `GET /api/admin/payment-providers/enabled` - Get enabled providers +- `PUT /api/admin/payment-providers/{providerType}/enable` - Enable/disable provider +- `PUT /api/admin/payment-providers/{providerType}/configuration` - Update configuration +- `POST /api/admin/payment-providers/{providerType}/webhook` - Register webhook +- `DELETE /api/admin/payment-providers/{providerType}/webhook` - Delete webhook +- `GET /api/admin/payment-providers/{providerType}/webhook` - Get webhook info + +### Email Testing + +- `POST /api/admin/test/email` - Send test email + +## Webhook Endpoints + +Server-to-server communication endpoints (no authentication required): + +- `POST /api/webhooks/stripe` - Stripe webhook +- `POST /api/webhooks/mobilepay` - MobilePay webhook + +## Authentication + +Most endpoints require authentication via JWT token in the Authorization header: + +``` +Authorization: Bearer +``` + +## Permission Levels + +1. **Public** - No authentication required +2. **Authenticated** - Valid JWT token required +3. **Admin** - JWT token with admin role required +4. **Webhook** - Server-to-server, signature verification + +## Status Codes + +- `200 OK` - Request successful +- `201 Created` - Resource created successfully +- `400 Bad Request` - Invalid request data +- `401 Unauthorized` - Authentication required +- `403 Forbidden` - Insufficient permissions +- `404 Not Found` - Resource not found +- `409 Conflict` - Resource already exists or conflict +- `500 Internal Server Error` - Server error diff --git a/docs/DATABASE_SETUP.md b/docs/DATABASE_SETUP.md deleted file mode 100644 index 6cd5793..0000000 --- a/docs/DATABASE_SETUP.md +++ /dev/null @@ -1,211 +0,0 @@ -# Database Setup Guide - -This document explains how to configure and use different databases with Commercify. - -## Supported Databases - -Commercify supports two database backends: - -- **SQLite**: Recommended for local development, testing, and small deployments -- **PostgreSQL**: Recommended for production and larger deployments - -## Quick Start - -### SQLite (Recommended for Development) - -The fastest way to get started: - -```bash -# Copy local development environment -cp .env.local .env - -# Start the application (database will be created automatically) -make dev-sqlite -``` - -This will: -- Create a SQLite database file (`commercify.db`) in the project root -- Run all database migrations automatically -- Start the API server - -### PostgreSQL (Production) - -For production or when you need a full-featured database: - -```bash -# Start PostgreSQL with Docker -make db-start - -# Setup environment and run migrations -make dev-setup - -# Start the application -go run cmd/api/main.go -``` - -## Environment Configuration - -The database is configured via environment variables. You can either: - -1. Use the provided environment templates: - - `.env.local` - SQLite configuration - - `.env.example` - PostgreSQL configuration template - - `.env.production` - Production PostgreSQL template - -2. Set environment variables directly: - -### SQLite Configuration - -```bash -DB_DRIVER=sqlite -DB_NAME=commercify.db -DB_DEBUG=false -``` - -### PostgreSQL Configuration - -```bash -DB_DRIVER=postgres -DB_HOST=localhost -DB_PORT=5432 -DB_USER=postgres -DB_PASSWORD=postgres -DB_NAME=commercify -DB_SSL_MODE=disable -DB_DEBUG=false -``` - -## Make Commands - -The project includes helpful Make commands for database management: - -### SQLite Commands - -```bash -make dev-sqlite # Start application with SQLite -make dev-setup-sqlite # Setup SQLite environment -make dev-reset-sqlite # Reset SQLite database -``` - -### PostgreSQL Commands - -```bash -make dev-postgres # Start application with PostgreSQL -make dev-setup # Setup PostgreSQL environment (start DB, migrate, seed) -make dev-reset # Reset PostgreSQL environment - -# Database container management -make db-start # Start PostgreSQL container -make db-stop # Stop PostgreSQL container -make db-restart # Restart PostgreSQL container -make db-logs # View database logs -make db-clean # Stop and remove database container and volumes -``` - -### Migration Commands - -```bash -make migrate-up # Run pending migrations -make migrate-down # Rollback last migration -make migrate-status # Show migration status -make seed-data # Seed database with sample data -``` - -## Docker Setup - -### SQLite with Docker - -```bash -# Run with SQLite in Docker -make run-docker-sqlite - -# Stop SQLite Docker setup -make stop-docker-sqlite -``` - -### PostgreSQL with Docker - -```bash -# Run full stack with PostgreSQL -make run-docker - -# Stop PostgreSQL Docker setup -make stop-docker -``` - -## Database Files and Cleanup - -### SQLite - -- Database file: `commercify.db` (created in project root) -- To reset: Delete the file or run `make dev-reset-sqlite` -- Backup: Copy the `commercify.db` file - -### PostgreSQL - -- Data persisted in Docker volume: `commercify_postgres_data` -- To reset: Run `make dev-reset` or `make db-clean` -- Backup: Use PostgreSQL backup tools (`pg_dump`) - -## Switching Between Databases - -You can easily switch between databases by changing your environment configuration: - -1. **SQLite to PostgreSQL**: - ```bash - cp .env.example .env - # Edit .env to set DB_DRIVER=postgres and configure connection - make db-start - ``` - -2. **PostgreSQL to SQLite**: - ```bash - cp .env.local .env - make db-stop # Stop PostgreSQL if running - ``` - -## Production Deployment - -For production deployments: - -1. Use PostgreSQL as the database backend -2. Configure environment variables securely -3. Use SSL mode for database connections (`DB_SSL_MODE=require`) -4. Set strong passwords and limit database access -5. Regular backups are recommended - -### Environment Template for Production - -```bash -DB_DRIVER=postgres -DB_HOST=your-postgres-host -DB_PORT=5432 -DB_USER=your-db-user -DB_PASSWORD=your-secure-password -DB_NAME=commercify_production -DB_SSL_MODE=require -DB_DEBUG=false -``` - -## Troubleshooting - -### Common Issues - -1. **"Database file locked" (SQLite)** - - Ensure no other instances are running - - Check file permissions - -2. **"Connection refused" (PostgreSQL)** - - Ensure PostgreSQL is running (`make db-start`) - - Check connection parameters in `.env` - -3. **Migration errors** - - Check database permissions - - Ensure database exists - - Run `make migrate-status` to check migration state - -### Getting Help - -- Check the logs: `make db-logs` (PostgreSQL) or `make logs-sqlite` (SQLite Docker) -- Verify configuration: Check your `.env` file -- Reset environment: Use `make dev-reset` or `make dev-reset-sqlite` diff --git a/docs/PAYMENT_PROVIDER_SYSTEM.md b/docs/PAYMENT_PROVIDER_SYSTEM.md deleted file mode 100644 index cc59adc..0000000 --- a/docs/PAYMENT_PROVIDER_SYSTEM.md +++ /dev/null @@ -1,169 +0,0 @@ -# PaymentProviderRepository System Implementation - -## Overview -We have successfully implemented a PaymentProviderRepository system to replace the webhook repository approach. This new system provides a centralized way to manage all payment providers and their configurations, including webhook information. - -## Key Components - -### 1. Domain Layer - -#### Payment Provider Entity (`internal/domain/entity/payment_provider.go`) -- **PaymentProvider**: Main entity representing a payment provider configuration -- Contains all provider details: type, name, description, methods, currencies, webhooks, etc. -- Includes validation and helper methods for JSON serialization -- Supports webhook configuration and external provider integration - -#### Common Types (`internal/domain/common/payment_types.go`) -- **PaymentProviderType**: Enum for provider types (stripe, mobilepay, mock) -- **PaymentMethod**: Enum for payment methods (credit_card, wallet) -- Prevents circular imports between packages - -#### Repository Interface (`internal/domain/repository/payment_provider_repository.go`) -- **PaymentProviderRepository**: Interface defining all payment provider operations -- Methods for CRUD operations, filtering by currency/method, webhook management -- Clean separation between domain and infrastructure - -#### Service Interface (`internal/domain/service/payment_provider_service.go`) -- **PaymentProviderService**: Business logic interface for payment provider management -- Higher-level operations like enabling/disabling providers, webhook registration -- Integration with payment provider management - -### 2. Infrastructure Layer - -#### Repository Implementation (`internal/infrastructure/repository/gorm/payment_provider_repository.go`) -- GORM-based implementation of PaymentProviderRepository -- Advanced querying with JSON field support for arrays -- Proper error handling and validation - -#### Service Implementation (`internal/infrastructure/payment/payment_provider_service.go`) -- Business logic implementation for payment provider management -- Default provider initialization -- Integration with repository layer - -#### Updated Multi-Provider Service (`internal/infrastructure/payment/multi_provider_payment_service.go`) -- Now uses PaymentProviderRepository instead of hardcoded providers -- Dynamic provider discovery from database -- Improved separation of concerns - -### 3. Application Layer - -#### Dependency Injection (`internal/infrastructure/container/`) -- Updated RepositoryProvider to include PaymentProviderRepository -- Updated ServiceProvider to include PaymentProviderService -- Proper initialization order to prevent circular dependencies - -### 4. Interface Layer - -#### Payment Provider Handler (`internal/interfaces/api/handler/payment_provider_handler.go`) -- REST API endpoints for payment provider management -- Admin-only operations for enabling/disabling providers -- Webhook registration and configuration management -- CRUD operations with proper error handling - -### 5. Server Integration (`internal/interfaces/api/server.go`) -- Automatic initialization of default payment providers on startup -- Integration with existing payment system -- Backward compatibility maintained - -## Benefits of This Approach - -### 1. **Centralized Management** -- All payment provider configurations in one place -- Unified approach to webhook management -- Single source of truth for provider capabilities - -### 2. **Database-Driven Configuration** -- Providers can be enabled/disabled without code changes -- Configuration changes persist across restarts -- Easy to add new providers without redeployment - -### 3. **Clean Architecture Compliance** -- Clear separation between domain, application, and infrastructure layers -- Dependency inversion principle followed -- Easy to test and maintain - -### 4. **Webhook Consolidation** -- Webhook information stored with provider configuration -- No separate webhook entities needed -- Simplified webhook management - -### 5. **Extensibility** -- Easy to add new payment providers -- Configurable priority system for provider selection -- Support for test/production mode switching - -## Migration from Webhook Repository - -### What Changed -- **Removed**: Separate WebhookRepository system -- **Added**: PaymentProviderRepository with integrated webhook support -- **Updated**: MultiProviderPaymentService to use repository -- **Enhanced**: Admin interface for provider management - -### Backward Compatibility -- Existing payment flow remains unchanged -- API endpoints for getting payment providers work as before -- WebhookRepository kept for temporary compatibility - -### Benefits -- **Reduced Complexity**: One system instead of two -- **Better Data Model**: Webhooks belong to providers naturally -- **Improved Admin Experience**: Single interface for all provider management -- **Enhanced Reliability**: Database-driven configuration - -## API Endpoints - -### Public Endpoints -- `GET /api/payment/providers` - Get available payment providers -- `GET /api/payment/providers?currency=NOK` - Get providers for specific currency - -### Admin Endpoints (New) -- `GET /admin/payment-providers` - Get all payment providers -- `POST /admin/payment-providers/{providerType}/enable` - Enable/disable provider -- `PUT /admin/payment-providers/{providerType}/configuration` - Update configuration -- `POST /admin/payment-providers/{providerType}/webhook` - Register webhook -- `DELETE /admin/payment-providers/{providerType}/webhook` - Delete webhook -- `GET /admin/payment-providers/{providerType}/webhook` - Get webhook info - -## Default Providers - -The system automatically creates these default providers: - -1. **Stripe** - - Type: `stripe` - - Methods: Credit Card - - Currencies: USD, EUR, GBP, NOK, DKK, etc. - - Status: Disabled (requires configuration) - - Priority: 100 - -2. **MobilePay** - - Type: `mobilepay` - - Methods: Wallet - - Currencies: NOK, DKK, EUR - - Status: Disabled (requires configuration) - - Priority: 90 - -3. **Mock (Test)** - - Type: `mock` - - Methods: Credit Card - - Currencies: USD, EUR, NOK, DKK - - Status: Enabled (for testing) - - Priority: 10 - -## Next Steps - -1. **Database Schema**: GORM will automatically create the payment_providers table -2. **Configuration**: Update config files to specify enabled providers -3. **Testing**: Verify payment provider selection works correctly -4. **Documentation**: Update API documentation with new endpoints -5. **Migration**: Eventually remove deprecated WebhookRepository - -## Implementation Notes - -- The system uses JSONB fields for storing arrays (methods, currencies, events) -- Proper indexes are in place for performance -- Error handling follows the project's patterns -- All operations are logged for debugging -- The priority field allows for intelligent provider selection - -This implementation provides a solid foundation for managing payment providers in a scalable, maintainable way while following clean architecture principles. diff --git a/docs/RESTAPI.md b/docs/RESTAPI.md new file mode 100644 index 0000000..2bae948 --- /dev/null +++ b/docs/RESTAPI.md @@ -0,0 +1,1185 @@ +# Commercify REST API Documentation + +This document provides comprehensive documentation for the Commercify e-commerce backend API. + +## Base URL + +``` +https://api.commercify.com/api +``` + +All API endpoints are prefixed with `/api` unless otherwise specified. + +## Authentication + +The API uses JWT (JSON Web Token) authentication. Include the token in the Authorization header: + +``` +Authorization: Bearer +``` + +## Response Format + +All API responses follow a consistent format: + +```json +{ + "success": boolean, + "message": "string (optional)", + "data": object | array | null, + "error": "string (optional)", + "pagination": { + "page": number, + "page_size": number, + "total": number + } +} +``` + +## Status Codes + +- `200 OK`: Request successful +- `201 Created`: Resource created successfully +- `400 Bad Request`: Invalid request data +- `401 Unauthorized`: Authentication required +- `403 Forbidden`: Insufficient permissions +- `404 Not Found`: Resource not found +- `409 Conflict`: Resource already exists or conflict +- `500 Internal Server Error`: Server error + +## Public Endpoints + +### Health Check + +```plaintext +GET /health +``` + +Health check endpoint for load balancers and monitoring. + +**Response:** + +```json +{ + "status": "healthy", + "timestamp": "2025-07-07T10:30:45Z", + "services": { + "database": "healthy" + } +} +``` + +### Authentication + +#### Register User + +```plaintext +POST /api/auth/register +``` + +Register a new user account. + +**Request Body:** + +```json +{ + "email": "user@example.com", + "password": "Password123!", + "first_name": "John", + "last_name": "Smith" +} +``` + +**Response:** + +```json +{ + "success": true, + "data": { + "user": { + "id": 1, + "email": "user@example.com", + "first_name": "John", + "last_name": "Smith", + "role": "user", + "created_at": "2025-07-07T10:30:45Z", + "updated_at": "2025-07-07T10:30:45Z" + }, + "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", + "refresh_token": "", + "expires_in": 3600 + } +} +``` + +#### Login + +```plaintext +POST /api/auth/signin +``` + +Authenticate a user and retrieve a JWT token. + +**Request Body:** + +```json +{ + "email": "user@example.com", + "password": "Password123!" +} +``` + +**Response:** + +```json +{ + "success": true, + "data": { + "user": { + "id": 1, + "email": "user@example.com", + "first_name": "John", + "last_name": "Smith", + "role": "user", + "created_at": "2025-07-07T10:30:45Z", + "updated_at": "2025-07-07T10:30:45Z" + }, + "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", + "refresh_token": "", + "expires_in": 3600 + } +} +``` + +### Products + +#### Get Product + +```plaintext +GET /api/products/{productId} +``` + +Get a product by ID. + +**Response:** + +```json +{ + "success": true, + "data": { + "id": 1, + "name": "Product Name", + "description": "Product description", + "currency": "USD", + "price": 99.99, + "sku": "PROD-001", + "total_stock": 100, + "category": "Electronics", + "category_id": 1, + "images": ["https://example.com/image1.jpg"], + "has_variants": true, + "active": true, + "variants": [ + { + "id": 1, + "product_id": 1, + "variant_name": "Size L", + "sku": "PROD-001-L", + "stock": 50, + "attributes": { + "size": "L", + "color": "blue" + }, + "images": ["https://example.com/variant1.jpg"], + "is_default": true, + "weight": 0.5, + "price": 99.99, + "currency": "USD", + "created_at": "2025-07-07T10:30:45Z", + "updated_at": "2025-07-07T10:30:45Z" + } + ], + "created_at": "2025-07-07T10:30:45Z", + "updated_at": "2025-07-07T10:30:45Z" + } +} +``` + +#### Search Products + +```plaintext +GET /api/products/search +``` + +Search for products with optional filters. + +**Query Parameters:** + +- `query` (string, optional): Search term +- `category_id` (number, optional): Filter by category ID +- `min_price` (number, optional): Minimum price filter +- `max_price` (number, optional): Maximum price filter +- `currency` (string, optional): Currency code +- `active_only` (boolean, optional): Show only active products +- `page` (number, optional): Page number (default: 1) +- `page_size` (number, optional): Items per page (default: 10) + +### Categories + +#### List Categories + +```plaintext +GET /api/categories +``` + +Get all categories. + +#### Get Category + +```plaintext +GET /api/categories/{id} +``` + +Get a category by ID. + +#### Get Child Categories + +```plaintext +GET /api/categories/{id}/children +``` + +Get child categories of a parent category. + +### Payment Providers + +#### Get Available Payment Providers + +```plaintext +GET /api/payment/providers +``` + +Get available payment providers. + +### Discounts + +#### Validate Discount Code + +```plaintext +POST /api/discounts/validate +``` + +Validate a discount code. + +**Request Body:** + +```json +{ + "discount_code": "SUMMER2025" +} +``` + +### Currencies + +#### List Enabled Currencies + +```plaintext +GET /api/currencies +``` + +Get all enabled currencies. + +#### Get Default Currency + +```plaintext +GET /api/currencies/default +``` + +Get the default currency. + +#### Convert Amount + +```plaintext +POST /api/currencies/convert +``` + +Convert amount between currencies. + +**Request Body:** + +```json +{ + "amount": 100.0, + "from_currency": "USD", + "to_currency": "EUR" +} +``` + +### Shipping + +#### Calculate Shipping Options + +```plaintext +POST /api/shipping/options +``` + +Calculate available shipping options. + +**Request Body:** + +```json +{ + "address": { + "address_line1": "123 Main St", + "address_line2": "", + "city": "New York", + "state": "NY", + "postal_code": "10001", + "country": "US" + }, + "order_value": 150.0, + "order_weight": 2.5 +} +``` + +### Checkout (Guest) + +#### Get Checkout + +```plaintext +GET /api/checkout +``` + +Get current checkout session. + +#### Add to Checkout + +```plaintext +POST /api/checkout/items +``` + +Add item to checkout. + +**Request Body:** + +```json +{ + "sku": "PROD-001-L", + "quantity": 2, + "currency": "USD" +} +``` + +#### Update Checkout Item + +```plaintext +PUT /api/checkout/items/{sku} +``` + +Update checkout item quantity. + +**Request Body:** + +```json +{ + "quantity": 3 +} +``` + +#### Remove from Checkout + +```plaintext +DELETE /api/checkout/items/{sku} +``` + +Remove item from checkout. + +#### Clear Checkout + +```plaintext +DELETE /api/checkout +``` + +Clear entire checkout. + +#### Set Shipping Address + +```plaintext +PUT /api/checkout/shipping-address +``` + +Set checkout shipping address. + +**Request Body:** + +```json +{ + "address_line1": "123 Main St", + "address_line2": "Apt 4B", + "city": "New York", + "state": "NY", + "postal_code": "10001", + "country": "US" +} +``` + +#### Set Billing Address + +```plaintext +PUT /api/checkout/billing-address +``` + +Set checkout billing address. + +#### Set Customer Details + +```plaintext +PUT /api/checkout/customer-details +``` + +Set customer information. + +**Request Body:** + +```json +{ + "email": "customer@example.com", + "phone": "+1234567890", + "full_name": "John Smith" +} +``` + +#### Set Shipping Method + +```plaintext +PUT /api/checkout/shipping-method +``` + +Set shipping method. + +**Request Body:** + +```json +{ + "shipping_method_id": 1 +} +``` + +#### Set Currency + +```plaintext +PUT /api/checkout/currency +``` + +Set checkout currency. + +**Request Body:** + +```json +{ + "currency": "EUR" +} +``` + +#### Apply Discount + +```plaintext +POST /api/checkout/discount +``` + +Apply discount code to checkout. + +**Request Body:** + +```json +{ + "discount_code": "SUMMER2025" +} +``` + +#### Remove Discount + +```plaintext +DELETE /api/checkout/discount +``` + +Remove applied discount from checkout. + +#### Complete Checkout + +```plaintext +POST /api/checkout/complete +``` + +Complete checkout and create order. + +**Request Body:** + +```json +{ + "payment_provider": "stripe", + "payment_data": { + "card_details": { + "card_number": "4242424242424242", + "expiry_month": 12, + "expiry_year": 2025, + "cvv": "123", + "cardholder_name": "John Smith" + } + } +} +``` + +## Authenticated Endpoints + +### User Profile + +#### Get User Profile + +```plaintext +GET /api/users/me +``` + +Get authenticated user's profile. + +#### Update User Profile + +```plaintext +PUT /api/users/me +``` + +Update authenticated user's profile. + +**Request Body:** + +```json +{ + "first_name": "John", + "last_name": "Smith" +} +``` + +#### Change Password + +```plaintext +PUT /api/users/me/password +``` + +Change user password. + +**Request Body:** + +```json +{ + "current_password": "oldPassword123!", + "new_password": "newPassword123!" +} +``` + +### Orders + +#### List User Orders + +```plaintext +GET /api/orders +``` + +List orders for authenticated user. + +**Query Parameters:** + +- `page` (number, optional): Page number +- `pageSize` (number, optional): Items per page + +#### Get Order + +```plaintext +GET /api/orders/{orderId} +``` + +Get order by ID (accessible by order owner or via checkout session). + +## Admin Endpoints + +All admin endpoints require authentication and admin role. + +### User Management + +#### List All Users + +```plaintext +GET /api/admin/users +``` + +List all users (admin only). + +**Query Parameters:** + +- `page` (number, optional): Page number +- `page_size` (number, optional): Items per page + +### Order Management + +#### List All Orders + +```plaintext +GET /api/admin/orders +``` + +List all orders (admin only). + +**Query Parameters:** + +- `page` (number, optional): Page number +- `pageSize` (number, optional): Items per page +- `status` (string, optional): Filter by order status + +#### Update Order Status + +```plaintext +PUT /api/admin/orders/{orderId}/status +``` + +Update order status (admin only). + +### Checkout Management + +#### List Checkouts + +```plaintext +GET /api/admin/checkouts +``` + +List all checkouts (admin only). + +#### Get Checkout + +```plaintext +GET /api/admin/checkouts/{checkoutId} +``` + +Get checkout by ID (admin only). + +#### Delete Checkout + +```plaintext +DELETE /api/admin/checkouts/{checkoutId} +``` + +Delete checkout (admin only). + +### Currency Management + +#### List All Currencies + +```plaintext +GET /api/admin/currencies/all +``` + +List all currencies including disabled ones (admin only). + +#### Create Currency + +```plaintext +POST /api/admin/currencies +``` + +Create new currency (admin only). + +**Request Body:** + +```json +{ + "code": "EUR", + "name": "Euro", + "symbol": "€", + "exchange_rate": 0.85, + "is_enabled": true, + "is_default": false +} +``` + +#### Update Currency + +```plaintext +PUT /api/admin/currencies +``` + +Update currency (admin only). + +#### Delete Currency + +```plaintext +DELETE /api/admin/currencies +``` + +Delete currency (admin only). + +#### Set Default Currency + +```plaintext +PUT /api/admin/currencies/default +``` + +Set default currency (admin only). + +### Category Management + +#### Create Category + +```plaintext +POST /api/admin/categories +``` + +Create new category (admin only). + +**Request Body:** + +```json +{ + "name": "Electronics", + "description": "Electronic devices and accessories", + "parent_id": 1 +} +``` + +#### Update Category + +```plaintext +PUT /api/admin/categories/{id} +``` + +Update category (admin only). + +#### Delete Category + +```plaintext +DELETE /api/admin/categories/{id} +``` + +Delete category (admin only). + +### Product Management + +#### List Products + +```plaintext +GET /api/admin/products +``` + +List all products (admin only). + +**Query Parameters:** + +- `page` (number, optional): Page number +- `page_size` (number, optional): Items per page +- `query` (string, optional): Search term +- `category_id` (number, optional): Filter by category +- `min_price` (number, optional): Minimum price +- `max_price` (number, optional): Maximum price +- `currency` (string, optional): Currency code +- `active_only` (boolean, optional): Show only active products + +#### Create Product + +```plaintext +POST /api/admin/products +``` + +Create new product (admin only). + +**Request Body:** + +```json +{ + "name": "Product Name", + "description": "Product description", + "currency": "USD", + "category_id": 1, + "images": ["https://example.com/image1.jpg"], + "active": true, + "variants": [ + { + "sku": "PROD-001-L", + "stock": 100, + "attributes": [ + { "name": "size", "value": "L" }, + { "name": "color", "value": "blue" } + ], + "images": ["https://example.com/variant1.jpg"], + "is_default": true, + "weight": 0.5, + "price": 99.99 + } + ] +} +``` + +#### Update Product + +```plaintext +PUT /api/admin/products/{productId} +``` + +Update product (admin only). + +#### Delete Product + +```plaintext +DELETE /api/admin/products/{productId} +``` + +Delete product (admin only). + +#### Add Product Variant + +```plaintext +POST /api/admin/products/{productId}/variants +``` + +Add variant to product (admin only). + +#### Update Product Variant + +```plaintext +PUT /api/admin/products/{productId}/variants/{variantId} +``` + +Update product variant (admin only). + +#### Delete Product Variant + +```plaintext +DELETE /api/admin/products/{productId}/variants/{variantId} +``` + +Delete product variant (admin only). + +### Shipping Management + +#### Create Shipping Method + +```plaintext +POST /api/admin/shipping/methods +``` + +Create new shipping method (admin only). + +**Request Body:** + +```json +{ + "name": "Standard Shipping", + "description": "5-7 business days", + "estimated_delivery_days": 7 +} +``` + +#### Create Shipping Zone + +```plaintext +POST /api/admin/shipping/zones +``` + +Create new shipping zone (admin only). + +**Request Body:** + +```json +{ + "name": "US Zone", + "description": "United States shipping zone", + "countries": ["US"], + "states": ["NY", "CA", "TX"], + "zip_codes": ["10001", "90210"] +} +``` + +#### Create Shipping Rate + +```plaintext +POST /api/admin/shipping/rates +``` + +Create new shipping rate (admin only). + +**Request Body:** + +```json +{ + "shipping_method_id": 1, + "shipping_zone_id": 1, + "base_rate": 9.99, + "min_order_value": 0, + "free_shipping_threshold": 100.0, + "active": true +} +``` + +#### Create Weight-Based Rate + +```plaintext +POST /api/admin/shipping/rates/weight +``` + +Create weight-based shipping rate (admin only). + +**Request Body:** + +```json +{ + "shipping_rate_id": 1, + "min_weight": 0, + "max_weight": 5.0, + "rate": 5.99 +} +``` + +#### Create Value-Based Rate + +```plaintext +POST /api/admin/shipping/rates/value +``` + +Create value-based shipping rate (admin only). + +**Request Body:** + +```json +{ + "shipping_rate_id": 1, + "min_order_value": 0, + "max_order_value": 50.0, + "rate": 9.99 +} +``` + +### Discount Management + +#### Create Discount + +```plaintext +POST /api/admin/discounts +``` + +Create new discount (admin only). + +**Request Body:** + +```json +{ + "code": "SUMMER2025", + "type": "basket", + "method": "percentage", + "value": 15.0, + "min_order_value": 50.0, + "max_discount_value": 30.0, + "product_ids": [], + "category_ids": [], + "start_date": "2025-05-01T00:00:00Z", + "end_date": "2025-08-31T23:59:59Z", + "usage_limit": 500 +} +``` + +#### Get Discount + +```plaintext +GET /api/admin/discounts/{discountId} +``` + +Get discount by ID (admin only). + +#### Update Discount + +```plaintext +PUT /api/admin/discounts/{discountId} +``` + +Update discount (admin only). + +#### Delete Discount + +```plaintext +DELETE /api/admin/discounts/{discountId} +``` + +Delete discount (admin only). + +#### List Discounts + +```plaintext +GET /api/admin/discounts +``` + +List all discounts (admin only). + +#### List Active Discounts + +```plaintext +GET /api/admin/discounts/active +``` + +List active discounts (admin only). + +#### Apply Discount to Order + +```plaintext +POST /api/admin/discounts/apply/{orderId} +``` + +Apply discount to order (admin only). + +#### Remove Discount from Order + +```plaintext +DELETE /api/admin/discounts/remove/{orderId} +``` + +Remove discount from order (admin only). + +### Payment Management + +#### Capture Payment + +```plaintext +POST /api/admin/payments/{paymentId}/capture +``` + +Capture authorized payment (admin only). + +#### Cancel Payment + +```plaintext +POST /api/admin/payments/{paymentId}/cancel +``` + +Cancel payment (admin only). + +#### Refund Payment + +```plaintext +POST /api/admin/payments/{paymentId}/refund +``` + +Refund payment (admin only). + +#### Force Approve MobilePay Payment + +```plaintext +POST /api/admin/payments/{paymentId}/force-approve +``` + +Force approve MobilePay payment (admin only). + +### Payment Provider Management + +#### Get Payment Providers + +```plaintext +GET /api/admin/payment-providers +``` + +Get all payment providers (admin only). + +#### Get Enabled Payment Providers + +```plaintext +GET /api/admin/payment-providers/enabled +``` + +Get enabled payment providers (admin only). + +#### Enable Payment Provider + +```plaintext +PUT /api/admin/payment-providers/{providerType}/enable +``` + +Enable/disable payment provider (admin only). + +**Request Body:** + +```json +{ + "enabled": true +} +``` + +#### Update Provider Configuration + +```plaintext +PUT /api/admin/payment-providers/{providerType}/configuration +``` + +Update payment provider configuration (admin only). + +#### Register Webhook + +```plaintext +POST /api/admin/payment-providers/{providerType}/webhook +``` + +Register webhook for payment provider (admin only). + +#### Delete Webhook + +```plaintext +DELETE /api/admin/payment-providers/{providerType}/webhook +``` + +Delete webhook for payment provider (admin only). + +#### Get Webhook Info + +```plaintext +GET /api/admin/payment-providers/{providerType}/webhook +``` + +Get webhook information for payment provider (admin only). + +### Email Testing + +#### Test Email + +```plaintext +POST /api/admin/test/email +``` + +Send test email (admin only). + +## Webhook Endpoints + +### Stripe Webhook + +```plaintext +POST /api/webhooks/stripe +``` + +Stripe webhook endpoint for payment events. + +### MobilePay Webhook + +```plaintext +POST /api/webhooks/mobilepay +``` + +MobilePay webhook endpoint for payment events. + +## Error Responses + +All error responses follow this format: + +```json +{ + "success": false, + "error": "Error message describing what went wrong" +} +``` + +Common error scenarios: + +- Authentication required (401) +- Insufficient permissions (403) +- Resource not found (404) +- Validation errors (400) +- Server errors (500) diff --git a/docs/category_api_examples.md b/docs/category_api_examples.md new file mode 100644 index 0000000..b8e2f2d --- /dev/null +++ b/docs/category_api_examples.md @@ -0,0 +1,257 @@ +# Category API Examples + +This document provides example request bodies for the category system API endpoints. + +## Public Category Endpoints + +### List Categories + +```plaintext +GET /api/categories +``` + +Get all categories in the system. + +**Response Body:** + +```json +{ + "success": true, + "data": [ + { + "id": 1, + "name": "Electronics", + "description": "Electronic devices and accessories", + "parent_id": null, + "created_at": "2025-07-07T10:30:45Z", + "updated_at": "2025-07-07T10:30:45Z" + }, + { + "id": 2, + "name": "Smartphones", + "description": "Mobile phones and accessories", + "parent_id": 1, + "created_at": "2025-07-07T10:30:45Z", + "updated_at": "2025-07-07T10:30:45Z" + }, + { + "id": 3, + "name": "Laptops", + "description": "Laptop computers and accessories", + "parent_id": 1, + "created_at": "2025-07-07T10:30:45Z", + "updated_at": "2025-07-07T10:30:45Z" + } + ], + "pagination": { + "page": 1, + "page_size": 3, + "total": 3 + } +} +``` + +**Status Codes:** + +- `200 OK`: Categories retrieved successfully +- `500 Internal Server Error`: Failed to retrieve categories + +### Get Category + +```plaintext +GET /api/categories/{id} +``` + +Get a category by ID. + +**Path Parameters:** + +- `id` (required): Category ID + +**Response Body:** + +```json +{ + "success": true, + "data": { + "id": 1, + "name": "Electronics", + "description": "Electronic devices and accessories", + "parent_id": null, + "created_at": "2025-07-07T10:30:45Z", + "updated_at": "2025-07-07T10:30:45Z" + } +} +``` + +**Status Codes:** + +- `200 OK`: Category retrieved successfully +- `404 Not Found`: Category not found +- `500 Internal Server Error`: Failed to retrieve category + +### Get Child Categories + +```plaintext +GET /api/categories/{id}/children +``` + +Get child categories of a parent category. + +**Path Parameters:** + +- `id` (required): Parent category ID + +**Response Body:** + +```json +{ + "success": true, + "data": [ + { + "id": 2, + "name": "Smartphones", + "description": "Mobile phones and accessories", + "parent_id": 1, + "created_at": "2025-07-07T10:30:45Z", + "updated_at": "2025-07-07T10:30:45Z" + }, + { + "id": 3, + "name": "Laptops", + "description": "Laptop computers and accessories", + "parent_id": 1, + "created_at": "2025-07-07T10:30:45Z", + "updated_at": "2025-07-07T10:30:45Z" + } + ] +} +``` + +**Status Codes:** + +- `200 OK`: Child categories retrieved successfully +- `404 Not Found`: Parent category not found +- `500 Internal Server Error`: Failed to retrieve child categories + +## Admin Category Endpoints + +All admin category endpoints require authentication and admin role. + +### Create Category + +```plaintext +POST /api/admin/categories +``` + +Create a new category (admin only). + +**Request Body:** + +```json +{ + "name": "Gaming", + "description": "Gaming devices and accessories", + "parent_id": 1 +} +``` + +**Response Body:** + +```json +{ + "success": true, + "message": "Category created successfully", + "data": { + "id": 4, + "name": "Gaming", + "description": "Gaming devices and accessories", + "parent_id": 1, + "created_at": "2025-07-07T10:30:45Z", + "updated_at": "2025-07-07T10:30:45Z" + } +} +``` + +**Status Codes:** + +- `201 Created`: Category created successfully +- `400 Bad Request`: Invalid request body or validation error +- `401 Unauthorized`: Not authenticated +- `403 Forbidden`: Not authorized (not an admin) + +### Update Category + +```plaintext +PUT /api/admin/categories/{id} +``` + +Update an existing category (admin only). + +**Path Parameters:** + +- `id` (required): Category ID + +**Request Body:** + +```json +{ + "name": "Gaming Consoles", + "description": "Gaming consoles and accessories", + "parent_id": 1 +} +``` + +**Response Body:** + +```json +{ + "success": true, + "message": "Category updated successfully", + "data": { + "id": 4, + "name": "Gaming Consoles", + "description": "Gaming consoles and accessories", + "parent_id": 1, + "created_at": "2025-07-07T10:30:45Z", + "updated_at": "2025-07-07T10:35:15Z" + } +} +``` + +**Status Codes:** + +- `200 OK`: Category updated successfully +- `400 Bad Request`: Invalid request body or validation error +- `401 Unauthorized`: Not authenticated +- `403 Forbidden`: Not authorized (not an admin) +- `404 Not Found`: Category not found + +### Delete Category + +```plaintext +DELETE /api/admin/categories/{id} +``` + +Delete a category (admin only). + +**Path Parameters:** + +- `id` (required): Category ID + +**Response Body:** + +```json +{ + "success": true, + "message": "Category deleted successfully" +} +``` + +**Status Codes:** + +- `200 OK`: Category deleted successfully +- `401 Unauthorized`: Not authenticated +- `403 Forbidden`: Not authorized (not an admin) +- `404 Not Found`: Category not found +- `409 Conflict`: Cannot delete category with existing products or subcategories diff --git a/docs/checkout_api_examples.md b/docs/checkout_api_examples.md index 934c4cb..a353ad4 100644 --- a/docs/checkout_api_examples.md +++ b/docs/checkout_api_examples.md @@ -2,13 +2,24 @@ This document outlines the Checkout API endpoints for the Commercify e-commerce system. -## Important Notes +## Response Format -- **SKUs must be variant SKUs**: When adding or updating items in checkout, the SKU parameter must refer to a product variant SKU, not a product number. All products now have at least one variant, and SKU lookups are performed exclusively against the product_variants table. +All checkout API responses follow the standard Commercify response format: + +```json +{ + "success": boolean, + "message": "string (optional)", + "data": object, + "error": "string (optional, present when success is false)" +} +``` + +For checkout endpoints, the `data` field contains the checkout object with all its properties. -## Guest Checkout Endpoints +## Important Notes -The following endpoints support guest checkout functionality, allowing users to create and manage checkout sessions without authentication. +- **SKUs must be variant SKUs**: When adding or updating items in checkout, the SKU parameter must refer to a product variant SKU, not a product number. All products now have at least one variant, and SKU lookups are performed exclusively against the product_variants table. ### Get Current Checkout @@ -22,61 +33,62 @@ Retrieves the current checkout session for a user. If no checkout exists, a new ```json { - "id": 123, - "session_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", - "items": [ - { - "id": 1, - "product_id": 42, - "variant_id": 7, - "product_name": "Organic Cotton T-Shirt", - "variant_name": "Medium / Blue", - "sku": "TS-BL-M", - "price": 24.99, - "quantity": 2, - "weight": 0.3, - "subtotal": 49.98, - "created_at": "2025-05-24T10:30:00Z", - "updated_at": "2025-05-24T10:30:00Z" - } - ], - "status": "active", - "shipping_address": { - "address_line1": "", - "address_line2": "", - "city": "", - "state": "", - "postal_code": "", - "country": "" - }, - "billing_address": { - "address_line1": "", - "address_line2": "", - "city": "", - "state": "", - "postal_code": "", - "country": "" - }, - "shipping_method_id": 0, - "shipping_method": null, - "payment_provider": "", - "total_amount": 49.98, - "shipping_cost": 0, - "total_weight": 0.6, - "customer_details": { - "email": "", - "phone": "", - "full_name": "" - }, - "currency": "USD", - "discount_code": "", - "discount_amount": 0, - "final_amount": 49.98, - "applied_discount": null, - "created_at": "2025-05-24T10:30:00Z", - "updated_at": "2025-05-24T10:30:00Z", - "last_activity_at": "2025-05-24T10:30:00Z", - "expires_at": "2025-05-24T11:30:00Z" + "success": true, + "data": { + "id": 123, + "session_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", + "items": [ + { + "id": 1, + "product_id": 42, + "variant_id": 7, + "product_name": "Organic Cotton T-Shirt", + "variant_name": "Medium / Blue", + "sku": "TS-BL-M", + "price": 24.99, + "quantity": 2, + "weight": 0.3, + "subtotal": 49.98, + "created_at": "2025-05-24T10:30:00Z", + "updated_at": "2025-05-24T10:30:00Z" + } + ], + "status": "active", + "shipping_address": { + "address_line1": "", + "address_line2": "", + "city": "", + "state": "", + "postal_code": "", + "country": "" + }, + "billing_address": { + "address_line1": "", + "address_line2": "", + "city": "", + "state": "", + "postal_code": "", + "country": "" + }, + "shipping_method_id": 0, + "shipping_option": null, + "payment_provider": "", + "total_amount": 49.98, + "shipping_cost": 0, + "total_weight": 0.6, + "customer_details": { + "email": "", + "phone": "", + "full_name": "" + }, + "currency": "USD", + "discount_code": "", + "discount_amount": 0, + "final_amount": 49.98, + "applied_discount": null, + "last_activity_at": "2025-05-24T10:30:00Z", + "expires_at": "2025-05-24T11:30:00Z" + } } ``` @@ -106,48 +118,53 @@ Adds a product item to the current checkout session. ```json { - "id": 123, - "session_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", - "items": [ - { - "id": 1, - "product_id": 42, - "variant_id": 7, - "product_name": "Organic Cotton T-Shirt", - "variant_name": "Medium / Blue", - "sku": "TS-BL-M", - "price": 24.99, - "quantity": 1, - "weight": 0.3, - "subtotal": 24.99, - "created_at": "2025-05-24T10:30:00Z", - "updated_at": "2025-05-24T10:30:00Z" - } - ], - "status": "active", - "shipping_address": { - "address_line1": "", - "address_line2": "", - "city": "", - "state": "", - "postal_code": "", - "country": "" - }, - "billing_address": { - "address_line1": "", - "address_line2": "", - "city": "", - "state": "", - "postal_code": "", - "country": "" - }, - "total_amount": 24.99, - "shipping_cost": 0, - "total_weight": 0.3, - "currency": "USD", - "discount_amount": 0, - "final_amount": 24.99, - "created_at": "2025-05-24T10:30:00Z", + "success": true, + "data": { + "id": 123, + "session_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", + "items": [ + { + "id": 1, + "product_id": 42, + "variant_id": 7, + "product_name": "Organic Cotton T-Shirt", + "variant_name": "Medium / Blue", + "sku": "TS-BL-M", + "price": 24.99, + "quantity": 1, + "weight": 0.3, + "subtotal": 24.99, + "created_at": "2025-05-24T10:30:00Z", + "updated_at": "2025-05-24T10:30:00Z" + } + ], + "status": "active", + "shipping_address": { + "address_line1": "", + "address_line2": "", + "city": "", + "state": "", + "postal_code": "", + "country": "" + }, + "billing_address": { + "address_line1": "", + "address_line2": "", + "city": "", + "state": "", + "postal_code": "", + "country": "" + }, + "total_amount": 24.99, + "shipping_cost": 0, + "total_weight": 0.3, + "currency": "USD", + "discount_amount": 0, + "final_amount": 24.99, + "last_activity_at": "2025-05-24T10:30:00Z", + "expires_at": "2025-05-24T11:30:00Z" + } +} "updated_at": "2025-05-24T10:30:00Z", "last_activity_at": "2025-05-24T10:30:00Z", "expires_at": "2025-05-24T11:30:00Z" @@ -185,33 +202,37 @@ Updates the quantity of an item in the current checkout. ```json { - "id": 123, - "session_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", - "items": [ - { - "id": 1, - "product_id": 42, - "variant_id": 8, - "product_name": "Organic Cotton T-Shirt", - "variant_name": "Large / Blue", - "sku": "TS-BL-L", - "price": 24.99, - "quantity": 2, - "weight": 0.35, - "subtotal": 49.98, - "created_at": "2025-05-24T10:30:00Z", - "updated_at": "2025-05-24T10:35:00Z" - } - ], - "status": "active", - "total_amount": 49.98, - "shipping_cost": 0, - "total_weight": 0.7, - "currency": "USD", - "discount_amount": 0, - "final_amount": 49.98, - "updated_at": "2025-05-24T10:35:00Z", - "last_activity_at": "2025-05-24T10:35:00Z", + "success": true, + "data": { + "id": 123, + "session_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", + "items": [ + { + "id": 1, + "product_id": 42, + "variant_id": 8, + "product_name": "Organic Cotton T-Shirt", + "variant_name": "Large / Blue", + "sku": "TS-BL-L", + "price": 24.99, + "quantity": 2, + "weight": 0.35, + "subtotal": 49.98, + "created_at": "2025-05-24T10:30:00Z", + "updated_at": "2025-05-24T10:35:00Z" + } + ], + "status": "active", + "total_amount": 49.98, + "shipping_cost": 0, + "total_weight": 0.7, + "currency": "USD", + "discount_amount": 0, + "final_amount": 49.98, + "last_activity_at": "2025-05-24T10:35:00Z", + "expires_at": "2025-05-24T11:35:00Z" + } +} "expires_at": "2025-05-24T11:35:00Z" } ``` @@ -239,35 +260,38 @@ Removes an item from the current checkout session using the product variant SKU. ```json { - "id": 123, - "session_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", - "items": [], - "status": "active", - "shipping_address": { - "address_line1": "", - "address_line2": "", - "city": "", - "state": "", - "postal_code": "", - "country": "" - }, - "billing_address": { - "address_line1": "", - "address_line2": "", - "city": "", - "state": "", - "postal_code": "", - "country": "" - }, - "total_amount": 0, - "shipping_cost": 0, - "total_weight": 0, - "currency": "USD", - "discount_amount": 0, - "final_amount": 0, - "updated_at": "2025-05-24T10:40:00Z", - "last_activity_at": "2025-05-24T10:40:00Z", - "expires_at": "2025-05-24T11:40:00Z" + "success": true, + "data": { + "id": 123, + "session_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", + "items": [], + "status": "active", + "shipping_address": { + "address_line1": "", + "address_line2": "", + "city": "", + "state": "", + "postal_code": "", + "country": "" + }, + "billing_address": { + "address_line1": "", + "address_line2": "", + "city": "", + "state": "", + "postal_code": "", + "country": "" + }, + "total_amount": 0, + "shipping_cost": 0, + "total_weight": 0, + "currency": "USD", + "discount_amount": 0, + "final_amount": 0, + "last_activity_at": "2025-05-24T10:40:00Z", + "expires_at": "2025-05-24T11:40:00Z" + } +} } ``` @@ -290,31 +314,38 @@ Removes all items from the current checkout session. ```json { - "id": 123, - "session_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", - "items": [], - "status": "active", - "shipping_address": { - "address_line1": "", - "address_line2": "", - "city": "", - "state": "", - "postal_code": "", - "country": "" - }, - "billing_address": { - "address_line1": "", - "address_line2": "", - "city": "", - "state": "", - "postal_code": "", - "country": "" - }, - "total_amount": 0, - "shipping_cost": 0, - "total_weight": 0, - "currency": "USD", - "discount_amount": 0, + "success": true, + "data": { + "id": 123, + "session_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", + "items": [], + "status": "active", + "shipping_address": { + "address_line1": "", + "address_line2": "", + "city": "", + "state": "", + "postal_code": "", + "country": "" + }, + "billing_address": { + "address_line1": "", + "address_line2": "", + "city": "", + "state": "", + "postal_code": "", + "country": "" + }, + "total_amount": 0, + "shipping_cost": 0, + "total_weight": 0, + "currency": "USD", + "discount_amount": 0, + "final_amount": 0, + "last_activity_at": "2025-05-24T10:45:00Z", + "expires_at": "2025-05-24T11:45:00Z" + } +} "final_amount": 0, "updated_at": "2025-05-24T10:45:00Z", "last_activity_at": "2025-05-24T10:45:00Z", @@ -353,26 +384,36 @@ Sets the shipping address for the current checkout. ```json { - "id": 123, - "session_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", - "items": [], - "status": "active", - "shipping_address": { - "address_line1": "123 Main Street", - "address_line2": "Apt 4B", - "city": "Springfield", - "state": "IL", - "postal_code": "62704", - "country": "US" - }, - "billing_address": { - "address_line1": "", - "address_line2": "", - "city": "", - "state": "", - "postal_code": "", - "country": "" - }, + "success": true, + "data": { + "id": 123, + "session_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", + "items": [], + "status": "active", + "shipping_address": { + "address_line1": "123 Main Street", + "address_line2": "Apt 4B", + "city": "Springfield", + "state": "IL", + "postal_code": "62704", + "country": "US" + }, + "billing_address": { + "address_line1": "", + "address_line2": "", + "city": "", + "state": "", + "postal_code": "", + "country": "" + }, + "total_amount": 0, + "shipping_cost": 0, + "total_weight": 0, + "currency": "USD", + "last_activity_at": "2025-05-24T10:50:00Z", + "expires_at": "2025-05-24T11:50:00Z" + } +} "total_amount": 0, "shipping_cost": 0, "total_weight": 0, @@ -415,29 +456,36 @@ Sets the billing address for the current checkout. ```json { - "id": 123, - "session_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", - "items": [], - "status": "active", - "shipping_address": { - "address_line1": "123 Main Street", - "address_line2": "Apt 4B", - "city": "Springfield", - "state": "IL", - "postal_code": "62704", - "country": "US" - }, - "billing_address": { - "address_line1": "456 Commerce Ave", - "address_line2": "Suite 300", - "city": "Springfield", - "state": "IL", - "postal_code": "62704", - "country": "US" - }, - "total_amount": 0, - "shipping_cost": 0, - "total_weight": 0, + "success": true, + "data": { + "id": 123, + "session_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", + "items": [], + "status": "active", + "shipping_address": { + "address_line1": "123 Main Street", + "address_line2": "Apt 4B", + "city": "Springfield", + "state": "IL", + "postal_code": "62704", + "country": "US" + }, + "billing_address": { + "address_line1": "456 Commerce Ave", + "address_line2": "Suite 300", + "city": "Springfield", + "state": "IL", + "postal_code": "62704", + "country": "US" + }, + "total_amount": 0, + "shipping_cost": 0, + "total_weight": 0, + "currency": "USD", + "last_activity_at": "2025-05-24T10:55:00Z", + "expires_at": "2025-05-24T11:55:00Z" + } +} "currency": "USD", "updated_at": "2025-05-24T10:55:00Z", "last_activity_at": "2025-05-24T10:55:00Z", @@ -474,33 +522,41 @@ Sets the customer contact information for the current checkout. ```json { - "id": 123, - "session_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", - "items": [], - "status": "active", - "shipping_address": { - "address_line1": "123 Main Street", - "address_line2": "Apt 4B", - "city": "Springfield", - "state": "IL", - "postal_code": "62704", - "country": "US" - }, - "billing_address": { - "address_line1": "456 Commerce Ave", - "address_line2": "Suite 300", - "city": "Springfield", - "state": "IL", - "postal_code": "62704", - "country": "US" - }, - "customer_details": { - "email": "customer@example.com", - "phone": "+1234567890", - "full_name": "John Doe" - }, - "total_amount": 0, - "shipping_cost": 0, + "success": true, + "data": { + "id": 123, + "session_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", + "items": [], + "status": "active", + "shipping_address": { + "address_line1": "123 Main Street", + "address_line2": "Apt 4B", + "city": "Springfield", + "state": "IL", + "postal_code": "62704", + "country": "US" + }, + "billing_address": { + "address_line1": "456 Commerce Ave", + "address_line2": "Suite 300", + "city": "Springfield", + "state": "IL", + "postal_code": "62704", + "country": "US" + }, + "customer_details": { + "email": "customer@example.com", + "phone": "+1234567890", + "full_name": "John Doe" + }, + "total_amount": 0, + "shipping_cost": 0, + "total_weight": 0, + "currency": "USD", + "last_activity_at": "2025-05-24T11:00:00Z", + "expires_at": "2025-05-24T12:00:00Z" + } +} "total_weight": 0, "currency": "USD", "updated_at": "2025-05-24T11:00:00Z", @@ -758,63 +814,31 @@ Alternatively, for mobile payment methods: ```json { "success": true, - "message": "Order created successfully", "data": { - "id": 456, - "user_id": 123, - "order_number": "ORD-2025-0001", - "status": "pending", - "total_amount": 49.95, - "final_amount": 49.95, - "currency": "USD", - "items": [ - { - "id": 1, - "product_id": 42, - "variant_id": 7, - "product_name": "Organic Cotton T-Shirt", - "variant_name": "Medium / Blue", - "sku": "TS-BL-M", - "price": 24.99, - "quantity": 2, - "subtotal": 49.98 - } - ], - "shipping_address": { - "address_line1": "123 Main Street", - "address_line2": "Apt 4B", - "city": "Springfield", - "state": "IL", - "postal_code": "62704", - "country": "US" - }, - "billing_address": { - "address_line1": "456 Commerce Ave", - "address_line2": "Suite 300", - "city": "Springfield", - "state": "IL", - "postal_code": "62704", - "country": "US" - }, - "customer_details": { - "email": "customer@example.com", - "phone": "+1234567890", - "full_name": "John Doe" + "order": { + "id": 456, + "order_number": "ORD-2025-0001", + "checkout_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", + "user_id": 123, + "customer": { + "email": "customer@example.com", + "phone": "+1234567890", + "full_name": "John Doe" + }, + "status": "pending", + "payment_status": "pending", + "total_amount": 49.98, + "shipping_cost": 5.99, + "discount_amount": 0, + "final_amount": 55.97, + "order_lines_amount": 1, + "currency": "USD", + "created_at": "2025-05-24T11:20:00Z", + "updated_at": "2025-05-24T11:20:00Z" }, - "shipping_method": "Standard Shipping", - "shipping_cost": 5.99, - "subtotal": 49.98, - "total": 55.97, - "discount_code": "", - "discount_amount": 0, - "final_amount": 55.97, - "currency": "USD", - "payment_provider": "stripe", - "payment_status": "pending", - "created_at": "2025-05-24T11:20:00Z" - }, - "action_required": false, - "redirect_url": "" + "action_required": false, + "redirect_url": "" + } } ``` diff --git a/docs/discount_api_examples.md b/docs/discount_api_examples.md index 11a3779..0705065 100644 --- a/docs/discount_api_examples.md +++ b/docs/discount_api_examples.md @@ -2,98 +2,265 @@ This document provides example request bodies for the discount system API endpoints. +# Discount API Examples + +This document provides example request bodies for the discount system API endpoints. + ## Public Discount Endpoints -### List Active Discounts +### Validate Discount Code -`GET /api/discounts` +```plaintext +POST /api/discounts/validate +``` -List all currently active discounts. +Validate a discount code to check if it's valid and applicable. -**Query Parameters:** +**Request Body:** -- `offset` (optional): Pagination offset (default: 0) -- `limit` (optional): Pagination limit (default: 10) +```json +{ + "discount_code": "SUMMER2025" +} +``` -Example response: +**Response Body:** ```json -[ - { - "id": 1, - "code": "SUMMER2023", +{ + "success": true, + "data": { + "valid": true, + "discount_id": 1, + "code": "SUMMER2025", "type": "basket", "method": "percentage", - "value": 10.0, + "value": 15.0, "min_order_value": 50.0, - "max_discount_value": 20.0, - "start_date": "2023-06-01T00:00:00Z", - "end_date": "2023-08-31T23:59:59Z", - "usage_limit": 1000, - "current_usage": 243, - "active": true - }, - { - "id": 2, - "code": "WELCOME10", + "max_discount_value": 30.0 + } +} +``` + +**Status Codes:** + +- `200 OK`: Validation completed (check `valid` field for result) +- `400 Bad Request`: Invalid request body + +## Admin Discount Endpoints + +All admin discount endpoints require authentication and admin role. + +### Create Discount + +```plaintext +POST /api/admin/discounts +``` + +Create a new discount (admin only). + +**Request Body:** + +```json +{ + "code": "SUMMER2025", + "type": "basket", + "method": "percentage", + "value": 15.0, + "min_order_value": 50.0, + "max_discount_value": 30.0, + "product_ids": [], + "category_ids": [], + "start_date": "2025-05-01T00:00:00Z", + "end_date": "2025-08-31T23:59:59Z", + "usage_limit": 500 +} +``` + +**Response Body:** + +```json +{ + "success": true, + "message": "Discount created successfully", + "data": { + "id": 7, + "code": "SUMMER2025", "type": "basket", - "method": "fixed", - "value": 10.0, - "min_order_value": 0.0, - "max_discount_value": 10.0, - "start_date": "2023-01-01T00:00:00Z", - "end_date": "2023-12-31T23:59:59Z", - "usage_limit": 0, - "current_usage": 567, - "active": true + "method": "percentage", + "value": 15.0, + "min_order_value": 50.0, + "max_discount_value": 30.0, + "product_ids": [], + "category_ids": [], + "start_date": "2025-05-01T00:00:00Z", + "end_date": "2025-08-31T23:59:59Z", + "usage_limit": 500, + "current_usage": 0, + "active": true, + "created_at": "2025-07-07T10:30:45Z", + "updated_at": "2025-07-07T10:30:45Z" } -] +} ``` -### Apply Discount to Order +**Status Codes:** + +- `201 Created`: Discount created successfully +- `400 Bad Request`: Invalid request body +- `401 Unauthorized`: Not authenticated +- `403 Forbidden`: Not authorized (not an admin) +- `409 Conflict`: Discount code already exists + +### Get Discount + +```plaintext +GET /api/admin/discounts/{discountId} +``` + +Get discount by ID (admin only). + +**Path Parameters:** + +- `discountId` (required): Discount ID + +**Status Codes:** + +- `200 OK`: Discount retrieved successfully +- `401 Unauthorized`: Not authenticated +- `403 Forbidden`: Not authorized (not an admin) +- `404 Not Found`: Discount not found -`POST /api/orders/{id}/discounts` +### Update Discount + +```plaintext +PUT /api/admin/discounts/{discountId} +``` -Apply a discount code to an existing order. +Update an existing discount (admin only). + +**Path Parameters:** + +- `discountId` (required): Discount ID + +**Request Body:** ```json { - "discount_code": "SUMMER2023" + "code": "SUMMER2025_UPDATED", + "type": "basket", + "method": "percentage", + "value": 20.0, + "min_order_value": 75.0, + "max_discount_value": 40.0, + "start_date": "2025-05-01T00:00:00Z", + "end_date": "2025-09-30T23:59:59Z", + "usage_limit": 750, + "active": true } ``` -Example response: +**Status Codes:** + +- `200 OK`: Discount updated successfully +- `400 Bad Request`: Invalid request body +- `401 Unauthorized`: Not authenticated +- `403 Forbidden`: Not authorized (not an admin) +- `404 Not Found`: Discount not found + +### Delete Discount + +```plaintext +DELETE /api/admin/discounts/{discountId} +``` + +Delete a discount (admin only). + +**Path Parameters:** + +- `discountId` (required): Discount ID + +**Status Codes:** + +- `200 OK`: Discount deleted successfully +- `401 Unauthorized`: Not authenticated +- `403 Forbidden`: Not authorized (not an admin) +- `404 Not Found`: Discount not found + +### List Discounts + +```plaintext +GET /api/admin/discounts +``` + +List all discounts (admin only). + +**Status Codes:** + +- `200 OK`: Discounts retrieved successfully +- `401 Unauthorized`: Not authenticated +- `403 Forbidden`: Not authorized (not an admin) + +### List Active Discounts + +```plaintext +GET /api/admin/discounts/active +``` + +List only active discounts (admin only). + +**Status Codes:** + +- `200 OK`: Active discounts retrieved successfully +- `401 Unauthorized`: Not authenticated +- `403 Forbidden`: Not authorized (not an admin) + +### Apply Discount to Order + +```plaintext +POST /api/admin/discounts/apply/{orderId} +``` + +Apply a discount code to an existing order (admin only). + +**Path Parameters:** + +- `orderId` (required): Order ID + +**Request Body:** ```json { - "id": 5, - "user_id": 1, - "items": [ - { - "id": 12, - "order_id": 5, - "product_id": 3, - "quantity": 2, - "price": 24.99, - "subtotal": 49.98 - } - ], - "subtotal": 49.98, - "discount_code": "SUMMER2023", - "discount_amount": 5.00, - "shipping_cost": 5.99, - "total_amount": 50.97, - "status": "pending", - "created_at": "2023-06-15T14:22:15Z", - "updated_at": "2023-06-15T14:23:05Z" + "discount_code": "SUMMER2025" } ``` +**Status Codes:** + +- `200 OK`: Discount applied successfully +- `400 Bad Request`: Invalid request body or discount cannot be applied +- `401 Unauthorized`: Not authenticated +- `403 Forbidden`: Not authorized (not an admin) +- `404 Not Found`: Order or discount not found + ### Remove Discount from Order -`DELETE /api/orders/{id}/discounts` +```plaintext +DELETE /api/admin/discounts/remove/{orderId} +``` + +Remove an applied discount from an order (admin only). + +**Path Parameters:** -Remove an applied discount from an order. +- `orderId` (required): Order ID + +**Status Codes:** + +- `200 OK`: Discount removed successfully +- `401 Unauthorized`: Not authenticated +- `403 Forbidden`: Not authorized (not an admin) +- `404 Not Found`: Order not found Example response: @@ -113,7 +280,7 @@ Example response: ], "subtotal": 49.98, "discount_code": null, - "discount_amount": 0.00, + "discount_amount": 0.0, "shipping_cost": 5.99, "total_amount": 55.97, "status": "pending", diff --git a/docs/order_api_examples.md b/docs/order_api_examples.md index f876674..812f1f9 100644 --- a/docs/order_api_examples.md +++ b/docs/order_api_examples.md @@ -2,140 +2,277 @@ This document provides example request bodies for the order system API endpoints. +# Order API Examples + +This document provides example request bodies for the order system API endpoints. + +## Public Order Endpoints + ### Get Order ```plaintext -GET /api/orders/{id} +GET /api/orders/{orderId} ``` -Retrieve a specific order for the authenticated user. +Retrieve a specific order. This endpoint supports optional authentication - users can access their own orders, while non-authenticated users can access orders via checkout session cookie. -**Query Parameters:** +**Path Parameters:** -- `include_payment_transactions` (optional): Include payment transaction details in the response (default: false) - - Values: `true` or `false` -- `include_items` (optional): Include order items in the response (default: true) - - Values: `true` or `false` +- `orderId` (required): Order ID -**Examples:** +**Authorization:** -- Get order with payment transactions: `GET /api/orders/123?include_payment_transactions=true` -- Get order without items: `GET /api/orders/123?include_items=false` -- Get order with both: `GET /api/orders/123?include_payment_transactions=true&include_items=true` +- Authenticated users can access their own orders +- Admin users can access any order +- Non-authenticated users can access orders if they have a valid checkout session cookie -Example response: +**Response Body:** ```json { "success": true, - "message": "Order retrieved successfully", "data": { - "id": "550e8400-e29b-41d4-a716-446655440003", - "user_id": "550e8400-e29b-41d4-a716-446655440004", - "status": "paid", - "total_amount": 2514.97, - "currency": "USD", + "id": 123, + "order_number": "ORD-20250707-123", + "user_id": 1, + "checkout_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "items": [ { - "id": "550e8400-e29b-41d4-a716-446655440005", - "order_id": "550e8400-e29b-41d4-a716-446655440003", - "product_id": "550e8400-e29b-41d4-a716-446655440006", - "name": "Premium Product", - "sku": "PROD-002", - "quantity": 1, - "unit_price": 2499.99, - "total_price": 2499.99 + "id": 1, + "order_id": 123, + "product_id": 42, + "variant_id": 7, + "sku": "PROD-001-L", + "product_name": "Organic Cotton T-Shirt", + "variant_name": "Size L, Color Blue", + "quantity": 2, + "unit_price": 24.99, + "total_price": 49.98, + "image_url": "https://example.com/image.jpg", + "created_at": "2025-07-07T10:30:45Z", + "updated_at": "2025-07-07T10:30:45Z" } ], + "status": "paid", + "payment_status": "captured", + "total_amount": 49.98, + "shipping_cost": 9.99, + "discount_amount": 5.0, + "final_amount": 54.97, + "currency": "USD", "shipping_address": { - "first_name": "Sarah", - "last_name": "Johnson", - "address_line1": "456 Oak Avenue", - "address_line2": "Suite 100", - "city": "Seattle", - "state": "WA", - "postal_code": "98101", - "country": "US", - "phone_number": "+1987654321" + "address_line1": "123 Main St", + "address_line2": "Apt 4B", + "city": "New York", + "state": "NY", + "postal_code": "10001", + "country": "US" }, "billing_address": { - "first_name": "Sarah", - "last_name": "Johnson", - "address_line1": "456 Oak Avenue", - "address_line2": "Suite 100", - "city": "Seattle", - "state": "WA", - "postal_code": "98101", - "country": "US", - "phone_number": "+1987654321" + "address_line1": "123 Main St", + "address_line2": "Apt 4B", + "city": "New York", + "state": "NY", + "postal_code": "10001", + "country": "US" + }, + "shipping_details": { + "shipping_rate_id": 1, + "shipping_method_id": 1, + "name": "Standard Shipping", + "description": "5-7 business days", + "estimated_delivery_days": 7, + "cost": 9.99, + "free_shipping": false + }, + "discount_details": { + "id": 1, + "code": "SUMMER2025", + "type": "basket", + "method": "percentage", + "value": 10.0, + "amount": 5.0 }, - "payment_method": "wallet", - "payment_status": "captured", - "shipping_method": "express", - "shipping_cost": 14.99, - "tax_amount": 0, - "discount_amount": 0, - "created_at": "2024-03-20T11:00:00Z", - "updated_at": "2024-03-20T11:05:00Z" - } -} -``` - -**Example response with payment transactions (`include_payment_transactions=true`):** - -```json -{ - "success": true, - "message": "Order retrieved successfully", - "data": { - "id": "550e8400-e29b-41d4-a716-446655440003", - "user_id": "550e8400-e29b-41d4-a716-446655440004", - "status": "paid", - "payment_status": "captured", - "total_amount": 2514.97, - "currency": "USD", - "items": [...], "payment_transactions": [ { "id": 1, - "transaction_id": "TXN-AUTH-2025-001", + "transaction_id": "txn_123456789", "external_id": "pi_1234567890", "type": "authorize", "status": "successful", - "amount": 2514.97, - "currency": "USD", - "provider": "stripe", - "created_at": "2024-03-20T11:00:00Z", - "updated_at": "2024-03-20T11:00:00Z" - }, - { - "id": 2, - "transaction_id": "TXN-CAPTURE-2025-001", - "external_id": "ch_1234567890", - "type": "capture", - "status": "successful", - "amount": 2514.97, + "amount": 54.97, "currency": "USD", "provider": "stripe", - "created_at": "2024-03-20T11:05:00Z", - "updated_at": "2024-03-20T11:05:00Z" + "created_at": "2025-07-07T10:30:45Z", + "updated_at": "2025-07-07T10:30:45Z" } ], - "shipping_address": {...}, - "billing_address": {...}, - "payment_method": "credit_card", - "shipping_method": "express", - "shipping_cost": 14.99, - "tax_amount": 0, - "discount_amount": 0, - "created_at": "2024-03-20T11:00:00Z", - "updated_at": "2024-03-20T11:05:00Z" + "customer": { + "email": "customer@example.com", + "phone": "+1234567890", + "full_name": "John Smith" + }, + "action_required": false, + "action_url": null, + "created_at": "2025-07-07T10:30:45Z", + "updated_at": "2025-07-07T10:30:45Z" } } ``` **Status Codes:** +- `200 OK`: Order retrieved successfully +- `401 Unauthorized`: Not authenticated and no valid checkout session +- `403 Forbidden`: Not authorized to access this order +- `404 Not Found`: Order not found + +## Authenticated User Endpoints + +### List User Orders + +```plaintext +GET /api/orders +``` + +List orders for the authenticated user. + +**Query Parameters:** + +- `page` (number, optional): Page number (default: 1) +- `pageSize` (number, optional): Items per page (default: 10) + +**Response Body:** + +```json +{ + "success": true, + "data": [ + { + "id": 123, + "order_number": "ORD-20250707-123", + "checkout_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", + "user_id": 1, + "customer": { + "email": "customer@example.com", + "phone": "+1234567890", + "full_name": "John Smith" + }, + "status": "paid", + "payment_status": "captured", + "total_amount": 49.98, + "shipping_cost": 9.99, + "discount_amount": 5.0, + "final_amount": 54.97, + "order_lines_amount": 2, + "currency": "USD", + "created_at": "2025-07-07T10:30:45Z", + "updated_at": "2025-07-07T10:30:45Z" + } + ], + "pagination": { + "page": 1, + "page_size": 10, + "total": 1 + } +} +``` + +**Status Codes:** + +- `200 OK`: Orders retrieved successfully +- `401 Unauthorized`: Not authenticated + +## Admin Order Endpoints + +All admin order endpoints require authentication and admin role. + +### List All Orders + +```plaintext +GET /api/admin/orders +``` + +List all orders in the system (admin only). + +**Query Parameters:** + +- `page` (number, optional): Page number (default: 1) +- `pageSize` (number, optional): Items per page (default: 10) +- `status` (string, optional): Filter by order status + +**Status Codes:** + +- `200 OK`: Orders retrieved successfully +- `401 Unauthorized`: Not authenticated +- `403 Forbidden`: Not authorized (not an admin) + +### Update Order Status + +```plaintext +PUT /api/admin/orders/{orderId}/status +``` + +Update the status of an order (admin only). + +**Path Parameters:** + +- `orderId` (required): Order ID + +**Request Body:** + +```json +{ + "status": "shipped" +} +``` + +**Status Codes:** + +- `200 OK`: Order status updated successfully +- `400 Bad Request`: Invalid request body or status +- `401 Unauthorized`: Not authenticated +- `403 Forbidden`: Not authorized (not an admin) +- `404 Not Found`: Order not found + "transaction_id": "TXN-AUTH-2025-001", + "external_id": "pi_1234567890", + "type": "authorize", + "status": "successful", + "amount": 2514.97, + "currency": "USD", + "provider": "stripe", + "created_at": "2024-03-20T11:00:00Z", + "updated_at": "2024-03-20T11:00:00Z" + }, + { + "id": 2, + "transaction_id": "TXN-CAPTURE-2025-001", + "external_id": "ch_1234567890", + "type": "capture", + "status": "successful", + "amount": 2514.97, + "currency": "USD", + "provider": "stripe", + "created_at": "2024-03-20T11:05:00Z", + "updated_at": "2024-03-20T11:05:00Z" + } + ], + "shipping_address": {...}, + "billing_address": {...}, + "payment_method": "credit_card", + "shipping_method": "express", + "shipping_cost": 14.99, + "tax_amount": 0, + "discount_amount": 0, + "created_at": "2024-03-20T11:00:00Z", + "updated_at": "2024-03-20T11:05:00Z" + } + } + +```` + +**Status Codes:** + - `200 OK`: Order retrieved successfully - `401 Unauthorized`: User not authenticated - `403 Forbidden`: User not authorized for this order @@ -146,7 +283,7 @@ Example response: ```plaintext GET /api/orders -``` +```` List all orders for the authenticated user. diff --git a/docs/payment_api_examples.md b/docs/payment_api_examples.md index 075f32f..14fb542 100644 --- a/docs/payment_api_examples.md +++ b/docs/payment_api_examples.md @@ -4,87 +4,90 @@ This document provides example request bodies for the payment system API endpoin ## Public Payment Endpoints +# Payment API Examples + +This document provides example request bodies for the payment system API endpoints. + +## Public Payment Endpoints + ### Get Available Payment Providers ```plaintext GET /api/payment/providers -GET /api/payment/providers?currency= ``` -Retrieves the list of available payment providers for the store. Optionally filter by currency to get only providers that support the specified currency. +Retrieves the list of available payment providers for the store. **Query Parameters:** -- `currency` (optional): Three-letter ISO currency code (e.g., "USD", "EUR", "NOK") to filter providers by supported currency +- `currency` (string, optional): Three-letter ISO currency code to filter providers by supported currency -Example response: +**Response Body:** ```json -[ - { - "type": "stripe", - "name": "Stripe", - "description": "Pay with credit or debit card", - "enabled": true, - "methods": ["credit_card"], - "supported_currencies": [ - "USD", - "EUR", - "GBP", - "JPY", - "CAD", - "AUD", - "CHF", - "SEK", - "NOK", - "DKK", - "PLN", - "CZK", - "HUF", - "BGN", - "RON", - "HRK", - "ISK", - "MXN", - "BRL", - "SGD", - "HKD", - "INR", - "MYR", - "PHP", - "THB", - "TWD", - "KRW", - "NZD", - "ILS", - "ZAR" - ] - }, - { - "type": "mobilepay", - "name": "MobilePay", - "description": "Pay with MobilePay app", - "enabled": true, - "methods": ["wallet"], - "supported_currencies": ["NOK", "DKK", "EUR"] - } -] -``` - -Example request filtering by currency: - -```plaintext -GET /api/payment/providers?currency=NOK +{ + "success": true, + "data": [ + { + "type": "stripe", + "name": "Stripe", + "description": "Pay with credit or debit card", + "enabled": true, + "methods": ["credit_card"], + "supported_currencies": [ + "USD", + "EUR", + "GBP", + "JPY", + "CAD", + "AUD", + "CHF", + "SEK", + "NOK", + "DKK", + "PLN", + "CZK", + "HUF", + "BGN", + "RON", + "HRK", + "ISK", + "MXN", + "BRL", + "SGD", + "HKD", + "INR", + "MYR", + "PHP", + "THB", + "TWD", + "KRW", + "NZD", + "ILS", + "ZAR" + ] + }, + { + "type": "mobilepay", + "name": "MobilePay", + "description": "Pay with MobilePay app", + "enabled": true, + "methods": ["wallet"], + "supported_currencies": ["NOK", "DKK", "EUR"] + } + ] +} ``` -This would return only payment providers that support Norwegian Krone (NOK), which would include Stripe and MobilePay but exclude providers that don't support NOK. - **Status Codes:** - `200 OK`: Providers retrieved successfully +- `500 Internal Server Error`: Failed to retrieve providers ## Admin Payment Management Endpoints +All admin payment endpoints require authentication and admin role. + ### Capture Payment ```plaintext @@ -93,24 +96,265 @@ POST /api/admin/payments/{paymentId}/capture Capture a previously authorized payment (admin only). -**Request Body (Partial Capture):** +**Path Parameters:** + +- `paymentId` (required): Payment ID + +**Request Body (Optional for partial capture):** ```json { - "amount": 1500.00, - "is_full": false + "amount": 150.0 +} +``` + +**Status Codes:** + +- `200 OK`: Payment captured successfully +- `400 Bad Request`: Invalid request or payment cannot be captured +- `401 Unauthorized`: Not authenticated +- `403 Forbidden`: Not authorized (not an admin) +- `404 Not Found`: Payment not found + +### Cancel Payment + +```plaintext +POST /api/admin/payments/{paymentId}/cancel +``` + +Cancel an authorized payment (admin only). + +**Path Parameters:** + +- `paymentId` (required): Payment ID + +**Status Codes:** + +- `200 OK`: Payment cancelled successfully +- `400 Bad Request`: Payment cannot be cancelled +- `401 Unauthorized`: Not authenticated +- `403 Forbidden`: Not authorized (not an admin) +- `404 Not Found`: Payment not found + +### Refund Payment + +```plaintext +POST /api/admin/payments/{paymentId}/refund +``` + +Refund a captured payment (admin only). + +**Path Parameters:** + +- `paymentId` (required): Payment ID + +**Request Body (Optional for partial refund):** + +```json +{ + "amount": 75.0, + "reason": "Customer requested refund" +} +``` + +**Status Codes:** + +- `200 OK`: Payment refunded successfully +- `400 Bad Request`: Invalid request or payment cannot be refunded +- `401 Unauthorized`: Not authenticated +- `403 Forbidden`: Not authorized (not an admin) +- `404 Not Found`: Payment not found + +### Force Approve MobilePay Payment + +```plaintext +POST /api/admin/payments/{paymentId}/force-approve +``` + +Force approve a MobilePay payment (admin only). This is typically used for testing purposes. + +**Path Parameters:** + +- `paymentId` (required): Payment ID + +**Status Codes:** + +- `200 OK`: Payment force approved successfully +- `400 Bad Request`: Payment cannot be force approved or not a MobilePay payment +- `401 Unauthorized`: Not authenticated +- `403 Forbidden`: Not authorized (not an admin) +- `404 Not Found`: Payment not found + +## Admin Payment Provider Management Endpoints + +### Get Payment Providers + +```plaintext +GET /api/admin/payment-providers +``` + +Get all payment providers with their configuration (admin only). + +**Status Codes:** + +- `200 OK`: Payment providers retrieved successfully +- `401 Unauthorized`: Not authenticated +- `403 Forbidden`: Not authorized (not an admin) + +### Get Enabled Payment Providers + +```plaintext +GET /api/admin/payment-providers/enabled +``` + +Get only enabled payment providers (admin only). + +**Status Codes:** + +- `200 OK`: Enabled payment providers retrieved successfully +- `401 Unauthorized`: Not authenticated +- `403 Forbidden`: Not authorized (not an admin) + +### Enable/Disable Payment Provider + +```plaintext +PUT /api/admin/payment-providers/{providerType}/enable +``` + +Enable or disable a payment provider (admin only). + +**Path Parameters:** + +- `providerType` (required): Provider type (e.g., "stripe", "mobilepay") + +**Request Body:** + +```json +{ + "enabled": true } ``` +**Status Codes:** + +- `200 OK`: Provider status updated successfully +- `400 Bad Request`: Invalid request body +- `401 Unauthorized`: Not authenticated +- `403 Forbidden`: Not authorized (not an admin) +- `404 Not Found`: Provider not found + +### Update Provider Configuration + +```plaintext +PUT /api/admin/payment-providers/{providerType}/configuration +``` + +Update payment provider configuration (admin only). + +**Path Parameters:** + +- `providerType` (required): Provider type (e.g., "stripe", "mobilepay") + +**Request Body:** + +```json +{ + "configuration": { + "api_key": "sk_test_...", + "webhook_secret": "whsec_...", + "sandbox_mode": true + } +} +``` + +**Status Codes:** + +- `200 OK`: Configuration updated successfully +- `400 Bad Request`: Invalid configuration +- `401 Unauthorized`: Not authenticated +- `403 Forbidden`: Not authorized (not an admin) +- `404 Not Found`: Provider not found + +### Register Webhook + +```plaintext +POST /api/admin/payment-providers/{providerType}/webhook +``` + +Register a webhook for a payment provider (admin only). + +**Path Parameters:** + +- `providerType` (required): Provider type (e.g., "stripe", "mobilepay") + +**Request Body:** + +```json +{ + "url": "https://api.example.com/webhooks/stripe", + "events": ["payment_intent.succeeded", "payment_intent.payment_failed"] +} +``` + +**Status Codes:** + +- `201 Created`: Webhook registered successfully +- `400 Bad Request`: Invalid request body +- `401 Unauthorized`: Not authenticated +- `403 Forbidden`: Not authorized (not an admin) + +### Delete Webhook + +```plaintext +DELETE /api/admin/payment-providers/{providerType}/webhook +``` + +Delete webhook for a payment provider (admin only). + +**Path Parameters:** + +- `providerType` (required): Provider type (e.g., "stripe", "mobilepay") + +**Status Codes:** + +- `200 OK`: Webhook deleted successfully +- `401 Unauthorized`: Not authenticated +- `403 Forbidden`: Not authorized (not an admin) +- `404 Not Found`: Webhook not found + +### Get Webhook Info + +```plaintext +GET /api/admin/payment-providers/{providerType}/webhook +``` + +Get webhook information for a payment provider (admin only). + +**Path Parameters:** + +- `providerType` (required): Provider type (e.g., "stripe", "mobilepay") + +**Status Codes:** + +- `200 OK`: Webhook information retrieved successfully +- `401 Unauthorized`: Not authenticated +- `403 Forbidden`: Not authorized (not an admin) +- `404 Not Found`: Webhook not found + "is_full": false + } + +```` + **Request Body (Full Capture):** ```json { "is_full": true } -``` +```` + +**Note:** -**Note:** - When `is_full` is `true`, the `amount` field is ignored and the full authorized amount is captured - When `is_full` is `false` (or omitted), the `amount` field is required - If both `amount` and `is_full: true` are provided, `is_full` takes precedence @@ -171,7 +415,7 @@ Refund a captured payment (admin only). ```json { - "amount": 1500.00, + "amount": 1500.0, "is_full": false } ``` @@ -184,7 +428,8 @@ Refund a captured payment (admin only). } ``` -**Note:** +**Note:** + - When `is_full` is `true`, the `amount` field is ignored and the full captured amount is refunded - When `is_full` is `false` (or omitted), the `amount` field is required - If both `amount` and `is_full: true` are provided, `is_full` takes precedence diff --git a/docs/product_api_examples.md b/docs/product_api_examples.md index 7f960b3..b060a0a 100644 --- a/docs/product_api_examples.md +++ b/docs/product_api_examples.md @@ -10,16 +10,85 @@ This document provides example request bodies and responses for the product syst ## Public Product Endpoints -### List Products +### Get Product + +```plaintext +GET /api/products/{productId} +``` + +Get a product by ID. + +**Path Parameters:** + +- `productId` (required): Product ID + +**Response Body:** + +```json +{ + "success": true, + "data": { + "id": 1, + "name": "Smartphone", + "description": "Latest smartphone model", + "currency": "USD", + "price": 999.99, + "sku": "PROD-001", + "total_stock": 50, + "category": "Electronics", + "category_id": 1, + "images": ["https://example.com/smartphone.jpg"], + "has_variants": true, + "active": true, + "variants": [ + { + "id": 1, + "product_id": 1, + "variant_name": "Size L", + "sku": "PROD-001-L", + "stock": 50, + "attributes": { + "size": "L", + "color": "black" + }, + "images": ["https://example.com/variant1.jpg"], + "is_default": true, + "weight": 0.35, + "price": 999.99, + "currency": "USD", + "created_at": "2025-07-07T10:30:45Z", + "updated_at": "2025-07-07T10:30:45Z" + } + ], + "created_at": "2025-07-07T10:30:45Z", + "updated_at": "2025-07-07T10:30:45Z" + } +} +``` + +**Status Codes:** -`GET /api/products` +- `200 OK`: Product retrieved successfully +- `404 Not Found`: Product not found + +### Search Products -List all products with pagination. +```plaintext +GET /api/products/search +``` + +Search for products with optional filters. **Query Parameters:** -- `page` (optional): Page number (default: 1) -- `page_size` (optional): Items per page (default: 10) +- `query` (string, optional): Search term +- `category_id` (number, optional): Filter by category ID +- `min_price` (number, optional): Minimum price filter +- `max_price` (number, optional): Maximum price filter +- `currency` (string, optional): Currency code (default: USD) +- `active_only` (boolean, optional): Show only active products (default: true) +- `page` (number, optional): Page number (default: 1) +- `page_size` (number, optional): Items per page (default: 10) Example response: @@ -272,30 +341,176 @@ Example response: - `200 OK`: Categories retrieved successfully - `500 Internal Server Error`: Server error occurred -## Seller Product Endpoints +## Admin Product Endpoints + +All admin product endpoints require authentication and admin role. + +### List Products + +```plaintext +GET /api/admin/products +``` + +List all products (admin only). + +**Query Parameters:** + +- `page` (number, optional): Page number (default: 1) +- `page_size` (number, optional): Items per page (default: 10) +- `query` (string, optional): Search term +- `category_id` (number, optional): Filter by category ID +- `min_price` (number, optional): Minimum price filter +- `max_price` (number, optional): Maximum price filter +- `currency` (string, optional): Currency code +- `active_only` (boolean, optional): Show only active products + +**Status Codes:** + +- `200 OK`: Products retrieved successfully +- `401 Unauthorized`: Not authenticated +- `403 Forbidden`: Not authorized (not an admin) ### Create Product -`POST /api/products` +```plaintext +POST /api/admin/products +``` -Create a new product (seller only). +Create a new product (admin only). -Request body: +**Request Body:** ```json { "name": "New Product", "description": "Product description", - "price": 199.99, - "stock_quantity": 100, - "weight": 1.5, + "currency": "USD", "category_id": 1, - "images": ["product.jpg"], - "variants": [] + "images": ["https://example.com/product.jpg"], + "active": true, + "variants": [ + { + "sku": "PROD-004-L", + "stock": 100, + "attributes": [ + { "name": "size", "value": "L" }, + { "name": "color", "value": "blue" } + ], + "images": ["https://example.com/variant1.jpg"], + "is_default": true, + "weight": 1.5, + "price": 199.99 + } + ] +} +``` + +**Note:** All products must have at least one variant. If no variants are provided in the request, a default variant will be automatically created. + +**Response Body:** + +```json +{ + "success": true, + "message": "Product created successfully", + "data": { + "id": 4, + "name": "New Product", + "description": "Product description", + "currency": "USD", + "price": 199.99, + "sku": "PROD-004-L", + "total_stock": 100, + "category": "Electronics", + "category_id": 1, + "images": ["https://example.com/product.jpg"], + "has_variants": true, + "active": true, + "variants": [ + { + "id": 1, + "product_id": 4, + "variant_name": "Size L", + "sku": "PROD-004-L", + "stock": 100, + "attributes": { + "size": "L", + "color": "blue" + }, + "images": ["https://example.com/variant1.jpg"], + "is_default": true, + "weight": 1.5, + "price": 199.99, + "currency": "USD", + "created_at": "2025-07-07T10:30:45Z", + "updated_at": "2025-07-07T10:30:45Z" + } + ], + "created_at": "2025-07-07T10:30:45Z", + "updated_at": "2025-07-07T10:30:45Z" + } +} +``` + +**Status Codes:** + +- `201 Created`: Product created successfully +- `400 Bad Request`: Invalid request body or validation error +- `401 Unauthorized`: Not authenticated +- `403 Forbidden`: Not authorized (not an admin) + +### Update Product + +```plaintext +PUT /api/admin/products/{productId} +``` + +Update an existing product (admin only). + +**Path Parameters:** + +- `productId` (required): Product ID + +**Request Body:** + +```json +{ + "name": "Updated Product Name", + "description": "Updated description", + "currency": "USD", + "category_id": 2, + "images": ["https://example.com/updated-product.jpg"], + "active": true } ``` -**Note:** All products must have at least one variant. If no variants are provided in the request, a default variant will be automatically created using the product's basic information (price, stock) and the product number as the SKU. +**Status Codes:** + +- `200 OK`: Product updated successfully +- `400 Bad Request`: Invalid request body +- `401 Unauthorized`: Not authenticated +- `403 Forbidden`: Not authorized (not an admin) +- `404 Not Found`: Product not found + +### Delete Product + +```plaintext +DELETE /api/admin/products/{productId} +``` + +Delete a product (admin only). + +**Path Parameters:** + +- `productId` (required): Product ID + +**Status Codes:** + +- `200 OK`: Product deleted successfully +- `401 Unauthorized`: Not authenticated +- `403 Forbidden`: Not authorized (not an admin) +- `404 Not Found`: Product not found +- `409 Conflict`: Cannot delete product with existing orders Example response: @@ -464,49 +679,60 @@ Example response: ## Product Variant Endpoints +All variant endpoints require authentication and admin role. + ### Add Product Variant -`POST /api/products/{productId}/variants` +```plaintext +POST /api/admin/products/{productId}/variants +``` -Add a variant to a product (seller only). +Add a variant to a product (admin only). -Request body: +**Path Parameters:** + +- `productId` (required): Product ID + +**Request Body:** ```json { - "sku": "PROD-RED-M", - "price": 29.99, - "compare_price": 39.99, - "stock_quantity": 10, - "attributes": { - "color": "Red", - "size": "Medium" - }, - "images": ["red-shirt.jpg"], - "is_default": true + "sku": "PROD-004-M", + "stock": 10, + "attributes": [ + { "name": "color", "value": "Red" }, + { "name": "size", "value": "Medium" } + ], + "images": ["https://example.com/red-variant.jpg"], + "is_default": false, + "weight": 1.2, + "price": 29.99 } ``` -Example response: +**Response Body:** ```json { "success": true, + "message": "Variant added successfully", "data": { "id": 11, - "created_at": "2023-04-28T15:00:00Z", - "updated_at": "2023-04-28T15:00:00Z", - "product_id": 3, - "sku": "PROD-RED-M", - "price": 29.99, - "compare_price": 39.99, - "stock_quantity": 10, + "product_id": 4, + "variant_name": "Color Red, Size Medium", + "sku": "PROD-004-M", + "stock": 10, "attributes": { "color": "Red", "size": "Medium" }, - "images": ["red-shirt.jpg"], - "is_default": true + "images": ["https://example.com/red-variant.jpg"], + "is_default": false, + "weight": 1.2, + "price": 29.99, + "currency": "USD", + "created_at": "2025-07-07T10:30:45Z", + "updated_at": "2025-07-07T10:30:45Z" } } ``` @@ -514,34 +740,72 @@ Example response: **Status Codes:** - `201 Created`: Variant created successfully -- `400 Bad Request`: Invalid request body +- `400 Bad Request`: Invalid request body or validation error - `401 Unauthorized`: Not authenticated -- `403 Forbidden`: Not authorized (not the seller of this product) -- `500 Internal Server Error`: Server error occurred +- `403 Forbidden`: Not authorized (not an admin) +- `404 Not Found`: Product not found +- `409 Conflict`: Variant with this SKU already exists ### Update Product Variant -`PUT /api/products/{productId}/variants/{variantId}` +```plaintext +PUT /api/admin/products/{productId}/variants/{variantId} +``` -Update a product variant (seller only). +Update a product variant (admin only). -Request body: +**Path Parameters:** + +- `productId` (required): Product ID +- `variantId` (required): Variant ID + +**Request Body:** ```json { - "sku": "PROD-RED-M", - "price": 24.99, - "compare_price": 34.99, - "stock_quantity": 15, - "attributes": { - "color": "Red", - "size": "Medium" - }, - "images": ["red-shirt-updated.jpg"], - "is_default": true + "sku": "PROD-004-M-UPDATED", + "stock": 15, + "attributes": [ + { "name": "color", "value": "Dark Red" }, + { "name": "size", "value": "Medium" } + ], + "images": ["https://example.com/dark-red-variant.jpg"], + "is_default": false, + "weight": 1.3, + "price": 24.99 } ``` +**Status Codes:** + +- `200 OK`: Variant updated successfully +- `400 Bad Request`: Invalid request body +- `401 Unauthorized`: Not authenticated +- `403 Forbidden`: Not authorized (not an admin) +- `404 Not Found`: Product or variant not found +- `409 Conflict`: Variant with this SKU already exists + +### Delete Product Variant + +```plaintext +DELETE /api/admin/products/{productId}/variants/{variantId} +``` + +Delete a product variant (admin only). + +**Path Parameters:** + +- `productId` (required): Product ID +- `variantId` (required): Variant ID + +**Status Codes:** + +- `200 OK`: Variant deleted successfully +- `401 Unauthorized`: Not authenticated +- `403 Forbidden`: Not authorized (not an admin) +- `404 Not Found`: Product or variant not found +- `409 Conflict`: Cannot delete the last variant of a product or variant with existing orders + Example response: ```json diff --git a/docs/shipping_api_examples.md b/docs/shipping_api_examples.md index 0efca1a..2577865 100644 --- a/docs/shipping_api_examples.md +++ b/docs/shipping_api_examples.md @@ -6,97 +6,209 @@ This document provides example request bodies for the shipping system API endpoi ### Calculate Shipping Options -`POST /api/shipping/options` +```plaintext +POST /api/shipping/options +``` Calculate available shipping options for an address and order details. +**Request Body:** + ```json { "address": { - "street_address": "123 Main St", + "address_line1": "123 Main St", + "address_line2": "Apt 4B", "city": "San Francisco", "state": "CA", "postal_code": "94105", "country": "US" }, - "order_value": 150.00, + "order_value": 150.0, "order_weight": 2.5 } ``` -Example response: +**Response Body:** ```json { - "options": [ - { - "shipping_rate_id": 1, - "shipping_method_id": 1, - "name": "Standard Shipping", - "description": "Delivery in 3-5 business days", - "estimated_delivery_days": 5, - "cost": 7.99, - "free_shipping": false - }, - { - "shipping_rate_id": 2, - "shipping_method_id": 2, - "name": "Express Shipping", - "description": "Delivery in 1-2 business days", - "estimated_delivery_days": 2, - "cost": 14.99, - "free_shipping": false - }, - { - "shipping_rate_id": 3, - "shipping_method_id": 3, - "name": "Free Ground Shipping", - "description": "Free shipping for orders over $100", - "estimated_delivery_days": 7, - "cost": 0, - "free_shipping": true - } - ] + "success": true, + "data": { + "options": [ + { + "shipping_rate_id": 1, + "shipping_method_id": 1, + "name": "Standard Shipping", + "description": "Delivery in 3-5 business days", + "estimated_delivery_days": 5, + "cost": 7.99, + "free_shipping": false + }, + { + "shipping_rate_id": 2, + "shipping_method_id": 2, + "name": "Express Shipping", + "description": "Delivery in 1-2 business days", + "estimated_delivery_days": 2, + "cost": 14.99, + "free_shipping": false + }, + { + "shipping_rate_id": 3, + "shipping_method_id": 3, + "name": "Free Ground Shipping", + "description": "Free shipping for orders over $100", + "estimated_delivery_days": 7, + "cost": 0.0, + "free_shipping": true + } + ] + } } ``` -### Get Shipping Cost for a Specific Rate +**Status Codes:** + +- `200 OK`: Shipping options calculated successfully +- `400 Bad Request`: Invalid request body or address + +## Admin Shipping Endpoints + +All admin shipping endpoints require authentication and admin role. + +### Create Shipping Method + +```plaintext +POST /api/admin/shipping/methods +``` -`POST /api/shipping/rates/{id}/cost` +Create a new shipping method (admin only). -Calculate shipping cost for a specific shipping rate. +**Request Body:** ```json { - "order_value": 99.95, - "order_weight": 1.5 + "name": "Premium Overnight", + "description": "Next day delivery guaranteed", + "estimated_delivery_days": 1 } ``` -Example response: +**Status Codes:** + +- `201 Created`: Shipping method created successfully +- `400 Bad Request`: Invalid request body +- `401 Unauthorized`: Not authenticated +- `403 Forbidden`: Not authorized (not an admin) + +### Create Shipping Zone + +```plaintext +POST /api/admin/shipping/zones +``` + +Create a new shipping zone (admin only). + +**Request Body:** ```json { - "cost": 5.99 + "name": "US West Coast", + "description": "West coast shipping zone", + "countries": ["US"], + "states": ["CA", "OR", "WA"], + "zip_codes": ["9****", "8****"] } ``` -## Admin Shipping Endpoints +**Status Codes:** -### Create Shipping Method +- `201 Created`: Shipping zone created successfully +- `400 Bad Request`: Invalid request body +- `401 Unauthorized`: Not authenticated +- `403 Forbidden`: Not authorized (not an admin) -`POST /api/admin/shipping/methods` +### Create Shipping Rate + +```plaintext +POST /api/admin/shipping/rates +``` + +Create a new shipping rate (admin only). -Create a new shipping method. +**Request Body:** ```json { - "name": "Premium Overnight", - "description": "Next day delivery guaranteed", - "estimated_delivery_days": 1 + "shipping_method_id": 1, + "shipping_zone_id": 1, + "base_rate": 9.99, + "min_order_value": 0.0, + "free_shipping_threshold": 100.0, + "active": true +} +``` + +**Status Codes:** + +- `201 Created`: Shipping rate created successfully +- `400 Bad Request`: Invalid request body +- `401 Unauthorized`: Not authenticated +- `403 Forbidden`: Not authorized (not an admin) + +### Create Weight-Based Rate + +```plaintext +POST /api/admin/shipping/rates/weight +``` + +Create a weight-based shipping rate (admin only). + +**Request Body:** + +```json +{ + "shipping_rate_id": 1, + "min_weight": 0.0, + "max_weight": 5.0, + "rate": 5.99 } ``` +**Status Codes:** + +- `201 Created`: Weight-based rate created successfully +- `400 Bad Request`: Invalid request body +- `401 Unauthorized`: Not authenticated +- `403 Forbidden`: Not authorized (not an admin) + +### Create Value-Based Rate + +```plaintext +POST /api/admin/shipping/rates/value +``` + +Create a value-based shipping rate (admin only). + +**Request Body:** + +```json +{ + "shipping_rate_id": 1, + "min_order_value": 0.0, + "max_order_value": 50.0, + "rate": 9.99 +} +``` + +**Status Codes:** + +- `201 Created`: Value-based rate created successfully +- `400 Bad Request`: Invalid request body +- `401 Unauthorized`: Not authenticated +- `403 Forbidden`: Not authorized (not an admin) + ### Update Shipping Method `PUT /api/admin/shipping/methods/{id}` @@ -156,8 +268,8 @@ Create a new shipping rate connecting a method and zone. "shipping_method_id": 1, "shipping_zone_id": 1, "base_rate": 8.99, - "min_order_value": 0.00, - "free_shipping_threshold": 100.00, + "min_order_value": 0.0, + "free_shipping_threshold": 100.0, "active": true } ``` @@ -171,8 +283,8 @@ Update an existing shipping rate. ```json { "base_rate": 7.99, - "min_order_value": 0.00, - "free_shipping_threshold": 75.00, + "min_order_value": 0.0, + "free_shipping_threshold": 75.0, "active": true } ``` @@ -203,7 +315,7 @@ Add a value-based rate to an existing shipping rate. "shipping_rate_id": 1, "min_order_value": 50.0, "max_order_value": 100.0, - "rate": -1.50 + "rate": -1.5 } ``` @@ -222,4 +334,4 @@ Add a value-based rate to an existing shipping rate. 2. Available shipping options are displayed to the customer based on their location and order details 3. Customer selects a shipping option during checkout 4. The selected shipping method is included in the order -5. Shipping cost is calculated and added to the order total \ No newline at end of file +5. Shipping cost is calculated and added to the order total diff --git a/docs/user_api_examples.md b/docs/user_api_examples.md index 0eb21c6..916cb94 100644 --- a/docs/user_api_examples.md +++ b/docs/user_api_examples.md @@ -7,7 +7,7 @@ This document provides example request bodies for the user system API endpoints. ### Register User ```plaintext -POST /api/users/register +POST /api/auth/register ``` Register a new user account. @@ -19,8 +19,7 @@ Register a new user account. "email": "user@example.com", "password": "Password123!", "first_name": "John", - "last_name": "Smith", - "role": "user" + "last_name": "Smith" } ``` @@ -55,7 +54,7 @@ Example response: ### Login ```plaintext -POST /api/users/login +POST /api/auth/signin ``` Authenticate a user and retrieve a JWT token. diff --git a/docs/webhook_api_examples.md b/docs/webhook_api_examples.md new file mode 100644 index 0000000..a1041b7 --- /dev/null +++ b/docs/webhook_api_examples.md @@ -0,0 +1,123 @@ +# Webhook API Documentation + +This document outlines the webhook endpoints for receiving payment provider notifications. + +## Webhook Endpoints + +Webhook endpoints are designed for server-to-server communication and do not require authentication or CORS handling. They are used by payment providers to notify the system about payment events. + +### Stripe Webhook + +```plaintext +POST /api/webhooks/stripe +``` + +Stripe webhook endpoint for receiving payment events from Stripe. + +**Description:** +This endpoint handles incoming webhook events from Stripe, including: + +- Payment authorization events +- Payment capture events +- Payment failure events +- Payment cancellation events + +**Headers:** + +- `Stripe-Signature`: Webhook signature for verification + +**Request Body:** +The request body contains the Stripe event data in JSON format. The exact structure depends on the event type. + +**Response:** + +- `200 OK`: Event processed successfully +- `400 Bad Request`: Invalid signature or malformed payload +- `500 Internal Server Error`: Error processing the event + +### MobilePay Webhook + +```plaintext +POST /api/webhooks/mobilepay +``` + +MobilePay webhook endpoint for receiving payment events from MobilePay. + +**Description:** +This endpoint handles incoming webhook events from MobilePay, including: + +- Payment authorization events +- Payment capture events +- Payment cancellation events +- Payment expiration events +- Payment refund events + +**Headers:** + +- Content verification headers as required by MobilePay + +**Request Body:** +The request body contains the MobilePay event data in JSON format. The exact structure depends on the event type and follows the MobilePay webhook specification. + +**Response:** + +- `200 OK`: Event processed successfully +- `400 Bad Request`: Invalid signature or malformed payload +- `500 Internal Server Error`: Error processing the event + +## Security + +### Signature Verification + +Both webhook endpoints implement signature verification to ensure the authenticity of incoming requests: + +- **Stripe**: Uses the `Stripe-Signature` header with HMAC-SHA256 verification +- **MobilePay**: Uses MobilePay's signature verification mechanism + +### Event Processing + +Webhook events are processed asynchronously and include: + +1. **Signature Verification**: Verify the request comes from the legitimate payment provider +2. **Event Parsing**: Parse the event data and extract relevant information +3. **Order Updates**: Update order status and payment transactions +4. **Database Recording**: Record payment transactions in the database +5. **Response**: Return appropriate HTTP status code + +### Error Handling + +If webhook processing fails: + +- The endpoint returns an appropriate error status code +- The error is logged for debugging purposes +- Payment providers typically retry failed webhook deliveries + +### Event Types + +#### Stripe Events + +- `payment_intent.succeeded`: Payment successfully captured +- `payment_intent.payment_failed`: Payment failed +- `payment_intent.canceled`: Payment was canceled + +#### MobilePay Events + +- `payment.authorized`: Payment was authorized +- `payment.captured`: Payment was captured +- `payment.cancelled`: Payment was cancelled +- `payment.expired`: Payment authorization expired +- `payment.refunded`: Payment was refunded + +## Testing Webhooks + +### Development + +During development, you can use tools like ngrok to expose your local webhook endpoints to payment providers for testing. + +### Production + +In production, ensure webhook endpoints are: + +- Accessible over HTTPS +- Properly configured in the payment provider dashboard +- Monitoring webhook delivery success rates diff --git a/internal/domain/entity/order.go b/internal/domain/entity/order.go index 6f1b76e..a29580c 100644 --- a/internal/domain/entity/order.go +++ b/internal/domain/entity/order.go @@ -123,6 +123,7 @@ func NewOrderFromCheckout(checkout *Checkout) (*Order, error) { ProductVariantID: item.ProductVariantID, Quantity: item.Quantity, Price: item.Price, + Subtotal: item.Price * int64(item.Quantity), SKU: item.SKU, ProductName: item.ProductName, ImageURL: item.ImageURL, @@ -317,8 +318,13 @@ func (o *Order) SetOrderNumber(id *uint) { prefix = "GS" } + var orderID uint + if id != nil { + orderID = *id + } + // Format: ORD-YYYYMMDD-000001 or GS-YYYYMMDD-000001 - o.OrderNumber = fmt.Sprintf("%s-%s-%06d", prefix, o.CreatedAt.Format("20060102"), id) + o.OrderNumber = fmt.Sprintf("%s-%s-%06d", prefix, o.CreatedAt.Format("20060102"), orderID) } // ApplyDiscount applies a discount to the order