# 🔒 Filtro de Campanhas por Merchant

## ✅ **Problema Resolvido**

**Antes:** Merchant users podiam ver campanhas de todos os merchants  
**Agora:** Merchant users veem apenas campanhas das suas próprias lojas

---

## 🔧 **Implementação**

### **1. Controller Atualizado (`controllers/campaignsController.js`)**

#### **`getAllCampaigns` - Filtrado por merchant**
```javascript
// Se não for admin, filtrar apenas campanhas das lojas do usuário
if (!isAdmin) {
    const MerchantUsers = require('../models/MerchantUsersModel');
    const merchantUsers = await MerchantUsers.findByUser(userId);
    
    if (merchantUsers.length === 0) {
        // Usuário não tem lojas, retornar vazio
        return res.status(200).json({
            success: true,
            data: [],
            pagination: { ... }
        });
    }

    // Extrair IDs das lojas
    merchantIds = merchantUsers.map(mu => mu.merchant_id);
}

const options = {
    page: parseInt(page),
    limit: parseInt(limit),
    active: active !== undefined ? active === 'true' : null,
    merchant_ids: merchantIds  // Filtrar por lojas do usuário
};
```

#### **`getCampaignsByEstablishment` - Verificação de acesso**
```javascript
// Se não for admin, verificar se usuário tem acesso a esta loja
if (!isAdmin) {
    const MerchantUsers = require('../models/MerchantUsersModel');
    const hasAccess = await MerchantUsers.findOne(merchantId, userId);
    
    // Verificar se é owner da loja
    const merchant = await Merchants.findById(merchantId);
    
    if (!hasAccess && (!merchant || merchant.owner_id !== userId)) {
        return next(ErrorResponse.forbidden('Você não tem acesso a esta loja'));
    }
}
```

---

### **2. Model Atualizado (`models/CampaignsModel.js`)**

#### **`findAll` - Suporte para filtro por merchant_ids**
```javascript
findAll: async (options = {}) => {
    const { page = 1, limit = 10, active = null, merchant_ids = null } = options;
    
    // ...
    
    let whereConditions = [];

    // Filtrar por merchant_ids se fornecido
    if (merchant_ids && Array.isArray(merchant_ids) && merchant_ids.length > 0 && hasMerchantId) {
        whereConditions.push(`c.merchant_id = ANY($${paramIndex})`);
        params.push(merchant_ids);
        paramIndex++;
    }

    if (active !== null) {
        whereConditions.push(`c.${activeField} = $${paramIndex}`);
        params.push(active);
        paramIndex++;
    }

    if (whereConditions.length > 0) {
        whereClause = `WHERE ${whereConditions.join(' AND ')}`;
    }
    
    // ...
}
```

---

## 🔐 **Regras de Acesso**

### **Admin:**
- ✅ Pode ver todas as campanhas
- ✅ Não há filtro aplicado

### **Merchant User:**
- ✅ Vê apenas campanhas das suas lojas
- ✅ Filtro automático baseado em `merchant_users`
- ✅ Se não tiver lojas, retorna lista vazia

### **Owner:**
- ✅ Vê campanhas das suas lojas (via `merchants.owner_id`)
- ✅ Pode ver campanhas mesmo se não estiver em `merchant_users`

---

## 📡 **Endpoints Afetados**

### **1. GET /api/campaigns**
**Antes:** Retornava todas as campanhas  
**Agora:** 
- Admin: Todas as campanhas
- Merchant User: Apenas campanhas das suas lojas

### **2. GET /api/campaigns/establishment/:establishmentId**
**Antes:** Retornava campanhas sem verificar acesso  
**Agora:** 
- Admin: Sempre permite
- Merchant User: Verifica se tem acesso à loja antes de retornar

---

## 🔄 **Fluxo de Funcionamento**

### **Cenário 1: Merchant User faz login**
```javascript
POST /api/auth/login
{
    "username": "merchant.user",
    "password": "senha123"
}

// Resposta inclui:
{
    "user": {
        ...
        "merchants": [
            { "merchant_id": 1, ... },
            { "merchant_id": 2, ... }
        ]
    }
}
```

### **Cenário 2: Merchant User lista campanhas**
```javascript
GET /api/campaigns

// Sistema automaticamente:
// 1. Busca lojas do usuário via MerchantUsers.findByUser(userId)
// 2. Extrai merchant_ids: [1, 2]
// 3. Filtra campanhas: WHERE c.merchant_id IN (1, 2)

// Resposta:
{
    "success": true,
    "data": [
        // Apenas campanhas das lojas 1 e 2
    ]
}
```

### **Cenário 3: Merchant User tenta ver campanhas de outra loja**
```javascript
GET /api/campaigns/establishment/999

// Sistema verifica:
// 1. MerchantUsers.findOne(999, userId) → null
// 2. Merchants.findById(999) → owner_id !== userId
// 3. Retorna: 403 Forbidden - "Você não tem acesso a esta loja"
```

---

## ✅ **Benefícios**

1. ✅ **Segurança**: Merchant users não podem ver campanhas de outras lojas
2. ✅ **Isolamento**: Cada merchant vê apenas seus dados
3. ✅ **Automatizado**: Filtro aplicado automaticamente sem necessidade de parâmetros
4. ✅ **Flexível**: Admin continua vendo tudo, merchant users veem apenas suas lojas

---

## 📝 **Notas Técnicas**

- O filtro é aplicado no nível do modelo (`CampaignsModel.findAll`)
- O controle de acesso é verificado no controller
- Se um merchant user não tiver lojas, retorna lista vazia (não erro)
- Owner da loja pode ver campanhas mesmo sem estar em `merchant_users`

---

## ✅ **Conclusão**

Agora cada merchant user vê apenas campanhas das suas próprias lojas! 🎉

**Status:** ✅ Implementado e funcional

