# Merchandise Return Request Controller Documentation

**File**: `/controllers/mechandiseReturnRequest.php`  
**Purpose**: Manages customer merchandise return requests with approval workflow  
**Last Updated**: December 20, 2024  
**Total Functions**: 8  
**Lines of Code**: ~325

---

## 📋 Overview

The Merchandise Return Request Controller handles the complete lifecycle of customer return requests for damaged or intact products. It manages:
- Customer return request creation and tracking
- Product condition assessment (damaged vs. intact)
- Multi-product return requests with individual comments
- Approval workflow with status tracking
- Dynamic product selection and management
- Client lookup and association
- Soft delete functionality for data integrity

### Primary Functions
- [x] Create and manage return requests
- [x] Track product conditions (damaged/intact)
- [x] Multi-product return handling
- [x] Approval workflow management
- [x] Dynamic product/client selection via AJAX
- [x] Soft delete with audit trail
- [x] Advanced filtering and search
- [x] Status tracking and reporting

### Related Controllers
- [sellbillController.php](#) - Original sales tracking
- [clientController.php](#) - Customer management
- [productController.php](#) - Product catalog
- [returnSellBillController.php](#) - Return processing

---

## 🗄️ Database Tables

### Primary Tables (Direct Operations)
| Table Name | Purpose | Key Columns |
|------------|---------|-------------|
| **mechandisereturnrequest** | Return request headers | id, clientid, damagedintact, agrees, addtoday, adduserid, updatetoday, updateuserid, deltoday, deluserid, conditions |
| **mechandisereturnproduct** | Return request product details | id, mechandisereturnrequestid, productid, comment, addtoday, adduserid, updatetoday, updateuserid, deltoday, deluserid, conditions |

### Reference Tables
| Table Name | Purpose | Key Columns |
|------------|---------|-------------|
| **client** | Customer information | clientid, clientname, clientphone |
| **product** | Product catalog | productId, productName, conditions |
| **user** | System users | userid, employeename |

---

## 🔑 Key Functions

### 1. **Default Action** - Add New Return Request
**Location**: Lines 6-9  
**Purpose**: Display form for creating new return requests

**Process Flow**:
1. Display header and add form template
2. Initialize empty form for new request

---

### 2. **appendproduct** - Dynamic Product Addition
**Location**: Lines 10-13  
**Purpose**: AJAX endpoint for adding product entries to return request

**Function Signature**:
```php
$itr = filter_input(INPUT_POST, 'itr');
```

**Process Flow**:
1. Accept iteration number for unique field naming
2. Display product addition template with unique identifiers
3. Enable dynamic form expansion

---

### 3. **show()** - Display Return Requests
**Location**: Lines 14-18  
**Purpose**: Show listing of all return requests with filtering

**Features**:
- DataTables integration for advanced filtering
- Real-time search and pagination
- Status-based filtering

---

### 4. **edit()** - Edit Return Request
**Location**: Lines 19-33  
**Purpose**: Edit existing return request with products

**Function Signature**:
```php
$id = filter_input(INPUT_GET, 'id');
```

**Process Flow**:
1. Load return request data by ID
2. Get associated client information
3. Load all products in the return request
4. Fetch product names for display
5. Assign data to edit template

**Data Loading**:
```php
$editdata = R::load('mechandisereturnrequest', $id);
$client = R::getRow('SELECT * FROM `client` WHERE clientid = ?',[$editdata->clientid]);
$editdata->clientname = $client['clientname'];

$mechandisereturnproducts = R::findAll('mechandisereturnproduct',
    'mechandisereturnrequestid = ? and conditions = 0',[$id]);

foreach($mechandisereturnproducts as $mechandisereturnproduct){
    $product = R::getRow('SELECT * FROM `product` WHERE productId = ?',
        [$mechandisereturnproduct->productid]);
    $mechandisereturnproduct->productname = $product['productName'];
}
```

---

### 5. **savedata()** - Save/Update Return Request
**Location**: Lines 102-161  
**Purpose**: Main function for saving return requests with products

**Function Signature**:
```php
function savedata()
```

**Input Parameters**:
- `damagedintact` - Condition flag (1=damaged, 0=intact)
- `clientid` - Customer ID making the return request
- `productsitr` - Number of products in request
- `productid_X` - Product IDs for each item
- `comment_X` - Comments for each product
- `mechandiseReturnProductid_X` - Existing product record IDs (for updates)

**Process Flow**:
1. Validate input parameters and get user information
2. Create new request or load existing for updates
3. Set appropriate timestamps and user tracking
4. Loop through all products and save/update each item
5. Redirect to show page on success

**Request Record Handling**:
```php
if (!$id) {
    $realestates = R::dispense('mechandisereturnrequest');
    $realestates->conditions = 0;
    $realestates->addtoday = $today;          
    $realestates->adduserid = $userid;
    $realestates->agrees = 0; // Pending approval
} else {
    $realestates = R::load('mechandisereturnrequest',$id);
    $realestates->updatetoday = $today;          
    $realestates->updateuserid = $userid; 
}
```

**Product Processing Loop**:
```php
for ($i = 1; $i <= $productsitr; $i++) {
    $productid = filter_input(INPUT_POST, 'productid_' . $i);
    $comment = filter_input(INPUT_POST, 'comment_' . $i);
    $mechandiseReturnProductid = filter_input(INPUT_POST, 'mechandiseReturnProductid_' . $i);
    
    if (!$productid) {continue;} // Skip empty products
    
    if (!$mechandiseReturnProductid) {
        // Create new product record
        $realestatesunits = R::dispense('mechandisereturnproduct');
        $realestatesunits->addtoday = $today;  
        $realestatesunits->adduserid = $userid;
    } else {
        // Update existing product record
        $realestatesunits = R::load('mechandisereturnproduct',$mechandiseReturnProductid); 
        $realestatesunits->updatetoday = $today;          
        $realestatesunits->updateuserid = $userid;
    }
    
    $realestatesunits->mechandisereturnrequestid = $mechandisereturnrequestid;  
    $realestatesunits->productid = $productid;
    $realestatesunits->comment = $comment;
    $realestatesunits->conditions = 0;
    R::store($realestatesunits);
}
```

---

### 6. **select2client()** - Client Search AJAX
**Location**: Lines 85-97  
**Purpose**: AJAX endpoint for client autocomplete search

**Function Signature**:
```php
function select2client()
```

**Process Flow**:
1. Accept search term from POST
2. Query clients with name/phone matching
3. Return formatted JSON for Select2 dropdown

**Search Query**:
```sql
SELECT clientid, CONCAT(clientname,'/',clientphone) as texts
FROM client 
WHERE conditions = 0 
  AND CONCAT(clientname,'/',clientphone) LIKE '%[searchTerm]%' 
LIMIT 50
```

---

### 7. **select2product()** - Product Search AJAX
**Location**: Lines 68-80  
**Purpose**: AJAX endpoint for product autocomplete search

**Function Signature**:
```php
function select2product()
```

**Process Flow**:
1. Accept product search term
2. Query active products by name
3. Return formatted JSON for dropdown selection

**Search Query**:
```sql
SELECT productId, CONCAT(productName) as texts
FROM product 
WHERE conditions = 0 
  AND CONCAT(productName) LIKE '%[searchTerm]%' 
LIMIT 50
```

---

### 8. **showajax()** - DataTables AJAX Handler
**Location**: Lines 166-284  
**Purpose**: Provide server-side processing for return request listing

**Function Signature**:
```php
function showajax()
```

**Filter Parameters**:
- `start_date` / `end_date` - Date range filtering
- `conditions` - Record status filter
- `clientid` - Client filter
- `productid` - Product filter
- `damagedintact` - Condition filter (damaged/intact)

**Process Flow**:
1. Build dynamic WHERE clause based on filters
2. Add optional product JOIN if filtering by product
3. Apply search functionality across multiple columns
4. Generate approval status dropdown for each record
5. Return formatted data with action buttons

**Approval Status Handling**:
```php
$agrees = '<select name="agrees" class="selectnew agrees" data-id="'.$row["id"].'">
    <option value="0" ';if($row["agrees"] == 0){$agrees .= 'selected';}$agrees .= '>قيد الانتظار</option>
    <option value="1" ';if($row["agrees"] == 1){$agrees .= 'selected';}$agrees .='>قبول</option>
    <option value="2" ';if($row["agrees"] == 2){$agrees .= 'selected';}$agrees .='>رفض</option>
</select>';
```

**Complex Product Loading**:
```php
$mechandisereturnproduct = R::getAll('SELECT * FROM `mechandisereturnproduct` 
    LEFT JOIN product ON mechandisereturnproduct.productid = product.productId  
    WHERE mechandisereturnproduct.conditions = 0');
    
$allproductName = '';
foreach($mechandisereturnproduct as $product){
    $allproductName .= $product['productName'] . ' / ';
}
```

---

### 9. **agrees()** - Approval Status Management
**Location**: Lines 51-67  
**Purpose**: AJAX endpoint for updating approval status

**Function Signature**:
```php
function agrees()
```

**Process Flow**:
1. Get return request ID and approval status
2. Update agreement status with timestamp and user
3. Return success/failure response

**Approval Logic**:
```php
$tables = R::load('mechandisereturnrequest',$id);
$tables->agrees = $agrees;
$tables->agreetoday = $today;
$tables->agreeuserid = $userid;
```

---

### 10. **removeappend()** - Remove Product from Request
**Location**: Lines 288-303  
**Purpose**: Soft delete individual products from return request

**Function Signature**:
```php
function removeappend()
```

**Process Flow**:
1. Get product record ID
2. Set conditions to 1 (soft delete)
3. Record deletion timestamp and user
4. Return success status

---

### 11. **remove()** - Delete Return Request
**Location**: Lines 305-322  
**Purpose**: Soft delete entire return request

**Function Signature**:
```php
function remove()
```

**Process Flow**:
1. Load return request by ID
2. Set soft delete flags and audit information
3. Redirect to listing page

---

## 🔄 Workflows

### Workflow 1: Return Request Creation
```
┌─────────────────────────────────────────────────────────────┐
│             START: Create Return Request                   │
└────────────────────┬────────────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────────────┐
│  1. Select Customer                                         │
│     - Search clients via AJAX autocomplete                 │
│     - Select customer making return request                │
│     - Load customer information for display                │
└────────────────────┬────────────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────────────┐
│  2. Set Return Condition                                    │
│     - Choose condition: Damaged (1) or Intact (0)          │
│     - Affects processing and approval workflow             │
└────────────────────┬────────────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────────────┐
│  3. Add Products to Return                                  │
│     FOR EACH product to return:                             │
│       │                                                     │
│       ├─→ Search and select product via AJAX              │
│       ├─→ Add specific comments/reasons                    │
│       ├─→ Option to add more products dynamically          │
│       └─→ Remove products if needed                        │
└────────────────────┬────────────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────────────┐
│  4. Save and Track                                          │
│     - Create return request with pending status            │
│     - Link all products to request                         │
│     - Set agrees = 0 (pending approval)                    │
│     - Ready for management review                          │
└─────────────────────────────────────────────────────────────┘
```

---

### Workflow 2: Approval Process
```
┌─────────────────────────────────────────────────────────────┐
│                Return Request Lifecycle                    │
└────────────────────┬────────────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────────────┐
│  Status 0: Pending Approval                                │
│     - Request submitted by customer/staff                   │
│     - Awaiting management review                           │
│     - All products listed with conditions                  │
└────────────────────┬────────────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────────────┐
│  Management Review                                          │
│     - Review customer details and reason                   │
│     - Assess product conditions and comments               │
│     - Check return policy compliance                       │
│     - Make approval decision                               │
└────────────────────┬────────────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────────────┐
│  Final Status                                               │
│     Status 1: Approved                                     │
│       └─→ Process return and refund                        │
│     Status 2: Rejected                                     │
│       └─→ Mark as "مرتجع للتسليم" (returned to delivery)   │
└─────────────────────────────────────────────────────────────┘
```

---

## 🌐 URL Routes & Actions

| URL Parameter | Function Called | Description |
|---------------|----------------|-------------|
| `do=` (empty) | Default action | Display add return request form |
| `do=appendproduct` | appendproduct | AJAX add product form |
| `do=show` | show() | Display return request listing |
| `do=edit` | edit() | Edit return request |
| `do=savedata` | savedata() | Save/update return request |
| `do=showajax` | showajax() | DataTables AJAX data |
| `do=select2client` | select2client() | Client search AJAX |
| `do=select2product` | select2product() | Product search AJAX |
| `do=removeappend` | removeappend() | Remove product from request |
| `do=agrees` | agrees() | Update approval status |
| `do=remove` | remove() | Delete return request |

---

## 🧮 Calculation Methods

### Condition Assessment
```php
// Product condition flag
if($row["damagedintact"] == 1){
    $condition = 'تالف'; // Damaged
} else {
    $condition = 'سليم'; // Intact
}
```

### Approval Status Logic
- `agrees = 0` - Pending approval (قيد الانتظار)
- `agrees = 1` - Approved (قبول)
- `agrees = 2` - Rejected (رفض)

### Audit Trail Tracking
```php
// Creation tracking
$addtoday = date("Y-m-d H:i:s");
$adduserid = $_SESSION['userid'];

// Update tracking  
$updatetoday = date("Y-m-d H:i:s");
$updateuserid = $_SESSION['userid'];

// Deletion tracking
$deltoday = date("Y-m-d H:i:s");
$deluserid = $_SESSION['userid'];
```

---

## 🔒 Security & Permissions

### Input Sanitization
```php
// Proper input filtering throughout
$damagedintact = filter_input(INPUT_POST, 'damagedintact');
$clientid = filter_input(INPUT_POST, 'clientid');
$productid = filter_input(INPUT_POST, 'productid_' . $i);
```

### Soft Delete Implementation
- Uses `conditions` flag instead of hard delete
- Preserves audit trail and data integrity
- Allows for data recovery if needed

### Session-Based User Tracking
- All operations tracked with user ID from session
- Timestamps recorded for all modifications
- Complete audit trail for compliance

---

## 📊 Performance Considerations

### Database Optimization
1. **Indexes Needed**:
   - `mechandisereturnrequest(clientid, addtoday)`
   - `mechandisereturnrequest(agrees, conditions)`
   - `mechandisereturnproduct(mechandisereturnrequestid, conditions)`
   - `mechandisereturnproduct(productid, conditions)`

2. **Query Performance**:
   - AJAX searches limited to 50 results
   - Efficient filtering with proper WHERE clauses
   - Soft delete queries may benefit from conditions index

### AJAX Optimization
- Autocomplete searches with result limits
- Dynamic form expansion without full page reload
- Efficient JSON responses for Select2 dropdowns

---

## 🐛 Common Issues & Troubleshooting

### 1. **Incorrect Product Loading in showajax()**
**Issue**: Product query may return all products instead of products for specific request  
**Location**: Line 239-240  
**Problem**: Query missing WHERE clause for specific request

**Fix**: Filter products by request ID:
```php
$mechandisereturnproduct = R::getAll('SELECT * FROM `mechandisereturnproduct` 
    LEFT JOIN product ON mechandisereturnproduct.productid = product.productId  
    WHERE mechandisereturnproduct.conditions = 0 
      AND mechandisereturnproduct.mechandisereturnrequestid = ?', [$row['id']]);
```

### 2. **Approval Status Not Updating**
**Issue**: AJAX approval updates failing  
**Cause**: Missing proper response handling

**Debug**:
```javascript
// Check AJAX response
$('.agrees').change(function(){
    var id = $(this).data('id');
    var agrees = $(this).val();
    // Add error handling
});
```

### 3. **Dynamic Product Addition Issues**
**Issue**: Product fields not appearing correctly  
**Cause**: JavaScript iteration conflicts

**Fix**: Ensure unique field naming and proper template rendering

### 4. **Search Performance**
**Issue**: Client/product searches slow with large datasets  
**Cause**: No indexes on search fields

**Fix**: Add indexes on commonly searched columns:
```sql
CREATE INDEX idx_client_search ON client(clientname, clientphone, conditions);
CREATE INDEX idx_product_search ON product(productName, conditions);
```

---

## 🧪 Testing Scenarios

### Test Case 1: Basic Return Request Creation
```
1. Select client via autocomplete search
2. Set product condition (damaged/intact)
3. Add multiple products with comments
4. Save request and verify in listing
```

### Test Case 2: Approval Workflow
```
1. Create return request with pending status
2. Update approval status via dropdown
3. Verify status change and audit trail
4. Test rejection with proper display
```

### Test Case 3: Dynamic Product Management
```
1. Add products dynamically to request
2. Remove products from request
3. Edit existing request products
4. Verify product association integrity
```

### Test Case 4: Search and Filtering
```
1. Filter by date range
2. Filter by client and product
3. Filter by condition and approval status
4. Test search functionality across fields
```

---

## 📚 Related Documentation

- [CLAUDE.md](/Applications/AMPPS/www/erp19/CLAUDE.md) - PHP 8.2 migration guide
- [Return Policy Documentation](#) - Business rules for returns
- [AJAX Integration Guide](#) - Frontend integration patterns
- [Database Schema Documentation](#) - Table relationships

---

**Documented By**: AI Assistant  
**Review Status**: ⚠️ Needs Product Query Fix in showajax()  
**Next Review**: After product loading issue resolved