SellingReportByArea Documentation

Selling Report By Area Controller Documentation

File: /controllers/sellingReportByArea.php

Purpose: Generate comprehensive sales reports grouped by geographic areas and product categories

Last Updated: December 21, 2024

Total Functions: 6

Lines of Code: ~647

---

๐Ÿ“‹ Overview

The Selling Report By Area Controller provides detailed sales analysis organized by geographic regions and product hierarchies. It offers:

Primary Functions

Related Controllers

---

๐Ÿ—„๏ธ Database Tables

Geographic Tables

Table NamePurposeKey Columns
**government**Province/governorate mastergovernmetid, governmentname
**goverarea**Areas within governmentsgovernmentid, clientareaid
**clientarea**Client area definitionsid, name, description
**client**Customer data with areaclientid, clientname, clientareaid
### Sales Transaction Tables

Table NamePurposeKey Columns
**sellbill**Sales billssellbillid, sellbillclientid, sellbilldate, sellbilltotalbill, sellbilldiscount, tax
**sellbilldetail**Sales bill line itemssellbilldetailid, sellbilldetailproductid, sellbilldetailquantity, sellbilldetailtotalprice, productunitid
**returnsellbill**Sales return billsreturnsellbillid, returnsellbillclientid, returnsellbilldate, returnsellbilltotalbill
**returnsellbilldetail**Return bill detailsreturnsellbilldetailid, returnsellbilldetailproductid, returnsellbilldetailquantity
**sellbillandrutern**Combined billssellbillid, sellbillclientid, sellbilldate, sellbillprice
**sellandruternbilldetail**Combined bill detailssellandruternbilldetailid, sellbilldetailproductid, sellbilldetailquantity, selltype
### Service Bills Tables

Table NamePurposeKey Columns
**bills**Service billsid, clientid, billdate, productstotalprice, finalnetbillvalue
**billsproducts**Service bill productsbillproductsid, billid, productid, productno, producttotalprice
**billsreturn**Service bill returnsbillsreturnid, clientid, date, productstotalprice
**billsreturnproducts**Return bill productsbillsreturnproductsid, billproductid, productid, productno
### Product Tables

Table NamePurposeKey Columns
**product**Product masterproductid, productname, productcatid, productbuyprice, isoptic
**productcat**Product categoriesproductcatid, productcatname, productcatparent
**productunit**Unit conversionsproductunitid, productid, unitid, productnumber
### Reference Tables

Table NamePurposeKey Columns
**programsettings**System settingsprogramsettingsid, reportsplushhours
**youtubelink**Tutorial videosyoutubelinkid, title, url
---

๐Ÿ”‘ Key Functions

1. Default Action - Area-Based Sales Report

Location: Line 200 (empty($do) or $do == "show")

Purpose: Generate comprehensive sales report organized by geographic areas

Function Signature:

// POST parameters: clientareaid, from, to, governmentid
$clientareaid = $_POST["clientareaid"];
$startDate = $_POST["from"];
$endDate = $_POST["to"];  
$governmentId = $_POST['governmentid'];

Process Flow:

1. Load authentication and program settings

2. Load dropdown data (governments, areas, clients)

3. Build date range with time offset handling:

   if (isset($Programsetting->reportsPlusHours) && !empty($Programsetting->reportsPlusHours)) {
       $startDate = date('Y-m-d H:i:s', strtotime('+' . $Programsetting->reportsPlusHours . ' hour', strtotime($startDate)));
   }
   ```
4. Build query strings for multiple bill types
5. Load data from all transaction types:
   - Service bills (`billsData`)
   - Service bill returns (`billsDataReturn`) 
   - Sales bills (`sellBillData`)
   - Sales returns (`sellBillDataReturn`)
   - Combined bills (`sellBillDataSellAndReturn`)
6. Process all transaction types into unified product analysis
7. Calculate totals, profits, and current inventory
8. Generate hierarchical product paths
9. Display comprehensive report

**Key Data Structures**:
php

class productData {

public $id; // Product ID

public $productName; // Product name with full path

public $soldNo = 0; // Quantity sold

public $soldVal = 0; // Value sold

public $returnNo = 0; // Quantity returned

public $returnVal = 0; // Value returned

public $netNo = 0; // Net quantity (sold - returned)

public $netVal = 0; // Net value (sold - returned)

public $discount = 0; // Total discount applied

public $realCost = 0; // Cost price total

public $netProfit = 0; // Net profit (net value - real cost)

public $buyPrice = 0; // Unit buy price

public $currentQuantity = 0; // Current stock level

}

---

### 2. **Service Bills Processing**
**Location**: Lines 288-342 (Bills), 343-395 (Bill Returns)  
**Purpose**: Process service bills with complex discount calculations

**Process Flow for Service Bills**:
1. Load service bill data with geographic filters
2. For each product in bills:
   - Load bill master data for discount calculation
   - Calculate discounts based on payment method:
     ```php
     if ($theBill->card == 1) {
         if ($theBill->paymentnetworkid == 4) { // ู…ุฏู‰ (Mada)
             $madaData = $billsEX->queryTotalNetworkReportMadaSimple($theBill->billdate);
             if ($madaData->totalCarry < 5000)
                 $discount = (7 * $madaData->totalCarry) / 1000;
             else
                 $discount = 40;
         } else {
             $discount = ($theBill->cardvalue * $theBill->netdiscountpercent) / 100;
         }
     }
     ```
   - Calculate proportional discount per product
   - Update product totals and quantities

**Discount Allocation Logic**:
php

$discount += ($theBill->productstotalprice - $theBill->finalnetbillvalue);

if ($billNoOfProducts > 0) {

$theDiscount = ($value->productno * $discount) / $billNoOfProduct;

} else {

$theDiscount = $discount;

}

---

### 3. **Sales Bills Processing**  
**Location**: Lines 396-443 (Sales), 445-490 (Returns), 492-547 (Combined)
**Purpose**: Process regular sales transactions with unit conversions

**Unit Conversion Logic**:
php

$quantity = $value->sellbilldetailquantity;

$productId = $value->sellbilldetailproductid;

$productunitId = $value->productunitid;

$productunitData = loadProductUnitWithProductAndUnit($productId, $productunitId);

$productnumber = $productunitData->productnumber;

$finalquantity = $quantity * $productnumber; // Convert to base unit (pieces)

**Sales Bill Discount Processing**:
php

// Bill-level discount calculation

$dicount = $value->parcode - $value->note; // From bill totals

if ($dicount != 0) {

$billpecies = $sellbilldetailEX->queryBillNoOfPecies($value->sellbillid);

$billNoOfProduct = $billpecies->note;

$theDiscount = ($finalquantity * $dicount) / $billNoOfProduct;

$theDiscount -= $value->discountvalue; // Subtract line-item discount

}

---

### 4. **Final Calculations and Analysis**
**Location**: Lines 549-588  
**Purpose**: Calculate final metrics including profit and inventory

**Process Flow**:
1. Calculate net quantities and values:
   ```php
   foreach ($allDataArr as $data) {
       $data->netNo = $data->soldNo - $data->returnNo;
       $data->netVal = $data->soldVal - $data->returnVal;
   }
   ```

2. Calculate cost and profit:
   ```php
   $buyDatail = $ProductDAO->load($data->id);
   $data->realCost = $data->netNo * $buyDatail->productBuyPrice;
   $data->netProfit = $data->netVal - $data->realCost;
   ```

3. Load current inventory levels:
   ```php
   $buyDatail = $ProductEX->getProductQuantity($data->id, $myQuery);
   $data->currentQuantity = $buyDatail->sumProductQuantity;
   ```

4. Generate hierarchical product names for optic products:
   ```php
   if ($buyDatail->isOptic == 2) {
       $catName = $ProductEX->loadProductCatNameOnly($data->id);
       $data->productName = $data->productName . "/" . $catName;
   }
   ```

---

### 5. **get_parents_of_products()** - Hierarchical Product Paths
**Location**: Line 594  
**Purpose**: Generate complete category path for products

**Function Signature**:
php

function get_parents_of_products($product_id)

**Process Flow**:
1. Load product data to get category ID
2. Call recursive `get_parents()` to build path
3. Combine path with product name
4. Return full hierarchical name

**Example Output**: "Electronics / Mobile Phones / Smartphones / iPhone 13"

---

### 6. **get_parents()** - Recursive Category Path Builder
**Location**: Line 613  
**Purpose**: Recursively build category hierarchy paths

**Function Signature**:
php

function get_parents($productCatId, $parent_name)

**Recursive Logic**:
php

$product_cat_data = $productCatDAO->load($productCatId);

$parent_name = $product_cat_data->productCatName . ' / ' . $parent_name;

if ($productCatParent != 0) {

$product_cat_data_parent = $productCatDAO->load($productCatParent);

$parent_name = $product_cat_data_parent->productCatName . ' / ' . $parent_name;

if ($productCatParent_parent != 0) {

get_parents($productCatParent_parent, $parent_name);

}

}

---

## ๐Ÿ”„ Workflows

### Workflow 1: Area-Based Sales Analysis

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”

โ”‚ START: Select Geographic Filters โ”‚

โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

โ”‚

โ–ผ

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”

โ”‚ 1. Initialize and Load Settings โ”‚

โ”‚ - Load program settings for time zones โ”‚

โ”‚ - Apply authentication โ”‚

โ”‚ - Load dropdown data (governments, areas, clients) โ”‚

โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

โ”‚

โ–ผ

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”

โ”‚ 2. Build Query Filters โ”‚

โ”‚ - Apply government/area geographic filters โ”‚

โ”‚ - Add date range with timezone adjustments โ”‚

โ”‚ - Build separate query strings for each bill type โ”‚

โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

โ”‚

โ–ผ

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”

โ”‚ 3. Load Transaction Data (Multiple Sources) โ”‚

โ”‚ โ”œโ”€โ†’ Service Bills (bills + billsproducts) โ”‚

โ”‚ โ”œโ”€โ†’ Service Returns (billsreturn + billsreturnproducts)โ”‚

โ”‚ โ”œโ”€โ†’ Sales Bills (sellbill + sellbilldetail) โ”‚

โ”‚ โ”œโ”€โ†’ Sales Returns (returnsellbill + returnsellbilldetail)โ”‚

โ”‚ โ””โ”€โ†’ Combined Bills (sellbillandrutern + details) โ”‚

โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

โ”‚

โ–ผ

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”

โ”‚ 4. Process Each Transaction Type โ”‚

โ”‚ FOR EACH transaction type: โ”‚

โ”‚ โ”‚ โ”‚

โ”‚ โ”œโ”€โ†’ Service Bills: โ”‚

โ”‚ โ”‚ โ”œโ”€ Calculate complex payment discounts โ”‚

โ”‚ โ”‚ โ”œโ”€ Handle Mada payment special rates โ”‚

โ”‚ โ”‚ โ””โ”€ Allocate discounts proportionally โ”‚

โ”‚ โ”‚ โ”‚

โ”‚ โ”œโ”€โ†’ Sales Bills: โ”‚

โ”‚ โ”‚ โ”œโ”€ Convert units to base quantities โ”‚

โ”‚ โ”‚ โ”œโ”€ Calculate bill and line discounts โ”‚

โ”‚ โ”‚ โ””โ”€ Process sell vs return types โ”‚

โ”‚ โ”‚ โ”‚

โ”‚ โ””โ”€โ†’ Aggregate into unified product structure โ”‚

โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

โ”‚

โ–ผ

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”

โ”‚ 5. Calculate Final Metrics โ”‚

โ”‚ FOR EACH product: โ”‚

โ”‚ โ”‚ โ”‚

โ”‚ โ”œโ”€โ†’ Calculate net quantities (sold - returned) โ”‚

โ”‚ โ”‚ โ”‚

โ”‚ โ”œโ”€โ†’ Calculate net values (sales - returns) โ”‚

โ”‚ โ”‚ โ”‚

โ”‚ โ”œโ”€โ†’ Load current inventory levels โ”‚

โ”‚ โ”‚ โ”‚

โ”‚ โ”œโ”€โ†’ Calculate costs and profit margins โ”‚

โ”‚ โ”‚ โ””โ”€ netProfit = netValue - (netQty * buyPrice) โ”‚

โ”‚ โ”‚ โ”‚

โ”‚ โ””โ”€โ†’ Generate hierarchical product paths โ”‚

โ”‚ โ””โ”€ "Category/Subcategory/Product Name" โ”‚

โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

โ”‚

โ–ผ

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”

โ”‚ 6. Generate Report Output โ”‚

โ”‚ - Calculate summary totals across all products โ”‚

โ”‚ - Display geographic breakdown โ”‚

โ”‚ - Show profit analysis and inventory levels โ”‚

โ”‚ - Present hierarchical product categorization โ”‚

โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

---

## ๐ŸŒ URL Routes & Actions

| URL Parameter | Function Called | Description |
|---------------|----------------|-------------|
| No `do` parameter or `do=show` | Default action | Main area-based sales report |

### Required Parameters

**Main Sales Report**:
- `governmentid` - Government/province ID for geographic filtering (optional)
- `clientareaid` - Client area ID within government (optional)
- `from` - Start date (YYYY-MM-DD, optional)
- `to` - End date (YYYY-MM-DD, optional)

**Example URLs**:

sellingReportByArea.php - All sales across all areas

sellingReportByArea.php?governmentid=1&from=2024-01-01&to=2024-01-31

sellingReportByArea.php?clientareaid=5&from=2024-01-01&to=2024-01-31

---

## ๐Ÿงฎ Calculation Methods

### Unit Conversion to Base Units
php

function convertToBaseUnits($quantity, $productId, $unitId) {

$productunitData = loadProductUnitWithProductAndUnit($productId, $unitId);

$productnumber = $productunitData->productnumber;

return $quantity * $productnumber; // Convert to pieces

}

### Payment Network Discount Calculation
php

// Special Mada payment network discount

if ($theBill->paymentnetworkid == 4) { // ู…ุฏู‰

$madaData = $billsEX->queryTotalNetworkReportMadaSimple($theBill->billdate);

if ($madaData->totalCarry < 5000)

$discount = (7 * $madaData->totalCarry) / 1000; // 0.7% for amounts < 5000

else

$discount = 40; // Fixed 40 for amounts >= 5000

}

### Proportional Discount Allocation
php

// Allocate bill discount proportionally to products

if ($billNoOfProduct > 0) {

$theDiscount = ($finalquantity * $billDiscount) / $billNoOfProduct;

$theDiscount -= $lineItemDiscount; // Subtract already applied line discounts

}

### Profit Margin Calculation
php

$data->netNo = $data->soldNo - $data->returnNo;

$data->netVal = $data->soldVal - $data->returnVal;

$data->realCost = $data->netNo * $data->buyPrice;

$data->netProfit = $data->netVal - $data->realCost;

// Profit margin percentage

$profitMargin = ($data->netVal > 0) ? ($data->netProfit / $data->netVal) * 100 : 0;

---

## ๐Ÿ”’ Security & Permissions

### Authentication
php

include_once("../public/authentication.php");

### Geographic Access Control
- No specific geographic access restrictions implemented
- Users can access all areas and governments
- Could be enhanced with territory-based permissions

### Input Sanitization
- Date inputs should be validated for proper format
- Geographic IDs should be validated as integers
- Currently relies on DAO layer for SQL injection prevention

---

## ๐Ÿ“Š Performance Considerations

### Database Performance Issues
1. **Multiple Query Types**: Queries 5 different transaction tables separately
2. **Complex Joins**: Geographic filtering involves multiple table joins
3. **Unit Conversion Queries**: Individual queries for each product unit conversion
4. **No Pagination**: Can load thousands of products for large areas

### Optimization Recommendations
sql

-- Current: Multiple separate queries

-- Optimized: Single unified query with UNION

SELECT 'service' as source, p.productid, p.productname, bp.productno as quantity,

bp.producttotalprice as value, b.billdate as date

FROM bills b

JOIN billsproducts bp ON b.id = bp.billid

JOIN product p ON bp.productid = p.productid

WHERE [filters]

UNION ALL

SELECT 'sales' as source, p.productid, p.productname,

(sd.sellbilldetailquantity * pu.productnumber) as quantity,

sd.sellbilldetailtotalprice as value, s.sellbilldate as date

FROM sellbill s

JOIN sellbilldetail sd ON s.sellbillid = sd.sellbillid

JOIN product p ON sd.sellbilldetailproductid = p.productid

JOIN productunit pu ON sd.productunitid = pu.productunitid

WHERE [filters]

### Memory Optimization
- Consider streaming results for large datasets
- Implement pagination for areas with many products
- Cache product hierarchy paths to avoid repeated calculations

---

## ๐Ÿ› Common Issues & Troubleshooting

### 1. **Incorrect Unit Conversions**
**Issue**: Quantities don't match between reports  
**Cause**: Missing or incorrect productunit data

**Debug**:
sql

-- Check unit conversion data

SELECT p.productname, pu.productnumber, u.unitname

FROM product p

LEFT JOIN productunit pu ON p.productid = pu.productid

LEFT JOIN unit u ON pu.unitid = u.unitid

WHERE p.productid = [PRODUCT_ID];

-- Find products without unit data

SELECT p.productid, p.productname

FROM product p

LEFT JOIN productunit pu ON p.productid = pu.productid

WHERE pu.productunitid IS NULL;

### 2. **Missing Geographic Data**
**Issue**: Products show for wrong areas or don't appear  
**Cause**: Client area assignments incomplete

**Fix**:
sql

-- Verify client-area relationships

SELECT c.clientname, ca.name as area_name, g.governmentname

FROM client c

LEFT JOIN clientarea ca ON c.clientareaid = ca.id

LEFT JOIN goverarea ga ON ca.id = ga.clientareaid

LEFT JOIN government g ON ga.governmentid = g.governmetid

WHERE c.clientareaid IS NULL OR ca.id IS NULL;

### 3. **Discount Calculation Errors**
**Issue**: Profit margins don't match expected values  
**Cause**: Complex discount allocation logic errors

**Debug**: Add logging to discount calculation:
php

error_log("Product: {$productId}, Bill Discount: {$billDiscount}, Line Discount: {$lineDiscount}, Final: {$theDiscount}");

---

## ๐Ÿงช Testing Scenarios

### Test Case 1: Multi-Bill Type Consolidation

1. Create sales bill, return bill, and service bill for same product

2. Run area report for date range covering all bills

3. Verify quantities and values aggregate correctly

4. Check net calculations (sold - returned)

### Test Case 2: Geographic Filtering

1. Set up clients in different areas/governments

2. Create sales for each area

3. Filter by specific government

4. Verify only sales from that government appear

5. Test area-level filtering within government

### Test Case 3: Unit Conversion Accuracy

1. Create products with different unit types (pieces, boxes, cartons)

2. Create sales with various units

3. Verify all quantities convert to base unit (pieces)

4. Compare with manual calculations

### Test Case 4: Profit Calculation Verification

1. Create sales with known buy prices and selling prices

2. Apply various discount types

3. Verify profit calculations match expected margins

4. Test with returns to ensure proper net profit calculation

```

---

๐Ÿ“š Related Documentation

---

Documented By: AI Assistant

Review Status: โœ… Complete

Next Review: When major changes occur