→ كل القوالب
موارد بشرية

إدارة شركات وموظفين ورواتب

إعدادات مستقلة لكل شركة، فروع وإدارات، ملف موظف متكامل، ورديات وتأخير وإجازات ومكونات راتب مفصلة.

طريقة الاستخدام: الملف المحمّل (.vbs) لا يُفتح من أكسيس. انقر عليه نقراً مزدوجاً من مجلد التنزيلات، فيُنشئ ملف HRPayroll.accdb بجواره ويعرض عليك فتحه في أكسيس. إذا منعه ويندوز: كليك يمين ← خصائص ← Unblock.

مخطط العلاقات

1∞1∞1∞1∞1∞1∞1∞1∞1∞1∞1∞1∞1∞1∞1∞1∞Companies🔑 CompanyIDترقيم تلقائيCompanyNameنص مختصرRegistrationNoنص مختصرTaxNumberنص مختصرAddressنص مختصرPhoneنص مختصرSalaryDaysرقمEmployeeInsuranceRateرقم عشريNotesنص مختصرBranches🔑 BranchIDترقيم تلقائيCompanyIDرقمBranchNameنص مختصرAddressنص مختصرPhoneنص مختصرDepartments🔑 DeptIDترقيم تلقائيCompanyIDرقمBranchIDرقمDeptNameنص مختصرManagerNameنص مختصرShiftRules🔑 ShiftIDترقيم تلقائيCompanyIDرقمShiftNameنص مختصرShiftStartتاريخ/وقتDailyHoursرقم عشريGraceMinutesرقمLateFactorرقم عشريOvertimeFactorرقم عشريNotesنص مختصرLeavePolicies🔑 LeavePolicyIDترقيم تلقائيCompanyIDرقمLeaveNameنص مختصرAnnualDaysرقمIsPaidنعم/لاNotesنص مختصرEmployees🔑 EmpIDترقيم تلقائيEmpCodeنص مختصرFullNameنص مختصرNationalIDنص مختصرBirthDateتاريخ/وقتGenderنص مختصرMaritalStatusنص مختصرAddressنص مختصرPhoneنص مختصرEmailنص مختصرEmergencyContactنص مختصرEmergencyPhoneنص مختصرCompanyIDرقمBranchIDرقمDeptIDرقمJobTitleنص مختصرHireDateتاريخ/وقتContractEndتاريخ/وقتEmploymentTypeنص مختصرShiftIDرقمLeavePolicyIDرقمIsActiveنعم/لاBasicSalaryعملةNonTaxableVariableعملةInsurableSalaryعملةFixedAllowanceعملةInsuranceNumberنص مختصرInsuranceStartDateتاريخ/وقتBankNameنص مختصرBankAccountنص مختصرNotesنص مختصرAttendance🔑 AttIDترقيم تلقائيEmpIDرقمWorkDateتاريخ/وقتCheckInتاريخ/وقتCheckOutتاريخ/وقتLateMinutesرقمOvertimeHoursرقم عشريEmployeeLeaves🔑 LeaveIDترقيم تلقائيEmpIDرقمLeavePolicyIDرقمStartDateتاريخ/وقتEndDateتاريخ/وقتLeaveDaysرقمIsApprovedنعم/لاReasonنص مختصرDeductions🔑 DedIDترقيم تلقائيEmpIDرقمDedDateتاريخ/وقتAmountعملةReasonنص مختصرAdvances🔑 AdvIDترقيم تلقائيEmpIDرقمAdvDateتاريخ/وقتAmountعملةInstallmentعملةNotesنص مختصرPayroll🔑 PayIDترقيم تلقائيEmpIDرقمPayMonthتاريخ/وقتBasicSalaryعملةNonTaxableVariableعملةInsurableSalaryعملةAllowancesعملةOvertimeعملةLateDeductionعملةInsuranceDeductionعملةLeaveDeductionعملةTaxDeductionعملةAdvanceDeductionعملةOtherDeductionsعملةTotalDeductionsعملةNetSalaryعملةIsPaidنعم/لا

المميزات

  • إعدادات الرواتب والتأمين لكل شركة
  • فروع وإدارات وتبعية الموظفين
  • ورديات وسماح تأخير ومعاملات خصم وإضافي
  • إجازات معتمدة ورصيد سنوي لكل نوع
  • أساسي ومتغير غير خاضع للضريبة وراتب تأميني وبدلات
  • قسيمة راتب وكشف شهري

الشاشات والنماذج

  • frmCompanies

    إعدادات الشركات والرواتب والتأمين

  • frmBranches

    الفروع التابعة للشركات

  • frmDepartments

    الإدارات والتبعية للفروع

  • frmShiftRules

    قواعد الورديات والتأخير والإضافي

  • frmLeavePolicies

    قواعد وأنواع الإجازات

  • frmEmployees

    ملف الموظف الكامل

  • frmAttendance

    الحضور والانصراف

  • frmEmployeeLeaves

    طلبات الإجازات واعتمادها

  • frmDeductions

    الخصومات والجزاءات

  • frmAdvances

    السلف والأقساط

  • frmPayroll

    احتساب وصرف الرواتب

  • rptPayslip

    قسيمة الراتب

  • rptPayrollSheet

    كشف الرواتب الشهري

معاينة الشاشات الاحترافية

إدارة شركات وموظفين ورواتب

القائمة الرئيسية

خروج من البرنامج

كود إنشاء الشاشات تلقائياً (VBA)

بعد إنشاء القاعدة: افتحها ← Alt+F11 ← Insert ← Module ← الصق الكود ← ضع المؤشر داخل BuildAllScreens واضغط F5.

HRPayroll_Screens.bas
' ===== Module: modBuildScreens  (HRPayroll) =====
' Run BuildAllScreens (put the cursor inside it and press F5)
' Close all open forms and reports before running.

Private Const TW As Long = 567            ' 1 cm in twips
Private Const PRIMARY As Long = &H5A3A12  ' deep navy (BGR)
Private Const ACCENT As Long = &H2E9BF0   ' amber (BGR)
Private Const SURFACE As Long = &HF7F4F2
Private Const WHITE As Long = &HFFFFFF
Private Const MUTED As Long = &H7A706A
Private Const LINE_C As Long = &HE2DCD6

Public Sub BuildAllScreens()
    DoCmd.Hourglass True
    SetCaptions

    BuildForm "frmCompanies", "Companies", ChrW(1573) & ChrW(1593) & ChrW(1583) & ChrW(1575) & ChrW(1583) & ChrW(1575) & ChrW(1578) & " " & ChrW(1575) & ChrW(1604) & ChrW(1588) & ChrW(1585) & ChrW(1603) & ChrW(1575) & ChrW(1578) & " " & ChrW(1608) & ChrW(1575) & ChrW(1604) & ChrW(1585) & ChrW(1608) & ChrW(1575) & ChrW(1578) & ChrW(1576) & " " & ChrW(1608) & ChrW(1575) & ChrW(1604) & ChrW(1578) & ChrW(1571) & ChrW(1605) & ChrW(1610) & ChrW(1606), True, "", "", ""
    BuildForm "frmBranches", "Branches", ChrW(1575) & ChrW(1604) & ChrW(1601) & ChrW(1585) & ChrW(1608) & ChrW(1593) & " " & ChrW(1575) & ChrW(1604) & ChrW(1578) & ChrW(1575) & ChrW(1576) & ChrW(1593) & ChrW(1577) & " " & ChrW(1604) & ChrW(1604) & ChrW(1588) & ChrW(1585) & ChrW(1603) & ChrW(1575) & ChrW(1578), True, "", "", ""
    BuildForm "frmDepartments", "Departments", ChrW(1575) & ChrW(1604) & ChrW(1573) & ChrW(1583) & ChrW(1575) & ChrW(1585) & ChrW(1575) & ChrW(1578) & " " & ChrW(1608) & ChrW(1575) & ChrW(1604) & ChrW(1578) & ChrW(1576) & ChrW(1593) & ChrW(1610) & ChrW(1577) & " " & ChrW(1604) & ChrW(1604) & ChrW(1601) & ChrW(1585) & ChrW(1608) & ChrW(1593), True, "", "", ""
    BuildForm "frmShiftRules", "ShiftRules", ChrW(1602) & ChrW(1608) & ChrW(1575) & ChrW(1593) & ChrW(1583) & " " & ChrW(1575) & ChrW(1604) & ChrW(1608) & ChrW(1585) & ChrW(1583) & ChrW(1610) & ChrW(1575) & ChrW(1578) & " " & ChrW(1608) & ChrW(1575) & ChrW(1604) & ChrW(1578) & ChrW(1571) & ChrW(1582) & ChrW(1610) & ChrW(1585) & " " & ChrW(1608) & ChrW(1575) & ChrW(1604) & ChrW(1573) & ChrW(1590) & ChrW(1575) & ChrW(1601) & ChrW(1610), True, "", "", ""
    BuildForm "frmLeavePolicies", "LeavePolicies", ChrW(1602) & ChrW(1608) & ChrW(1575) & ChrW(1593) & ChrW(1583) & " " & ChrW(1608) & ChrW(1571) & ChrW(1606) & ChrW(1608) & ChrW(1575) & ChrW(1593) & " " & ChrW(1575) & ChrW(1604) & ChrW(1573) & ChrW(1580) & ChrW(1575) & ChrW(1586) & ChrW(1575) & ChrW(1578), True, "", "", ""
    BuildForm "frmEmployees", "Employees", ChrW(1605) & ChrW(1604) & ChrW(1601) & " " & ChrW(1575) & ChrW(1604) & ChrW(1605) & ChrW(1608) & ChrW(1592) & ChrW(1601) & " " & ChrW(1575) & ChrW(1604) & ChrW(1603) & ChrW(1575) & ChrW(1605) & ChrW(1604), True, "", "", ""
    BuildForm "frmAttendance", "Attendance", ChrW(1575) & ChrW(1604) & ChrW(1581) & ChrW(1590) & ChrW(1608) & ChrW(1585) & " " & ChrW(1608) & ChrW(1575) & ChrW(1604) & ChrW(1575) & ChrW(1606) & ChrW(1589) & ChrW(1585) & ChrW(1575) & ChrW(1601), True, "", "", ""
    BuildForm "frmEmployeeLeaves", "EmployeeLeaves", ChrW(1591) & ChrW(1604) & ChrW(1576) & ChrW(1575) & ChrW(1578) & " " & ChrW(1575) & ChrW(1604) & ChrW(1573) & ChrW(1580) & ChrW(1575) & ChrW(1586) & ChrW(1575) & ChrW(1578) & " " & ChrW(1608) & ChrW(1575) & ChrW(1593) & ChrW(1578) & ChrW(1605) & ChrW(1575) & ChrW(1583) & ChrW(1607) & ChrW(1575), True, "", "", ""
    BuildForm "frmDeductions", "Deductions", ChrW(1575) & ChrW(1604) & ChrW(1582) & ChrW(1589) & ChrW(1608) & ChrW(1605) & ChrW(1575) & ChrW(1578) & " " & ChrW(1608) & ChrW(1575) & ChrW(1604) & ChrW(1580) & ChrW(1586) & ChrW(1575) & ChrW(1569) & ChrW(1575) & ChrW(1578), True, "", "", ""
    BuildForm "frmAdvances", "Advances", ChrW(1575) & ChrW(1604) & ChrW(1587) & ChrW(1604) & ChrW(1601) & " " & ChrW(1608) & ChrW(1575) & ChrW(1604) & ChrW(1571) & ChrW(1602) & ChrW(1587) & ChrW(1575) & ChrW(1591), True, "", "", ""
    BuildForm "frmPayroll", "Payroll", ChrW(1575) & ChrW(1581) & ChrW(1578) & ChrW(1587) & ChrW(1575) & ChrW(1576) & " " & ChrW(1608) & ChrW(1589) & ChrW(1585) & ChrW(1601) & " " & ChrW(1575) & ChrW(1604) & ChrW(1585) & ChrW(1608) & ChrW(1575) & ChrW(1578) & ChrW(1576), True, "", "", ChrW(1575) & ChrW(1581) & ChrW(1578) & ChrW(1587) & ChrW(1575) & ChrW(1576) & " " & ChrW(1575) & ChrW(1604) & ChrW(1585) & ChrW(1575) & ChrW(1578) & ChrW(1576)
    BuildReport "rptPayslip", "SELECT p.PayID, e.FullName, e.JobTitle, d.DeptName, p.PayMonth, p.BasicSalary, p.NonTaxableVariable, p.InsurableSalary, p.Allowances, p.Overtime, p.LateDeduction, p.InsuranceDeduction, p.LeaveDeduction, p.TaxDeduction, p.AdvanceDeduction, p.OtherDeductions, p.TotalDeductions, p.NetSalary FROM (Payroll AS p INNER JOIN Employees AS e ON p.EmpID = e.EmpID) LEFT JOIN Departments AS d ON e.DeptID = d.DeptID", ChrW(1602) & ChrW(1587) & ChrW(1610) & ChrW(1605) & ChrW(1577) & " " & ChrW(1575) & ChrW(1604) & ChrW(1585) & ChrW(1575) & ChrW(1578) & ChrW(1576), False
    BuildReport "rptPayrollSheet", "SELECT e.FullName, d.DeptName, p.PayMonth, p.BasicSalary, p.NonTaxableVariable, p.Allowances, p.TotalDeductions, p.NetSalary FROM (Payroll AS p INNER JOIN Employees AS e ON p.EmpID = e.EmpID) LEFT JOIN Departments AS d ON e.DeptID = d.DeptID ORDER BY d.DeptName, e.FullName", ChrW(1603) & ChrW(1588) & ChrW(1601) & " " & ChrW(1575) & ChrW(1604) & ChrW(1585) & ChrW(1608) & ChrW(1575) & ChrW(1578) & ChrW(1576) & " " & ChrW(1575) & ChrW(1604) & ChrW(1588) & ChrW(1607) & ChrW(1585) & ChrW(1610), True
    BuildMenu
    DoCmd.Hourglass False
    MsgBox ChrW(1578) & ChrW(1605) & " " & ChrW(1573) & ChrW(1606) & ChrW(1588) & ChrW(1575) & ChrW(1569) & " 11 " & ChrW(1588) & ChrW(1575) & ChrW(1588) & ChrW(1577) & " " & ChrW(1608) & " 2 " & ChrW(1578) & ChrW(1602) & ChrW(1585) & ChrW(1610) & ChrW(1585) & " + " & ChrW(1575) & ChrW(1604) & ChrW(1602) & ChrW(1575) & ChrW(1574) & ChrW(1605) & ChrW(1577) & " " & ChrW(1575) & ChrW(1604) & ChrW(1585) & ChrW(1574) & ChrW(1610) & ChrW(1587) & ChrW(1610) & ChrW(1577) & " " & ChrW(1576) & ChrW(1606) & ChrW(1580) & ChrW(1575) & ChrW(1581), vbInformation
    DoCmd.OpenForm "frmMain"
End Sub

' ---------- Arabic captions ----------
Private Function Cap(ByVal n As String) As String
    Select Case n
        Case "Companies": Cap = ChrW(1575) & ChrW(1604) & ChrW(1588) & ChrW(1585) & ChrW(1603) & ChrW(1575) & ChrW(1578)
        Case "CompanyID": Cap = ChrW(1575) & ChrW(1604) & ChrW(1588) & ChrW(1585) & ChrW(1603) & ChrW(1577)
        Case "CompanyName": Cap = ChrW(1575) & ChrW(1587) & ChrW(1605) & " " & ChrW(1575) & ChrW(1604) & ChrW(1588) & ChrW(1585) & ChrW(1603) & ChrW(1577)
        Case "RegistrationNo": Cap = ChrW(1575) & ChrW(1604) & ChrW(1587) & ChrW(1580) & ChrW(1604) & " " & ChrW(1575) & ChrW(1604) & ChrW(1578) & ChrW(1580) & ChrW(1575) & ChrW(1585) & ChrW(1610)
        Case "TaxNumber": Cap = ChrW(1575) & ChrW(1604) & ChrW(1585) & ChrW(1602) & ChrW(1605) & " " & ChrW(1575) & ChrW(1604) & ChrW(1590) & ChrW(1585) & ChrW(1610) & ChrW(1576) & ChrW(1610)
        Case "Address": Cap = ChrW(1575) & ChrW(1604) & ChrW(1593) & ChrW(1606) & ChrW(1608) & ChrW(1575) & ChrW(1606)
        Case "Phone": Cap = ChrW(1575) & ChrW(1604) & ChrW(1607) & ChrW(1575) & ChrW(1578) & ChrW(1601)
        Case "SalaryDays": Cap = ChrW(1571) & ChrW(1610) & ChrW(1575) & ChrW(1605) & " " & ChrW(1571) & ChrW(1587) & ChrW(1575) & ChrW(1587) & " " & ChrW(1581) & ChrW(1587) & ChrW(1575) & ChrW(1576) & " " & ChrW(1575) & ChrW(1604) & ChrW(1585) & ChrW(1575) & ChrW(1578) & ChrW(1576)
        Case "EmployeeInsuranceRate": Cap = ChrW(1575) & ChrW(1588) & ChrW(1578) & ChrW(1585) & ChrW(1575) & ChrW(1603) & " " & ChrW(1575) & ChrW(1604) & ChrW(1605) & ChrW(1608) & ChrW(1592) & ChrW(1601) & " " & ChrW(1575) & ChrW(1604) & ChrW(1578) & ChrW(1571) & ChrW(1605) & ChrW(1610) & ChrW(1606) & ChrW(1610) & " (%)"
        Case "Notes": Cap = ChrW(1605) & ChrW(1604) & ChrW(1575) & ChrW(1581) & ChrW(1592) & ChrW(1575) & ChrW(1578)
        Case "Branches": Cap = ChrW(1575) & ChrW(1604) & ChrW(1601) & ChrW(1585) & ChrW(1608) & ChrW(1593)
        Case "BranchID": Cap = ChrW(1575) & ChrW(1604) & ChrW(1601) & ChrW(1585) & ChrW(1593)
        Case "BranchName": Cap = ChrW(1575) & ChrW(1587) & ChrW(1605) & " " & ChrW(1575) & ChrW(1604) & ChrW(1601) & ChrW(1585) & ChrW(1593)
        Case "Departments": Cap = ChrW(1575) & ChrW(1604) & ChrW(1571) & ChrW(1602) & ChrW(1587) & ChrW(1575) & ChrW(1605)
        Case "DeptID": Cap = ChrW(1575) & ChrW(1604) & ChrW(1602) & ChrW(1587) & ChrW(1605)
        Case "DeptName": Cap = ChrW(1575) & ChrW(1587) & ChrW(1605) & " " & ChrW(1575) & ChrW(1604) & ChrW(1602) & ChrW(1587) & ChrW(1605)
        Case "ManagerName": Cap = ChrW(1605) & ChrW(1583) & ChrW(1610) & ChrW(1585) & " " & ChrW(1575) & ChrW(1604) & ChrW(1573) & ChrW(1583) & ChrW(1575) & ChrW(1585) & ChrW(1577)
        Case "ShiftRules": Cap = ChrW(1575) & ChrW(1604) & ChrW(1608) & ChrW(1585) & ChrW(1583) & ChrW(1610) & ChrW(1575) & ChrW(1578) & " " & ChrW(1608) & ChrW(1602) & ChrW(1608) & ChrW(1575) & ChrW(1593) & ChrW(1583) & " " & ChrW(1575) & ChrW(1604) & ChrW(1578) & ChrW(1571) & ChrW(1582) & ChrW(1610) & ChrW(1585)
        Case "ShiftID": Cap = ChrW(1575) & ChrW(1604) & ChrW(1608) & ChrW(1585) & ChrW(1583) & ChrW(1610) & ChrW(1577)
        Case "ShiftName": Cap = ChrW(1575) & ChrW(1587) & ChrW(1605) & " " & ChrW(1575) & ChrW(1604) & ChrW(1608) & ChrW(1585) & ChrW(1583) & ChrW(1610) & ChrW(1577)
        Case "ShiftStart": Cap = ChrW(1576) & ChrW(1583) & ChrW(1575) & ChrW(1610) & ChrW(1577) & " " & ChrW(1575) & ChrW(1604) & ChrW(1583) & ChrW(1608) & ChrW(1575) & ChrW(1605)
        Case "DailyHours": Cap = ChrW(1587) & ChrW(1575) & ChrW(1593) & ChrW(1575) & ChrW(1578) & " " & ChrW(1575) & ChrW(1604) & ChrW(1608) & ChrW(1585) & ChrW(1583) & ChrW(1610) & ChrW(1577)
        Case "GraceMinutes": Cap = ChrW(1587) & ChrW(1605) & ChrW(1575) & ChrW(1581) & " " & ChrW(1575) & ChrW(1604) & ChrW(1578) & ChrW(1571) & ChrW(1582) & ChrW(1610) & ChrW(1585) & " (" & ChrW(1583) & ChrW(1602) & ChrW(1610) & ChrW(1602) & ChrW(1577) & ")"
        Case "LateFactor": Cap = ChrW(1605) & ChrW(1593) & ChrW(1575) & ChrW(1605) & ChrW(1604) & " " & ChrW(1582) & ChrW(1589) & ChrW(1605) & " " & ChrW(1575) & ChrW(1604) & ChrW(1578) & ChrW(1571) & ChrW(1582) & ChrW(1610) & ChrW(1585)
        Case "OvertimeFactor": Cap = ChrW(1605) & ChrW(1593) & ChrW(1575) & ChrW(1605) & ChrW(1604) & " " & ChrW(1571) & ChrW(1580) & ChrW(1585) & " " & ChrW(1575) & ChrW(1604) & ChrW(1573) & ChrW(1590) & ChrW(1575) & ChrW(1601) & ChrW(1610)
        Case "LeavePolicies": Cap = ChrW(1602) & ChrW(1608) & ChrW(1575) & ChrW(1593) & ChrW(1583) & " " & ChrW(1575) & ChrW(1604) & ChrW(1573) & ChrW(1580) & ChrW(1575) & ChrW(1586) & ChrW(1575) & ChrW(1578)
        Case "LeavePolicyID": Cap = ChrW(1606) & ChrW(1608) & ChrW(1593) & " " & ChrW(1575) & ChrW(1604) & ChrW(1573) & ChrW(1580) & ChrW(1575) & ChrW(1586) & ChrW(1577)
        Case "LeaveName": Cap = ChrW(1575) & ChrW(1587) & ChrW(1605) & " " & ChrW(1606) & ChrW(1608) & ChrW(1593) & " " & ChrW(1575) & ChrW(1604) & ChrW(1573) & ChrW(1580) & ChrW(1575) & ChrW(1586) & ChrW(1577)
        Case "AnnualDays": Cap = ChrW(1575) & ChrW(1604) & ChrW(1585) & ChrW(1589) & ChrW(1610) & ChrW(1583) & " " & ChrW(1575) & ChrW(1604) & ChrW(1587) & ChrW(1606) & ChrW(1608) & ChrW(1610) & " (" & ChrW(1610) & ChrW(1608) & ChrW(1605) & ")"
        Case "IsPaid": Cap = ChrW(1578) & ChrW(1605) & " " & ChrW(1575) & ChrW(1604) & ChrW(1589) & ChrW(1585) & ChrW(1601)
        Case "Employees": Cap = ChrW(1575) & ChrW(1604) & ChrW(1605) & ChrW(1608) & ChrW(1592) & ChrW(1601) & ChrW(1608) & ChrW(1606)
        Case "EmpID": Cap = ChrW(1575) & ChrW(1604) & ChrW(1605) & ChrW(1608) & ChrW(1592) & ChrW(1601)
        Case "EmpCode": Cap = ChrW(1603) & ChrW(1608) & ChrW(1583) & " " & ChrW(1575) & ChrW(1604) & ChrW(1605) & ChrW(1608) & ChrW(1592) & ChrW(1601)
        Case "FullName": Cap = ChrW(1575) & ChrW(1587) & ChrW(1605) & " " & ChrW(1575) & ChrW(1604) & ChrW(1605) & ChrW(1608) & ChrW(1592) & ChrW(1601)
        Case "NationalID": Cap = ChrW(1575) & ChrW(1604) & ChrW(1585) & ChrW(1602) & ChrW(1605) & " " & ChrW(1575) & ChrW(1604) & ChrW(1602) & ChrW(1608) & ChrW(1605) & ChrW(1610)
        Case "BirthDate": Cap = ChrW(1578) & ChrW(1575) & ChrW(1585) & ChrW(1610) & ChrW(1582) & " " & ChrW(1575) & ChrW(1604) & ChrW(1605) & ChrW(1610) & ChrW(1604) & ChrW(1575) & ChrW(1583)
        Case "Gender": Cap = ChrW(1575) & ChrW(1604) & ChrW(1606) & ChrW(1608) & ChrW(1593)
        Case "MaritalStatus": Cap = ChrW(1575) & ChrW(1604) & ChrW(1581) & ChrW(1575) & ChrW(1604) & ChrW(1577) & " " & ChrW(1575) & ChrW(1604) & ChrW(1575) & ChrW(1580) & ChrW(1578) & ChrW(1605) & ChrW(1575) & ChrW(1593) & ChrW(1610) & ChrW(1577)
        Case "Email": Cap = ChrW(1575) & ChrW(1604) & ChrW(1576) & ChrW(1585) & ChrW(1610) & ChrW(1583) & " " & ChrW(1575) & ChrW(1604) & ChrW(1573) & ChrW(1604) & ChrW(1603) & ChrW(1578) & ChrW(1585) & ChrW(1608) & ChrW(1606) & ChrW(1610)
        Case "EmergencyContact": Cap = ChrW(1580) & ChrW(1607) & ChrW(1577) & " " & ChrW(1575) & ChrW(1578) & ChrW(1589) & ChrW(1575) & ChrW(1604) & " " & ChrW(1575) & ChrW(1604) & ChrW(1591) & ChrW(1608) & ChrW(1575) & ChrW(1585) & ChrW(1574)
        Case "EmergencyPhone": Cap = ChrW(1607) & ChrW(1575) & ChrW(1578) & ChrW(1601) & " " & ChrW(1575) & ChrW(1604) & ChrW(1591) & ChrW(1608) & ChrW(1575) & ChrW(1585) & ChrW(1574)
        Case "JobTitle": Cap = ChrW(1575) & ChrW(1604) & ChrW(1605) & ChrW(1587) & ChrW(1605) & ChrW(1609) & " " & ChrW(1575) & ChrW(1604) & ChrW(1608) & ChrW(1592) & ChrW(1610) & ChrW(1601) & ChrW(1610)
        Case "HireDate": Cap = ChrW(1578) & ChrW(1575) & ChrW(1585) & ChrW(1610) & ChrW(1582) & " " & ChrW(1575) & ChrW(1604) & ChrW(1578) & ChrW(1593) & ChrW(1610) & ChrW(1610) & ChrW(1606)
        Case "ContractEnd": Cap = ChrW(1606) & ChrW(1607) & ChrW(1575) & ChrW(1610) & ChrW(1577) & " " & ChrW(1575) & ChrW(1604) & ChrW(1593) & ChrW(1602) & ChrW(1583)
        Case "EmploymentType": Cap = ChrW(1606) & ChrW(1608) & ChrW(1593) & " " & ChrW(1575) & ChrW(1604) & ChrW(1578) & ChrW(1593) & ChrW(1575) & ChrW(1602) & ChrW(1583)
        Case "IsActive": Cap = ChrW(1593) & ChrW(1604) & ChrW(1609) & " " & ChrW(1585) & ChrW(1571) & ChrW(1587) & " " & ChrW(1575) & ChrW(1604) & ChrW(1593) & ChrW(1605) & ChrW(1604)
        Case "BasicSalary": Cap = ChrW(1575) & ChrW(1604) & ChrW(1585) & ChrW(1575) & ChrW(1578) & ChrW(1576) & " " & ChrW(1575) & ChrW(1604) & ChrW(1571) & ChrW(1587) & ChrW(1575) & ChrW(1587) & ChrW(1610)
        Case "NonTaxableVariable": Cap = ChrW(1605) & ChrW(1578) & ChrW(1594) & ChrW(1610) & ChrW(1585) & " " & ChrW(1594) & ChrW(1610) & ChrW(1585) & " " & ChrW(1582) & ChrW(1575) & ChrW(1590) & ChrW(1593) & " " & ChrW(1604) & ChrW(1604) & ChrW(1590) & ChrW(1585) & ChrW(1610) & ChrW(1576) & ChrW(1577)
        Case "InsurableSalary": Cap = ChrW(1575) & ChrW(1604) & ChrW(1585) & ChrW(1575) & ChrW(1578) & ChrW(1576) & " " & ChrW(1575) & ChrW(1604) & ChrW(1578) & ChrW(1571) & ChrW(1605) & ChrW(1610) & ChrW(1606) & ChrW(1610)
        Case "FixedAllowance": Cap = ChrW(1575) & ChrW(1604) & ChrW(1576) & ChrW(1583) & ChrW(1604) & ChrW(1575) & ChrW(1578) & " " & ChrW(1575) & ChrW(1604) & ChrW(1579) & ChrW(1575) & ChrW(1576) & ChrW(1578) & ChrW(1577)
        Case "InsuranceNumber": Cap = ChrW(1575) & ChrW(1604) & ChrW(1585) & ChrW(1602) & ChrW(1605) & " " & ChrW(1575) & ChrW(1604) & ChrW(1578) & ChrW(1571) & ChrW(1605) & ChrW(1610) & ChrW(1606) & ChrW(1610)
        Case "InsuranceStartDate": Cap = ChrW(1576) & ChrW(1583) & ChrW(1575) & ChrW(1610) & ChrW(1577) & " " & ChrW(1575) & ChrW(1604) & ChrW(1578) & ChrW(1571) & ChrW(1605) & ChrW(1610) & ChrW(1606)
        Case "BankName": Cap = ChrW(1575) & ChrW(1604) & ChrW(1576) & ChrW(1606) & ChrW(1603)
        Case "BankAccount": Cap = ChrW(1575) & ChrW(1604) & ChrW(1581) & ChrW(1587) & ChrW(1575) & ChrW(1576) & " " & ChrW(1575) & ChrW(1604) & ChrW(1576) & ChrW(1606) & ChrW(1603) & ChrW(1610)
        Case "Attendance": Cap = ChrW(1575) & ChrW(1604) & ChrW(1581) & ChrW(1590) & ChrW(1608) & ChrW(1585) & " " & ChrW(1608) & ChrW(1575) & ChrW(1604) & ChrW(1575) & ChrW(1606) & ChrW(1589) & ChrW(1585) & ChrW(1575) & ChrW(1601)
        Case "AttID": Cap = ChrW(1585) & ChrW(1602) & ChrW(1605) & " " & ChrW(1575) & ChrW(1604) & ChrW(1581) & ChrW(1585) & ChrW(1603) & ChrW(1577)
        Case "WorkDate": Cap = ChrW(1575) & ChrW(1604) & ChrW(1578) & ChrW(1575) & ChrW(1585) & ChrW(1610) & ChrW(1582)
        Case "CheckIn": Cap = ChrW(1608) & ChrW(1602) & ChrW(1578) & " " & ChrW(1575) & ChrW(1604) & ChrW(1581) & ChrW(1590) & ChrW(1608) & ChrW(1585)
        Case "CheckOut": Cap = ChrW(1608) & ChrW(1602) & ChrW(1578) & " " & ChrW(1575) & ChrW(1604) & ChrW(1575) & ChrW(1606) & ChrW(1589) & ChrW(1585) & ChrW(1575) & ChrW(1601)
        Case "LateMinutes": Cap = ChrW(1583) & ChrW(1602) & ChrW(1575) & ChrW(1574) & ChrW(1602) & " " & ChrW(1575) & ChrW(1604) & ChrW(1578) & ChrW(1571) & ChrW(1582) & ChrW(1610) & ChrW(1585)
        Case "OvertimeHours": Cap = ChrW(1587) & ChrW(1575) & ChrW(1593) & ChrW(1575) & ChrW(1578) & " " & ChrW(1573) & ChrW(1590) & ChrW(1575) & ChrW(1601) & ChrW(1610) & ChrW(1577)
        Case "EmployeeLeaves": Cap = ChrW(1591) & ChrW(1604) & ChrW(1576) & ChrW(1575) & ChrW(1578) & " " & ChrW(1575) & ChrW(1604) & ChrW(1573) & ChrW(1580) & ChrW(1575) & ChrW(1586) & ChrW(1575) & ChrW(1578)
        Case "LeaveID": Cap = ChrW(1585) & ChrW(1602) & ChrW(1605) & " " & ChrW(1575) & ChrW(1604) & ChrW(1591) & ChrW(1604) & ChrW(1576)
        Case "StartDate": Cap = ChrW(1576) & ChrW(1583) & ChrW(1575) & ChrW(1610) & ChrW(1577) & " " & ChrW(1575) & ChrW(1604) & ChrW(1573) & ChrW(1580) & ChrW(1575) & ChrW(1586) & ChrW(1577)
        Case "EndDate": Cap = ChrW(1606) & ChrW(1607) & ChrW(1575) & ChrW(1610) & ChrW(1577) & " " & ChrW(1575) & ChrW(1604) & ChrW(1573) & ChrW(1580) & ChrW(1575) & ChrW(1586) & ChrW(1577)
        Case "LeaveDays": Cap = ChrW(1571) & ChrW(1610) & ChrW(1575) & ChrW(1605) & " " & ChrW(1575) & ChrW(1604) & ChrW(1573) & ChrW(1580) & ChrW(1575) & ChrW(1586) & ChrW(1577)
        Case "IsApproved": Cap = ChrW(1578) & ChrW(1605) & " " & ChrW(1575) & ChrW(1604) & ChrW(1575) & ChrW(1593) & ChrW(1578) & ChrW(1605) & ChrW(1575) & ChrW(1583)
        Case "Reason": Cap = ChrW(1575) & ChrW(1604) & ChrW(1587) & ChrW(1576) & ChrW(1576)
        Case "Deductions": Cap = ChrW(1575) & ChrW(1604) & ChrW(1582) & ChrW(1589) & ChrW(1608) & ChrW(1605) & ChrW(1575) & ChrW(1578) & " " & ChrW(1608) & ChrW(1575) & ChrW(1604) & ChrW(1580) & ChrW(1586) & ChrW(1575) & ChrW(1569) & ChrW(1575) & ChrW(1578)
        Case "DedID": Cap = ChrW(1585) & ChrW(1602) & ChrW(1605) & " " & ChrW(1575) & ChrW(1604) & ChrW(1582) & ChrW(1589) & ChrW(1605)
        Case "DedDate": Cap = ChrW(1578) & ChrW(1575) & ChrW(1585) & ChrW(1610) & ChrW(1582) & " " & ChrW(1575) & ChrW(1604) & ChrW(1582) & ChrW(1589) & ChrW(1605)
        Case "Amount": Cap = ChrW(1575) & ChrW(1604) & ChrW(1605) & ChrW(1576) & ChrW(1604) & ChrW(1594)
        Case "Advances": Cap = ChrW(1575) & ChrW(1604) & ChrW(1587) & ChrW(1604) & ChrW(1601)
        Case "AdvID": Cap = ChrW(1585) & ChrW(1602) & ChrW(1605) & " " & ChrW(1575) & ChrW(1604) & ChrW(1587) & ChrW(1604) & ChrW(1601) & ChrW(1577)
        Case "AdvDate": Cap = ChrW(1578) & ChrW(1575) & ChrW(1585) & ChrW(1610) & ChrW(1582) & " " & ChrW(1575) & ChrW(1604) & ChrW(1587) & ChrW(1604) & ChrW(1601) & ChrW(1577)
        Case "Installment": Cap = ChrW(1575) & ChrW(1604) & ChrW(1602) & ChrW(1587) & ChrW(1591) & " " & ChrW(1575) & ChrW(1604) & ChrW(1588) & ChrW(1607) & ChrW(1585) & ChrW(1610)
        Case "Payroll": Cap = ChrW(1605) & ChrW(1587) & ChrW(1610) & ChrW(1585) & " " & ChrW(1575) & ChrW(1604) & ChrW(1585) & ChrW(1608) & ChrW(1575) & ChrW(1578) & ChrW(1576)
        Case "PayID": Cap = ChrW(1585) & ChrW(1602) & ChrW(1605) & " " & ChrW(1575) & ChrW(1604) & ChrW(1605) & ChrW(1587) & ChrW(1610) & ChrW(1585)
        Case "PayMonth": Cap = ChrW(1588) & ChrW(1607) & ChrW(1585) & " " & ChrW(1575) & ChrW(1604) & ChrW(1589) & ChrW(1585) & ChrW(1601)
        Case "Allowances": Cap = ChrW(1575) & ChrW(1604) & ChrW(1576) & ChrW(1583) & ChrW(1604) & ChrW(1575) & ChrW(1578)
        Case "Overtime": Cap = ChrW(1602) & ChrW(1610) & ChrW(1605) & ChrW(1577) & " " & ChrW(1575) & ChrW(1604) & ChrW(1573) & ChrW(1590) & ChrW(1575) & ChrW(1601) & ChrW(1610)
        Case "LateDeduction": Cap = ChrW(1582) & ChrW(1589) & ChrW(1605) & " " & ChrW(1575) & ChrW(1604) & ChrW(1578) & ChrW(1571) & ChrW(1582) & ChrW(1610) & ChrW(1585)
        Case "InsuranceDeduction": Cap = ChrW(1582) & ChrW(1589) & ChrW(1605) & " " & ChrW(1575) & ChrW(1604) & ChrW(1578) & ChrW(1571) & ChrW(1605) & ChrW(1610) & ChrW(1606)
        Case "LeaveDeduction": Cap = ChrW(1582) & ChrW(1589) & ChrW(1605) & " " & ChrW(1573) & ChrW(1580) & ChrW(1575) & ChrW(1586) & ChrW(1577) & " " & ChrW(1594) & ChrW(1610) & ChrW(1585) & " " & ChrW(1605) & ChrW(1583) & ChrW(1601) & ChrW(1608) & ChrW(1593) & ChrW(1577)
        Case "TaxDeduction": Cap = ChrW(1590) & ChrW(1585) & ChrW(1610) & ChrW(1576) & ChrW(1577) & " " & ChrW(1605) & ChrW(1593) & ChrW(1578) & ChrW(1605) & ChrW(1583) & ChrW(1577) & " " & ChrW(1610) & ChrW(1583) & ChrW(1608) & ChrW(1610) & ChrW(1575) & ChrW(1611)
        Case "AdvanceDeduction": Cap = ChrW(1602) & ChrW(1587) & ChrW(1591) & " " & ChrW(1575) & ChrW(1604) & ChrW(1587) & ChrW(1604) & ChrW(1601) & ChrW(1577)
        Case "OtherDeductions": Cap = ChrW(1582) & ChrW(1589) & ChrW(1608) & ChrW(1605) & ChrW(1575) & ChrW(1578) & " " & ChrW(1571) & ChrW(1582) & ChrW(1585) & ChrW(1609)
        Case "TotalDeductions": Cap = ChrW(1573) & ChrW(1580) & ChrW(1605) & ChrW(1575) & ChrW(1604) & ChrW(1610) & " " & ChrW(1575) & ChrW(1604) & ChrW(1582) & ChrW(1589) & ChrW(1608) & ChrW(1605) & ChrW(1575) & ChrW(1578)
        Case "NetSalary": Cap = ChrW(1589) & ChrW(1575) & ChrW(1601) & ChrW(1610) & " " & ChrW(1575) & ChrW(1604) & ChrW(1585) & ChrW(1575) & ChrW(1578) & ChrW(1576)
        Case Else: Cap = n
    End Select
End Function

Private Function LookupSql(ByVal key As String) As String
    Select Case key
        Case "Branches.CompanyID": LookupSql = "SELECT [CompanyID], [CompanyName] FROM [Companies] ORDER BY [CompanyName]"
        Case "Departments.CompanyID": LookupSql = "SELECT [CompanyID], [CompanyName] FROM [Companies] ORDER BY [CompanyName]"
        Case "Departments.BranchID": LookupSql = "SELECT [BranchID], [BranchName] FROM [Branches] ORDER BY [BranchName]"
        Case "ShiftRules.CompanyID": LookupSql = "SELECT [CompanyID], [CompanyName] FROM [Companies] ORDER BY [CompanyName]"
        Case "LeavePolicies.CompanyID": LookupSql = "SELECT [CompanyID], [CompanyName] FROM [Companies] ORDER BY [CompanyName]"
        Case "Employees.CompanyID": LookupSql = "SELECT [CompanyID], [CompanyName] FROM [Companies] ORDER BY [CompanyName]"
        Case "Employees.BranchID": LookupSql = "SELECT [BranchID], [BranchName] FROM [Branches] ORDER BY [BranchName]"
        Case "Employees.DeptID": LookupSql = "SELECT [DeptID], [DeptName] FROM [Departments] ORDER BY [DeptName]"
        Case "Employees.ShiftID": LookupSql = "SELECT [ShiftID], [ShiftName] FROM [ShiftRules] ORDER BY [ShiftName]"
        Case "Employees.LeavePolicyID": LookupSql = "SELECT [LeavePolicyID], [LeaveName] FROM [LeavePolicies] ORDER BY [LeaveName]"
        Case "Attendance.EmpID": LookupSql = "SELECT [EmpID], [EmpCode] FROM [Employees] ORDER BY [EmpCode]"
        Case "EmployeeLeaves.EmpID": LookupSql = "SELECT [EmpID], [EmpCode] FROM [Employees] ORDER BY [EmpCode]"
        Case "EmployeeLeaves.LeavePolicyID": LookupSql = "SELECT [LeavePolicyID], [LeaveName] FROM [LeavePolicies] ORDER BY [LeaveName]"
        Case "Deductions.EmpID": LookupSql = "SELECT [EmpID], [EmpCode] FROM [Employees] ORDER BY [EmpCode]"
        Case "Advances.EmpID": LookupSql = "SELECT [EmpID], [EmpCode] FROM [Employees] ORDER BY [EmpCode]"
        Case "Payroll.EmpID": LookupSql = "SELECT [EmpID], [EmpCode] FROM [Employees] ORDER BY [EmpCode]"
        Case Else: LookupSql = ""
    End Select
End Function

' Arabic column captions on the tables themselves (datasheets, queries, exports)
Private Sub SetCaptions()
    Dim db As DAO.Database, tdf As DAO.TableDef, fld As DAO.Field, c As String
    Set db = CurrentDb
    On Error Resume Next
    For Each tdf In db.TableDefs
        If Left(tdf.Name, 4) <> "MSys" And Left(tdf.Name, 1) <> "~" Then
            For Each fld In tdf.Fields
                c = Cap(fld.Name)
                If c <> fld.Name Then
                    Err.Clear
                    fld.Properties("Caption") = c
                    If Err.Number <> 0 Then Err.Clear: fld.Properties.Append fld.CreateProperty("Caption", dbText, c)
                End If
            Next
        End If
    Next
End Sub

' ---------- helpers ----------
Private Sub L(ByRef m As String, ByVal s As String)
    m = m & s & vbCrLf
End Sub

Private Sub SafeDelete(ByVal n As String)
    On Error Resume Next
    DoCmd.Close acForm, n, acSaveNo
    DoCmd.DeleteObject acForm, n
End Sub

Private Sub SafeDeleteRpt(ByVal n As String)
    On Error Resume Next
    DoCmd.Close acReport, n, acSaveNo
    DoCmd.DeleteObject acReport, n
End Sub

Private Sub FinishForm(frm As Form, ByVal frmName As String)
    Dim tmp As String: tmp = frm.Name
    DoCmd.Close acForm, tmp, acSaveYes
    DoCmd.Rename frmName, acForm, tmp
End Sub

Private Sub Txt(c As Control, ByVal sz As Integer, ByVal clr As Long, ByVal bold As Boolean)
    On Error Resume Next
    c.FontName = "Segoe UI": c.FontSize = sz: c.ForeColor = clr: c.FontBold = bold
    c.ReadingOrder = 1   ' right-to-left
End Sub

Private Sub StyleBtn(b As Control, ByVal primary As Boolean)
    On Error Resume Next
    b.UseTheme = False
    b.FontName = "Segoe UI": b.FontSize = 11: b.FontBold = True
    b.BackColor = IIf(primary, PRIMARY, &HF1ECE8)
    b.ForeColor = IIf(primary, WHITE, &H3A3A3A)
    b.HoverColor = IIf(primary, ACCENT, &HE3DBD5)
    b.HoverForeColor = IIf(primary, WHITE, &H3A3A3A)
    b.PressedColor = ACCENT
    b.BorderStyle = 0
    b.Shape = 1          ' rounded corners (Access 2013+)
    b.CursorOnHover = 1  ' hand cursor
End Sub

Private Function Btn(frm As Object, ByVal sec As Integer, ByVal n As String, ByVal cap As String, _
                     ByVal x As Double, ByVal y As Double, ByVal w As Double, ByVal h As Double, ByVal primary As Boolean) As Control
    Dim b As Control
    Set b = CreateControl(frm.Name, acCommandButton, sec, , , x * TW, y * TW, w * TW, h * TW)
    b.Name = n: b.Caption = cap: b.OnClick = "[Event Procedure]"
    StyleBtn b, primary
    Set Btn = b
End Function

Private Sub Header(frm As Form, ByVal title As String, ByVal subTitle As String, ByVal w As Double)
    Dim c As Control
    DoCmd.RunCommand acCmdFormHdrFtr
    frm.Section(acHeader).Height = 2.4 * TW
    frm.Section(acHeader).BackColor = PRIMARY
    Set c = CreateControl(frm.Name, acRectangle, acHeader, , , 0, 2.25 * TW, w * TW, 0.15 * TW)
    c.BackStyle = 1: c.BackColor = ACCENT: c.BorderStyle = 0
    Set c = CreateControl(frm.Name, acLabel, acHeader, , , (w - 10) * TW, 0.3 * TW, 9.5 * TW, 1 * TW)
    c.Caption = title: c.TextAlign = 3: Txt c, 18, WHITE, True
    Set c = CreateControl(frm.Name, acLabel, acHeader, , , (w - 10) * TW, 1.35 * TW, 9.5 * TW, 0.6 * TW)
    c.Caption = subTitle: c.TextAlign = 3: Txt c, 10, &HE8D9C8, False
End Sub

' textbox / combo / checkbox bound to a field (combo for foreign keys)
Private Function FieldCtl(frm As Form, ByVal src As String, fld As DAO.Field, ByVal x As Double, ByVal y As Double, ByVal w As Double, Optional ByVal parent As String = "") As Control
    Dim ctl As Control, sql As String
    sql = LookupSql(src & "." & fld.Name)
    If fld.Type = dbBoolean Then
        Set ctl = CreateControl(frm.Name, acCheckBox, acDetail, parent, fld.Name, (x + w - 0.6) * TW, (y + 0.2) * TW)
    ElseIf sql <> "" Then
        Set ctl = CreateControl(frm.Name, acComboBox, acDetail, parent, fld.Name, x * TW, y * TW, w * TW, 0.8 * TW)
        ctl.RowSourceType = "Table/Query": ctl.RowSource = sql
        ctl.ColumnCount = 2: ctl.BoundColumn = 1: ctl.ColumnWidths = "0;" & CStr(CLng(w * TW))
        ctl.LimitToList = True: ctl.ListRows = 12
        ctl.BorderStyle = 1: ctl.BorderColor = &HD5CEC7: ctl.TextAlign = 3
        Txt ctl, 11, &H222222, False
    Else
        Set ctl = CreateControl(frm.Name, acTextBox, acDetail, parent, fld.Name, x * TW, y * TW, w * TW, 0.8 * TW)
        ctl.BorderStyle = 1: ctl.BorderColor = &HD5CEC7: ctl.TextAlign = 3
        Txt ctl, 11, &H222222, False
        If (fld.Attributes And dbAutoIncrField) Then ctl.Locked = True: ctl.TabStop = False: ctl.BackColor = &HF0ECE9
        If fld.Type = dbCurrency Then ctl.Format = "#,##0.00": ctl.TextAlign = 1
        If fld.Type = dbDate Then
            If fld.Name = "ApptDate" Or fld.Name = "ApptEnd" Then
                ctl.Format = "yyyy/mm/dd hh:nn"
            ElseIf fld.Name Like "Check*" Or fld.Name Like "Shift*" Then
                ctl.Format = "Short Time"
            Else
                ctl.Format = "Short Date": ctl.ShowDatePicker = 1
            End If
        End If
        If fld.Type = dbMemo Then ctl.Height = 1.6 * TW: ctl.ScrollBars = 2
    End If
    If fld.Type = dbDouble Then ctl.Format = "0.00"
    If fld.Name = "LateMinutes" Or fld.Name = "OvertimeHours" Or fld.Name = "LeaveDays" Then ctl.Locked = True
    If fld.Required Then ctl.BorderColor = ACCENT
    ctl.Name = "txt" & fld.Name
    Set FieldCtl = ctl
End Function

Private Sub BindEvents(frm As Form, ByVal screen As String)
    Select Case screen
        Case "frmCompanies"
            frm.BeforeUpdate = "[Event Procedure]"
        Case "frmDepartments"
            frm.BeforeUpdate = "[Event Procedure]"
        Case "frmShiftRules"
            frm.BeforeUpdate = "[Event Procedure]"
        Case "frmLeavePolicies"
            frm.BeforeUpdate = "[Event Procedure]"
        Case "frmEmployees"
            frm.BeforeUpdate = "[Event Procedure]"
        Case "frmAttendance"
            frm.BeforeUpdate = "[Event Procedure]"
            frm.Controls("txtCheckIn").AfterUpdate = "[Event Procedure]"
            frm.Controls("txtCheckOut").AfterUpdate = "[Event Procedure]"
            frm.Controls("txtEmpID").AfterUpdate = "[Event Procedure]"
        Case "frmEmployeeLeaves"
            frm.BeforeUpdate = "[Event Procedure]"
        Case "frmPayroll"
            frm.BeforeUpdate = "[Event Procedure]"
    End Select
End Sub

' ---------- datasheet subform ----------
Private Sub BuildSub(ByVal frmName As String, ByVal src As String)
    Dim frm As Form, ctl As Control, lbl As Control, fld As DAO.Field
    Dim db As DAO.Database, tdf As DAO.TableDef, y As Double, m As String
    Set db = CurrentDb: Set tdf = db.TableDefs(src)
    SafeDelete frmName
    Set frm = CreateForm()
    frm.RecordSource = src
    frm.DefaultView = 2   ' datasheet
    frm.Orientation = 1
    frm.DatasheetFontName = "Segoe UI": frm.DatasheetFontHeight = 11
    For Each fld In tdf.Fields
        Set ctl = FieldCtl(frm, src, fld, 4, y, 5)
        Set lbl = CreateControl(frm.Name, acLabel, acDetail, ctl.Name, , 0, y * TW, 3.8 * TW, 0.8 * TW)
        lbl.Caption = Cap(fld.Name)
        y = y + 1
    Next
    Select Case src

    End Select
    If Len(m) > 0 Then frm.Module.InsertText m
    FinishForm frm, frmName
End Sub

Private Function EmployeeGroup(ByVal n As String) As Integer
    Select Case n
        Case "EmpID", "EmpCode", "FullName", "NationalID", "BirthDate", "Gender", "MaritalStatus", "Address", "Phone", "Email", "EmergencyContact", "EmergencyPhone": EmployeeGroup = 0
        Case "CompanyID", "BranchID", "DeptID", "JobTitle", "HireDate", "ContractEnd", "EmploymentType", "ShiftID", "LeavePolicyID", "IsActive": EmployeeGroup = 1
        Case "BasicSalary", "NonTaxableVariable", "InsurableSalary", "FixedAllowance", "InsuranceNumber", "InsuranceStartDate", "BankName", "BankAccount", "Notes": EmployeeGroup = 2
        Case Else: EmployeeGroup = 0
    End Select
End Function

' ---------- data-entry screen ----------
Private Sub BuildForm(ByVal frmName As String, ByVal src As String, ByVal title As String, _
                      ByVal hasSearch As Boolean, ByVal subName As String, ByVal linkFld As String, ByVal extraBtn As String)
    Const W As Double = 21
    Dim frm As Form, ctl As Control, lbl As Control, fld As DAO.Field
    Dim db As DAO.Database, tdf As DAO.TableDef
    Dim i As Integer, rowsN As Integer, x As Double, y As Double, m As String
    Dim tabs As Control, pg As Page, groupN As Integer, counts(0 To 2) As Integer, parent As String
    Set db = CurrentDb: Set tdf = db.TableDefs(src)
    SafeDelete frmName

    Set frm = CreateForm()
    With frm
        .RecordSource = src: .Caption = title
        .Orientation = 1: .AutoCenter = True: .AutoResize = True
        .RecordSelectors = False: .DividingLines = False
        .ScrollBars = 2: .NavigationButtons = False
        .Width = W * TW
        .Section(acDetail).BackColor = SURFACE
    End With
    Header frm, title, ChrW(1573) & ChrW(1583) & ChrW(1575) & ChrW(1585) & ChrW(1577) & " " & Cap(src), W

    ' header: close + search
    Btn frm, acHeader, "btnClose", ChrW(1573) & ChrW(1594) & ChrW(1604) & ChrW(1575) & ChrW(1602) & "  " & ChrW(215), 0.4, 0.75, 2.2, 0.8, False
    If hasSearch Then
        Set ctl = CreateControl(frm.Name, acTextBox, acHeader, , , 2.9 * TW, 0.75 * TW, 5.2 * TW, 0.8 * TW)
        ctl.OnChange = "[Event Procedure]"
        ctl.Name = "txtSearch": ctl.BorderStyle = 0: ctl.BackColor = WHITE: ctl.TextAlign = 3
        Txt ctl, 11, &H333333, False
        Set lbl = CreateControl(frm.Name, acLabel, acHeader, "txtSearch", , 8.2 * TW, 0.8 * TW, 2 * TW, 0.7 * TW)
        lbl.Caption = ChrW(1576) & ChrW(1581) & ChrW(1579) & " " & ChrW(1587) & ChrW(1585) & ChrW(1610) & ChrW(1593): Txt lbl, 11, WHITE, True
    End If

    rowsN = (tdf.Fields.Count + 1) \ 2
    If src = "Employees" Then rowsN = 6
    If src = "Employees" Then
        Set tabs = CreateControl(frm.Name, acTabCtl, acDetail, , , 0.3 * TW, 0.3 * TW, (W - 0.6) * TW, (rowsN * 1.3 + 1.7) * TW)
        tabs.Name = "tabEmployee"
        Do While tabs.Pages.Count < 3
            tabs.Pages.Add
        Loop
        tabs.Pages(0).Caption = ChrW(1575) & ChrW(1604) & ChrW(1576) & ChrW(1610) & ChrW(1575) & ChrW(1606) & ChrW(1575) & ChrW(1578) & " " & ChrW(1575) & ChrW(1604) & ChrW(1588) & ChrW(1582) & ChrW(1589) & ChrW(1610) & ChrW(1577)
        tabs.Pages(1).Caption = ChrW(1575) & ChrW(1604) & ChrW(1578) & ChrW(1576) & ChrW(1593) & ChrW(1610) & ChrW(1577) & " " & ChrW(1608) & ChrW(1575) & ChrW(1604) & ChrW(1608) & ChrW(1592) & ChrW(1610) & ChrW(1601) & ChrW(1577)
        tabs.Pages(2).Caption = ChrW(1575) & ChrW(1604) & ChrW(1585) & ChrW(1575) & ChrW(1578) & ChrW(1576) & " " & ChrW(1608) & ChrW(1575) & ChrW(1604) & ChrW(1578) & ChrW(1571) & ChrW(1605) & ChrW(1610) & ChrW(1606) & " " & ChrW(1608) & ChrW(1575) & ChrW(1604) & ChrW(1589) & ChrW(1585) & ChrW(1601)
    Else
        Set lbl = CreateControl(frm.Name, acLabel, acDetail, , , (W - 8.5) * TW, 0.4 * TW, 7.8 * TW, 0.7 * TW)
        lbl.Caption = ChrW(1576) & ChrW(1610) & ChrW(1575) & ChrW(1606) & ChrW(1575) & ChrW(1578) & " " & Cap(src): lbl.TextAlign = 3: Txt lbl, 12, PRIMARY, True
    End If
    For Each fld In tdf.Fields
        parent = ""
        If src = "Employees" Then
            groupN = EmployeeGroup(fld.Name): i = counts(groupN)
            parent = tabs.Pages(groupN).Name
            counts(groupN) = counts(groupN) + 1
        End If
        x = IIf(i Mod 2 = 0, 11.2, 0.8)
        y = 1.4 + (i \ 2) * 1.3
        Set ctl = FieldCtl(frm, src, fld, x, y, 5.1, parent)
        Set lbl = CreateControl(frm.Name, acLabel, acDetail, ctl.Name, , (x + 5.2) * TW, y * TW, 3.9 * TW, 0.9 * TW)
        lbl.Caption = Cap(fld.Name) & IIf(fld.Required, " *", ""): lbl.TextAlign = 3
        Txt lbl, 10, MUTED, True
        i = i + 1
    Next
    y = rowsN * 1.3 + 2.4

    ' linked details (subform)
    If subName <> "" Then
        Set lbl = CreateControl(frm.Name, acLabel, acDetail, , , (W - 8.3) * TW, y * TW, 8 * TW, 0.7 * TW)
        lbl.Caption = Cap(Mid(subName, 5)) & " " & ChrW(1575) & ChrW(1604) & ChrW(1605) & ChrW(1585) & ChrW(1578) & ChrW(1576) & ChrW(1591) & ChrW(1577): lbl.TextAlign = 3: Txt lbl, 12, PRIMARY, True
        Set ctl = CreateControl(frm.Name, acSubform, acDetail, , , 0.3 * TW, (y + 0.8) * TW, (W - 0.6) * TW, 5 * TW)
        ctl.Name = "subDetails"
        ctl.SourceObject = "Form." & subName
        ctl.LinkChildFields = linkFld: ctl.LinkMasterFields = linkFld
        y = y + 6.2
    End If
    frm.Section(acDetail).Height = y * TW

    ' footer: actions + record navigation
    frm.Section(acFooter).Height = 1.6 * TW
    frm.Section(acFooter).BackColor = WHITE
    Btn frm, acFooter, "btnSave", ChrW(1581) & ChrW(1601) & ChrW(1592), 18.2, 0.35, 2.4, 0.9, True
    Btn frm, acFooter, "btnNew", ChrW(1580) & ChrW(1583) & ChrW(1610) & ChrW(1583) & " +", 15.6, 0.35, 2.4, 0.9, False
    Btn frm, acFooter, "btnDelete", ChrW(1581) & ChrW(1584) & ChrW(1601), 13, 0.35, 2.4, 0.9, False
    Btn frm, acFooter, "btnPrint", ChrW(1591) & ChrW(1576) & ChrW(1575) & ChrW(1593) & ChrW(1577), 10.4, 0.35, 2.4, 0.9, False
    If extraBtn <> "" Then
        Set ctl = Btn(frm, acFooter, "btnExtra", extraBtn, 7.3, 0.35, 2.9, 0.9, True)
        ctl.BackColor = ACCENT: ctl.HoverColor = PRIMARY
    End If
    Btn frm, acFooter, "btnLast", ">>", 0.4, 0.35, 1, 0.9, False
    Btn frm, acFooter, "btnNext", ">", 1.5, 0.35, 1, 0.9, False
    Set lbl = CreateControl(frm.Name, acLabel, acFooter, , , 2.6 * TW, 0.5 * TW, 2.2 * TW, 0.6 * TW)
    lbl.Name = "lblCount": lbl.Caption = "0 / 0": lbl.TextAlign = 2: Txt lbl, 10, MUTED, True
    Btn frm, acFooter, "btnPrev", "<", 4.9, 0.35, 1, 0.9, False
    Btn frm, acFooter, "btnFirst", "<<", 6, 0.35, 1, 0.9, False

    ' event code inside the form module
    L m, "Private Sub Form_Current()"
    L m, "  On Error Resume Next"
    L m, "  Me.lblCount.Caption = IIf(Me.NewRecord, ChrW(1587) & ChrW(1580) & ChrW(1604) & ChrW(32) & ChrW(1580) & ChrW(1583) & ChrW(1610) & ChrW(1583), Me.CurrentRecord & "" / "" & Me.RecordsetClone.RecordCount)"
    L m, "End Sub"
    L m, "Private Sub btnNew_Click()"
    L m, "  On Error Resume Next"
    L m, "  If Me.Dirty Then Me.Dirty = False"
    L m, "  DoCmd.GoToRecord , , acNewRec"
    L m, "End Sub"
    L m, "Private Sub btnSave_Click()"
    L m, "  On Error GoTo E"
    L m, "  If Me.Dirty Then Me.Dirty = False"
    L m, "  MsgBox ChrW(1578) & ChrW(1605) & ChrW(32) & ChrW(1575) & ChrW(1604) & ChrW(1581) & ChrW(1601) & ChrW(1592) & ChrW(32) & ChrW(1576) & ChrW(1606) & ChrW(1580) & ChrW(1575) & ChrW(1581), vbInformation"
    L m, "  Exit Sub"
    L m, "E: MsgBox Err.Description, vbExclamation"
    L m, "End Sub"
    L m, "Private Sub btnDelete_Click()"
    L m, "  If Me.NewRecord Then Me.Undo: Exit Sub"
    L m, "  If MsgBox(ChrW(1607) & ChrW(1604) & ChrW(32) & ChrW(1578) & ChrW(1585) & ChrW(1610) & ChrW(1583) & ChrW(32) & ChrW(1581) & ChrW(1584) & ChrW(1601) & ChrW(32) & ChrW(1607) & ChrW(1584) & ChrW(1575) & ChrW(32) & ChrW(1575) & ChrW(1604) & ChrW(1587) & ChrW(1580) & ChrW(1604) & ChrW(1567), vbYesNo + vbQuestion) = vbYes Then DoCmd.SetWarnings False: DoCmd.RunCommand acCmdDeleteRecord: DoCmd.SetWarnings True"
    L m, "End Sub"
    L m, "Private Sub btnClose_Click()"
    L m, "  DoCmd.Close acForm, Me.Name"
    L m, "End Sub"
    L m, "Private Sub btnFirst_Click(): On Error Resume Next: DoCmd.GoToRecord , , acFirst: End Sub"
    L m, "Private Sub btnPrev_Click(): On Error Resume Next: DoCmd.GoToRecord , , acPrevious: End Sub"
    L m, "Private Sub btnNext_Click(): On Error Resume Next: DoCmd.GoToRecord , , acNext: End Sub"
    L m, "Private Sub btnLast_Click(): On Error Resume Next: DoCmd.GoToRecord , , acLast: End Sub"
    frm.OnCurrent = "[Event Procedure]"
    BindEvents frm, frmName
    FormCode frmName, m
    frm.Module.InsertText m
    FinishForm frm, frmName
End Sub

' search + business logic for each screen
Private Sub FormCode(ByVal frmName As String, ByRef m As String)
    Select Case frmName
        Case "frmCompanies"
    L m, "Private Sub txtSearch_Change()"
    L m, "  Dim s As String: s = Replace(Me.txtSearch.Text, ""'"", ""''"")"
    L m, "  If Len(s) = 0 Then"
    L m, "    Me.FilterOn = False"
    L m, "  Else"
    L m, "    Me.Filter = ""[CompanyName] Like '*"" & s & ""*'"": Me.FilterOn = True"
    L m, "  End If"
    L m, "  Me.txtSearch.SetFocus: Me.txtSearch.SelStart = Len(Me.txtSearch.Text)"
    L m, "End Sub"
    L m, "Private Sub btnPrint_Click()"
    L m, "  If Me.Dirty Then Me.Dirty = False"
    L m, "  DoCmd.SelectObject acForm, Me.Name: DoCmd.PrintOut acSelection"
    L m, "End Sub"
    L m, "Private Sub Form_BeforeUpdate(Cancel As Integer)"
    L m, "  If Nz(Me!SalaryDays, 0) <= 0 Or Nz(Me!EmployeeInsuranceRate, -1) < 0 Or Nz(Me!EmployeeInsuranceRate, 101) > 100 Then MsgBox """ & ChrW(1571) & ChrW(1583) & ChrW(1582) & ChrW(1604) & " " & ChrW(1571) & ChrW(1610) & ChrW(1575) & ChrW(1605) & " " & ChrW(1581) & ChrW(1587) & ChrW(1575) & ChrW(1576) & " " & ChrW(1605) & ChrW(1608) & ChrW(1580) & ChrW(1576) & ChrW(1577) & " " & ChrW(1608) & ChrW(1606) & ChrW(1587) & ChrW(1576) & ChrW(1577) & " " & ChrW(1578) & ChrW(1571) & ChrW(1605) & ChrW(1610) & ChrW(1606) & " " & ChrW(1576) & ChrW(1610) & ChrW(1606) & " " & ChrW(1589) & ChrW(1601) & ChrW(1585) & " " & ChrW(1608) & "100"", vbExclamation: Cancel = True"
    L m, "End Sub"
        Case "frmBranches"
    L m, "Private Sub txtSearch_Change()"
    L m, "  Dim s As String: s = Replace(Me.txtSearch.Text, ""'"", ""''"")"
    L m, "  If Len(s) = 0 Then"
    L m, "    Me.FilterOn = False"
    L m, "  Else"
    L m, "    Me.Filter = ""[BranchName] Like '*"" & s & ""*'"": Me.FilterOn = True"
    L m, "  End If"
    L m, "  Me.txtSearch.SetFocus: Me.txtSearch.SelStart = Len(Me.txtSearch.Text)"
    L m, "End Sub"
    L m, "Private Sub btnPrint_Click()"
    L m, "  If Me.Dirty Then Me.Dirty = False"
    L m, "  DoCmd.SelectObject acForm, Me.Name: DoCmd.PrintOut acSelection"
    L m, "End Sub"
        Case "frmDepartments"
    L m, "Private Sub txtSearch_Change()"
    L m, "  Dim s As String: s = Replace(Me.txtSearch.Text, ""'"", ""''"")"
    L m, "  If Len(s) = 0 Then"
    L m, "    Me.FilterOn = False"
    L m, "  Else"
    L m, "    Me.Filter = ""[DeptName] Like '*"" & s & ""*'"": Me.FilterOn = True"
    L m, "  End If"
    L m, "  Me.txtSearch.SetFocus: Me.txtSearch.SelStart = Len(Me.txtSearch.Text)"
    L m, "End Sub"
    L m, "Private Sub btnPrint_Click()"
    L m, "  If Me.Dirty Then Me.Dirty = False"
    L m, "  DoCmd.SelectObject acForm, Me.Name: DoCmd.PrintOut acSelection"
    L m, "End Sub"
    L m, "Private Sub Form_BeforeUpdate(Cancel As Integer)"
    L m, "  If Not IsNull(Me!BranchID) Then If Nz(DLookup(""CompanyID"", ""Branches"", ""BranchID="" & Me!BranchID), 0) <> Me!CompanyID Then MsgBox """ & ChrW(1575) & ChrW(1604) & ChrW(1575) & ChrW(1582) & ChrW(1578) & ChrW(1610) & ChrW(1575) & ChrW(1585) & " " & ChrW(1604) & ChrW(1575) & " " & ChrW(1610) & ChrW(1578) & ChrW(1576) & ChrW(1593) & " " & ChrW(1575) & ChrW(1604) & ChrW(1588) & ChrW(1585) & ChrW(1603) & ChrW(1577) & " " & ChrW(1575) & ChrW(1604) & ChrW(1605) & ChrW(1581) & ChrW(1583) & ChrW(1583) & ChrW(1577) & """, vbExclamation: Cancel = True: Exit Sub"
    L m, "End Sub"
        Case "frmShiftRules"
    L m, "Private Sub txtSearch_Change()"
    L m, "  Dim s As String: s = Replace(Me.txtSearch.Text, ""'"", ""''"")"
    L m, "  If Len(s) = 0 Then"
    L m, "    Me.FilterOn = False"
    L m, "  Else"
    L m, "    Me.Filter = ""[ShiftName] Like '*"" & s & ""*'"": Me.FilterOn = True"
    L m, "  End If"
    L m, "  Me.txtSearch.SetFocus: Me.txtSearch.SelStart = Len(Me.txtSearch.Text)"
    L m, "End Sub"
    L m, "Private Sub btnPrint_Click()"
    L m, "  If Me.Dirty Then Me.Dirty = False"
    L m, "  DoCmd.SelectObject acForm, Me.Name: DoCmd.PrintOut acSelection"
    L m, "End Sub"
    L m, "Private Sub Form_BeforeUpdate(Cancel As Integer)"
    L m, "  If IsNull(Me!ShiftStart) Or Nz(Me!DailyHours, 0) <= 0 Or Nz(Me!GraceMinutes, -1) < 0 Or Nz(Me!OvertimeFactor, -1) < 0 Or Nz(Me!LateFactor, -1) < 0 Then MsgBox """ & ChrW(1571) & ChrW(1603) & ChrW(1605) & ChrW(1604) & " " & ChrW(1608) & ChrW(1602) & ChrW(1578) & " " & ChrW(1575) & ChrW(1604) & ChrW(1608) & ChrW(1585) & ChrW(1583) & ChrW(1610) & ChrW(1577) & " " & ChrW(1608) & ChrW(1587) & ChrW(1575) & ChrW(1593) & ChrW(1575) & ChrW(1578) & ChrW(1607) & ChrW(1575) & " " & ChrW(1608) & ChrW(1602) & ChrW(1608) & ChrW(1575) & ChrW(1593) & ChrW(1583) & " " & ChrW(1575) & ChrW(1604) & ChrW(1578) & ChrW(1571) & ChrW(1582) & ChrW(1610) & ChrW(1585) & " " & ChrW(1608) & ChrW(1575) & ChrW(1604) & ChrW(1573) & ChrW(1590) & ChrW(1575) & ChrW(1601) & ChrW(1610) & " " & ChrW(1576) & ChrW(1602) & ChrW(1610) & ChrW(1605) & " " & ChrW(1594) & ChrW(1610) & ChrW(1585) & " " & ChrW(1587) & ChrW(1575) & ChrW(1604) & ChrW(1576) & ChrW(1577) & """, vbExclamation: Cancel = True"
    L m, "End Sub"
        Case "frmLeavePolicies"
    L m, "Private Sub txtSearch_Change()"
    L m, "  Dim s As String: s = Replace(Me.txtSearch.Text, ""'"", ""''"")"
    L m, "  If Len(s) = 0 Then"
    L m, "    Me.FilterOn = False"
    L m, "  Else"
    L m, "    Me.Filter = ""[LeaveName] Like '*"" & s & ""*'"": Me.FilterOn = True"
    L m, "  End If"
    L m, "  Me.txtSearch.SetFocus: Me.txtSearch.SelStart = Len(Me.txtSearch.Text)"
    L m, "End Sub"
    L m, "Private Sub btnPrint_Click()"
    L m, "  If Me.Dirty Then Me.Dirty = False"
    L m, "  DoCmd.SelectObject acForm, Me.Name: DoCmd.PrintOut acSelection"
    L m, "End Sub"
    L m, "Private Sub Form_BeforeUpdate(Cancel As Integer)"
    L m, "  If Nz(Me!AnnualDays, -1) < 0 Then MsgBox """ & ChrW(1585) & ChrW(1589) & ChrW(1610) & ChrW(1583) & " " & ChrW(1575) & ChrW(1604) & ChrW(1573) & ChrW(1580) & ChrW(1575) & ChrW(1586) & ChrW(1577) & " " & ChrW(1610) & ChrW(1580) & ChrW(1576) & " " & ChrW(1571) & ChrW(1606) & " " & ChrW(1610) & ChrW(1603) & ChrW(1608) & ChrW(1606) & " " & ChrW(1589) & ChrW(1601) & ChrW(1585) & ChrW(1575) & ChrW(1611) & " " & ChrW(1571) & ChrW(1608) & " " & ChrW(1571) & ChrW(1603) & ChrW(1579) & ChrW(1585) & """, vbExclamation: Cancel = True"
    L m, "End Sub"
        Case "frmEmployees"
    L m, "Private Sub txtSearch_Change()"
    L m, "  Dim s As String: s = Replace(Me.txtSearch.Text, ""'"", ""''"")"
    L m, "  If Len(s) = 0 Then"
    L m, "    Me.FilterOn = False"
    L m, "  Else"
    L m, "    Me.Filter = ""[EmpCode] Like '*"" & s & ""*'"": Me.FilterOn = True"
    L m, "  End If"
    L m, "  Me.txtSearch.SetFocus: Me.txtSearch.SelStart = Len(Me.txtSearch.Text)"
    L m, "End Sub"
    L m, "Private Sub btnPrint_Click()"
    L m, "  If Me.Dirty Then Me.Dirty = False"
    L m, "  DoCmd.SelectObject acForm, Me.Name: DoCmd.PrintOut acSelection"
    L m, "End Sub"
    L m, "Private Sub Form_BeforeUpdate(Cancel As Integer)"
    L m, "  If IsNull(Me!CompanyID) Or IsNull(Me!BranchID) Or IsNull(Me!DeptID) Or IsNull(Me!ShiftID) Or IsNull(Me!LeavePolicyID) Then MsgBox """ & ChrW(1581) & ChrW(1583) & ChrW(1583) & " " & ChrW(1588) & ChrW(1585) & ChrW(1603) & ChrW(1577) & " " & ChrW(1575) & ChrW(1604) & ChrW(1605) & ChrW(1608) & ChrW(1592) & ChrW(1601) & " " & ChrW(1608) & ChrW(1601) & ChrW(1585) & ChrW(1593) & ChrW(1607) & " " & ChrW(1608) & ChrW(1573) & ChrW(1583) & ChrW(1575) & ChrW(1585) & ChrW(1578) & ChrW(1607) & " " & ChrW(1608) & ChrW(1608) & ChrW(1585) & ChrW(1583) & ChrW(1610) & ChrW(1578) & ChrW(1607) & " " & ChrW(1608) & ChrW(1587) & ChrW(1610) & ChrW(1575) & ChrW(1587) & ChrW(1577) & " " & ChrW(1573) & ChrW(1580) & ChrW(1575) & ChrW(1586) & ChrW(1575) & ChrW(1578) & ChrW(1607) & """, vbExclamation: Cancel = True: Exit Sub"
    L m, "  If Not IsNull(Me!BranchID) Then If Nz(DLookup(""CompanyID"", ""Branches"", ""BranchID="" & Me!BranchID), 0) <> Me!CompanyID Then MsgBox """ & ChrW(1575) & ChrW(1604) & ChrW(1575) & ChrW(1582) & ChrW(1578) & ChrW(1610) & ChrW(1575) & ChrW(1585) & " " & ChrW(1604) & ChrW(1575) & " " & ChrW(1610) & ChrW(1578) & ChrW(1576) & ChrW(1593) & " " & ChrW(1575) & ChrW(1604) & ChrW(1588) & ChrW(1585) & ChrW(1603) & ChrW(1577) & " " & ChrW(1575) & ChrW(1604) & ChrW(1605) & ChrW(1581) & ChrW(1583) & ChrW(1583) & ChrW(1577) & """, vbExclamation: Cancel = True: Exit Sub"
    L m, "  If Not IsNull(Me!DeptID) Then If Nz(DLookup(""CompanyID"", ""Departments"", ""DeptID="" & Me!DeptID), 0) <> Me!CompanyID Then MsgBox """ & ChrW(1575) & ChrW(1604) & ChrW(1575) & ChrW(1582) & ChrW(1578) & ChrW(1610) & ChrW(1575) & ChrW(1585) & " " & ChrW(1604) & ChrW(1575) & " " & ChrW(1610) & ChrW(1578) & ChrW(1576) & ChrW(1593) & " " & ChrW(1575) & ChrW(1604) & ChrW(1588) & ChrW(1585) & ChrW(1603) & ChrW(1577) & " " & ChrW(1575) & ChrW(1604) & ChrW(1605) & ChrW(1581) & ChrW(1583) & ChrW(1583) & ChrW(1577) & """, vbExclamation: Cancel = True: Exit Sub"
    L m, "  If Not IsNull(Me!ShiftID) Then If Nz(DLookup(""CompanyID"", ""ShiftRules"", ""ShiftID="" & Me!ShiftID), 0) <> Me!CompanyID Then MsgBox """ & ChrW(1575) & ChrW(1604) & ChrW(1575) & ChrW(1582) & ChrW(1578) & ChrW(1610) & ChrW(1575) & ChrW(1585) & " " & ChrW(1604) & ChrW(1575) & " " & ChrW(1610) & ChrW(1578) & ChrW(1576) & ChrW(1593) & " " & ChrW(1575) & ChrW(1604) & ChrW(1588) & ChrW(1585) & ChrW(1603) & ChrW(1577) & " " & ChrW(1575) & ChrW(1604) & ChrW(1605) & ChrW(1581) & ChrW(1583) & ChrW(1583) & ChrW(1577) & """, vbExclamation: Cancel = True: Exit Sub"
    L m, "  If Not IsNull(Me!LeavePolicyID) Then If Nz(DLookup(""CompanyID"", ""LeavePolicies"", ""LeavePolicyID="" & Me!LeavePolicyID), 0) <> Me!CompanyID Then MsgBox """ & ChrW(1575) & ChrW(1604) & ChrW(1575) & ChrW(1582) & ChrW(1578) & ChrW(1610) & ChrW(1575) & ChrW(1585) & " " & ChrW(1604) & ChrW(1575) & " " & ChrW(1610) & ChrW(1578) & ChrW(1576) & ChrW(1593) & " " & ChrW(1575) & ChrW(1604) & ChrW(1588) & ChrW(1585) & ChrW(1603) & ChrW(1577) & " " & ChrW(1575) & ChrW(1604) & ChrW(1605) & ChrW(1581) & ChrW(1583) & ChrW(1583) & ChrW(1577) & """, vbExclamation: Cancel = True: Exit Sub"
    L m, "  If Nz(DLookup(""BranchID"", ""Departments"", ""DeptID="" & Me!DeptID), 0) <> Me!BranchID Then MsgBox """ & ChrW(1575) & ChrW(1604) & ChrW(1573) & ChrW(1583) & ChrW(1575) & ChrW(1585) & ChrW(1577) & " " & ChrW(1575) & ChrW(1604) & ChrW(1605) & ChrW(1582) & ChrW(1578) & ChrW(1575) & ChrW(1585) & ChrW(1577) & " " & ChrW(1604) & ChrW(1575) & " " & ChrW(1578) & ChrW(1578) & ChrW(1576) & ChrW(1593) & " " & ChrW(1575) & ChrW(1604) & ChrW(1601) & ChrW(1585) & ChrW(1593) & """, vbExclamation: Cancel = True: Exit Sub"
    L m, "  If Nz(Me!BasicSalary, -1) < 0 Or Nz(Me!NonTaxableVariable, 0) < 0 Or Nz(Me!InsurableSalary, -1) < 0 Or Nz(Me!FixedAllowance, 0) < 0 Then MsgBox """ & ChrW(1605) & ChrW(1603) & ChrW(1608) & ChrW(1606) & ChrW(1575) & ChrW(1578) & " " & ChrW(1575) & ChrW(1604) & ChrW(1585) & ChrW(1575) & ChrW(1578) & ChrW(1576) & " " & ChrW(1604) & ChrW(1575) & " " & ChrW(1578) & ChrW(1602) & ChrW(1576) & ChrW(1604) & " " & ChrW(1602) & ChrW(1610) & ChrW(1605) & ChrW(1575) & ChrW(1611) & " " & ChrW(1587) & ChrW(1575) & ChrW(1604) & ChrW(1576) & ChrW(1577) & """, vbExclamation: Cancel = True"
    L m, "End Sub"
        Case "frmAttendance"
    L m, "Private Sub txtSearch_Change()"
    L m, "  Dim s As String: s = Replace(Me.txtSearch.Text, ""'"", ""''"")"
    L m, "  If Len(s) = 0 Then"
    L m, "    Me.FilterOn = False"
    L m, "  Else"
    L m, "    Me.Filter = ""[EmpID] IN (SELECT [EmpID] FROM [Employees] WHERE [EmpCode] Like '*"" & s & ""*')"": Me.FilterOn = True"
    L m, "  End If"
    L m, "  Me.txtSearch.SetFocus: Me.txtSearch.SelStart = Len(Me.txtSearch.Text)"
    L m, "End Sub"
    L m, "Private Sub btnPrint_Click()"
    L m, "  If Me.Dirty Then Me.Dirty = False"
    L m, "  DoCmd.SelectObject acForm, Me.Name: DoCmd.PrintOut acSelection"
    L m, "End Sub"
    L m, "Private Sub RecalculateAttendance()"
    L m, "  On Error GoTo E"
    L m, "  Dim shift As Long, st As Variant, mins As Long, elapsed As Long, grace As Long, hours As Double"
    L m, "  shift = Nz(DLookup(""ShiftID"", ""Employees"", ""EmpID="" & Nz(Me!EmpID, 0)), 0)"
    L m, "  st = DLookup(""ShiftStart"", ""ShiftRules"", ""ShiftID="" & shift)"
    L m, "  hours = Nz(DLookup(""DailyHours"", ""ShiftRules"", ""ShiftID="" & shift), 0)"
    L m, "  If IsNull(st) Or hours <= 0 Then MsgBox """ & ChrW(1571) & ChrW(1603) & ChrW(1605) & ChrW(1604) & " " & ChrW(1573) & ChrW(1593) & ChrW(1583) & ChrW(1575) & ChrW(1583) & ChrW(1575) & ChrW(1578) & " " & ChrW(1608) & ChrW(1585) & ChrW(1583) & ChrW(1610) & ChrW(1577) & " " & ChrW(1575) & ChrW(1604) & ChrW(1605) & ChrW(1608) & ChrW(1592) & ChrW(1601) & " " & ChrW(1571) & ChrW(1608) & ChrW(1604) & ChrW(1575) & ChrW(1611) & """, vbExclamation: Exit Sub"
    L m, "  grace = Nz(DLookup(""GraceMinutes"", ""ShiftRules"", ""ShiftID="" & shift), 0)"
    L m, "  Me!LateMinutes = 0: Me!OvertimeHours = 0"
    L m, "  If Not IsNull(Me!CheckIn) Then"
    L m, "    mins = DateDiff(""n"", TimeValue(st), TimeValue(Me!CheckIn))"
    L m, "    If mins > 720 Then mins = mins - 1440"
    L m, "    If mins < -720 Then mins = mins + 1440"
    L m, "    If mins > grace Then Me!LateMinutes = mins - grace"
    L m, "  End If"
    L m, "  If Not IsNull(Me!CheckIn) And Not IsNull(Me!CheckOut) Then"
    L m, "    elapsed = DateDiff(""n"", Me!CheckIn, Me!CheckOut)"
    L m, "    If elapsed < 0 Then elapsed = elapsed + 1440"
    L m, "    If elapsed / 60 > hours Then Me!OvertimeHours = Round(elapsed / 60 - hours, 2)"
    L m, "  End If"
    L m, "  Exit Sub"
    L m, "E: MsgBox Err.Description, vbExclamation"
    L m, "End Sub"
    L m, "Private Sub txtCheckIn_AfterUpdate(): RecalculateAttendance: End Sub"
    L m, "Private Sub txtCheckOut_AfterUpdate(): RecalculateAttendance: End Sub"
    L m, "Private Sub txtEmpID_AfterUpdate(): RecalculateAttendance: End Sub"
    L m, "Private Sub Form_BeforeUpdate(Cancel As Integer): RecalculateAttendance: End Sub"
        Case "frmEmployeeLeaves"
    L m, "Private Sub txtSearch_Change()"
    L m, "  Dim s As String: s = Replace(Me.txtSearch.Text, ""'"", ""''"")"
    L m, "  If Len(s) = 0 Then"
    L m, "    Me.FilterOn = False"
    L m, "  Else"
    L m, "    Me.Filter = ""[Reason] Like '*"" & s & ""*'"": Me.FilterOn = True"
    L m, "  End If"
    L m, "  Me.txtSearch.SetFocus: Me.txtSearch.SelStart = Len(Me.txtSearch.Text)"
    L m, "End Sub"
    L m, "Private Sub btnPrint_Click()"
    L m, "  If Me.Dirty Then Me.Dirty = False"
    L m, "  DoCmd.SelectObject acForm, Me.Name: DoCmd.PrintOut acSelection"
    L m, "End Sub"
    L m, "Private Sub Form_BeforeUpdate(Cancel As Integer)"
    L m, "  Dim policy As Long, allowance As Long, used As Long, w As String"
    L m, "  If IsNull(Me!EmpID) Or IsNull(Me!LeavePolicyID) Or IsNull(Me!StartDate) Or IsNull(Me!EndDate) Then MsgBox """ & ChrW(1571) & ChrW(1603) & ChrW(1605) & ChrW(1604) & " " & ChrW(1575) & ChrW(1604) & ChrW(1605) & ChrW(1608) & ChrW(1592) & ChrW(1601) & " " & ChrW(1608) & ChrW(1606) & ChrW(1608) & ChrW(1593) & " " & ChrW(1575) & ChrW(1604) & ChrW(1573) & ChrW(1580) & ChrW(1575) & ChrW(1586) & ChrW(1577) & " " & ChrW(1608) & ChrW(1578) & ChrW(1608) & ChrW(1575) & ChrW(1585) & ChrW(1610) & ChrW(1582) & ChrW(1607) & ChrW(1575) & """, vbExclamation: Cancel = True: Exit Sub"
    L m, "  If Me!EndDate < Me!StartDate Or Year(Me!StartDate) <> Year(Me!EndDate) Then MsgBox """ & ChrW(1571) & ChrW(1583) & ChrW(1582) & ChrW(1604) & " " & ChrW(1601) & ChrW(1578) & ChrW(1585) & ChrW(1577) & " " & ChrW(1589) & ChrW(1581) & ChrW(1610) & ChrW(1581) & ChrW(1577) & " " & ChrW(1583) & ChrW(1575) & ChrW(1582) & ChrW(1604) & " " & ChrW(1587) & ChrW(1606) & ChrW(1577) & " " & ChrW(1608) & ChrW(1575) & ChrW(1581) & ChrW(1583) & ChrW(1577) & ChrW(1563) & " " & ChrW(1602) & ChrW(1587) & ChrW(1617) & ChrW(1605) & " " & ChrW(1575) & ChrW(1604) & ChrW(1573) & ChrW(1580) & ChrW(1575) & ChrW(1586) & ChrW(1577) & " " & ChrW(1575) & ChrW(1604) & ChrW(1593) & ChrW(1575) & ChrW(1576) & ChrW(1585) & ChrW(1577) & " " & ChrW(1604) & ChrW(1604) & ChrW(1587) & ChrW(1606) & ChrW(1577) & """, vbExclamation: Cancel = True: Exit Sub"
    L m, "  If Nz(DLookup(""CompanyID"", ""LeavePolicies"", ""LeavePolicyID="" & Me!LeavePolicyID), 0) <> Nz(DLookup(""CompanyID"", ""Employees"", ""EmpID="" & Me!EmpID), 0) Then"
    L m, "    MsgBox """ & ChrW(1587) & ChrW(1610) & ChrW(1575) & ChrW(1587) & ChrW(1577) & " " & ChrW(1575) & ChrW(1604) & ChrW(1573) & ChrW(1580) & ChrW(1575) & ChrW(1586) & ChrW(1577) & " " & ChrW(1604) & ChrW(1575) & " " & ChrW(1578) & ChrW(1578) & ChrW(1576) & ChrW(1593) & " " & ChrW(1588) & ChrW(1585) & ChrW(1603) & ChrW(1577) & " " & ChrW(1575) & ChrW(1604) & ChrW(1605) & ChrW(1608) & ChrW(1592) & ChrW(1601) & """, vbExclamation: Cancel = True: Exit Sub"
    L m, "  End If"
    L m, "  Me!LeaveDays = DateDiff(""d"", Me!StartDate, Me!EndDate) + 1"
    L m, "  If Nz(Me!IsApproved, False) Then"
    L m, "    w = ""EmpID="" & Me!EmpID & "" AND IsApproved=True AND LeaveID<>"" & Nz(Me!LeaveID, 0)"
    L m, "    If DCount(""*"", ""EmployeeLeaves"", w & "" AND StartDate<=#"" & Format(Me!EndDate, ""mm/dd/yyyy"") & ""# AND EndDate>=#"" & Format(Me!StartDate, ""mm/dd/yyyy"") & ""#"") > 0 Then"
    L m, "      MsgBox """ & ChrW(1578) & ChrW(1608) & ChrW(1580) & ChrW(1583) & " " & ChrW(1573) & ChrW(1580) & ChrW(1575) & ChrW(1586) & ChrW(1577) & " " & ChrW(1605) & ChrW(1593) & ChrW(1578) & ChrW(1605) & ChrW(1583) & ChrW(1577) & " " & ChrW(1605) & ChrW(1578) & ChrW(1583) & ChrW(1575) & ChrW(1582) & ChrW(1604) & ChrW(1577) & " " & ChrW(1605) & ChrW(1593) & " " & ChrW(1607) & ChrW(1584) & ChrW(1607) & " " & ChrW(1575) & ChrW(1604) & ChrW(1601) & ChrW(1578) & ChrW(1585) & ChrW(1577) & """, vbExclamation: Cancel = True: Exit Sub"
    L m, "    End If"
    L m, "    allowance = Nz(DLookup(""AnnualDays"", ""LeavePolicies"", ""LeavePolicyID="" & Me!LeavePolicyID), 0)"
    L m, "    used = Nz(DSum(""LeaveDays"", ""EmployeeLeaves"", w & "" AND LeavePolicyID="" & Me!LeavePolicyID & "" AND Year(StartDate)="" & Year(Me!StartDate)), 0)"
    L m, "    If used + Me!LeaveDays > allowance Then MsgBox """ & ChrW(1575) & ChrW(1604) & ChrW(1591) & ChrW(1604) & ChrW(1576) & " " & ChrW(1610) & ChrW(1578) & ChrW(1580) & ChrW(1575) & ChrW(1608) & ChrW(1586) & " " & ChrW(1575) & ChrW(1604) & ChrW(1585) & ChrW(1589) & ChrW(1610) & ChrW(1583) & " " & ChrW(1575) & ChrW(1604) & ChrW(1587) & ChrW(1606) & ChrW(1608) & ChrW(1610) & " " & ChrW(1604) & ChrW(1607) & ChrW(1584) & ChrW(1575) & " " & ChrW(1575) & ChrW(1604) & ChrW(1606) & ChrW(1608) & ChrW(1593) & " " & ChrW(1605) & ChrW(1606) & " " & ChrW(1575) & ChrW(1604) & ChrW(1573) & ChrW(1580) & ChrW(1575) & ChrW(1586) & ChrW(1577) & """, vbExclamation: Cancel = True"
    L m, "  End If"
    L m, "End Sub"
        Case "frmDeductions"
    L m, "Private Sub txtSearch_Change()"
    L m, "  Dim s As String: s = Replace(Me.txtSearch.Text, ""'"", ""''"")"
    L m, "  If Len(s) = 0 Then"
    L m, "    Me.FilterOn = False"
    L m, "  Else"
    L m, "    Me.Filter = ""[Reason] Like '*"" & s & ""*'"": Me.FilterOn = True"
    L m, "  End If"
    L m, "  Me.txtSearch.SetFocus: Me.txtSearch.SelStart = Len(Me.txtSearch.Text)"
    L m, "End Sub"
    L m, "Private Sub btnPrint_Click()"
    L m, "  If Me.Dirty Then Me.Dirty = False"
    L m, "  DoCmd.SelectObject acForm, Me.Name: DoCmd.PrintOut acSelection"
    L m, "End Sub"
        Case "frmAdvances"
    L m, "Private Sub txtSearch_Change()"
    L m, "  Dim s As String: s = Replace(Me.txtSearch.Text, ""'"", ""''"")"
    L m, "  If Len(s) = 0 Then"
    L m, "    Me.FilterOn = False"
    L m, "  Else"
    L m, "    Me.Filter = ""[Notes] Like '*"" & s & ""*'"": Me.FilterOn = True"
    L m, "  End If"
    L m, "  Me.txtSearch.SetFocus: Me.txtSearch.SelStart = Len(Me.txtSearch.Text)"
    L m, "End Sub"
    L m, "Private Sub btnPrint_Click()"
    L m, "  If Me.Dirty Then Me.Dirty = False"
    L m, "  DoCmd.SelectObject acForm, Me.Name: DoCmd.PrintOut acSelection"
    L m, "End Sub"
        Case "frmPayroll"
    L m, "Private Sub txtSearch_Change()"
    L m, "  Dim s As String: s = Replace(Me.txtSearch.Text, ""'"", ""''"")"
    L m, "  If Len(s) = 0 Then"
    L m, "    Me.FilterOn = False"
    L m, "  Else"
    L m, "    Me.Filter = ""[EmpID] IN (SELECT [EmpID] FROM [Employees] WHERE [EmpCode] Like '*"" & s & ""*')"": Me.FilterOn = True"
    L m, "  End If"
    L m, "  Me.txtSearch.SetFocus: Me.txtSearch.SelStart = Len(Me.txtSearch.Text)"
    L m, "End Sub"
    L m, "Private Sub btnPrint_Click()"
    L m, "  If Me.Dirty Then Me.Dirty = False"
    L m, "  If Me.NewRecord Then Exit Sub"
    L m, "  DoCmd.OpenReport ""rptPayslip"", acViewPreview, , ""PayID="" & Me!PayID"
    L m, "End Sub"
    L m, "Private Sub Form_BeforeUpdate(Cancel As Integer)"
    L m, "  If IsNull(Me!EmpID) Or IsNull(Me!PayMonth) Then Exit Sub"
    L m, "  Me!PayMonth = DateSerial(Year(Me!PayMonth), Month(Me!PayMonth), 1)"
    L m, "  If DCount(""*"", ""Payroll"", ""EmpID="" & Me!EmpID & "" AND PayMonth=#"" & Format(Me!PayMonth, ""mm/dd/yyyy"") & ""# AND PayID<>"" & Nz(Me!PayID, 0)) > 0 Then"
    L m, "    MsgBox """ & ChrW(1578) & ChrW(1605) & " " & ChrW(1575) & ChrW(1581) & ChrW(1578) & ChrW(1587) & ChrW(1575) & ChrW(1576) & " " & ChrW(1585) & ChrW(1575) & ChrW(1578) & ChrW(1576) & " " & ChrW(1607) & ChrW(1584) & ChrW(1575) & " " & ChrW(1575) & ChrW(1604) & ChrW(1605) & ChrW(1608) & ChrW(1592) & ChrW(1601) & " " & ChrW(1604) & ChrW(1607) & ChrW(1584) & ChrW(1575) & " " & ChrW(1575) & ChrW(1604) & ChrW(1588) & ChrW(1607) & ChrW(1585) & " " & ChrW(1605) & ChrW(1606) & " " & ChrW(1602) & ChrW(1576) & ChrW(1604) & """, vbExclamation: Cancel = True"
    L m, "  End If"
    L m, "End Sub"
    L m, "Private Sub btnExtra_Click()"
    L m, "  On Error GoTo E"
    L m, "  If IsNull(Me!EmpID) Or IsNull(Me!PayMonth) Then MsgBox """ & ChrW(1575) & ChrW(1582) & ChrW(1578) & ChrW(1585) & " " & ChrW(1575) & ChrW(1604) & ChrW(1605) & ChrW(1608) & ChrW(1592) & ChrW(1601) & " " & ChrW(1608) & ChrW(1588) & ChrW(1607) & ChrW(1585) & " " & ChrW(1575) & ChrW(1604) & ChrW(1589) & ChrW(1585) & ChrW(1601) & " " & ChrW(1571) & ChrW(1608) & ChrW(1604) & ChrW(1575) & ChrW(1611) & """, vbExclamation: Exit Sub"
    L m, "  Dim company As Long, shift As Long, days As Double, hours As Double, otFactor As Double, lateFactor As Double, insuranceRate As Double"
    L m, "  Dim d1 As Date, d2 As Date, w As String, emp As String, basic As Currency, hr As Double, lateM As Double, otH As Double, unpaid As Long"
    L m, "  emp = ""EmpID="" & Me!EmpID"
    L m, "  company = Nz(DLookup(""CompanyID"", ""Employees"", emp), 0): shift = Nz(DLookup(""ShiftID"", ""Employees"", emp), 0)"
    L m, "  days = Nz(DLookup(""SalaryDays"", ""Companies"", ""CompanyID="" & company), 0)"
    L m, "  hours = Nz(DLookup(""DailyHours"", ""ShiftRules"", ""ShiftID="" & shift), 0)"
    L m, "  otFactor = Nz(DLookup(""OvertimeFactor"", ""ShiftRules"", ""ShiftID="" & shift), -1)"
    L m, "  lateFactor = Nz(DLookup(""LateFactor"", ""ShiftRules"", ""ShiftID="" & shift), -1)"
    L m, "  insuranceRate = Nz(DLookup(""EmployeeInsuranceRate"", ""Companies"", ""CompanyID="" & company), -1)"
    L m, "  If days <= 0 Or hours <= 0 Or otFactor < 0 Or lateFactor < 0 Or insuranceRate < 0 Or insuranceRate > 100 Then MsgBox """ & ChrW(1571) & ChrW(1603) & ChrW(1605) & ChrW(1604) & " " & ChrW(1602) & ChrW(1608) & ChrW(1575) & ChrW(1593) & ChrW(1583) & " " & ChrW(1575) & ChrW(1604) & ChrW(1585) & ChrW(1608) & ChrW(1575) & ChrW(1578) & ChrW(1576) & " " & ChrW(1608) & ChrW(1575) & ChrW(1604) & ChrW(1578) & ChrW(1571) & ChrW(1605) & ChrW(1610) & ChrW(1606) & " " & ChrW(1608) & ChrW(1575) & ChrW(1604) & ChrW(1608) & ChrW(1585) & ChrW(1583) & ChrW(1610) & ChrW(1577) & " " & ChrW(1604) & ChrW(1604) & ChrW(1588) & ChrW(1585) & ChrW(1603) & ChrW(1577) & " " & ChrW(1571) & ChrW(1608) & ChrW(1604) & ChrW(1575) & ChrW(1611) & """, vbExclamation: Exit Sub"
    L m, "  d1 = DateSerial(Year(Me!PayMonth), Month(Me!PayMonth), 1): d2 = DateAdd(""m"", 1, d1): Me!PayMonth = d1"
    L m, "  w = emp & "" AND [X]>=#"" & Format(d1, ""mm/dd/yyyy"") & ""# AND [X]<#"" & Format(d2, ""mm/dd/yyyy"") & ""#"""
    L m, "  basic = Nz(DLookup(""BasicSalary"", ""Employees"", emp), 0): hr = basic / days / hours"
    L m, "  lateM = Nz(DSum(""LateMinutes"", ""Attendance"", Replace(w, ""[X]"", ""[WorkDate]"")), 0)"
    L m, "  otH = Nz(DSum(""OvertimeHours"", ""Attendance"", Replace(w, ""[X]"", ""[WorkDate]"")), 0)"
    L m, "  Me!BasicSalary = basic"
    L m, "  Me!NonTaxableVariable = Nz(DLookup(""NonTaxableVariable"", ""Employees"", emp), 0)"
    L m, "  Me!InsurableSalary = Nz(DLookup(""InsurableSalary"", ""Employees"", emp), 0)"
    L m, "  Me!Allowances = Nz(DLookup(""FixedAllowance"", ""Employees"", emp), 0)"
    L m, "  Me!Overtime = Round(otH * hr * otFactor, 2)"
    L m, "  Me!LateDeduction = Round(lateM * hr / 60 * lateFactor, 2)"
    L m, "  Me!InsuranceDeduction = Round(Me!InsurableSalary * insuranceRate / 100, 2)"
    L m, "  Me!OtherDeductions = Nz(DSum(""Amount"", ""Deductions"", Replace(w, ""[X]"", ""[DedDate]"")), 0)"
    L m, "  Me!AdvanceDeduction = Nz(DSum(""Installment"", ""Advances"", emp & "" AND Installment>0 AND AdvDate<#"" & Format(d2, ""mm/dd/yyyy"") & ""# AND DateAdd('m', Int([Amount]/IIf([Installment]=0,1,[Installment])), [AdvDate])>=#"" & Format(d1, ""mm/dd/yyyy"") & ""#""), 0)"
    L m, "  unpaid = UnpaidLeaveDays(Me!EmpID, d1, d2)"
    L m, "  Me!LeaveDeduction = Round(unpaid * basic / days, 2)"
    L m, "  Me!TotalDeductions = Me!LateDeduction + Me!AdvanceDeduction + Me!OtherDeductions + Me!InsuranceDeduction + Me!LeaveDeduction + Nz(Me!TaxDeduction, 0)"
    L m, "  Me!NetSalary = Me!BasicSalary + Me!NonTaxableVariable + Me!Allowances + Me!Overtime - Me!TotalDeductions"
    L m, "  If Me.Dirty Then Me.Dirty = False"
    L m, "  MsgBox """ & ChrW(1578) & ChrW(1605) & " " & ChrW(1575) & ChrW(1581) & ChrW(1578) & ChrW(1587) & ChrW(1575) & ChrW(1576) & " " & ChrW(1575) & ChrW(1604) & ChrW(1585) & ChrW(1575) & ChrW(1578) & ChrW(1576) & " " & ChrW(1608) & ChrW(1601) & ChrW(1602) & " " & ChrW(1573) & ChrW(1593) & ChrW(1583) & ChrW(1575) & ChrW(1583) & ChrW(1575) & ChrW(1578) & " " & ChrW(1575) & ChrW(1604) & ChrW(1588) & ChrW(1585) & ChrW(1603) & ChrW(1577) & """, vbInformation"
    L m, "  Exit Sub"
    L m, "E: MsgBox Err.Description, vbExclamation"
    L m, "End Sub"
    L m, "Private Function UnpaidLeaveDays(ByVal employee As Long, ByVal d1 As Date, ByVal d2 As Date) As Long"
    L m, "  Dim db As DAO.Database, rs As DAO.Recordset, a As Date, b As Date"
    L m, "  Set db = CurrentDb"
    L m, "  Set rs = db.OpenRecordset(""SELECT l.StartDate, l.EndDate FROM EmployeeLeaves AS l INNER JOIN LeavePolicies AS p ON l.LeavePolicyID=p.LeavePolicyID WHERE l.IsApproved=True AND p.IsPaid=False AND l.EmpID="" & employee & "" AND l.StartDate<#"" & Format(d2, ""mm/dd/yyyy"") & ""# AND l.EndDate>=#"" & Format(d1, ""mm/dd/yyyy"") & ""#"", dbOpenSnapshot)"
    L m, "  Do While Not rs.EOF"
    L m, "    a = rs!StartDate: b = rs!EndDate"
    L m, "    If a < d1 Then a = d1"
    L m, "    If b >= d2 Then b = DateAdd(""d"", -1, d2)"
    L m, "    UnpaidLeaveDays = UnpaidLeaveDays + DateDiff(""d"", a, b) + 1"
    L m, "    rs.MoveNext"
    L m, "  Loop"
    L m, "  rs.Close"
    L m, "End Function"
    End Select
End Sub

' ---------- reports ----------
Private Sub BuildReport(ByVal rptName As String, ByVal src As String, ByVal title As String, ByVal tabular As Boolean)
    Const W As Double = 19
    Dim rpt As Report, ctl As Control, lbl As Control, fld As DAO.Field, rs As DAO.Recordset, tmp As String
    Dim i As Integer, n As Integer, x As Double, y As Double, cw As Double, rowsN As Integer, hasFooter As Boolean
    SafeDeleteRpt rptName
    Dim db As DAO.Database
    Set db = CurrentDb
    Set rs = db.OpenRecordset(src, dbOpenSnapshot)
    n = rs.Fields.Count
    Set rpt = CreateReport()
    rpt.RecordSource = src: rpt.Caption = title: rpt.Width = W * TW

    ' page header: title band
    rpt.Section(acPageHeader).Height = IIf(tabular, 3.2, 2.4) * TW
    Set ctl = CreateReportControl(rpt.Name, acRectangle, acPageHeader, , , 0, 0, W * TW, 1.9 * TW)
    ctl.BackStyle = 1: ctl.BackColor = PRIMARY: ctl.BorderStyle = 0
    Set ctl = CreateReportControl(rpt.Name, acLabel, acPageHeader, , , 6 * TW, 0.25 * TW, 12.6 * TW, 0.9 * TW)
    ctl.Caption = title: ctl.TextAlign = 3: Txt ctl, 18, WHITE, True
    Set ctl = CreateReportControl(rpt.Name, acLabel, acPageHeader, , , 6 * TW, 1.1 * TW, 12.6 * TW, 0.6 * TW)
    ctl.Caption = ChrW(1573) & ChrW(1583) & ChrW(1575) & ChrW(1585) & ChrW(1577) & " " & ChrW(1588) & ChrW(1585) & ChrW(1603) & ChrW(1575) & ChrW(1578) & " " & ChrW(1608) & ChrW(1605) & ChrW(1608) & ChrW(1592) & ChrW(1601) & ChrW(1610) & ChrW(1606) & " " & ChrW(1608) & ChrW(1585) & ChrW(1608) & ChrW(1575) & ChrW(1578) & ChrW(1576): ctl.TextAlign = 3: Txt ctl, 10, &HE8D9C8, False
    Set ctl = CreateReportControl(rpt.Name, acTextBox, acPageHeader, , , 0.4 * TW, 0.6 * TW, 5 * TW, 0.6 * TW)
    ctl.ControlSource = "=Format(Date(),""yyyy/mm/dd"")": ctl.BorderStyle = 0: ctl.BackStyle = 0: ctl.TextAlign = 1: Txt ctl, 10, WHITE, False
    Set ctl = CreateReportControl(rpt.Name, acRectangle, acPageHeader, , , 0, 1.9 * TW, W * TW, 0.12 * TW)
    ctl.BackStyle = 1: ctl.BackColor = ACCENT: ctl.BorderStyle = 0

    If tabular Then
        On Error Resume Next
        DoCmd.RunCommand acCmdReportHdrFtr
        hasFooter = (Err.Number = 0)
        Err.Clear
        On Error GoTo 0
        If hasFooter Then rpt.Section(acHeader).Height = 0
        cw = W / n
        For Each fld In rs.Fields
            x = W - (i + 1) * cw
            Set lbl = CreateReportControl(rpt.Name, acLabel, acPageHeader, , , x * TW, 2.3 * TW, cw * TW, 0.7 * TW)
            lbl.Caption = Cap(fld.Name): lbl.TextAlign = 2: Txt lbl, 10, PRIMARY, True
            Set ctl = CreateReportControl(rpt.Name, acTextBox, acDetail, , fld.Name, x * TW, 0.1 * TW, cw * TW, 0.6 * TW)
            ctl.BorderStyle = 0: ctl.TextAlign = 2: Txt ctl, 10, &H222222, False
            If fld.Type = dbCurrency Or fld.Type = dbDouble Then ctl.Format = "#,##0.00"
            If fld.Type = dbDate Then ctl.Format = "yyyy/mm"
            If hasFooter And fld.Type = dbCurrency Then
                Set ctl = CreateReportControl(rpt.Name, acTextBox, acFooter, , , x * TW, 0.3 * TW, cw * TW, 0.7 * TW)
                ctl.ControlSource = "=Sum([" & fld.Name & "])": ctl.Format = "#,##0.00"
                ctl.BorderStyle = 0: ctl.TextAlign = 2: Txt ctl, 11, PRIMARY, True
            End If
            i = i + 1
        Next
        Set ctl = CreateReportControl(rpt.Name, acLine, acPageHeader, , , 0, 3.1 * TW, W * TW, 0)
        ctl.BorderColor = PRIMARY: ctl.BorderWidth = 2
        rpt.Section(acDetail).Height = 0.8 * TW
        rpt.Section(acDetail).AlternateBackColor = SURFACE
        If hasFooter Then
            rpt.Section(acFooter).Height = 1.2 * TW
            Set lbl = CreateReportControl(rpt.Name, acLabel, acFooter, , , (W - 4) * TW, 0.3 * TW, 3.8 * TW, 0.7 * TW)
            lbl.Caption = ChrW(1575) & ChrW(1604) & ChrW(1573) & ChrW(1580) & ChrW(1605) & ChrW(1575) & ChrW(1604) & ChrW(1610): lbl.TextAlign = 3: Txt lbl, 11, PRIMARY, True
        End If
    Else
        ' one card per record (e.g. payslip)
        rowsN = (n + 1) \ 2
        Set ctl = CreateReportControl(rpt.Name, acRectangle, acDetail, , , 0.1 * TW, 0.3 * TW, (W - 0.2) * TW, (rowsN * 0.85 + 0.4) * TW)
        ctl.BackStyle = 0: ctl.BorderColor = LINE_C: ctl.BorderWidth = 1
        For Each fld In rs.Fields
            x = IIf(i Mod 2 = 0, 9.8, 0.4)
            y = 0.5 + (i \ 2) * 0.85
            Set lbl = CreateReportControl(rpt.Name, acLabel, acDetail, , , (x + 5.2) * TW, y * TW, 3.6 * TW, 0.7 * TW)
            lbl.Caption = Cap(fld.Name): lbl.TextAlign = 3: Txt lbl, 10, MUTED, True
            Set ctl = CreateReportControl(rpt.Name, acTextBox, acDetail, , fld.Name, x * TW, y * TW, 5 * TW, 0.7 * TW)
            ctl.BorderStyle = 0: ctl.TextAlign = 3: Txt ctl, 11, &H222222, (fld.Name = "NetSalary")
            If fld.Type = dbCurrency Or fld.Type = dbDouble Then ctl.Format = "#,##0.00"
            If fld.Type = dbDate Then ctl.Format = "yyyy/mm"
            If fld.Name = "NetSalary" Then ctl.BackStyle = 1: ctl.BackColor = &HE6F4EA: ctl.FontSize = 13
            i = i + 1
        Next
        rpt.Section(acDetail).Height = (rowsN * 0.85 + 1.2) * TW
        rpt.Section(acDetail).KeepTogether = True
        Set lbl = CreateReportControl(rpt.Name, acLabel, acDetail, , , (W - 6) * TW, (rowsN * 0.85 + 0.75) * TW, 5.8 * TW, 0.5 * TW)
        lbl.Caption = ChrW(1578) & ChrW(1608) & ChrW(1602) & ChrW(1610) & ChrW(1593) & " " & ChrW(1575) & ChrW(1604) & ChrW(1605) & ChrW(1587) & ChrW(1578) & ChrW(1604) & ChrW(1605) & ": ..................": lbl.TextAlign = 3: Txt lbl, 9, MUTED, False
    End If
    rs.Close

    ' page footer: page numbers
    rpt.Section(acPageFooter).Height = 0.9 * TW
    Set ctl = CreateReportControl(rpt.Name, acTextBox, acPageFooter, , , 0, 0.2 * TW, W * TW, 0.6 * TW)
    ctl.ControlSource = "=""" & ChrW(1589) & ChrW(1601) & ChrW(1581) & ChrW(1577) & " "" & [Page] & "" / "" & [Pages]": ctl.BorderStyle = 0: ctl.TextAlign = 2: Txt ctl, 9, MUTED, False

    tmp = rpt.Name
    DoCmd.Close acReport, tmp, acSaveYes
    DoCmd.Rename rptName, acReport, tmp
End Sub

' ---------- main menu ----------
Private Sub Kpi(frm As Form, ByVal idx As Integer, ByVal cnt As Integer, ByVal cap As String, ByVal expr As String)
    Dim c As Control, tw_ As Double, x As Double
    tw_ = (18 - 0.6 * (cnt + 1)) / cnt
    x = 18 - 0.6 - (idx + 1) * tw_ - idx * 0.6
    Set c = CreateControl(frm.Name, acRectangle, acDetail, , , x * TW, 0.5 * TW, tw_ * TW, 2 * TW)
    c.BackStyle = 1: c.BackColor = WHITE: c.BorderColor = LINE_C
    Set c = CreateControl(frm.Name, acRectangle, acDetail, , , (x + tw_ - 0.15) * TW, 0.5 * TW, 0.15 * TW, 2 * TW)
    c.BackStyle = 1: c.BackColor = ACCENT: c.BorderStyle = 0
    Set c = CreateControl(frm.Name, acTextBox, acDetail, , , x * TW, 0.7 * TW, (tw_ - 0.4) * TW, 1 * TW)
    c.ControlSource = expr: c.BorderStyle = 0: c.BackStyle = 0: c.TextAlign = 3: c.Locked = True: c.TabStop = False
    Txt c, 20, PRIMARY, True
    Set c = CreateControl(frm.Name, acLabel, acDetail, , , x * TW, 1.75 * TW, (tw_ - 0.4) * TW, 0.6 * TW)
    c.Caption = cap: c.TextAlign = 3: Txt c, 10, MUTED, True
End Sub

Private Sub MenuBtn(frm As Form, ByRef m As String, ByVal idx As Integer, ByVal target As String, ByVal cap As String, ByVal isReport As Boolean)
    Dim x As Double, y As Double
    x = IIf(idx Mod 2 = 0, 9.3, 0.6)
    y = 3.1 + (idx \ 2) * 1.6
    Btn frm, acDetail, "btnOpen" & idx, cap, x, y, 8.1, 1.3, Not isReport
    L m, "Private Sub btnOpen" & idx & "_Click()"
    If isReport Then
        L m, "  DoCmd.OpenReport """ & target & """, acViewPreview"
    Else
        L m, "  DoCmd.OpenForm """ & target & """"
    End If
    L m, "End Sub"
End Sub

Private Sub BuildMenu()
    Dim frm As Form, m As String, db As DAO.Database
    SafeDelete "frmMain"
    Set frm = CreateForm()
    With frm
        .Caption = ChrW(1573) & ChrW(1583) & ChrW(1575) & ChrW(1585) & ChrW(1577) & " " & ChrW(1588) & ChrW(1585) & ChrW(1603) & ChrW(1575) & ChrW(1578) & " " & ChrW(1608) & ChrW(1605) & ChrW(1608) & ChrW(1592) & ChrW(1601) & ChrW(1610) & ChrW(1606) & " " & ChrW(1608) & ChrW(1585) & ChrW(1608) & ChrW(1575) & ChrW(1578) & ChrW(1576)
        .Orientation = 1: .AutoCenter = True: .AutoResize = True
        .RecordSelectors = False: .NavigationButtons = False: .ScrollBars = 2
        .Width = 18 * TW
        .Section(acDetail).BackColor = SURFACE
    End With
    Header frm, ChrW(1573) & ChrW(1583) & ChrW(1575) & ChrW(1585) & ChrW(1577) & " " & ChrW(1588) & ChrW(1585) & ChrW(1603) & ChrW(1575) & ChrW(1578) & " " & ChrW(1608) & ChrW(1605) & ChrW(1608) & ChrW(1592) & ChrW(1601) & ChrW(1610) & ChrW(1606) & " " & ChrW(1608) & ChrW(1585) & ChrW(1608) & ChrW(1575) & ChrW(1578) & ChrW(1576), ChrW(1604) & ChrW(1608) & ChrW(1581) & ChrW(1577) & " " & ChrW(1575) & ChrW(1604) & ChrW(1578) & ChrW(1581) & ChrW(1603) & ChrW(1605) & " " & ChrW(1575) & ChrW(1604) & ChrW(1585) & ChrW(1574) & ChrW(1610) & ChrW(1587) & ChrW(1610) & ChrW(1577), 18
    Kpi frm, 0, 4, ChrW(1575) & ChrW(1604) & ChrW(1588) & ChrW(1585) & ChrW(1603) & ChrW(1575) & ChrW(1578), "=DCount(""*"",""Companies"")"
    Kpi frm, 1, 4, ChrW(1575) & ChrW(1604) & ChrW(1601) & ChrW(1585) & ChrW(1608) & ChrW(1593), "=DCount(""*"",""Branches"")"
    Kpi frm, 2, 4, ChrW(1575) & ChrW(1604) & ChrW(1571) & ChrW(1602) & ChrW(1587) & ChrW(1575) & ChrW(1605), "=DCount(""*"",""Departments"")"
    Kpi frm, 3, 4, ChrW(1585) & ChrW(1608) & ChrW(1575) & ChrW(1578) & ChrW(1576) & " " & ChrW(1575) & ChrW(1604) & ChrW(1588) & ChrW(1607) & ChrW(1585), "=Format(Nz(DSum(""NetSalary"",""Payroll"",""Month([PayMonth])=Month(Date()) And Year([PayMonth])=Year(Date())""),0),""#,##0"")"
    frm.Section(acFooter).Height = 0.8 * TW
    frm.Section(acFooter).BackColor = WHITE
    MenuBtn frm, m, 0, "frmCompanies", ChrW(1573) & ChrW(1593) & ChrW(1583) & ChrW(1575) & ChrW(1583) & ChrW(1575) & ChrW(1578) & " " & ChrW(1575) & ChrW(1604) & ChrW(1588) & ChrW(1585) & ChrW(1603) & ChrW(1575) & ChrW(1578) & " " & ChrW(1608) & ChrW(1575) & ChrW(1604) & ChrW(1585) & ChrW(1608) & ChrW(1575) & ChrW(1578) & ChrW(1576) & " " & ChrW(1608) & ChrW(1575) & ChrW(1604) & ChrW(1578) & ChrW(1571) & ChrW(1605) & ChrW(1610) & ChrW(1606), False
    MenuBtn frm, m, 1, "frmBranches", ChrW(1575) & ChrW(1604) & ChrW(1601) & ChrW(1585) & ChrW(1608) & ChrW(1593) & " " & ChrW(1575) & ChrW(1604) & ChrW(1578) & ChrW(1575) & ChrW(1576) & ChrW(1593) & ChrW(1577) & " " & ChrW(1604) & ChrW(1604) & ChrW(1588) & ChrW(1585) & ChrW(1603) & ChrW(1575) & ChrW(1578), False
    MenuBtn frm, m, 2, "frmDepartments", ChrW(1575) & ChrW(1604) & ChrW(1573) & ChrW(1583) & ChrW(1575) & ChrW(1585) & ChrW(1575) & ChrW(1578) & " " & ChrW(1608) & ChrW(1575) & ChrW(1604) & ChrW(1578) & ChrW(1576) & ChrW(1593) & ChrW(1610) & ChrW(1577) & " " & ChrW(1604) & ChrW(1604) & ChrW(1601) & ChrW(1585) & ChrW(1608) & ChrW(1593), False
    MenuBtn frm, m, 3, "frmShiftRules", ChrW(1602) & ChrW(1608) & ChrW(1575) & ChrW(1593) & ChrW(1583) & " " & ChrW(1575) & ChrW(1604) & ChrW(1608) & ChrW(1585) & ChrW(1583) & ChrW(1610) & ChrW(1575) & ChrW(1578) & " " & ChrW(1608) & ChrW(1575) & ChrW(1604) & ChrW(1578) & ChrW(1571) & ChrW(1582) & ChrW(1610) & ChrW(1585) & " " & ChrW(1608) & ChrW(1575) & ChrW(1604) & ChrW(1573) & ChrW(1590) & ChrW(1575) & ChrW(1601) & ChrW(1610), False
    MenuBtn frm, m, 4, "frmLeavePolicies", ChrW(1602) & ChrW(1608) & ChrW(1575) & ChrW(1593) & ChrW(1583) & " " & ChrW(1608) & ChrW(1571) & ChrW(1606) & ChrW(1608) & ChrW(1575) & ChrW(1593) & " " & ChrW(1575) & ChrW(1604) & ChrW(1573) & ChrW(1580) & ChrW(1575) & ChrW(1586) & ChrW(1575) & ChrW(1578), False
    MenuBtn frm, m, 5, "frmEmployees", ChrW(1605) & ChrW(1604) & ChrW(1601) & " " & ChrW(1575) & ChrW(1604) & ChrW(1605) & ChrW(1608) & ChrW(1592) & ChrW(1601) & " " & ChrW(1575) & ChrW(1604) & ChrW(1603) & ChrW(1575) & ChrW(1605) & ChrW(1604), False
    MenuBtn frm, m, 6, "frmAttendance", ChrW(1575) & ChrW(1604) & ChrW(1581) & ChrW(1590) & ChrW(1608) & ChrW(1585) & " " & ChrW(1608) & ChrW(1575) & ChrW(1604) & ChrW(1575) & ChrW(1606) & ChrW(1589) & ChrW(1585) & ChrW(1575) & ChrW(1601), False
    MenuBtn frm, m, 7, "frmEmployeeLeaves", ChrW(1591) & ChrW(1604) & ChrW(1576) & ChrW(1575) & ChrW(1578) & " " & ChrW(1575) & ChrW(1604) & ChrW(1573) & ChrW(1580) & ChrW(1575) & ChrW(1586) & ChrW(1575) & ChrW(1578) & " " & ChrW(1608) & ChrW(1575) & ChrW(1593) & ChrW(1578) & ChrW(1605) & ChrW(1575) & ChrW(1583) & ChrW(1607) & ChrW(1575), False
    MenuBtn frm, m, 8, "frmDeductions", ChrW(1575) & ChrW(1604) & ChrW(1582) & ChrW(1589) & ChrW(1608) & ChrW(1605) & ChrW(1575) & ChrW(1578) & " " & ChrW(1608) & ChrW(1575) & ChrW(1604) & ChrW(1580) & ChrW(1586) & ChrW(1575) & ChrW(1569) & ChrW(1575) & ChrW(1578), False
    MenuBtn frm, m, 9, "frmAdvances", ChrW(1575) & ChrW(1604) & ChrW(1587) & ChrW(1604) & ChrW(1601) & " " & ChrW(1608) & ChrW(1575) & ChrW(1604) & ChrW(1571) & ChrW(1602) & ChrW(1587) & ChrW(1575) & ChrW(1591), False
    MenuBtn frm, m, 10, "frmPayroll", ChrW(1575) & ChrW(1581) & ChrW(1578) & ChrW(1587) & ChrW(1575) & ChrW(1576) & " " & ChrW(1608) & ChrW(1589) & ChrW(1585) & ChrW(1601) & " " & ChrW(1575) & ChrW(1604) & ChrW(1585) & ChrW(1608) & ChrW(1575) & ChrW(1578) & ChrW(1576), False
    MenuBtn frm, m, 11, "rptPayslip", ChrW(1602) & ChrW(1587) & ChrW(1610) & ChrW(1605) & ChrW(1577) & " " & ChrW(1575) & ChrW(1604) & ChrW(1585) & ChrW(1575) & ChrW(1578) & ChrW(1576), True
    MenuBtn frm, m, 12, "rptPayrollSheet", ChrW(1603) & ChrW(1588) & ChrW(1601) & " " & ChrW(1575) & ChrW(1604) & ChrW(1585) & ChrW(1608) & ChrW(1575) & ChrW(1578) & ChrW(1576) & " " & ChrW(1575) & ChrW(1604) & ChrW(1588) & ChrW(1607) & ChrW(1585) & ChrW(1610), True
    Btn frm, acDetail, "btnExit", ChrW(1582) & ChrW(1585) & ChrW(1608) & ChrW(1580) & " " & ChrW(1605) & ChrW(1606) & " " & ChrW(1575) & ChrW(1604) & ChrW(1576) & ChrW(1585) & ChrW(1606) & ChrW(1575) & ChrW(1605) & ChrW(1580), 0.6, 12.7, 8.1, 1.3, False
    L m, "Private Sub Form_Activate()"
    L m, "  Me.Recalc"
    L m, "End Sub"
    L m, "Private Sub btnExit_Click()"
    L m, "  If MsgBox(ChrW(1607) & ChrW(1604) & ChrW(32) & ChrW(1578) & ChrW(1585) & ChrW(1610) & ChrW(1583) & ChrW(32) & ChrW(1575) & ChrW(1604) & ChrW(1582) & ChrW(1585) & ChrW(1608) & ChrW(1580) & ChrW(1567), vbYesNo + vbQuestion) = vbYes Then DoCmd.Quit"
    L m, "End Sub"
    frm.Section(acDetail).Height = 14.6 * TW
    frm.OnActivate = "[Event Procedure]"
    frm.Module.InsertText m
    FinishForm frm, "frmMain"

    ' open frmMain automatically when the database starts
    Set db = CurrentDb
    On Error Resume Next
    db.Properties("StartUpForm") = "frmMain"
    If Err.Number <> 0 Then
        Err.Clear
        db.Properties.Append db.CreateProperty("StartUpForm", dbText, "frmMain")
    End If
End Sub

دليل الاستخدام خطوة بخطوة

  1. 1

    احتفظ بنسخة احتياطية من بياناتك؛ شغّل سكربت الإنشاء الجديد لإنشاء HRPayroll.accdb ثم شغّل كود الشاشات. هذا الإصدار لا ينقل بيانات القاعدة القديمة تلقائياً.

  2. 2

    أدخل الشركات وأيام أساس حساب الراتب ونسبة اشتراك الموظف التأميني؛ لا توجد نسب قانونية مفترضة.

  3. 3

    أضف فروع كل شركة وإدارات كل فرع، ثم الورديات: وقت البداية والساعات والسماح بالدقائق ومعاملَي التأخير والإضافي. الخصم يحسب على الدقائق التي تتجاوز السماح.

  4. 4

    عرّف أنواع الإجازات ورصيدها السنوي وهل هي مدفوعة. الأيام تقويمية شاملة البداية والنهاية؛ قسّم الطلب العابر للسنة إلى طلبين.

  5. 5

    أكمل ملف الموظف الشخصي والوظيفي وتبعيته وورديته وسياسة إجازاته؛ أدخل الأساسي والمتغير غير الخاضع للضريبة والراتب التأميني والبدلات الاختيارية.

  6. 6

    سجّل الحضور والإجازات واعتمد الطلبات. الطلبات المعتمدة تمنع التداخل وتتحقق من الرصيد السنوي للنوع المختار.

  7. 7

    احتسب الرواتب وفق إعدادات الشركة. الراتب التأميني أساس لخصم التأمين وليس إضافة إلى الإجمالي؛ المتغير غير الخاضع يضاف للصافي. الضريبة تُدخل يدوياً بعد مراجعة محاسب، دون حساب قانوني آلي.

كود SQL للجداول

HRPayroll.sql
-- HRPayroll.accdb — Microsoft Access SQL
-- ملاحظة: محرر SQL في أكسيس ينفذ جملة واحدة في كل مرة. انسخ كل جملة على حدة.

CREATE TABLE [Companies] (
    [CompanyID] COUNTER,
    [CompanyName] TEXT(255) NOT NULL,
    [RegistrationNo] TEXT(255),
    [TaxNumber] TEXT(255),
    [Address] TEXT(255),
    [Phone] TEXT(255),
    [SalaryDays] LONG NOT NULL,
    [EmployeeInsuranceRate] DOUBLE NOT NULL,
    [Notes] TEXT(255),
    CONSTRAINT [PK_Companies] PRIMARY KEY ([CompanyID])
);

CREATE TABLE [Branches] (
    [BranchID] COUNTER,
    [CompanyID] LONG NOT NULL,
    [BranchName] TEXT(255) NOT NULL,
    [Address] TEXT(255),
    [Phone] TEXT(255),
    CONSTRAINT [PK_Branches] PRIMARY KEY ([BranchID])
);

CREATE TABLE [Departments] (
    [DeptID] COUNTER,
    [CompanyID] LONG NOT NULL,
    [BranchID] LONG NOT NULL,
    [DeptName] TEXT(255) NOT NULL,
    [ManagerName] TEXT(255),
    CONSTRAINT [PK_Departments] PRIMARY KEY ([DeptID])
);

CREATE TABLE [ShiftRules] (
    [ShiftID] COUNTER,
    [CompanyID] LONG NOT NULL,
    [ShiftName] TEXT(255) NOT NULL,
    [ShiftStart] DATETIME NOT NULL,
    [DailyHours] DOUBLE NOT NULL,
    [GraceMinutes] LONG NOT NULL,
    [LateFactor] DOUBLE NOT NULL,
    [OvertimeFactor] DOUBLE NOT NULL,
    [Notes] TEXT(255),
    CONSTRAINT [PK_ShiftRules] PRIMARY KEY ([ShiftID])
);

CREATE TABLE [LeavePolicies] (
    [LeavePolicyID] COUNTER,
    [CompanyID] LONG NOT NULL,
    [LeaveName] TEXT(255) NOT NULL,
    [AnnualDays] LONG NOT NULL,
    [IsPaid] YESNO,
    [Notes] TEXT(255),
    CONSTRAINT [PK_LeavePolicies] PRIMARY KEY ([LeavePolicyID])
);

CREATE TABLE [Employees] (
    [EmpID] COUNTER,
    [EmpCode] TEXT(255) NOT NULL,
    [FullName] TEXT(255) NOT NULL,
    [NationalID] TEXT(255) NOT NULL,
    [BirthDate] DATETIME,
    [Gender] TEXT(255),
    [MaritalStatus] TEXT(255),
    [Address] TEXT(255),
    [Phone] TEXT(255),
    [Email] TEXT(255),
    [EmergencyContact] TEXT(255),
    [EmergencyPhone] TEXT(255),
    [CompanyID] LONG NOT NULL,
    [BranchID] LONG NOT NULL,
    [DeptID] LONG NOT NULL,
    [JobTitle] TEXT(255),
    [HireDate] DATETIME NOT NULL,
    [ContractEnd] DATETIME,
    [EmploymentType] TEXT(255),
    [ShiftID] LONG NOT NULL,
    [LeavePolicyID] LONG NOT NULL,
    [IsActive] YESNO,
    [BasicSalary] CURRENCY NOT NULL,
    [NonTaxableVariable] CURRENCY,
    [InsurableSalary] CURRENCY NOT NULL,
    [FixedAllowance] CURRENCY,
    [InsuranceNumber] TEXT(255),
    [InsuranceStartDate] DATETIME,
    [BankName] TEXT(255),
    [BankAccount] TEXT(255),
    [Notes] TEXT(255),
    CONSTRAINT [PK_Employees] PRIMARY KEY ([EmpID])
);

CREATE TABLE [Attendance] (
    [AttID] COUNTER,
    [EmpID] LONG NOT NULL,
    [WorkDate] DATETIME NOT NULL,
    [CheckIn] DATETIME,
    [CheckOut] DATETIME,
    [LateMinutes] LONG,
    [OvertimeHours] DOUBLE,
    CONSTRAINT [PK_Attendance] PRIMARY KEY ([AttID])
);

CREATE TABLE [EmployeeLeaves] (
    [LeaveID] COUNTER,
    [EmpID] LONG NOT NULL,
    [LeavePolicyID] LONG NOT NULL,
    [StartDate] DATETIME NOT NULL,
    [EndDate] DATETIME NOT NULL,
    [LeaveDays] LONG,
    [IsApproved] YESNO,
    [Reason] TEXT(255),
    CONSTRAINT [PK_EmployeeLeaves] PRIMARY KEY ([LeaveID])
);

CREATE TABLE [Deductions] (
    [DedID] COUNTER,
    [EmpID] LONG NOT NULL,
    [DedDate] DATETIME NOT NULL,
    [Amount] CURRENCY NOT NULL,
    [Reason] TEXT(255),
    CONSTRAINT [PK_Deductions] PRIMARY KEY ([DedID])
);

CREATE TABLE [Advances] (
    [AdvID] COUNTER,
    [EmpID] LONG NOT NULL,
    [AdvDate] DATETIME NOT NULL,
    [Amount] CURRENCY NOT NULL,
    [Installment] CURRENCY NOT NULL,
    [Notes] TEXT(255),
    CONSTRAINT [PK_Advances] PRIMARY KEY ([AdvID])
);

CREATE TABLE [Payroll] (
    [PayID] COUNTER,
    [EmpID] LONG NOT NULL,
    [PayMonth] DATETIME NOT NULL,
    [BasicSalary] CURRENCY,
    [NonTaxableVariable] CURRENCY,
    [InsurableSalary] CURRENCY,
    [Allowances] CURRENCY,
    [Overtime] CURRENCY,
    [LateDeduction] CURRENCY,
    [InsuranceDeduction] CURRENCY,
    [LeaveDeduction] CURRENCY,
    [TaxDeduction] CURRENCY,
    [AdvanceDeduction] CURRENCY,
    [OtherDeductions] CURRENCY,
    [TotalDeductions] CURRENCY,
    [NetSalary] CURRENCY,
    [IsPaid] YESNO,
    CONSTRAINT [PK_Payroll] PRIMARY KEY ([PayID])
);

ALTER TABLE [Branches] ADD CONSTRAINT [FK_Branches_Companies]
    FOREIGN KEY ([CompanyID]) REFERENCES [Companies] ([CompanyID]);

ALTER TABLE [Departments] ADD CONSTRAINT [FK_Departments_Companies]
    FOREIGN KEY ([CompanyID]) REFERENCES [Companies] ([CompanyID]);

ALTER TABLE [Departments] ADD CONSTRAINT [FK_Departments_Branches]
    FOREIGN KEY ([BranchID]) REFERENCES [Branches] ([BranchID]);

ALTER TABLE [ShiftRules] ADD CONSTRAINT [FK_ShiftRules_Companies]
    FOREIGN KEY ([CompanyID]) REFERENCES [Companies] ([CompanyID]);

ALTER TABLE [LeavePolicies] ADD CONSTRAINT [FK_LeavePolicies_Companies]
    FOREIGN KEY ([CompanyID]) REFERENCES [Companies] ([CompanyID]);

ALTER TABLE [Employees] ADD CONSTRAINT [FK_Employees_Companies]
    FOREIGN KEY ([CompanyID]) REFERENCES [Companies] ([CompanyID]);

ALTER TABLE [Employees] ADD CONSTRAINT [FK_Employees_Branches]
    FOREIGN KEY ([BranchID]) REFERENCES [Branches] ([BranchID]);

ALTER TABLE [Employees] ADD CONSTRAINT [FK_Employees_Departments]
    FOREIGN KEY ([DeptID]) REFERENCES [Departments] ([DeptID]);

ALTER TABLE [Employees] ADD CONSTRAINT [FK_Employees_ShiftRules]
    FOREIGN KEY ([ShiftID]) REFERENCES [ShiftRules] ([ShiftID]);

ALTER TABLE [Employees] ADD CONSTRAINT [FK_Employees_LeavePolicies]
    FOREIGN KEY ([LeavePolicyID]) REFERENCES [LeavePolicies] ([LeavePolicyID]);

ALTER TABLE [Attendance] ADD CONSTRAINT [FK_Attendance_Employees]
    FOREIGN KEY ([EmpID]) REFERENCES [Employees] ([EmpID]);

ALTER TABLE [EmployeeLeaves] ADD CONSTRAINT [FK_EmployeeLeaves_Employees]
    FOREIGN KEY ([EmpID]) REFERENCES [Employees] ([EmpID]);

ALTER TABLE [EmployeeLeaves] ADD CONSTRAINT [FK_EmployeeLeaves_LeavePolicies]
    FOREIGN KEY ([LeavePolicyID]) REFERENCES [LeavePolicies] ([LeavePolicyID]);

ALTER TABLE [Deductions] ADD CONSTRAINT [FK_Deductions_Employees]
    FOREIGN KEY ([EmpID]) REFERENCES [Employees] ([EmpID]);

ALTER TABLE [Advances] ADD CONSTRAINT [FK_Advances_Employees]
    FOREIGN KEY ([EmpID]) REFERENCES [Employees] ([EmpID]);

ALTER TABLE [Payroll] ADD CONSTRAINT [FK_Payroll_Employees]
    FOREIGN KEY ([EmpID]) REFERENCES [Employees] ([EmpID]);