# Quinio API

RESTful API built with **PHP 7.4** and **Laravel 5.3** for e-commerce order management and business integrations.

## Tech Stack

- **PHP:** 7.4
- **Framework:** Laravel 5.3
- **Authentication:** Laravel Passport (OAuth2)
- **Database:** MySQL with replication support
- **SOAP Client:** NuSOAP (econea/nusoap)
- **HTTP Client:** Guzzle 6.5

---

## Business Integrations

### 1. URL Shortener with Zip1.io

**Controller:** `app/Http/Controllers/UrlShortenerController.php`  
**Service:** `app/Services/UrlShortener/Zip1UrlShortener.php`

#### Business Purpose
Shortens long URLs for SMS campaigns and marketing communications. Critical for SMS delivery as messages are limited to 160 characters. Automatically used by SMS templates to optimize message length.

#### Features
- Custom URL aliases for branded links
- Click tracking with configurable limits
- Password-protected links
- Link descriptions for analytics
- Fallback to original URL on API failure
- Integration with SMS template system

#### API Endpoint
```
POST /api/url/shorten
```

**Authentication:** OAuth2 Bearer Token  
**Scope:** `url-shortener`

#### Request Parameters

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `url` | string | Yes | Long URL to shorten (must be valid URL) |
| `alias` | string | No | Custom short code (e.g., "summer-sale") |
| `max-clicks` | integer | No | Maximum number of clicks before expiration |
| `password` | string | No | Password protection for the link |
| `description` | string | No | Internal description for tracking |

#### Request Example
```json
{
  "url": "https://example.com/products/summer-collection-2024?utm_source=sms&utm_campaign=launch",
  "alias": "summer24",
  "max-clicks": 1000,
  "password": "secret123",
  "description": "Summer Campaign SMS Link"
}
```

#### Response Example

**Success (200):**
```json
{
  "success": true,
  "short_url": "https://zip1.io/summer24",
  "code": 200
}
```

**Error (400):**
```json
{
  "success": false,
  "short_url": "https://example.com/products/summer-collection-2024?utm_source=sms&utm_campaign=launch",
  "code": 400,
  "error": "Invalid URL format"
}
```

#### Implementation Details

**Validation:** `app/Http/Requests/UrlShortenRequest.php`
- URL format validation
- Optional parameter sanitization
- OAuth scope verification

**Service Layer:** `app/Services/UrlShortener/Zip1UrlShortener.php`
- HTTP client with Guzzle
- Error handling and logging
- Automatic fallback mechanism

**External API:** [Zip1.io API Documentation](https://zip1.io/api)

#### Usage in SMS Templates
```php
// Automatic URL shortening in TemplateParamMapper
if (isset($paramCombined['info_url'])) {
    $urlShortener = app(Zip1UrlShortener::class);
    $result = $urlShortener->shorten(['url' => $paramCombined['info_url']]);
    $paramCombined['short_url'] = $result['success'] 
        ? $result['short_url'] 
        : $paramCombined['info_url'];
}
```

---

### 2. SMS Notifications with Convergia

**Controller:** `app/Http/Controllers/ConvergiaSmsController.php`  
**Service:** `app/Services/Sms/ConvergiaSmsAdapter.php`

#### Business Purpose
Sends transactional SMS notifications for order lifecycle events (confirmation, shipping, delivery). Supports template-based messaging with dynamic parameters and direct message sending. All messages are logged for compliance and analytics.

#### Features
- 7 predefined order notification templates
- Mexican phone number validation (LADA codes)
- Automatic URL shortening in messages
- Company-specific template overrides
- SOAP API integration with Convergia
- Delivery status tracking
- Database logging in `notifications_log` table

#### API Endpoint
```
POST /api/notifications/sms
```

**Authentication:** None (internal use)  
**Note:** Middleware temporarily disabled for testing

#### SMS Templates

| Template Name | Use Case | Parameters |
|---------------|----------|------------|
| `order_confirm_cod` | Cash on delivery orders | customer, order_number, items, info_url, amount_cod |
| `order_confirm_credit_card` | Credit card payments | order_number, info_url |
| `order_confirm_credit_card_dummy` | Pending payment validation | order_number, info_url |
| `order_confirm_referenced_deposit` | Bank deposit instructions | order_number, info_url, amount |
| `order_confirm_referenced_deposit_quinio` | Quinio-specific deposit | order_number, bank_account, amount |
| `order_shipped` | Shipping confirmation | customer, order_number, tracking_url |
| `order_delivery` | Delivery confirmation | order_number |

#### Request Parameters

**Template-based Message:**

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `to` | string | Yes | Mexican phone number (10 digits) |
| `element_name` | string | Yes | Template identifier |
| `localizable_params` | string | Yes | Pipe-separated parameters |
| `e` | integer | Yes | Company ID |
| `order_id` | integer | No | Order ID for logging |

**Direct Message:**

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `to` | string | Yes | Mexican phone number (10 digits) |
| `message` | string | Yes | SMS text (max 160 chars) |

#### Request Examples

**Template-based (COD Order):**
```json
{
  "to": "5551234567",
  "element_name": "order_confirm_cod",
  "localizable_params": "Juan Pérez|ORD-789456|2 productos|https://pedidos.example.com/track/789456|$1,250.00",
  "e": 1,
  "order_id": 789456
}
```

**Template-based (Shipping):**
```json
{
  "to": "5559876543",
  "element_name": "order_shipped",
  "localizable_params": "María López|ORD-123456|items|https://tracking.example.com/123456",
  "e": 1,
  "order_id": 123456
}
```

**Direct Message:**
```json
{
  "to": "5551112222",
  "message": "Tu código de verificación es: 847392. Válido por 10 minutos."
}
```

#### Response Examples

**Success (200):**
```json
{
  "success": true,
  "code": 100,
  "message": "Mensaje enviado correctamente",
  "message_id": "MSG-20240115-789456"
}
```

**Validation Error (400):**
```json
{
  "success": false,
  "code": 400,
  "message": "The phone number must be a valid Mexican phone number.",
  "message_id": null
}
```

**Template Error (424):**
```json
{
  "success": false,
  "code": 500,
  "message": "Template \"invalid_template\" not found.",
  "message_id": null
}
```

**SOAP Error (424):**
```json
{
  "success": false,
  "code": 500,
  "message": "SOAP Fault: error communicating with Convergia",
  "message_id": null
}
```

#### Convergia Response Codes

| Code | Status | Description |
|------|--------|-------------|
| 100 | Success | Message sent successfully |
| 101 | Error | API User not included |
| 102 | Error | API Password not included |
| 103 | Error | SMS text not included |
| 104 | Error | Phone number not included |
| 105 | Error | Message size exceeded |
| 109 | Error | Network error |
| 200 | Error | System error |
| 201 | Error | Invalid credentials |
| 202 | Error | IP not allowed |
| 204 | Error | Message limit exceeded |
| 254 | Error | Failed to send message |
| 307 | Error | Invalid phone number |
| 313 | Error | Invalid, incorrect or landline number |
| 315 | Error | Incorrect number length |

#### Architecture

**Design Patterns:**

1. **Adapter Pattern** (`ConvergiaSmsAdapter`)
   - Abstracts SOAP client complexity
   - Provides clean interface for SMS operations
   - Handles error mapping and logging

2. **Factory Pattern** (`SmsTemplateFactory`)
   - Creates template instances dynamically
   - Validates template existence
   - Enforces SmsTemplateInterface contract

3. **Strategy Pattern** (`TemplateParamMapper`)
   - Maps raw parameters to template variables
   - Handles company-specific configurations
   - Integrates URL shortening service

4. **Validator** (`MXPhoneValidator`)
   - Validates Mexican phone format (10 digits)
   - Checks LADA codes (area codes)
   - Normalizes to international format (+52XXXXXXXXXX)
   - Rejects trivial numbers (0000000000, 1111111111)

**Component Structure:**
```
app/
├── Http/
│   ├── Controllers/
│   │   └── ConvergiaSmsController.php
│   └── Requests/
│       ├── SmsSendRequest.php
│       └── SmsStatusRequest.php
├── Services/
│   └── Sms/
│       ├── ConvergiaSmsAdapter.php
│       ├── MXPhoneValidator.php
│       ├── SmsTemplateFactory.php
│       ├── TemplateParamMapper.php
│       └── Templates/
│           ├── SmsTemplateInterface.php
│           ├── OrderConfirmCodTemplate.php
│           ├── OrderConfirmCreditCardTemplate.php
│           ├── OrderConfirmCreditCardDummyTemplate.php
│           ├── OrderConfirmReferencedDepositTemplate.php
│           ├── OrderConfirmReferencedDepositQuinioTemplate.php
│           ├── OrderShippedTemplate.php
│           └── OrderDeliveryTemplate.php
├── Exceptions/
│   ├── SmsTemplateNotFoundException.php
│   └── SmsTemplateParamNotFoundException.php
└── Models/
    └── NotificationsLog.php
```

#### Phone Number Validation

**Valid Mexican Phone Numbers:**
- Format: 10 digits
- Area codes (LADA): 55, 56, 33, 81, 222, 229, etc.
- Mobile prefixes: TELCEL, AT&T, Movistar
- Normalized output: `+52XXXXXXXXXX`

**Examples:**
```php
MXPhoneValidator::isValid('5551234567');     // true
MXPhoneValidator::isValid('525551234567');   // true (removes +52)
MXPhoneValidator::isValid('0000000000');     // false (trivial)
MXPhoneValidator::isValid('123456789');      // false (9 digits)
MXPhoneValidator::normalize('5551234567');   // +525551234567
```

#### Template Parameter Mapping

**Example: COD Order Template**

Input:
```
localizable_params: "Juan Pérez|ORD-789456|2 productos|https://example.com/track|$1,250.00"
```

Mapping:
```php
[
    'customer_name' => 'Juan Pérez',        // index 0
    'order_number' => 'ORD-789456',         // index 1
    'order_items_summary' => '2 productos', // index 2
    'info_url' => 'https://example.com/track', // index 3
    'short_url' => 'https://zip1.io/abc123',    // auto-shortened
    'amount_cod' => '$1,250.00'             // index -1 (last)
]
```

Output Message:
```
Pedido ORD-789456 recibido. Consulta mas informacion en https://zip1.io/abc123. Pago contra entrega $1,250.00 al repartidor
```

#### Company-Specific Overrides

**Quinio Companies (e ≠ 29):**
- Template `order_confirm_referenced_deposit` → `order_confirm_referenced_deposit_quinio`
- Uses BBVA account from config: `custom.company.e{id}.bbva_account`
- Different message format with CLABE account

**Other Companies (e = 29):**
- Uses standard `order_confirm_referenced_deposit` template
- Generic deposit instructions with info URL

#### Database Logging

**Table:** `notifications_log`

**Fields:**
- `Company` - Company ID
- `ID_orders` - Order ID
- `Notification_way` - "Sms"
- `Template_Name` - Template identifier
- `Status` - "Delivered" / "Undelivered"
- `Date` - CURDATE()
- `Time` - CURTIME()

**Model:** `app/Models/NotificationsLog.php`

#### Configuration

**Environment Variables (.env):**
```env
CONVERGIA_SOAP_WSDL=https://api.convergia.com/soap?wsdl
CONVERGIA_USERNAME=your_username
CONVERGIA_PASSWORD=your_password
```

**Config File (config/app.php):**
```php
'convergia_soap' => env('CONVERGIA_SOAP_WSDL'),
'convergia_username' => env('CONVERGIA_USERNAME'),
'convergia_password' => env('CONVERGIA_PASSWORD'),
```

#### Testing

**Test Suite Location:** `tests/`

- `ConvergiaSmsControllerTest.php` - Controller integration tests
- `SmsSendRequestTest.php` - Request validation tests
- `SmsStatusRequestTest.php` - Status request tests
- `SmsTemplateFactoryTest.php` - Factory pattern tests
- `SmsTemplatesTest.php` - Template output tests
- `TemplateParamMapperTest.php` - Parameter mapping tests

**Run Tests:**
```bash
phpunit tests/ConvergiaSmsControllerTest.php
phpunit tests/SmsTemplatesTest.php
```

---

## License

Proprietary software. All rights reserved.
