Payslip Based on Working Hours Odoo 18
By Braincuber Team
Published on January 3, 2026
Payroll teams struggle with hour-based salary calculations: warehouse employee works 168 hours including 8 overtime hours, HR manually cross-references attendance sheet with contract hourly rate, calculates overtime at 1.5x multiplier, subtracts 2 unpaid sick days, adds transport allowance, applies tax deduction—then discovers calculation error when employee complains about $247 discrepancy, requiring complete recalculation of every component. Manual payroll takes 3 days monthly and still produces errors.
Odoo 18 Payroll module automates salary computation based on employee standard working hours. Configure contracts defining hourly rates and weekly schedules, let system auto-generate work entries tracking regular hours, overtime, and leaves, define salary rules with Python formulas for wage calculation, allowances, and deductions—then generate accurate payslips with one click. The system references contract working hours, applies configured rules, computes gross and net pay, handles all edge cases automatically, reducing payroll processing from days to minutes while eliminating calculation errors.
Core Benefit: Configure once, calculate forever. Contract defines hourly rate + weekly schedule → Work entries track actual hours → Salary rules compute wages → Payslip generates automatically with zero manual math.
Understanding the Payroll Workflow
Contract Configuration
Define standard working hours (8 hours/day, 40 hours/week), wage type (hourly or fixed), working schedule (Monday-Friday 9-5), and payment frequency (monthly, weekly, daily). This becomes the calculation foundation.
Work Entry Generation
System automatically generates work entries based on contract schedule. Tracks regular working hours, overtime when exceeding standard, paid/unpaid leaves, sick time, and attendance variations.
Salary Rules Engine
Python-based formulas calculate each payslip component: basic wage from hours worked, allowances (transport, housing), deductions (tax, loans), overtime premiums. Rules chain together for final computation.
Payslip Generation
Batch processing generates payslips for selected employees. System pulls contract data, work entries, and salary rules to compute gross pay, apply deductions, and calculate net salary—all automatically.
Step 1: Configure Employee Contracts
Employee contracts define the foundation for payroll calculations. Navigate to Employees → Contracts or Payroll → Contracts to create or edit contracts.
Set Standard Working Hours
Define how many hours the employee is contractually obligated to work:
- Hours Per Day: Typical daily working hours (e.g., 8 hours)
- Hours Per Week: Total weekly commitment (e.g., 40 hours)
- Working Schedule: Specific days and times (e.g., "Monday-Friday, 9 AM - 5 PM")
- System uses these values to determine overtime vs regular hours
Configure Wage Type
Select how salary is calculated:
- Fixed Salary: Monthly/annual amount regardless of hours worked (for salaried employees)
- Hourly Wage: Pay varies based on actual hours worked (for hourly employees)
- For hourly, set the Hourly Rate (e.g., $75/hour)
- For fixed, set the Monthly Wage (e.g., $6,500/month)
Set Payment Schedule
Define payment frequency:
- Monthly: Most common for salaried employees (paid on 25th or last day)
- Weekly: Common for hourly workers (paid every Friday)
- Daily: For day laborers or contractors (paid end of each workday)
- Ensure contract status is set to Running for active payroll processing
Contract Configuration Example:
CONTRACT: Senior Warehouse Technician Employee: Marcus Thompson Department: Warehouse Operations Position: Warehouse Technician WORKING HOURS CONFIGURATION Standard Hours Per Day: 8 hours Standard Hours Per Week: 40 hours Working Schedule: Standard 40h/week (Mon-Fri, 8AM-5PM with 1hr lunch) WAGE CONFIGURATION Wage Type: Hourly Hourly Rate: $75.00 Overtime Rate: 1.5x ($112.50/hour) Double Time Rate: 2.0x ($150.00/hour for holidays) PAYMENT CONFIGURATION Schedule Pay: Weekly Payment Day: Every Friday Payment Method: Direct Deposit CONTRACT STATUS: Running Start Date: January 15, 2024 End Date: (Indefinite - permanent employee) EXPECTED MONTHLY CALCULATION (160 hours): Regular Hours: 160 hours × $75 = $12,000 Transport Allowance: $400 (fixed) Gross Pay: $12,400 Tax Deduction (15%): $1,860 Net Pay: $10,540
Step 2: Work Entry Generation
Odoo automatically generates work entries based on contract working schedules. These entries track actual vs expected hours and categorize time appropriately.
View Generated Work Entries
Navigate to Payroll → Work Entries to see system-generated entries:
- Regular Hours (WORK100): Standard working hours from contract schedule
- Overtime: Hours exceeding daily/weekly standard
- Paid Leave: Vacation, PTO, holidays (paid at regular rate)
- Sick Leave: Medical absences (may be paid or unpaid depending on policy)
- Unpaid Leave: Absences without pay (salary deduction applied)
Manual Work Entry Types
Create additional work entry types for special situations:
- Sick Time: Tracking illness-related absences
- Overtime Entries: Extra hours approved by management
- Holiday Work: Work performed on company holidays (often double-time)
- On-Call Hours: Availability payments for standby employees
Work Entry Types Reference:
WORK ENTRY TYPES AND CODES WORK100 - Regular Working Hours Description: Standard attendance per contract schedule Example: 8 hours/day × 20 working days = 160 hours Payment: contract.hourly_wage × hours OVERTIME - Overtime Hours Description: Hours exceeding daily/weekly standard Example: 10 hours worked on a day with 8-hour standard = 2 OT hours Payment: contract.hourly_wage × 1.5 × overtime_hours LEAVE110 - Paid Time Off (PTO) Description: Approved vacation or personal leave Example: 5 days PTO = 40 hours Payment: Paid at regular hourly rate LEAVE120 - Sick Leave (Paid) Description: Illness-related absence with pay Example: 3 sick days = 24 hours Payment: Paid at regular rate (or % based on policy) LEAVE130 - Sick Leave (Unpaid) Description: Illness beyond paid sick allowance Example: Exceeds 5 annual paid sick days Payment: $0 (no pay for excess days) LEAVE200 - Unpaid Leave Description: Personal leave without pay Example: 2 unpaid days = 16 hours Payment: Salary deduction applied HOLIDAY - Holiday Work Description: Work performed on company holidays Example: 8 hours on New Year's Day Payment: contract.hourly_wage × 2.0 (double time) MONTHLY WORK ENTRY EXAMPLE - Marcus Thompson (January 2026) Regular Hours (WORK100): 152 hours Overtime: 12 hours PTO: 8 hours (1 day vacation) Sick Leave (Paid): 8 hours (1 day illness) Total Tracked: 180 hours
Step 3: Define Salary Rules
Salary rules automate wage computation using Python formulas. Navigate to Payroll → Configuration → Salary Rules to create and configure rules.
Basic Wage Rule
Calculates base pay from hours worked:
- For Fixed Salary:
contract.wage(returns monthly wage) - For Hourly:
worked_days.WORK100.number_of_hours * contract.hourly_wage - Links to WORK100 work entry type for hour counting
- Result category: Earnings (positive amount added to gross)
Allowance Rules
Add fixed or percentage-based allowances:
- Transport Allowance (Fixed):
400(fixed $400 monthly) - Housing Allowance (Percentage):
contract.wage * 0.10(10% of base) - Meal Allowance:
worked_days.WORK100.number_of_days * 15($15/day) - All allowances contribute to gross salary calculation
Deduction Rules
Configure payroll deductions:
- Income Tax:
categories.GROSS * 0.15(15% of gross) - Social Security:
categories.GROSS * 0.062(6.2%) - Unpaid Leave Deduction:
worked_days.LEAVE200.number_of_hours * contract.hourly_wage - Loan Repayment (Fixed):
200(fixed monthly deduction)
Gross and Net Salary Rules
Calculate totals:
- Gross Salary:
categories.BASIC + categories.ALW(basic + allowances) - Total Deductions:
categories.DED(sum of all deductions) - Net Salary:
categories.GROSS - categories.DED - Net is the final amount paid to employee
Salary Rules Configuration:
SALARY STRUCTURE: Hourly Warehouse Employee RULE 1: Basic Wage (BASIC) Sequence: 1 Category: Basic Condition: True (always applies) Python Code: result = worked_days.WORK100.number_of_hours * contract.hourly_wage Note: Calculates base pay from regular hours × hourly rate RULE 2: Overtime Pay (OT) Sequence: 2 Category: Allowance (ALW) Condition: worked_days.OVERTIME.number_of_hours > 0 Python Code: result = worked_days.OVERTIME.number_of_hours * contract.hourly_wage * 1.5 Note: 1.5x multiplier for overtime hours RULE 3: PTO Pay (PTO) Sequence: 3 Category: Allowance (ALW) Condition: worked_days.LEAVE110.number_of_hours > 0 Python Code: result = worked_days.LEAVE110.number_of_hours * contract.hourly_wage Note: Paid time off at regular rate RULE 4: Transport Allowance (TRANS) Sequence: 4 Category: Allowance (ALW) Condition: True Python Code: result = 400 Note: Fixed monthly transport allowance RULE 5: Housing Allowance (HRA) Sequence: 5 Category: Allowance (ALW) Condition: True Python Code: result = categories.BASIC * 0.10 Note: 10% of basic wage RULE 6: Meal Allowance (MEAL) Sequence: 6 Category: Allowance (ALW) Condition: True Python Code: result = worked_days.WORK100.number_of_days * 15 Note: $15 per working day RULE 7: Gross Salary (GROSS) Sequence: 100 Category: Gross Condition: True Python Code: result = categories.BASIC + categories.ALW Note: Sum of basic + all allowances RULE 8: Income Tax (TAX) Sequence: 110 Category: Deduction (DED) Condition: True Python Code: result = categories.GROSS * 0.15 Note: 15% income tax deduction RULE 9: Social Security (SS) Sequence: 111 Category: Deduction (DED) Condition: True Python Code: result = categories.GROSS * 0.062 Note: 6.2% social security contribution RULE 10: Unpaid Leave Deduction (UNPAID) Sequence: 115 Category: Deduction (DED) Condition: worked_days.LEAVE200.number_of_hours > 0 Python Code: result = worked_days.LEAVE200.number_of_hours * contract.hourly_wage Note: Deduct pay for unpaid leave hours RULE 11: Net Salary (NET) Sequence: 200 Category: Net Condition: True Python Code: result = categories.GROSS - categories.DED Note: Final take-home pay
Step 4: Generate Payslips
With contracts configured and work entries tracked, generate payslips using batch processing. Navigate to Payroll → Payslips → Payslips to Pay.
Initiate Payslip Creation
Start the batch payslip process:
- Click New to create a new payslip batch
- Set the Period (e.g., January 1-31, 2026)
- Select Salary Structure to apply (e.g., "Hourly Warehouse")
- Batch name auto-generates or customize (e.g., "January 2026 - Warehouse Team")
Select Employees
Choose which employees to include:
- Select individual employees from list
- Or filter by department (e.g., "Warehouse Operations")
- Or use employee groups/tags for targeted processing
- Best Practice: Filter by contract type for consistent salary structure application
Compute Payslip Details
Let Odoo calculate all components:
- Click Compute Sheet button
- System pulls contract data (hourly rate, schedule)
- Fetches work entries for the period
- Applies salary rules in sequence
- Populates all earning, allowance, and deduction lines
- Troubleshooting: Check "Worked Days" tab to verify attendance data matches expectations
Validate and Finalize
Review and confirm payslips:
- Review each payslip for accuracy (hours, rates, calculations)
- Click Validate to confirm and lock payslip
- Validated payslips generate accounting entries
- Employees can view their payslips via employee portal
Complete Payslip Calculation Example:
PAYSLIP: Marcus Thompson Period: January 1-31, 2026 Contract: Senior Warehouse Technician Hourly Rate: $75.00 ═══════════════════════════════════════════════════════════ WORKED DAYS & HOURS (From Work Entries) ═══════════════════════════════════════════════════════════ Regular Work (WORK100): Days: 19 days Hours: 152 hours Overtime (OT): Days: 3 days Hours: 12 hours Paid Time Off (LEAVE110): Days: 1 day vacation Hours: 8 hours Sick Leave Paid (LEAVE120): Days: 1 day illness Hours: 8 hours Unpaid Leave (LEAVE200): Days: 1.5 days personal Hours: 12 hours ═══════════════════════════════════════════════════════════ EARNINGS CALCULATION ═══════════════════════════════════════════════════════════ Basic Wage: 152 hours × $75.00 = $11,400.00 Overtime Pay: 12 hours × $75.00 × 1.5 = $1,350.00 PTO Pay: 8 hours × $75.00 = $600.00 Sick Leave Pay: 8 hours × $75.00 = $600.00 Transport Allowance: Fixed monthly = $400.00 Housing Allowance (HRA): $11,400 × 10% = $1,140.00 Meal Allowance: 19 days × $15 = $285.00 ─────────────────────────────────────────────────────────── GROSS SALARY: $15,775.00 ═══════════════════════════════════════════════════════════ DEDUCTIONS ═══════════════════════════════════════════════════════════ Income Tax: $15,775 × 15% = $2,366.25 Social Security: $15,775 × 6.2% = $978.05 Unpaid Leave Deduction: 12 hours × $75.00 = $900.00 ─────────────────────────────────────────────────────────── TOTAL DEDUCTIONS: $4,244.30 ═══════════════════════════════════════════════════════════ NET SALARY: $11,530.70 ═══════════════════════════════════════════════════════════ Payment Method: Direct Deposit Payment Date: Friday, January 31, 2026 Bank Account: ****7842
Advanced Salary Rule Formulas
Customize salary rules for complex scenarios using Python expressions. Here are common formula patterns.
Formula Reference:
# ACCESSING CONTRACT DATA
contract.wage # Monthly wage (fixed salary)
contract.hourly_wage # Hourly rate
contract.hours_per_day # Standard daily hours (e.g., 8)
contract.hours_per_week # Standard weekly hours (e.g., 40)
# ACCESSING WORKED DAYS
worked_days.WORK100.number_of_hours # Regular working hours
worked_days.WORK100.number_of_days # Regular working days
worked_days.OVERTIME.number_of_hours # Overtime hours
worked_days.LEAVE110.number_of_hours # PTO hours
worked_days.LEAVE200.number_of_hours # Unpaid leave hours
# ACCESSING CATEGORY TOTALS
categories.BASIC # Sum of all rules in BASIC category
categories.ALW # Sum of all allowances
categories.DED # Sum of all deductions
categories.GROSS # Gross salary total
# COMMON FORMULA PATTERNS
# Basic hourly wage
result = worked_days.WORK100.number_of_hours * contract.hourly_wage
# Overtime at 1.5x
result = worked_days.OVERTIME.number_of_hours * contract.hourly_wage * 1.5
# Holiday double-time
result = worked_days.HOLIDAY.number_of_hours * contract.hourly_wage * 2.0
# Percentage-based allowance
result = categories.BASIC * 0.10 # 10% of basic
# Fixed allowance
result = 500 # Fixed $500
# Per-day allowance
result = worked_days.WORK100.number_of_days * 25 # $25/day
# Progressive tax bracket
if categories.GROSS <= 5000:
result = categories.GROSS * 0.10
elif categories.GROSS <= 10000:
result = 500 + (categories.GROSS - 5000) * 0.15
else:
result = 1250 + (categories.GROSS - 10000) * 0.20
# Conditional bonus
if worked_days.WORK100.number_of_hours >= 160:
result = 200 # Attendance bonus for full month
else:
result = 0
# Prorate salary for partial month (fixed salary employees)
standard_days = 22 # Expected working days
actual_days = worked_days.WORK100.number_of_days
result = contract.wage * (actual_days / standard_days)
Best Practices for Payroll Configuration
✅ Follow These Guidelines:
- Verify contracts before payroll: Ensure all employee contracts are in "Running" status with correct wage types and working hours before generating payslips
- Review work entries weekly: Check work entries regularly to catch attendance issues, missing overtime entries, or incorrectly coded leave before month-end
- Test salary rules with sample data: Before applying rules to all employees, test calculations on a single payslip to verify formula accuracy
- Use rule sequences wisely: Order rules logically—basic wage first (sequence 1-10), allowances (11-50), gross calculation (100), deductions (110-150), net salary last (200)
- Document custom formulas: Add comments explaining complex Python expressions for future maintenance and auditing
- Validate before finalizing: Always review computed payslips before validation—validated payslips generate accounting entries and are harder to modify
- Filter by department: Process payroll in batches by department or contract type to apply appropriate salary structures
- Keep audit trail: Never delete payslips—cancel and recreate if corrections needed to maintain complete history
Common Mistakes to Avoid
🚨 Mistake #1: Contract Not in Running Status
Payslip shows $0 because contract status is "Draft" or "Expired" = system can't pull contract data. Solution: Verify contract is "Running" with valid start/end dates covering payroll period.
🚨 Mistake #2: Missing Work Entry Types
Overtime rule references worked_days.OVERTIME but work entry type doesn't exist = formula returns zero. Solution: Create all required work entry types before configuring salary rules that reference them.
🚨 Mistake #3: Incorrect Rule Sequence
Gross salary rule (sequence 50) runs before all allowances computed (sequence 60-80) = gross doesn't include allowances. Solution: Set gross rule sequence higher than all contributing rules (100+).
🚨 Mistake #4: Forgetting to Compute Sheet
Payslip validated without clicking "Compute Sheet" = all lines show $0 because calculation never ran. Solution: Always click Compute Sheet after selecting employees, verify calculations, then validate.
Conclusion
Generating payslips based on employee standard working hours in Odoo 18 transforms manual spreadsheet calculations into automated, accurate payroll processing. Configure employee contracts with hourly rates and working schedules, let the system auto-generate work entries tracking regular hours, overtime, and leaves, define salary rules using Python formulas for wage calculation, allowances, deductions, and net pay computation, then generate payslips in batches with single-click computation—reducing payroll processing from days of manual calculation to minutes of automated precision. The structured approach ensures compliance, eliminates calculation errors, provides complete audit trails, and enables employee self-service access to payslip details through the portal.
🎯 Key Takeaway: Contract defines the rate, work entries track the hours, salary rules do the math, payslip shows the result. Configure once, generate accurate payslips forever. No more spreadsheet formulas, no more calculation errors, no more 3-day payroll marathons.
