📝 Markdown Document Manager

Upload markdown files and organize them in a tree structure

Add Document
Document Tree
Delete Document
View Document

Add New Document


Or Upload Markdown File

Max file size: 2M | Supported: .md, .txt, .markdown files | Content limit: 5MB

Document Tree Structure

🗑️ Delete Document

⚠️ Warning: This action cannot be undone!

SAVE_CONTROLLER_API_DOCUMENTATION

Created: 2025-08-09 18:14:57 | Updated: 2025-08-09 18:14:57

▶ Save Controller API Documentation (الخزن)

■ 1. Controller Overview

  • Purpose: Comprehensive cash box/safe management system with full accounting integration
  • Module: Financial Management / Cash Management
  • File: controllers/saveController.php (626 lines)
  • Primary Database Table: save
  • Dependencies:
  • → DAO/DTO pattern with Save, Savedaily, Currency models
  • → RedBean ORM for additional operations
  • → Accounting integration (dailyentryfun.php)
  • → Chart of accounts tree management
  • → Transaction management for data integrity
  • → CURL/API support for external integration

■ 2. Business Logic Analysis

• Core Operations

  1. CREATE: Add new cash boxes with initial balance and accounting entries
  2. READ: Display cash boxes with filtering and multi-currency support
  3. UPDATE: Edit cash box information with tree element updates
  4. DELETE: Soft delete preserving audit trail
  5. PERMANENT DELETE: Complete removal with tree cleanup
  6. PRINT VIEW: Generate printable cash box reports
  7. SORT ORDER: AJAX-based display ordering
  8. AUDIT TRAIL: Complete transaction logging in savedaily

• Complex Business Features

  • Multi-Currency Support: Each cash box can operate in different currency
  • Accounting Integration: Automatic double-entry bookkeeping
  • Chart of Accounts: Automatic tree element creation/updates
  • Cash Box Types: Categorization via savetype
  • Session-Based Access: Granular permissions per user
  • Transaction Management: Database rollback on errors
  • Daily Entry System: Automatic journal entries for all movements
  • Parent Type System: Regular (40) or Special (408) categorization

• Data Validation & Business Rules

  • Cash Box Name: Must be unique (checked before insert)
  • Initial Balance: Can be any amount including zero
  • Currency Assignment: Must be valid currency ID
  • Tree Parent Type: Determines position in chart of accounts
  • Sort Order: Numeric value for display ordering
  • Soft Delete: Changes conditions field (0=active, 1=deleted)

■ 3. Database Schema

• Primary Table: save


CREATE TABLE save (
    saveid INT PRIMARY KEY AUTO_INCREMENT,
    savename VARCHAR(255) NOT NULL,
    savecurrentvalue DECIMAL(10,2) NOT NULL DEFAULT 0,
    savedate DATETIME NOT NULL,
    conditions INT NOT NULL DEFAULT 0,  -- 0=active, 1=deleted

    userid INT NOT NULL,
    currencyId INT NOT NULL,
    sortby INT NOT NULL DEFAULT 0,
    treeId INT DEFAULT NULL,  -- link to accountstree

    saveTreeParentType INT DEFAULT 0,  -- 0=regular(40), 1=special(408)

    webApiId INT DEFAULT 0,
    savetypeid INT DEFAULT NULL
);

• Related Tables

savedaily - Cash Transaction Log


CREATE TABLE savedaily (
    savedailyid INT PRIMARY KEY AUTO_INCREMENT,
    savedailydate DATETIME NOT NULL,
    userid INT NOT NULL,
    savedailysavebefore DECIMAL(10,2) NOT NULL,
    savedailychangeamount DECIMAL(10,2) NOT NULL,
    savedailychangetype INT NOT NULL,  -- 0=increase, 1=decrease

    saveid INT NOT NULL,
    processname VARCHAR(500),  -- description of transaction

    savedailymodelid INT,  -- related record ID

    savedailysaveafter DECIMAL(10,2) NOT NULL,
    tablename VARCHAR(100)  -- source table

);

savetype - Cash Box Categories


CREATE TABLE savetype (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(255) NOT NULL,
    del INT NOT NULL DEFAULT 0  -- 0=active, 2=deleted

);

saveclose - Cash Box Transfers


CREATE TABLE saveclose (
    savecloseid INT PRIMARY KEY AUTO_INCREMENT,
    fromSaveId INT NOT NULL,
    toSaveId INT NOT NULL,
    amount DECIMAL(10,2) NOT NULL,
    transferDate DATETIME NOT NULL,
    userid INT NOT NULL,
    conditions INT NOT NULL DEFAULT 0
);

accountstree - Chart of Accounts Integration


CREATE TABLE accountstree (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(255) NOT NULL,
    customName VARCHAR(255),
    parent INT NOT NULL,
    type INT NOT NULL,  -- 3=cash box account

    level INT NOT NULL,
    conditions INT NOT NULL DEFAULT 0
);

• Relationships

  • saveid → savedaily: One-to-many transaction log
  • saveid → saveclose: Many-to-many transfers
  • currencyId → currency: Many-to-one currency
  • treeId → accountstree: One-to-one chart account
  • savetypeid → savetype: Many-to-one category
  • userid → users: Many-to-one user tracking

■ 4. Current Implementation Analysis

• SQL Operations from Current Controller

▪ 1. Add New Cash Box (add() function - Lines 338-422)


-- Check for duplicate name

SELECT * FROM save WHERE savename = '{saveName}' AND conditions = 0;


-- Insert new cash box

INSERT INTO save (
    savedate, conditions, savecurrentvalue, savename, 
    currencyId, sortby, userid, saveTreeParentType, 
    webApiId, savetypeid
) VALUES (
    NOW(), 0, {savecurrentValue}, '{saveName}', 

    {currencyId}, {sortby}, {userId}, {saveTreeParentType}, 
    {webApiId}, {savetypeid}
);

-- Insert into savedaily audit log

INSERT INTO savedaily (
    savedailydate, userid, savedailysavebefore, savedailychangeamount,
    savedailychangetype, saveid, processname, savedailymodelid,
    savedailysaveafter, tablename
) VALUES (
    NOW(), {userId}, 0, {savecurrentValue}, 
    0, {saveId}, 'تم اضافة خزنة باسم [{saveName}]', {saveId},

    {savecurrentValue}, 'saveController.php'

);

-- Add to chart of accounts tree

INSERT INTO accountstree (
    name, customName, parent, type, level, conditions
) VALUES (
    '{saveName}', '{saveName}', {parent}, 3, 1, 0

);

-- Update save with treeId

UPDATE save SET treeId = {treeId} WHERE saveid = {saveId};

-- Create accounting journal entry

INSERT INTO dailyentry (dDateTime, entryComment) 
VALUES (NOW(), 'إضافة في {saveName}');


-- Debit entry (cash account)

INSERT INTO dailyentrydebtor (accountstreeid, value, dailyentryid)
VALUES ({treeId}, {savecurrentValue}, {dailyEntryId});

-- Credit entry (equity account)

INSERT INTO dailyentrycreditor (accountstreeid, value, dailyentryid)
VALUES (121, {savecurrentValue}, {dailyEntryId});

▪ 2. Show All Cash Boxes (show() function - Lines 425-454)


-- Default query - all active cash boxes

SELECT s.*, c.name as currencyName, st.name as savetypeName
FROM save s
LEFT JOIN currency c ON s.currencyId = c.id
LEFT JOIN savetype st ON s.savetypeid = st.id
WHERE s.conditions = 0
ORDER BY s.sortby;

-- With type filter

SELECT s.*, c.name as currencyName, st.name as savetypeName
FROM save s
LEFT JOIN currency c ON s.currencyId = c.id
LEFT JOIN savetype st ON s.savetypeid = st.id
WHERE s.conditions = 0
AND s.savetypeid IN (0, {typeIds})
ORDER BY s.sortby;

-- With session-based access control

SELECT s.*, c.name as currencyName, st.name as savetypeName
FROM save s
LEFT JOIN currency c ON s.currencyId = c.id
LEFT JOIN savetype st ON s.savetypeid = st.id
WHERE s.conditions = 0
AND s.saveid IN ({allowedSaveIds})
ORDER BY s.sortby;

-- Single cash box view

SELECT s.*, c.name as currencyName, st.name as savetypeName
FROM save s
LEFT JOIN currency c ON s.currencyId = c.id
LEFT JOIN savetype st ON s.savetypeid = st.id
WHERE s.conditions = 0
AND s.saveid = {saveId};

▪ 3. Soft Delete (delete() function - Lines 457-479)


-- Toggle conditions field for soft delete

UPDATE save 
SET conditions = CASE 
    WHEN conditions = 1 THEN 0  -- Restore

    WHEN conditions = 0 THEN 1  -- Delete

    END,
    savedate = NOW(),
    userid = {userId}
WHERE saveid = {saveId};

-- Log the action in savedaily

INSERT INTO savedaily (
    savedailydate, userid, savedailysavebefore, savedailychangeamount,
    savedailychangetype, saveid, processname, savedailymodelid,
    savedailysaveafter, tablename
) VALUES (
    NOW(), {userId}, {currentValue}, 0, 
    2, {saveId}, 'حذف مؤقت للخزنة', {saveId},

    {currentValue}, 'saveController.php'

);

▪ 4. Permanent Delete (deleteFinaly() function - Lines 482-496)


-- Get save data for tree cleanup

SELECT * FROM save WHERE saveid = {saveId};

-- Delete from save table

DELETE FROM save WHERE saveid = {saveId};

-- Delete from chart of accounts

DELETE FROM accountstree WHERE id = {treeId};

-- Clean up related savedaily records (optional)

DELETE FROM savedaily WHERE saveid = {saveId};

▪ 5. Edit Cash Box (edit() function - Lines 499-514)


-- Load cash box data with currency

SELECT s.*, c.name as currencyName 
FROM save s
LEFT JOIN currency c ON s.currencyId = c.id
WHERE s.saveid = {saveId};

▪ 6. Update Cash Box (update() function - Lines 536-602)


-- Load existing data

SELECT * FROM save WHERE saveid = {saveId};

-- Update save record

UPDATE save SET
    savedate = '{saveDate}',

    conditions = {conditions},
    savecurrentvalue = {savecurrentValue},
    savename = '{saveName}',

    userid = {userId},
    sortby = {sortby},
    saveTreeParentType = {saveTreeParentType},
    savetypeid = {savetypeid}
WHERE saveid = {saveId};

-- Update chart of accounts tree

UPDATE accountstree SET
    name = '{saveName}',

    customName = '{saveName}',

    parent = {parent}
WHERE id = {treeId};

-- Log the update in savedaily

INSERT INTO savedaily (
    savedailydate, userid, savedailysavebefore, savedailychangeamount,
    savedailychangetype, saveid, processname, savedailymodelid,
    savedailysaveafter, tablename
) VALUES (
    NOW(), {userId}, {oldValue}, {changeAmount}, 
    {changeType}, {saveId}, 'تعديل بيانات الخزنة', {saveId},

    {newValue}, 'saveController.php'

);

▪ 7. Update Sort Order (sortby operation - Lines 307-310)


-- AJAX update for display order

UPDATE save SET sortby = {sortby} WHERE saveid = {id};

▪ 8. Get Save Types (Lines 131-132, 180-181)


-- Get all active save types

SELECT name, id FROM savetype WHERE del != 2;

▪ 9. Get All Currencies (Lines 128-129)


-- Get active currencies for dropdown

SELECT * FROM currency WHERE conditions = 0;

■ 5. API Operations Mapping

• Operation: Add New Cash Box

  • HTTP Method: POST
  • Endpoint: /api/save/add
  • Request Body:

{
    "savename": "الخزنة الرئيسية",
    "savecurrentvalue": 50000.00,
    "savedetails": "خزنة المكتب الرئيسي",
    "currencyId": 1,
    "sortby": 1,
    "saveTreeParentType": 0,
    "savetypeid": 1,
    "webApiId": 0,
    "curlpost": 1
}
  • Response:

{
    "status": 1,
    "message": "تمت العمليه بنجاح",
    "message_en": "Success",
    "saveId": 123,
    "treeId": 456
}

• Operation: Get All Cash Boxes

  • HTTP Method: GET
  • Endpoint: /api/save/list
  • Query Parameters:
  • savetypeids[]: Array of save type IDs to filter
  • conditions: 0 for active, 1 for deleted
  • Response:

{
    "status": "success",
    "data": [
        {
            "saveid": 1,
            "savename": "الخزنة الرئيسية",
            "savecurrentvalue": 50000.00,
            "currencyName": "ريال سعودي",
            "savetypeName": "خزنة نقدية",
            "conditions": 0,
            "sortby": 1
        }
    ]
}

• Operation: Update Cash Box

  • HTTP Method: PUT
  • Endpoint: /api/save/update/{saveid}
  • Request Body:

{
    "saveid": 1,
    "savename": "الخزنة الرئيسية - محدث",
    "savecurrentvalue": 75000.00,
    "savedate": "2024-01-15",
    "conditions": 0,
    "sortby": 1,
    "saveTreeParentType": 0,
    "savetypeid": 1,
    "curlpost": 1
}

• Operation: Delete Cash Box (Soft)

  • HTTP Method: DELETE
  • Endpoint: /api/save/delete/{saveid}
  • Response:

{
    "status": 1,
    "message": "تمت العمليه بنجاح",
    "message_en": "Success"
}

• Operation: Get Cash Box Details

  • HTTP Method: GET
  • Endpoint: /api/save/{saveid}
  • Response:

{
    "saveid": 1,
    "savename": "الخزنة الرئيسية",
    "savecurrentvalue": 50000.00,
    "savedate": "2024-01-01",
    "currencyId": 1,
    "currencyName": "ريال سعودي",
    "treeId": 456,
    "savetypeid": 1,
    "sortby": 1,
    "conditions": 0
}

■ 6. Integration Points

• Accounting Integration

The controller automatically creates journal entries for cash movements:
  1. Initial Balance: Debit Cash Account, Credit Equity (121)
  2. Updates: Adjusting entries for balance changes
  3. Tree Management: Automatic chart of accounts updates

• Session-Based Access Control


// Access control variables

$_SESSION['searchinonesave'] // 0=multiple, 1=single

$_SESSION['saveids'] // Comma-separated allowed IDs

$_SESSION['saveid'] // Single cash box access

• Transaction Management

All critical operations wrapped in database transactions:

try {
    // Operations

    $mytransactions->commit();
} ">catch (Exception $ex) {
    $mytransactions->rollback();
}

■ 7. Error Handling

• Status Codes

  • 1: Success - Operation completed
  • 2: Error - General failure
  • 3: Duplicate - Name already exists

• Error Messages

  • → Arabic: "تم ادخال اسم الخزنة من قبل" (Duplicate name)
  • → English: "This save has been added before"

■ 8. Security Features

  1. Authentication Required: All operations check ../public/authentication.php
  2. User Tracking: Every operation logs $_SESSION['userid']
  3. Soft Delete: Preserves audit trail with conditions field
  4. Transaction Rollback: Ensures data integrity on errors
  5. Session Validation: Checks user permissions per cash box

■ 9. Related Controllers

  • savedailyController.php: Daily transaction reporting
  • saveCloseController.php: Cash transfers between boxes
  • settlementsaveController.php: Cash reconciliation
  • saveTypeController.php: Cash box type management

■ 10. Special Features

• CURL/API Support


">if (isset($_POST['curlpost']) && $_POST['curlpost'] == 1) {

    // Return JSON response

    ">echo json_encode($data);
} else {
    // Standard web redirect

    header("location:?do=success");
}

• Tree Parent Types

  • Type 0: Regular cash boxes (parent=40)
  • Type 1: Special cash boxes (parent=408)

• Daily Entry Function

Automatic savedaily record creation for audit:

insertSavedaily(
    $savedailysavebefore,
    $savedailychangeamount,
    $savedailychangetype,
    $saveid,
    $processname,
    $savedailymodelid,
    $savedailysaveafter,
    $tablename
);

■ 11. Testing Scenarios

• Test Case 1: Create Cash Box

  1. POST to add with unique name
  2. Verify save record created
  3. Check savedaily log entry
  4. Confirm tree element added
  5. Validate journal entries

• Test Case 2: Duplicate Name Check

  1. Create cash box with name "Test"
  2. Attempt to create another with same name
  3. Should return status 2 with duplicate message

• Test Case 3: Multi-Currency Support

  1. Create cash boxes in different currencies
  2. Display list should show currency names
  3. Edit should maintain currency assignment

• Test Case 4: Soft Delete/Restore

  1. Delete cash box (conditions=1)
  2. Verify still in database
  3. Restore (conditions=0)
  4. Confirm functionality restored

• Test Case 5: Transaction Rollback

  1. Force error during update
  2. Verify rollback occurred
  3. Check no partial updates

■ 12. Performance Considerations

  1. Indexed Fields: saveid, conditions, currencyId, savetypeid
  2. Query Optimization: Use JOIN for currency/type names
  3. Session Caching: Store frequently accessed save IDs
  4. Transaction Scope: Minimize transaction duration

■ 13. Future Enhancement Opportunities

  1. RESTful API: Complete REST implementation
  2. Bulk Operations: Multiple cash box management
  3. Balance History: Time-series tracking
  4. Multi-Branch: Branch-specific cash boxes
  5. Mobile App: API endpoints for mobile access
  6. Real-time Updates: WebSocket for balance changes
  7. Reconciliation: Automated daily reconciliation
  8. Approval Workflow: Multi-level approval for large amounts