ProductBuyreport Documentation
Product Buy Report Controller Documentation
File: /controllers/productBuyreportController.php
Purpose: Generates comprehensive product purchase reports with quantity analysis and category filtering
Last Updated: December 20, 2024
Total Functions: 12+
Lines of Code: ~555
---
๐ Overview
The Product Buy Report Controller is a specialized reporting module that analyzes product purchase transactions across different time periods, categories, and stores. It provides detailed insights into:
- โข Product purchase quantities by category and date range
- โข Regular buy bills vs. combined buy/return bills
- โข Purchase returns and net purchase calculations
- โข Store-wise purchase filtering
- โข Unit conversion and quantity normalization
- โข Performance-optimized bulk queries
Primary Functions
- โ Generate category-based purchase reports
- โ Track purchase quantities by date range
- โ Handle multiple bill types (regular, combined, returns)
- โ Store-wise purchase filtering
- โ Unit conversion calculations
- โ Performance optimization with bulk queries
- โ Arabic language support
- โ YouTube tutorial integration
Related Controllers
- โข buyBillController.php - Purchase bill management
- โข returnBuyBillController.php - Purchase return management
- โข buyAndReturnBillController.php - Combined purchase operations
- โข productController.php - Product master data
- โข storeController.php - Store management
---
๐๏ธ Database Tables
Primary Tables (Direct Operations)
| Table Name | Purpose | Key Columns | |
|---|---|---|---|
| **buybilldetail** | Purchase bill line items | buybilldetailid, buybillid, buybilldetailproductid, buybilldetailquantity, productunitid | |
| **returnbuybilldetail** | Purchase return details | returnbuybilldetailid, returnbuybillid, returnbuybilldetailproductid, returnbuybilldetailquantity | |
| **buyandruternbilldetail** | Combined buy/return details | buybilldetailproductid, buybilldetailquantity, productunitid, billtype |
| Table Name | Purpose | Key Columns | |
|---|---|---|---|
| **product** | Product master data | productId, productName, productCatId, conditions | |
| **productcat** | Product categories | productCatId, productCatName, productCatParent | |
| **productunit** | Product units & conversions | productunitid, productId, unitId, productnumber | |
| **store** | Store master data | storeId, storeName, conditions |
| Table Name | Purpose | Key Columns | |
|---|---|---|---|
| **buybill** | Purchase bill headers | buybillid, buybillstoreid, buybilldate, conditions | |
| **returnbuybill** | Return bill headers | returnbuybillid, returnbuybillstoreid, returnbuybilldate, conditions | |
| **buyandruternbill** | Combined bill headers | buybillid, buybillstoreid, buybilldate, conditions | |
| **youtubelink** | Tutorial videos | youtubelinkid, title, url |
๐ Key Functions
1. show() / Default Action - Main Report Display
Location: Line 108
Purpose: Display purchase report form and generate results based on filters
Function Signature:
// URL Parameters
$startDate = $_REQUEST['from']; // Start date filter
$endDate = $_REQUEST['to']; // End date filter
$productCatId = $_REQUEST['productCatId']; // Category filter
$storeid = $_REQUEST['storeid']; // Store filter
Process Flow:
1. Set default date range (current date if not specified)
2. Apply date range formatting (00:00:00 to 23:59:59)
3. Load category and store data for dropdowns
4. Generate report message in Arabic
5. Call loadProductByAllCategoriesAndDate() for data processing
6. Display via productbuyreportview/show.html
Features:
- โข Date range validation and formatting
- โข Category filtering ("all" or specific category)
- โข Store-specific filtering
- โข Multilingual message generation
- โข YouTube tutorial integration
---
2. loadProductByAllCategoriesAndDate() - Core Report Engine
Location: Line 279
Purpose: Generate optimized purchase report with bulk queries
Function Signature:
function loadProductByAllCategoriesAndDate($startDate, $endDate, $productCatId, $storeid)
Process Flow:
1. Product Selection:
$queryString = " and product.conditions = 0 ";
if ($productCatId > 0) {
$queryString .= " and product.productCatId = $productCatId ";
}
$productData = R::getAll('SELECT productId,productName,productCatId FROM product where 1 ' . $queryString);
```
2. **Bulk Data Collection** (Performance Optimized):
- Regular purchases: `buybilldetail` JOIN `buybill`
- Combined purchases: `buyandruternbilldetail` (billtype=0)
- Regular returns: `returnbuybilldetail` JOIN `returnbuybill`
- Combined returns: `buyandruternbilldetail` (billtype=1)
3. **Unit Conversion Processing**:
```php
foreach ($productData as $product) {
$sellsfinalquantity = 0;
foreach ($sellsQuantity[$productId] as $value) {
$quantity = $value['quantity'];
$productnumber = $productUnitDataArr[$value['productunitid']]['productnumber'];
$sellsfinalquantity += $quantity * $productnumber;
}
}
```
4. **Net Calculation & Template Assignment**:
```php
$remainQuantity = $totalSellsQuantity - $totalReturnSellsQuantity;
$smarty->assign("remainQuantity" . $h . "", $remainQuantity);
```
---
### 3. **showSellByProductAndDate()** - Regular Purchase Query
**Location**: Line 222
**Purpose**: Get purchase quantities for specific product and date range
**Function Signature**:
php
function showSellByProductAndDate($productId, $startDate, $endDate, $storeid)
**SQL Query Pattern**:
sql
SELECT buybilldetailquantity, productunitid
FROM buybilldetail
JOIN buybill ON buybilldetail.buybillid = buybill.buybillid
WHERE buybill.conditions=0
AND buybilldetailproductid = ?
AND buybilldate >= ? AND buybilldate <= ?
[AND buybillstoreid = ?]
---
### 4. **showAditionalSellByProductAndDate()** - Combined Bill Query
**Location**: Line 234
**Purpose**: Handle combined buy/return bills (billtype = 0 for purchases)
**Function Signature**:
php
function showAditionalSellByProductAndDate($productId, $startDate, $endDate, $storeid)
**Process Flow**:
1. Query `buyandruternbilldetail` with `billtype = 0` (purchase portion)
2. Join with `buyandruternbill` for date and store filtering
3. Apply same unit conversion logic as regular purchases
---
### 5. **showReturnSellByProductAndDate()** - Return Processing
**Location**: Line 245
**Purpose**: Calculate purchase return quantities
**Function Signature**:
php
function showReturnSellByProductAndDate($productId, $startDate, $endDate, $storeid)
**Return Calculation**:
php
$ruturnquntity = 0;
foreach ($ruturndata as $myruturndata) {
$quantity = $myruturndata->returnbuybilldetailquantity;
$productunitId = $myruturndata->productunitid;
$productnumber = $myProductunitEx->getProductNumber($productunitId);
$ruturnquntity += ($quantity * $productnumber);
}
---
### 6. **loadProductCat()** - Category Hierarchy
**Location**: Line 519
**Purpose**: Load product categories with hierarchical names
**Function Signature**:
php
function loadProductCat()
**Recursive Name Building**:
php
function loadProductCatNameById($productCatId, $productcatName, $itr) {
$productcatData = $myProductcatRecord->load($productCatId);
if ($productcatData->productCatParent != 0) {
return loadProductCatNameById($productcatData->productCatParent, $productcatNamex, 2);
}
return $productcatNamex;
}
---
## ๐ Workflows
### Workflow 1: Purchase Report Generation
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ START: Purchase Report Request โ
โโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 1. Parameter Processing โ
โ - Parse date range (from/to) โ
โ - Parse category filter โ
โ - Parse store filter โ
โ - Set default values if empty โ
โโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 2. Product Selection โ
โ - Query products by category โ
โ - Apply conditions filter โ
โ - Load category hierarchy โ
โโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 3. Bulk Data Collection (Performance Optimized) โ
โ โโโ Regular purchases (buybilldetail) โ
โ โโโ Combined purchases (buyandruternbilldetail) โ
โ โโโ Regular returns (returnbuybilldetail) โ
โ โโโ Combined returns (buyandruternbilldetail) โ
โโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 4. Unit Conversion & Calculation โ
โ FOR EACH product: โ
โ โโโ Calculate total purchases (all sources) โ
โ โโโ Calculate total returns (all sources) โ
โ โโโ Apply unit conversions โ
โ โโโ Calculate net quantity โ
โโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 5. Report Generation โ
โ - Assign data to template variables โ
โ - Generate summary totals โ
โ - Display via Smarty template โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
---
## ๐ URL Routes & Actions
| URL Parameter | Function Called | Description |
|---------------|----------------|-------------|
| `do=` (empty) or `do=show` | Default action | Purchase report generation |
| `do=sucess` | Success page | Operation completed successfully |
| `do=error` | Error page | Operation failed |
### Required Parameters
**Purchase Report** (`do=show`):
- `from` - Start date (YYYY-MM-DD, optional)
- `to` - End date (YYYY-MM-DD, optional)
- `productCatId` - Category filter (-1 for all, specific ID, or "all")
- `storeid` - Store filter (0 for all stores)
---
## ๐งฎ Calculation Methods
### Unit Conversion Formula
php
$finalquantity = $quantity * $productnumber;
// Where:
// $quantity = quantity in specific unit
// $productnumber = conversion factor to base unit
// $finalquantity = normalized quantity in base units
### Net Purchase Calculation
php
$totalSellsQuantity = $sellsfinalquantity + $sellsaditionalSellsQuantity;
$totalReturnSellsQuantity = $finalreturnSellQuantity + $finaladitionalReturnSellsQuantity;
$remainQuantity = $totalSellsQuantity - $totalReturnSellsQuantity;
### Performance Optimization Pattern
php
// Old Way (N+1 queries)
foreach ($productData as $product) {
$sellsQuantity = showSellByProductAndDate($productId, $startDate, $endDate, $storeid);
}
// New Way (Bulk queries)
$sellsQuantity = R::getAll('SELECT buybilldetailproductid,buybilldetailquantity,productunitid
FROM buybilldetail JOIN buybill ON ...
WHERE buybilldetailproductid in(' . implode(',', $productIdsArr) . ')');
$sellsQuantity = customArrayIndexMany($sellsQuantity, 'buybilldetailproductid');
---
## ๐ Security & Permissions
### Input Sanitization
php
$storeid = (int) $_REQUEST['storeid']; // Integer casting
$productCatId = $_REQUEST['productCatId']; // String validation in queries
### SQL Injection Prevention
- Uses RedBeanPHP R::getAll() with proper parameter binding
- Integer casting for numeric parameters
- Proper WHERE clause construction
### Date Validation
php
if (isset($startDate) && isset($endDate) && $startDate != "" && $endDate != "") {
$startDate = $startDate . ' 00:00:00';
$endDate = $endDate . ' 23:59:59';
}
---
## ๐ Performance Considerations
### Optimization Techniques Used
1. **Bulk Queries**: Single queries for multiple products instead of individual queries
2. **Index-Friendly Queries**: Uses product IDs in WHERE clauses
3. **Memory Efficient**: Processes data in chunks using array indexing
4. **Reduced Database Calls**: Commented out old N+1 query approach
### Database Indexes Recommended
sql
-- Primary performance indexes
CREATE INDEX idx_buybilldetail_product_date ON buybilldetail(buybilldetailproductid, buybilldetaildate);
CREATE INDEX idx_returnbuybilldetail_product_date ON returnbuybilldetail(returnbuybilldetailproductid, returnbuybilldate);
CREATE INDEX idx_buyandruternbilldetail_product ON buyandruternbilldetail(buybilldetailproductid, billtype);
CREATE INDEX idx_product_category ON product(productCatId, conditions);
### Performance Metrics
- **Before Optimization**: ~N queries per product (could be 100+ queries)
- **After Optimization**: 4 bulk queries total regardless of product count
- **Memory Usage**: Optimized array indexing reduces memory footprint
---
## ๐ Common Issues & Troubleshooting
### 1. **Incorrect Quantity Totals**
**Issue**: Unit conversions not applied correctly
**Cause**: Missing or incorrect `productnumber` values
**Debug**:
sql
SELECT p.productId, p.productName, pu.productnumber
FROM product p
LEFT JOIN productunit pu ON p.productId = pu.productId
WHERE pu.productnumber IS NULL OR pu.productnumber = 0;
### 2. **Performance Issues**
**Issue**: Report takes too long to load
**Cause**: Missing indexes or large date ranges
**Solutions**:
- Add recommended indexes
- Limit date range to reasonable periods
- Monitor query execution with `EXPLAIN`
### 3. **Category Filter Not Working**
**Issue**: "All categories" shows no results
**Cause**: Category hierarchy issues
**Debug**:
sql
-- Check for orphaned products
SELECT COUNT(*) FROM product p
LEFT JOIN productcat pc ON p.productCatId = pc.productCatId
WHERE pc.productCatId IS NULL AND p.conditions = 0;
---
## ๐งช Testing Scenarios
### Test Case 1: Basic Purchase Report
1. Select date range with known purchases
2. Verify product count matches database
3. Check unit conversion calculations
4. Confirm net quantity = purchases - returns
### Test Case 2: Category Filtering
1. Select specific category
2. Verify only products in that category appear
3. Test "all categories" option
4. Check subcategory inclusion
### Test Case 3: Store Filtering
1. Select specific store
2. Verify quantities match store transactions
3. Test "all stores" aggregation
4. Check store-specific calculations
### Performance Testing
php
// Add timing to controller
$start_time = microtime(true);
loadProductByAllCategoriesAndDate($startDate, $endDate, $productCatId, $storeid);
$execution_time = microtime(true) - $start_time;
echo "Report generated in: " . $execution_time . " seconds";
```
---
๐ Related Documentation
- โข CLAUDE.md - PHP 8.2 migration guide
- โข buyBillController.md - Purchase management
- โข productController.md - Product master data
- โข Database Schema Documentation - Table relationships
---
Documented By: AI Assistant
Review Status: โ Complete
Next Review: When major changes occur