# Primary Account Model

## Overview

The `PrimaryAccount` model represents primary accounting ledgers for a company. It stores the main ledger accounts like Cash A/c, Bank accounts, etc.

## Database Table: `primary_account`

### Schema

| Column | Type | Constraints | Description |
|--------|------|-------------|-------------|
| `id` | INT | PRIMARY KEY, AUTO_INCREMENT | Unique identifier |
| `com_id` | INT | NOT NULL | Company ID |
| `uid` | INT | NOT NULL | User/Staff ID who created the account |
| `ledger_under` | VARCHAR(255) | NOT NULL | Parent ledger category (e.g., "Cash", "Bank") |
| `ledger_name` | VARCHAR(255) | NOT NULL | Ledger account name (e.g., "Cash A/c", "Canara") |
| `create_at` | DATETIME | DEFAULT CURRENT_TIMESTAMP | Creation timestamp |
| `modify_at` | DATETIME | DEFAULT CURRENT_TIMESTAMP ON UPDATE | Last modification timestamp |

### Indexes

1. **PRIMARY KEY**: `id`
2. **UNIQUE**: `unique_company_ledger` on (`com_id`, `ledger_under`, `ledger_name`)
3. **INDEX**: `idx_com_id` on `com_id`
4. **INDEX**: `idx_ledger_under` on `ledger_under`
5. **INDEX**: `idx_ledger_name` on `ledger_name`
6. **INDEX**: `idx_com_id_ledger_under` on (`com_id`, `ledger_under`)

### Unique Constraint

A company cannot have duplicate ledger names under the same ledger category.

**Example:**
- ✅ Allowed: Company 15 can have "Cash A/c" under "Cash" and "Canara" under "Bank"
- ❌ Not Allowed: Company 15 cannot have two "Cash A/c" entries under "Cash"

---

## Model Usage

### Import the Model

```javascript
const { PrimaryAccount } = require('../models');
```

### Associations

- **BelongsTo Company**: `PrimaryAccount.belongsTo(Company, { foreignKey: 'com_id', as: 'company' })`
- **BelongsTo Staff**: `PrimaryAccount.belongsTo(Staff, { foreignKey: 'uid', as: 'staff' })`
- **Staff hasMany**: `Staff.hasMany(PrimaryAccount, { foreignKey: 'uid', as: 'primaryAccounts' })`

---

## Example CRUD Operations

### 1. Create a Primary Account

```javascript
const { PrimaryAccount } = require('../models');

async function createPrimaryAccount(req, res) {
  try {
    const { com_id, uid, ledger_under, ledger_name } = req.body;

    const account = await PrimaryAccount.create({
      com_id,
      uid,
      ledger_under,
      ledger_name
    });

    return res.json({
      status: 'success',
      message: 'Primary account created successfully',
      data: account
    });
  } catch (error) {
    // Handle unique constraint violation
    if (error.name === 'SequelizeUniqueConstraintError') {
      return res.status(400).json({
        status: 'error',
        message: 'This ledger account already exists for the company'
      });
    }
    
    return res.status(500).json({
      status: 'error',
      message: 'Failed to create primary account',
      error: error.message
    });
  }
}
```

### 2. Get All Primary Accounts for a Company

```javascript
async function getPrimaryAccountsByCompany(req, res) {
  try {
    const { com_id } = req.params;

    const accounts = await PrimaryAccount.findAll({
      where: { com_id },
      order: [
        ['ledger_under', 'ASC'],
        ['ledger_name', 'ASC']
      ],
      include: [
        {
          association: 'staff',
          attributes: ['uid', 'name', 'user_name']
        }
      ]
    });

    return res.json({
      status: 'success',
      data: accounts
    });
  } catch (error) {
    return res.status(500).json({
      status: 'error',
      message: 'Failed to fetch primary accounts',
      error: error.message
    });
  }
}
```

### 3. Get Accounts by Ledger Category

```javascript
async function getAccountsByLedgerUnder(req, res) {
  try {
    const { com_id, ledger_under } = req.params;

    const accounts = await PrimaryAccount.findAll({
      where: { 
        com_id,
        ledger_under
      },
      order: [['ledger_name', 'ASC']]
    });

    return res.json({
      status: 'success',
      data: accounts
    });
  } catch (error) {
    return res.status(500).json({
      status: 'error',
      message: 'Failed to fetch accounts',
      error: error.message
    });
  }
}
```

### 4. Update a Primary Account

```javascript
async function updatePrimaryAccount(req, res) {
  try {
    const { id } = req.params;
    const { ledger_name } = req.body;

    const [updated] = await PrimaryAccount.update(
      { ledger_name },
      { where: { id } }
    );

    if (updated === 0) {
      return res.status(404).json({
        status: 'error',
        message: 'Primary account not found'
      });
    }

    const account = await PrimaryAccount.findByPk(id);

    return res.json({
      status: 'success',
      message: 'Primary account updated successfully',
      data: account
    });
  } catch (error) {
    return res.status(500).json({
      status: 'error',
      message: 'Failed to update primary account',
      error: error.message
    });
  }
}
```

### 5. Delete a Primary Account

```javascript
async function deletePrimaryAccount(req, res) {
  try {
    const { id } = req.params;

    const deleted = await PrimaryAccount.destroy({
      where: { id }
    });

    if (deleted === 0) {
      return res.status(404).json({
        status: 'error',
        message: 'Primary account not found'
      });
    }

    return res.json({
      status: 'success',
      message: 'Primary account deleted successfully'
    });
  } catch (error) {
    return res.status(500).json({
      status: 'error',
      message: 'Failed to delete primary account',
      error: error.message
    });
  }
}
```

---

## Common Ledger Categories

### Typical `ledger_under` Values:

1. **Cash** - For cash-based accounts
2. **Bank** - For bank accounts
3. **Assets** - For asset accounts
4. **Liabilities** - For liability accounts
5. **Income** - For income accounts
6. **Expenses** - For expense accounts
7. **Capital** - For capital accounts

### Example Accounts:

| ledger_under | ledger_name |
|--------------|-------------|
| Cash | Cash A/c |
| Bank | Canara Bank |
| Bank | HDFC Bank |
| Bank | State Bank of India |
| Assets | Office Equipment |
| Expenses | Operating Expenses |
| Income | Interest Income |

---

## Query Examples

### Get Cash Accounts Only

```javascript
const cashAccounts = await PrimaryAccount.findAll({
  where: {
    com_id: 15,
    ledger_under: 'Cash'
  }
});
```

### Get All Bank Accounts

```javascript
const bankAccounts = await PrimaryAccount.findAll({
  where: {
    com_id: 15,
    ledger_under: 'Bank'
  },
  order: [['ledger_name', 'ASC']]
});
```

### Count Accounts by Category

```javascript
const { Sequelize } = require('sequelize');

const accountCounts = await PrimaryAccount.findAll({
  where: { com_id: 15 },
  attributes: [
    'ledger_under',
    [Sequelize.fn('COUNT', Sequelize.col('id')), 'count']
  ],
  group: ['ledger_under']
});
```

### Get Account with Staff Details

```javascript
const account = await PrimaryAccount.findByPk(1, {
  include: [
    {
      association: 'staff',
      attributes: ['uid', 'name', 'user_name', 'user_type']
    },
    {
      association: 'company',
      attributes: ['com_id', 'com_name', 'email']
    }
  ]
});
```

---

## API Endpoint Examples

### Suggested Routes

```javascript
// In routes/auth.js or a new routes file

const { PrimaryAccount } = require('../models');

// Get all primary accounts for authenticated admin's company
router.get('/admin/primary-accounts', authenticateAdmin, async (req, res) => {
  try {
    const accounts = await PrimaryAccount.findAll({
      where: { com_id: req.admin.com_id },
      order: [
        ['ledger_under', 'ASC'],
        ['ledger_name', 'ASC']
      ]
    });
    
    res.json({
      status: 'success',
      data: accounts
    });
  } catch (error) {
    res.status(500).json({
      status: 'error',
      message: error.message
    });
  }
});

// Create a new primary account
router.post('/admin/primary-accounts', authenticateAdmin, async (req, res) => {
  try {
    const { ledger_under, ledger_name } = req.body;
    
    const account = await PrimaryAccount.create({
      com_id: req.admin.com_id,
      uid: req.admin.uid,
      ledger_under,
      ledger_name
    });
    
    res.json({
      status: 'success',
      message: 'Primary account created',
      data: account
    });
  } catch (error) {
    if (error.name === 'SequelizeUniqueConstraintError') {
      return res.status(400).json({
        status: 'error',
        message: 'This ledger account already exists'
      });
    }
    res.status(500).json({
      status: 'error',
      message: error.message
    });
  }
});

// Get accounts by ledger category
router.get('/admin/primary-accounts/:ledger_under', authenticateAdmin, async (req, res) => {
  try {
    const { ledger_under } = req.params;
    
    const accounts = await PrimaryAccount.findAll({
      where: {
        com_id: req.admin.com_id,
        ledger_under
      },
      order: [['ledger_name', 'ASC']]
    });
    
    res.json({
      status: 'success',
      data: accounts
    });
  } catch (error) {
    res.status(500).json({
      status: 'error',
      message: error.message
    });
  }
});

// Update primary account
router.put('/admin/primary-accounts/:id', authenticateAdmin, async (req, res) => {
  try {
    const { id } = req.params;
    const { ledger_name } = req.body;
    
    const [updated] = await PrimaryAccount.update(
      { ledger_name },
      {
        where: {
          id,
          com_id: req.admin.com_id // Ensure admin can only update their company's accounts
        }
      }
    );
    
    if (updated === 0) {
      return res.status(404).json({
        status: 'error',
        message: 'Account not found'
      });
    }
    
    const account = await PrimaryAccount.findByPk(id);
    
    res.json({
      status: 'success',
      message: 'Account updated',
      data: account
    });
  } catch (error) {
    res.status(500).json({
      status: 'error',
      message: error.message
    });
  }
});

// Delete primary account
router.delete('/admin/primary-accounts/:id', authenticateAdmin, async (req, res) => {
  try {
    const { id } = req.params;
    
    const deleted = await PrimaryAccount.destroy({
      where: {
        id,
        com_id: req.admin.com_id // Ensure admin can only delete their company's accounts
      }
    });
    
    if (deleted === 0) {
      return res.status(404).json({
        status: 'error',
        message: 'Account not found'
      });
    }
    
    res.json({
      status: 'success',
      message: 'Account deleted'
    });
  } catch (error) {
    res.status(500).json({
      status: 'error',
      message: error.message
    });
  }
});
```

---

## cURL Examples

### Get All Primary Accounts

```bash
curl -X GET 'https://dayloanapp.xesstechlink.com/admin/primary-accounts' \
  -H 'authorization: Bearer ADMIN_JWT_TOKEN' \
  -H 'content-type: application/json'
```

### Create Primary Account

```bash
curl -X POST 'https://dayloanapp.xesstechlink.com/admin/primary-accounts' \
  -H 'authorization: Bearer ADMIN_JWT_TOKEN' \
  -H 'content-type: application/json' \
  -d '{
    "ledger_under": "Bank",
    "ledger_name": "HDFC Bank"
  }'
```

### Get Bank Accounts Only

```bash
curl -X GET 'https://dayloanapp.xesstechlink.com/admin/primary-accounts/Bank' \
  -H 'authorization: Bearer ADMIN_JWT_TOKEN' \
  -H 'content-type: application/json'
```

### Update Primary Account

```bash
curl -X PUT 'https://dayloanapp.xesstechlink.com/admin/primary-accounts/1' \
  -H 'authorization: Bearer ADMIN_JWT_TOKEN' \
  -H 'content-type: application/json' \
  -d '{
    "ledger_name": "Cash Account"
  }'
```

### Delete Primary Account

```bash
curl -X DELETE 'https://dayloanapp.xesstechlink.com/admin/primary-accounts/1' \
  -H 'authorization: Bearer ADMIN_JWT_TOKEN' \
  -H 'content-type: application/json'
```

---

## Notes

1. **Unique Constraint**: Each combination of `(com_id, ledger_under, ledger_name)` must be unique
2. **Timestamps**: Both `create_at` and `modify_at` are automatically managed
3. **Associations**: The model is linked to both `Company` and `Staff` models
4. **Use Case**: This table is used for managing primary ledger accounts in the accounting system
5. **Expense Integration**: When agents create expenses, they use accounts from this table (e.g., "Cash A/c")

---

## Model File Location

```
/Volumes/KANINFOTECH/demo/Mobile_Dayloan_Api/models/PrimaryAccount.js
```

The model has been successfully created and integrated with the existing codebase! ✅

