# Implementation Plan: Automatic Residual / "Others" Allowance
## ERPFLOW Payroll Module — Dynamic Salary Gap Balancing

**Document Serial:** `PAY-IMP-2026-RESIDUAL-ALLOWANCE`  
**Target Module:** `Modules/Payroll` & `Modules/Employee`  
**Language:** Bengali (বিজনেস লজিক) + English (টেকনিক্যাল স্পেসিফিকেশন)  
**Status:** Draft for Review (বাস্তবায়নের পূর্বের অনুমোদনযোগ্য প্ল্যান)  

---

## ১. সমস্যার বিবরণ ও উদ্দেশ্য (Problem & Objective)

### বর্তমান পরিস্থিতি:
* কোম্পানিতে একাধিক কর্মীর গ্রস স্যালারি একই হতে পারে (যেমন: ৩ জনেরই **Gross = ৫০,০০০ টাকা**)।
* কিন্তু তাদের প্রত্যেকের চুক্তি ও গ্রেড অনুযায়ী মূল বেতন আলাদা (যেমন: **Basic = ২০,০০০**, **২৫,০০০**, **২২,০০০ টাকা**)।
* কোম্পানিতে কিছু সাধারণ ফিক্সড ভাতা আছে যা সবার জন্য সমান (যেমন: মোবাইল + বাড়িভাড়া + চিকিৎসা মিলিয়ে **২,২০০ টাকা**)।
* **সমস্যা:** বেসিক এবং ফিক্সড ভাতা যোগ করার পরেও গ্রস স্যালারির সাথে একটি ঘাটতি বা গ্যাপ থেকে যায়:
  * কর্মী ১: $৫০,০০০ - (২০,০০০ + ২,২০০) =$ **২৭,৮০০ টাকা বাকি**।
  * কর্মী ২: $৫০,০০০ - (২৫,০০০ + ২,২০০) =$ **২২,৮০০ টাকা বাকি**।
  * কর্মী ৩: $৫০,০০০ - (২২,০০০ + ২,২০০) =$ **২৫,৮০০ টাকা বাকি**।
* বর্তমান সিস্টেমে এই বাকি টাকা স্বয়ংক্রিয়ভাবে ব্যালান্স হয় না, ফলে পে-স্লিপে কর্মী ৫০,০০০ টাকার পরিবর্তে শুধু ২২,২০০ টাকা পায়।

### লক্ষ্য (Goal):
সফটওয়্যার স্বয়ংক্রিয়ভাবে এই ঘাটতি (`Gross - (Basic + Defined Allowances)`) হিসাব করে পে-স্লিপের আয়ের তালিকায় **`Others` (অন্যান্য ভাতা)** হিসেবে যুক্ত করবে—যাতে প্রতিটি কর্মীর মোট পে-স্লিপ গ্রস **হুবহু ৫০,০০০ টাকায় মিলে যায়**।

---

## ২. আর্কিটেকচার ও বিজনেস রুলস (Core Calculation Rules)

### গাণিতিক সূত্র (Formula):
$$\text{Raw Gap} = \text{Gross Salary} - \left( \text{Basic Salary} + \sum \text{All Active Defined Earnings} \right)$$

1. **যদি $\text{Raw Gap} > 0$ হয়:**
   * সিস্টেমে একটি স্বয়ংক্রিয় আর্নিং লাইন যুক্ত হবে: `code = 'OTHERS'`, `amount = Raw Gap`।
   * পে-স্লিপে এটি **"Others"** বা **"Other Allowance"** হিসেবে প্রদর্শিত হবে।
2. **যদি $\text{Raw Gap} == 0$ হয়:**
   * কোনো `OTHERS` লাইন যোগ হবে না, কারণ বেসিক ও অন্যান্য ভাতাতেই গ্রস ১০০% মিলে গেছে।
3. **যদি $\text{Raw Gap} < 0$ হয় (অর্থাৎ ভাতার যোগফল গ্রসের চেয়ে বেশি):**
   * ফর্মে ভ্যালিডেশন এরর দেবে: *"Total defined earnings exceed Gross salary."*
4. **অনুপস্থিতি ও ছুটির প্রভাব (Proration Rule):**
   * যদি কোনো কর্মী ওই মাসে অনুপস্থিত থাকে বা বিনা বেতনে ছুটি কাটায়, তবে বেসিকের মতোই `Others` ভাতাও কাজের দিনের অনুপাতে আনুপাতিকভাবে (`proRate`) কমবে:
     $$\text{Payslip Others Amount} = \text{Raw Gap} \times \text{ProRate Factor}$$
5. **ট্যাক্স রুল (Taxability):**
   * `Others` নিয়মিত ক্যাশ ইনকামের অংশ হওয়ায় এটি স্বয়ংক্রিয়ভাবে করযোগ্য আয়ের (`taxable_earnings`) মধ্যে যুক্ত হবে।

---

## ৩. ফাইলভিত্তিক পরিবর্তনের তালিকা (File-by-File Changes)

### ক. ব্যাকএন্ড ক্যালকুলেশন ইঞ্জিন (Backend Calculator)

#### ১. `backend/Modules/Payroll/app/Support/SalaryComponentCalculator.php`
* **পরিবর্তন:** `calculate()` মেথডের মধ্যে সব আর্নিংস কম্পোনেন্ট প্রসেস করার পর গ্রস স্যালারির সাথে মোট আর্নিংসের পার্থক্য (`$gap`) হিসাব করা হবে।
* **লজিক:**
  ```php
  $rawEarningSum = array_sum($rawEarnings);
  $gap = self::round2($grossSalary - $rawEarningSum);

  if ($gap > 0) {
      $othersRaw = $gap;
      $othersProrated = self::round2($othersRaw * $proRate);
      $earnings['OTHERS'] = $othersProrated;
  }
  ```
* **প্রভাব:** `earnings_breakdown` অ্যারেতে স্বয়ংক্রিয়ভাবে `OTHERS` কি (key) যুক্ত হবে।

#### ২. `backend/Modules/Payroll/app/Services/PayslipCalculatorService.php`
* **পরিবর্তন:** `taxableMonthly()` মেথডে নিশ্চিত করা যাতে `OTHERS` কোডটি করযোগ্য আয়ের মধ্যে অন্তর্ভুক্ত থাকে:
  ```php
  if ($code === 'overtime' || $code === 'commission' || $code === 'OTHERS' || $code === 'others' || isset($taxableCodes[$code])) {
      $total += (float) $amount;
  }
  ```

---

### খ. ফ্রন্টএন্ড ফর্ম ও ভ্যালিডেশন (Frontend Form & Helper)

#### ১. `frontend/src/modules/employee/components/EmployeeSalaryForm.tsx`
* **পরিবর্তন ১ (রিয়েল-টাইম ব্যালান্স ডিসপ্লে):**
  * ব্যবহারকারী যখন `Gross salary` (৫০,০০০) এবং `Basic salary` (২০,০০০) টাইপ করবে, ফর্মটি সিলেক্ট করা স্ট্রাকচারের ফিক্সড ভাতাগুলো (যেমন: ২,২০০) হিসাব করে নিচে একটি লাইভ ইনফো কার্ড দেখাবে:
    ```text
    💡 Others Allowance: 27,800 BDT
    (Will be automatically added as 'Others' on payslip to match Gross)
    ```
* **পরিবর্তন ২ (সেফটি ভ্যালিডেশন):**
  * যদি কেউ গ্রসের চেয়ে বেশি বেসিক বা ভাতা দেয় (যেমন: গ্রস ২৫,০০০ কিন্তু বেসিক ৩০,০০০), তবে সেভ বাটন লক থাকবে এবং এরর দেখাবে: *"Gross salary cannot be less than Basic and defined allowances."*

#### ২. `frontend/src/modules/payroll/components/payslips/PayslipBreakdown.tsx`
* **পরিবর্তন:** `humanizeCode('OTHERS')` বর্তমানে `"Others"` দেখায়। এটিকে আরও প্রাতিষ্ঠানিক দেখাতে লেবেল হিসেবে `"Other Allowance"` বা `"Others"` ম্যাপিং সুনির্দিষ্ট করা হবে।

#### ৩. `frontend/src/modules/payroll/pages/salary-structures/components/PayslipPreviewPanel.tsx`
* **পরিবর্তন:** স্ট্রাকচার পেজে স্যাম্পল পে-স্লিপ প্রিভিউ দেখার সময় যাতে `OTHERS` লাইনের নাম সুন্দরভাবে "Other Allowance" হিসেবে দেখা যায়।

---

### গ. পে-স্লিপ প্রিন্ট ও পিডিএফ টেমপ্লেট (PDF Payslip Blade)

#### ১. `backend/Modules/Payroll/resources/views/pdf/payslip.blade.php`
* **পরিবর্তন:** পিডিএফ রেন্ডারিংয়ের সময় আর্নিংস টেবিলে `$code === 'OTHERS'` থাকলে সেটির লেবেল দেখাবে:
  ```blade
  <tr>
      <td>{{ $code === 'OTHERS' ? 'Other Allowance' : $code }}</td>
      <td>{{ number_format((float) $amount, 2) }}</td>
  </tr>
  ```

---

## ৪. টেস্ট ও কোয়ালিটি প্ল্যান (Test & QA Strategy)

### ইউনিট টেস্ট (Unit Tests):
1. **`SalaryComponentCalculatorTest.php`:**
   * টেস্ট ১: গ্রস ৫০,০০০, বেসিক ২০,০০০, ভাতা ২,২০০ হলে `OTHERS = ২৭,৮০০` জেনারেট হচ্ছে কি না।
   * টেস্ট ২: কোনো গ্যাপ না থাকলে (গ্রস = বেসিক + ভাতা) `OTHERS` তৈরি হচ্ছে না তা নিশ্চিত করা।
   * টেস্ট ৩: কর্মী ৫ দিন অনুপস্থিত থাকলে `OTHERS` আনুপাতিক হারে (`proRate`) কমছে কি না।

### ফিচার টেস্ট (Feature Tests):
1. **`PayslipGenerationTest.php`:**
   * ফুল পেরোল রানে পে-স্লিপ তৈরির পর `payslips.earnings_breakdown` জেসন কলামে `OTHERS` ভ্যালু সংরক্ষণ ও `gross_earnings == 50000.00` নিশ্চিতকরণ।
2. **`PayslipPdfTest.php`:**
   * পে-স্লিপ পিডিএফ ডাউনলোডের সময় "Other Allowance" লাইন সঠিকভাবে রেন্ডার হওয়া যাচাই।

---

## ৫. ধাপভিত্তিক বাস্তবায়ন পরিকল্পনা (Execution Phasing)

```
┌────────────────────────────────────────────────────────┐
│ Phase 1: Calculator Core Logic                         │
│ ➔ SalaryComponentCalculator-এ গ্যাপ অটো-ডিটেকশন ও টেস্ট│
├────────────────────────────────────────────────────────┤
│ Phase 2: Payslip Service & Tax Integration             │
│ ➔ PayslipCalculatorService ও ট্যাক্স স্ল্যাব ম্যাপিং   │
├────────────────────────────────────────────────────────┤
│ Phase 3: Frontend Live Helper & Form Validation        │
│ ➔ EmployeeSalaryForm-এ লাইভ ব্যালান্স কার্ড প্রদর্শন    │
├────────────────────────────────────────────────────────┤
│ Phase 4: UI & PDF Display Polish                       │
│ ➔ PayslipBreakdown ও Blade PDF টেমপ্লেট ফরম্যাটিং     │
├────────────────────────────────────────────────────────┤
│ Phase 5: Verification & End-to-End Test Suite          │
│ ➔ পুরো পেরোল রান চালিয়ে ৫২+ টেস্ট অ্যাসর্শন যাচাই      │
└────────────────────────────────────────────────────────┘
```

---

## ৬. আর্কিটেকচারাল সেফটি চেকলিস্ট (Architecture Guardrails)

- [x] ডাটাবেস স্কিমা পরিবর্তনের প্রয়োজন নেই (কারণ `payslips.earnings_breakdown` একটি ওপেন JSON ফিল্ড)।
- [x] বিদ্যমান স্যালারি স্ট্রাকচার ভাঙবে না (Backward Compatible)।
- [x] কোনো থার্ড-পার্টি প্যাকেজ ইন্সটল করার প্রয়োজন নেই।
- [x] `AI/RULES/CODING-STANDARD.md` এবং পেরোল মডিউল স্ট্যান্ডার্ড পূর্ণাঙ্গভাবে বজায় থাকবে।
- [x] আপনার চূড়ান্ত অনুমতি ছাড়া কোনো কোড এডিট বা গিট কমিট করা হবে না।
