Profitproductcat Documentation

Profit Product Category Controller Documentation

File: /controllers/profitproductcatController.php

Purpose: Generates comprehensive profit analysis reports grouped by product categories

Last Updated: December 20, 2024

Total Functions: 18

Lines of Code: 1,400

---

๐Ÿ“‹ Overview

The Profit Product Category Controller provides category-level profit analysis with hierarchical category support and multi-level subcategory processing. It handles:

Primary Functions

Category Processing Features

Related Controllers

---

๐Ÿ—„๏ธ Database Tables

Category & Product Tables

Table NamePurposeKey Columns
**productcat**Product categories hierarchyproductcatid, productcatname, productcatparent
**product**Product master dataproductid, productname, productcatid, overallaverageprice, lastbuyprice, meanbuyprice
### Sales & Transaction Tables

Table NamePurposeKey Columns
**sellbilldetail**Sales line itemssellbilldetailproductid, sellbilldetailquantity, sellbilldetailprice, buyprice, discountvalue
**returnsellbilldetail**Return line itemsreturnsellbilldetailproductid, returnsellbilldetailquantity, returnsellbilldetailprice
**sellandruternbilldetail**Combined bill detailssellbilldetailproductid, sellbilldetailquantity, selltype, buyprice, sellbilldiscount
### Optical Products Tables

Table NamePurposeKey Columns
**billsproducts**Optical salesproductid, productno, productprice, producttotalprice, netbillvalue, buyprice
**billsreturnproducts**Optical returnsproductid, productno, productprice, producttotalprice, returnedprice
### Configuration & Support Tables

Table NamePurposeKey Columns
**programsettings**System configurationreportsplusHours, vatvalue
**youtubelink**Tutorial linksyoutubelinkid, title, url
**productunit**Units of measureproductunitid, productnumber
---

๐Ÿ”‘ Key Functions

1. show() / Default Action - Category Profit Report

Location: Line 230

Purpose: Generate comprehensive profit analysis for a product category and all subcategories

Function Signature:

// Triggered when: do=show or empty $do
$level = filter_input(INPUT_POST, 'level');
$productCatId = filter_input(INPUT_POST, 'productCatId' . $level);
$startDate = $_REQUEST['from'];
$endDate = $_REQUEST['to'];
$dis = filter_input(INPUT_GET, 'dis'); // Discount view flag

Process Flow:

1. Load category hierarchy data

2. Process multi-level category selection

3. Build category ID list including subcategories

4. Apply time zone adjustments

5. Call getProductInBillByDateAndCatId() for calculations

6. Display results via show.html or showdiscount.html

Category Tree Processing:

$level = filter_input(INPUT_POST, 'level');
$productCatId = filter_input(INPUT_POST, 'productCatId' . $level);
if (empty($productCatId) || $productCatId == -1) {
    $productCatId = filter_input(INPUT_POST, 'productCatId' . ($level - 1));
}

$catsIDS = '' . $productCatId;
if ($productCatId != '') {
    getAllSubCat($productCatId, 1); // mode = 1 get all sub cats
}

---

2. getProductInBillByDateAndCatId() - Core Category Analysis

Location: Line 303

Purpose: Calculate detailed profit metrics for all products in specified categories

Function Signature:

function getProductInBillByDateAndCatId($startDate, $endDate, $productcatId)

Process Flow:

1. Query all products in category tree

2. For each product, calculate:

- Sales revenue (regular + combined + optical)

- Return values (regular + combined + optical)

- Cost of goods sold

- Individual product profit

3. Aggregate totals across all products

4. Calculate final category profit

Product Processing Loop:

$h = 1;
foreach ($productIdData as $productIdDa) {
    $productId = $productIdDa->productid;
    
    // Load product data
    $productData = $myProductRecord->load($productId);
    $overAllAveragePrice = $productData->overAllAveragePrice;
    
    // Calculate sales data
    $sellPriceData = getTotalSellPriceByDateAndProductId($startDate, $endDate, $productId, $overAllAveragePrice);
    $sellPricePulsData = getTotalAditionalSellPriceByDateAndProductId($startDate, $endDate, $productId, $overAllAveragePrice);
    $sellOpticData = getTotalSellOpticByDateAndProductId($startDate, $endDate, $productId);
    
    // Aggregate totals
    $sellPrice = $sellPriceData[0] + $sellPricePulsData[0] + $sellOpticData[0];
    $quantityUnit = $sellPriceData[1] + $sellPricePlusData[1] + $sellOpticData[1];
    $discountPrice = $sellPriceData[3] + $sellPricePulsData[3] + $sellOpticData[3];
    
    // Calculate individual product profit
    $profitForOneProduct = round((($yy) - ($quantityForOneProduct * $xx)), 2);
    $finalProductcatProfit += $profitForOneProduct;
    
    $h++;
}

---

3. getAllSubCat() - Recursive Category Tree Processing

Location: Line 1362

Purpose: Recursively build list of all subcategories under a parent category

Function Signature:

function getAllSubCat($catid, $mode)
// mode = 1: get all sub categories
// mode = 2: get last level categories only

Recursive Logic:

$result = $productCatExt->queryByParentExt($catid);
if (count($result) > 0) {
    foreach ($result as $data) {
        if ($mode == 1) {
            $catsIDS .= "," . $data->productCatId;
            getAllSubCat($data->productCatId, $mode); // Recursive call
        } elseif ($mode == 2) {
            $childData = $productCatExt->queryByParentExt($data->productCatId);
            if (count($childData) > 0) {
                getAllSubCat($data->productCatId, $mode);
            } else {
                array_push($lastLevelCatIDS, $data->productCatId);
            }
        }
    }
}

Global Variables Used:

global $catsIDS; // Comma-separated list of category IDs
global $lastLevelCatIDS; // Array of leaf-level categories

---

4. getTotalSellPriceByDateAndProductId() - Sales Analysis

Location: Line 532

Purpose: Calculate sales revenue and costs for products in categories

Advanced Discount Handling:

// Product-level discount
$discountValue = $sellbilldetail->discountvalue;

// Bill-level discount calculation
if ($sellbillTotalBill == 0) {
    $sellbillTotalBill = 1;
}
$thirdStep = ($totalPrice / $sellbillTotalBill) * $sellbillDiscount;

// Combined discount calculation
$totalPriceDiscount = $discountValue + $thirdStep;
$sellPriceForOneProduct = $totalPriceBeforeDiscount - $totalPriceDiscount;
$discountPrice += $totalPriceDiscount;

Buy Price Selection (same as product controller):

switch ($buyPriceType) {
    case "first": $buyprice = (float) $sellbilldetail->buyprice; break;
    case "last": $buyprice = (float) $sellbilldetail->lastbuyprice; break;
    case "mean": $buyprice = (float) $sellbilldetail->meanbuyprice; break;
    case "last_discount": $buyprice = (float) $sellbilldetail->lastbuyprice_withDiscount; break;
    case "mean_discount": $buyprice = (float) $sellbilldetail->meanbuyprice_withDiscount; break;
    case "generalPrice": $buyprice = (float) $overAllAveragePrice; break;
    case "tax": $buyprice = (float) $sellbilldetail->lastbuyprice_withTax; break;
    case "mean_tax": $buyprice = (float) $sellbilldetail->meanbuyprice_withTax; break;
}

---

5. getTotalSellOpticByDateAndProductId() - Optical Category Products

Location: Line 1232

Purpose: Handle optical products within categories with specialized calculations

Optical-Specific Processing:

$quantity = $sellbilldetail->productno; // No unit conversion needed
$price = $sellbilldetail->productprice;
$totalPrice = $sellbilldetail->producttotalprice;
$sellbillTotalBill = $sellbilldetail->netbillvalue;

// Simplified discount calculation for optical products
$thirdStep = ($totalPrice / $sellbillTotalBill) * $sellbillDiscount;
$sellPriceForOneProduct = $totalPriceBeforeDiscount - $thirdStep;

---

6. loadProductCatNameById() - Category Name Builder

Location: Line 1203

Purpose: Build hierarchical category names with parent path

Function Signature:

function loadProductCatNameById($productCatId, $productcatName, $itr)

Recursive Path Building:

if ($itr == 1) {
    $productcatNamex = $productcatData->productCatName;
} elseif ($itr == 2) {
    $productcatNamex = $productcatData->productCatName . "/" . $productcatNamex;
}

if ($productcatData->productCatParent != 0) {
    return loadProductCatNameById($productcatData->productCatParent, $productcatNamex, 2);
}

Result Format: "Parent Category/Child Category/Product Name"

---

๐Ÿ”„ Workflows

Workflow 1: Category Profit Analysis

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
START: Select Category & Date Range
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
โ–ผ
โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
1Category Selection & Validation
- Load category hierarchy
- Process multi-level selection
- Validate category ID
- Apply time zone adjustments
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
โ–ผ
โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
2Build Category Tree
- Start with selected category
- Call getAllSubCat() recursively
- Build comma-separated ID list
- Include all descendant categories
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
โ–ผ
โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
3Query Products in Category Tree
- Get all products in category list
- Load product master data
- Prepare for individual analysis
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
โ–ผ
โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
4Process Each Product
FOR EACH product in category:
โ”‚
โ†’ Calculate sales data
โ”‚ โ”œโ”€ Regular sales
โ”‚ โ”œโ”€ Combined bills
โ”‚ โ”‚ โ””โ”€ Optical sales โ”‚
โ”‚
โ†’ Calculate return data
โ”‚ โ”œโ”€ Regular returns
โ”‚ โ”œโ”€ Combined returns
โ”‚ โ”‚ โ””โ”€ Optical returns โ”‚
โ”‚
โ†’ Calculate cost data
โ”‚ โ”œโ”€ Apply buy price method
โ”‚ โ”œโ”€ Handle unit conversions
โ”‚ โ”‚ โ””โ”€ Process discounts โ”‚
โ”‚
โ†’ Calculate individual profit
โ”‚
โ”‚ โ””โ”€โ†’ Add to category totals โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
โ–ผ
โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
5Aggregate Category Results
- Sum all individual product profits
- Calculate total quantities
- Sum discount amounts
- Compute final category metrics
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
โ–ผ
โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
6Display Results
- Assign data to template variables
- Include individual product data
- Show discount breakdown if requested
- Display appropriate view
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

---

Workflow 2: Recursive Category Tree Processing

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
START: getAllSubCat($catid, $mode)
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
โ–ผ
โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
1Query Direct Children
$result = $productCatExt->queryByParentExt($catid)
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
โ–ผ
โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
2Check if Children Exist
if (count($result) > 0)
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
โ–ผ
โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
3Process Each Child
FOR EACH child category:
โ”‚
โ†’ Add to category list
โ”‚ $catsIDS .= "," . $data->productCatId
โ”‚
โ”‚ โ””โ”€โ†’ Recursive call โ”‚
getAllSubCat($data->productCatId, $mode)
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
โ–ผ
โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
4Update Global Variables
- $catsIDS: Comma-separated ID list
- $lastLevelCatIDS: Leaf categories array
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

---

๐ŸŒ URL Routes & Actions

URL ParameterFunction CalledDescription
`do=` (empty) or `do=show`Default actionCategory profit analysis
`dis=T`Discount viewShow discount-focused report
`do=success`Success pageDisplay success message
`do=error`Error pageDisplay error message
### Required Parameters

Category Analysis (do=show):

Category Selection Structure

Level 1: productCatId1 (Top level category)
Level 2: productCatId2 (Subcategory of Level 1)  
Level 3: productCatId3 (Subcategory of Level 2)
Level 4: productCatId4 (Subcategory of Level 3)
Level 5: productCatId5 (Subcategory of Level 4)

---

๐Ÿงฎ Calculation Methods

Category Profit Aggregation

$finalProductcatProfit = 0;
foreach ($productIdData as $productIdDa) {
    // Individual product calculations...
    $profitForOneProduct = round((($yy) - ($quantityForOneProduct * $xx)), 2);
    $finalProductcatProfit += $profitForOneProduct;
}

Discount Breakdown per Product

// Product-level discount tracking
$discountPrice = $sellPriceData[3] + $sellPricePulsData[3] + $sellOpticData[3];
$totalDiscountPrice += $discountPrice;

// Template assignment for individual products
$smarty->assign("discountPrice" . $h . '', $discountPrice);
$smarty->assign("profitForOneProduct" . $h . '', $profitForOneProduct);

Category Tree ID Building

$catsIDS = '' . $productCatId; // Start with selected category
getAllSubCat($productCatId, 1); // Add all subcategories
// Result: "1,5,12,23,45" (comma-separated category IDs)

Time Zone Adjustment

if (isset($Programsetting->reportsPlusHours) && !empty($Programsetting->reportsPlusHours)) {
    $reportsPlusHours = $Programsetting->reportsPlusHours + 24;
    $endDate = date('Y-m-d H:i:s', strtotime('+' . $reportsPlusHours . ' hour', strtotime($endDate)));
    $startDate = date('Y-m-d H:i:s', strtotime('+' . $Programsetting->reportsPlusHours . ' hour', strtotime($startDate)));
} else {
    $endDate = $endDate . ' 23:59:59';
    $startDate = $startDate . " 00:00:00";
}

---

๐Ÿ”’ Security & Permissions

Authentication

Input Validation

Security Considerations

---

๐Ÿ“Š Performance Considerations

Database Optimization

1. Critical Indexes:

- productcat(productcatparent) for tree traversal

- product(productcatid) for category filtering

- sellbilldetail(sellbilldetailproductid, sysdate)

- Composite index on sellbilldetail(productid, date, conditions)

2. Performance Issues:

- Recursive category tree queries (N+1 problem)

- Multiple separate queries per product

- No result caching for category hierarchies

- Large category trees may cause timeouts

Memory Considerations

Optimization Opportunities

-- Current: Recursive queries for each category
SELECT * FROM productcat WHERE productcatparent = ?

-- Optimized: Single hierarchical query with CTE
WITH RECURSIVE category_tree AS (
    SELECT productcatid FROM productcat WHERE productcatid = ?
    UNION ALL
    SELECT p.productcatid FROM productcat p
    INNER JOIN category_tree ct ON p.productcatparent = ct.productcatid
)
SELECT * FROM product WHERE productcatid IN (SELECT productcatid FROM category_tree)

---

๐Ÿ› Common Issues & Troubleshooting

1. Recursive Category Issues

Issue: Stack overflow or infinite loops in category tree

Causes:

Debug:

// Add depth limiting
function getAllSubCat($catid, $mode, $depth = 0) {
    if ($depth > 10) { // Limit recursion depth
        error_log("Category tree too deep: $catid");
        return;
    }
    // ... existing code ...
    getAllSubCat($data->productCatId, $mode, $depth + 1);
}

2. Missing Category Data

Issue: Some products not included in category reports

Causes:

Fix:

-- Check for orphaned products
SELECT * FROM product WHERE productcatid NOT IN (SELECT productcatid FROM productcat);

-- Check for circular references
SELECT * FROM productcat p1 
JOIN productcat p2 ON p1.productcatid = p2.productcatparent 
WHERE p2.productcatid = p1.productcatparent;

3. Performance Degradation

Issue: Reports taking too long for large category trees

Solutions:

4. Discount Calculation Errors

Issue: Category discount totals don't match sum of products

Cause: Rounding errors accumulating across products

Solution: Use decimal precision functions for financial calculations

---

๐Ÿงช Testing Scenarios

Test Case 1: Simple Category Profit

1. Create category with 2-3 products
2. Add sales transactions for each product
3. Run category report
4. Verify total matches sum of individual products

Test Case 2: Multi-Level Category Tree

1. Create parent category with subcategories
2. Add products to different levels
3. Create transactions across all levels
4. Verify report includes all subcategory products

Test Case 3: Recursive Category Handling

1. Create 5-level deep category hierarchy
2. Add products at various levels
3. Select top-level category for report
4. Verify all descendant products included

Test Case 4: Category with Optical Products

1. Create category with both regular and optical products
2. Add transactions for both product types
3. Run category report
4. Verify different calculation methods applied correctly

---

๐Ÿ“š Related Documentation

---

Documented By: AI Assistant

Review Status: โœ… Complete

Next Review: When major changes occur