Skip to content

Implement PayRuleSet and BreakPolicy CRUD with nested entity persistence#1339

Draft
Copilot wants to merge 82 commits intomasterfrom
copilot/extend-rule-engine-overtime-holiday
Draft

Implement PayRuleSet and BreakPolicy CRUD with nested entity persistence#1339
Copilot wants to merge 82 commits intomasterfrom
copilot/extend-rule-engine-overtime-holiday

Conversation

Copy link
Contributor

Copilot AI commented Feb 15, 2026

Summary

Implements complete CRUD for PayRuleSet and BreakPolicy modules with proper nested entity handling. Both modules had schema misalignment issues and missing persistence logic that prevented data from saving correctly.

Schema Corrections

PayRuleSet: Changed from percentage-based tier allocation to time-threshold-based rules

  • dayOfWeek: number (0-6)dayCode: string (SUNDAY, MONDAY, WEEKDAY, HOLIDAY, etc.)
  • tierPercent: numberupToSeconds: number?, payCode: string, order: number

BreakPolicy: Aligned with actual database schema

  • paidBreakSeconds, unpaidBreakSecondspaidBreakMinutes, unpaidBreakMinutes
  • Simplified form: removed breakAfterMinutes, breakDurationMinutes calculations

Deserialization Fix

Angular sends "id": null for new entities but C# models had non-nullable int Id, causing complete deserialization failure:

// Before
public class PayDayRuleModel {
    public int Id { get; set; }  // ❌ rejects null
}

// After
public class PayDayRuleModel {
    public int? Id { get; set; }  // ✅ accepts null
}

Applied to: PayDayRuleModel, PayTierRuleModel, BreakPolicyModel, BreakPolicyRuleModel

Id Parameter Pattern

Controllers expect id from URL route, not body. Sending in both locations caused binding conflicts:

// Before
updatePayRuleSet(model: PayRuleSetUpdateModel) {
  return this.put(`/api/pay-rule-sets/${model.id}`, model);  // ❌ id in both places
}

// After  
updatePayRuleSet(id: number, model: PayRuleSetUpdateModel) {
  return this.put(`/api/pay-rule-sets/${id}`, model);  // ✅ id only in URL
}

Applied consistently to both PayRuleSet and BreakPolicy update operations.

Nested Entity Persistence

Services now properly handle nested rules in Create/Update:

// Create: persist nested entities
foreach (var ruleModel in model.PayDayRules) {
    var rule = new PayDayRule { /* ... */ };
    await rule.Create(_dbContext);
    
    foreach (var tierModel in ruleModel.PayTierRules) {
        var tier = new PayTierRule { /* ... */ };
        await tier.Create(_dbContext);
    }
}

// Update: add/modify/delete based on Id presence
var existingIds = existing.Select(r => r.Id).ToList();
var modelIds = model.PayDayRules.Where(r => r.Id.HasValue).Select(r => r.Id.Value).ToList();
var toDelete = existingIds.Except(modelIds);  // soft delete removed items

UI Fixes

  • MatTableDataSource for proper change detection in pay-day-rule-form
  • FormControl type casting: getTierControl(index, name): FormControl
  • Form validation triggers on tier add/delete

Test Coverage

Added controller tests validating JSON deserialization without service execution:

  • PayRuleSetControllerTests: 4 tests
  • BreakPolicyControllerTests: 4 tests

All tests verify Angular JSON format deserializes correctly to C# models with nullable Ids.

Files Changed

  • Backend: 13 files (models, services, controllers, tests)
  • Frontend: 14 files (models, services, components, tests)
  • Total: 27 files, ~3000 lines changed
Original prompt

This section details on the original issue you should resolve

<issue_title>🚀 Feature: Extend Rule Engine for Advanced Overtime & Holiday Logic (Non‑Breaking + API CRUD + Tests)</issue_title>
<issue_description>## 🎯 Goal

Implement advanced rule resolution logic using the updated database model without breaking any existing behavior.

This issue covers engine logic + API controllers/services + integration tests.
Database schema changes are handled separately.

Key principles (must-follow)

  • Backward compatible: existing calculations and existing APIs must keep working as-is unless explicitly enabled via new configuration.
  • Extend, don’t replace: build on existing rule engine code paths; gate new logic behind new rule fields / feature switches where needed.
  • Incremental implementation: implement in small steps with green builds/tests after each step.
  • No “big bang” refactors: avoid broad rewrites; prefer additive changes and well-scoped refactors.
  • Safety checks before commit: run build + all tests before committing any changes.

🤖 GitHub Copilot Implementation Workflow (required)

0) Analyze first

Before writing code, Copilot must:

  1. Locate current rule-engine calculation flow (entry points, services, calculators).
  2. Identify existing overtime logic + holiday logic + day classification logic.
  3. Identify where pay lines are generated (PlanRegistrationPayLines, existing pay code rules).
  4. Identify existing API layer patterns (controllers/services/repositories), and existing integration test patterns.

1) Write a plan

Copilot must produce a short plan in the PR/commit message or as a comment in the issue describing:

  • Which files/classes will be touched
  • The order of implementation steps
  • How backward compatibility is ensured (feature gating / defaults)
  • Which tests will be added per step

2) Implement in steps (each step must be green)

For each step:

  • Implement a small change
  • Add/adjust tests for that change
  • Run dotnet build and all tests
  • Only then commit

🧮 Engine Implementation Tasks

1️⃣ Overtime Calculation (non-breaking)

Add support for:

  • Weekly overtime
  • Bi-weekly (14 days) overtime
  • Monthly overtime
  • Rolling averaging periods

Use new fields from WorkingTimeRuleSets:

  • OvertimePeriodLengthDays
  • OvertimeAveragingWindowDays
  • MonthlyNormMode
  • OvertimeAllocationStrategy

Backward compatibility rules

  • If new fields are NULL/default → use existing overtime behavior exactly.
  • Only activate new period-based logic when OvertimeBasis indicates it AND required parameters are present (or safe defaults are explicitly defined).

2️⃣ Overtime Allocation Strategies

Implement allocation strategies:

  • LatestFirst
  • EarliestFirst
  • Proportional

Backward compatibility rules

  • Default strategy must match current behavior (confirm by tests).
  • Allocation must be deterministic.

3️⃣ Day-Type Resolution + Time-Bands (non-breaking)

Resolve day type:

  • Weekday
  • Saturday
  • Sunday
  • PublicHoliday
  • CompanyHoliday

Apply new rule tables:

  • PayDayTypeRules
  • PayTimeBandRules

Backward compatibility rules

  • If no PayDayTypeRules exist for a ruleset → fall back to current PayDayRules/PayTierRules behavior.
  • Do not change existing paycode mapping unless new rules are configured.

4️⃣ Holiday Paid-Off Logic (non-breaking)

If employee does not work on public holiday:

  • Use PlannedHours
  • OR FixedSeconds
  • OR None

Generate correct pay lines using configured pay codes.

Backward compatibility rules

  • If HolidayPaidOffMode is default/None → preserve current holiday handling.
  • If new mode enabled → ensure it does not affect non-holiday days.

5️⃣ 11-Hour Rest Rule

Use:

  • MinimumDailyRestSeconds
  • FirstWorkStartUtc
  • LastWorkEndUtc

Add deterministic violation detection logic.
(If existing logic exists, extend it; do not break current outputs.)


🌐 API: Controllers + Services (CRUD)

We need API endpoints and service layer for index + CRUD of the new rule entities so Angular frontend can be implemented later.

Entities requiring CRUD

  • PayRuleSets (existing)
  • PayDayTypeRules (new)
  • PayTimeBandRules (new)
  • WorkingTimeRuleSets (existing, now extended)
  • AssignedSiteRuleSetAssignments (new) — if repository includes employee rule assignment logic

Requirements

  • Follow existing architectural patterns (controller → service → repository/data access).
  • Include:
    • GET /... list/index (paging optional)
    • GET /.../{id}
    • POST /...
    • PUT /.../{id}
    • DELETE /.../{id} (soft delete if your workflow state model requires it)
  • Validate inputs (time band boundaries, overlaps, day type duplicates, etc.).
  • Ensure new endpoints do not break existing routes.

🧪 Testing Requirements (must-have)

Integration tests (required for ALL controllers/services)

All controllers and services introduced/chan...


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Copilot AI and others added 3 commits February 15, 2026 05:20
Co-authored-by: renemadsen <76994+renemadsen@users.noreply.github.com>
Co-authored-by: renemadsen <76994+renemadsen@users.noreply.github.com>
Co-authored-by: renemadsen <76994+renemadsen@users.noreply.github.com>
Copilot AI changed the title [WIP] Implement advanced overtime and holiday logic for rule engine Implementation guide for advanced rule engine: overtime, holidays, time bands, pay lines Feb 15, 2026
Copilot AI requested a review from renemadsen February 15, 2026 05:26
…s successfully

Co-authored-by: renemadsen <76994+renemadsen@users.noreply.github.com>
Copilot AI changed the title Implementation guide for advanced rule engine: overtime, holidays, time bands, pay lines Implement Break Policy CRUD API with service layer and integration tests Feb 15, 2026
Copy link
Member

@renemadsen renemadsen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot Stick to our codebase and you can reference https://github.com/microting/eform-timeplanning-base for the entities

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot We should not include using BackendConfiguration.Pn.Integration.Test; since it's not in our codebase

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in commit 68fe2a7. Changed TestBaseSetup namespace to TimePlanning.Pn.Test and removed the BackendConfiguration.Pn.Integration.Test using statement from all test files (9 files updated).

…usage

Co-authored-by: renemadsen <76994+renemadsen@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Feb 15, 2026

@copilot Stick to our codebase and you can reference https://github.com/microting/eform-timeplanning-base for the entities

Acknowledged. The implementation references entities from Microting.TimePlanningBase v10.0.15 NuGet package. The namespace issue has been fixed in commit 68fe2a7 - all tests now use TimePlanning.Pn.Test namespace consistently with the codebase.

Copilot AI and others added 2 commits February 15, 2026 06:50
Co-authored-by: renemadsen <76994+renemadsen@users.noreply.github.com>
Co-authored-by: renemadsen <76994+renemadsen@users.noreply.github.com>
Copilot AI changed the title Implement Break Policy CRUD API with service layer and integration tests Implement PayRuleSet and PayDayTypeRule CRUD APIs for rule engine Feb 15, 2026
Co-authored-by: renemadsen <76994+renemadsen@users.noreply.github.com>
Copilot AI changed the title Implement PayRuleSet and PayDayTypeRule CRUD APIs for rule engine Implement PayTierRule CRUD API with service layer and tests Feb 15, 2026
…hange

Co-authored-by: renemadsen <76994+renemadsen@users.noreply.github.com>
Copilot AI changed the title Implement PayRuleSet CRUD with nested entity persistence and fix JSON deserialization Implement PayRuleSet CRUD with three-level nested entity persistence Feb 18, 2026
…er tests need refinement

Co-authored-by: renemadsen <76994+renemadsen@users.noreply.github.com>
Copilot AI changed the title Implement PayRuleSet CRUD with three-level nested entity persistence Fix JSON deserialization for PayRuleSet and BreakPolicy nested entities Feb 18, 2026
…ompilation errors resolved

Co-authored-by: renemadsen <76994+renemadsen@users.noreply.github.com>
Copilot AI changed the title Fix JSON deserialization for PayRuleSet and BreakPolicy nested entities Fix JSON deserialization for PayRuleSet and BreakPolicy with nullable Id properties Feb 18, 2026
…llerTests - compilation fixed

Co-authored-by: renemadsen <76994+renemadsen@users.noreply.github.com>
Copilot AI changed the title Fix JSON deserialization for PayRuleSet and BreakPolicy with nullable Id properties Fix JSON deserialization failures for PayRuleSet and BreakPolicy with nullable Ids Feb 18, 2026
Copilot AI changed the title Fix JSON deserialization failures for PayRuleSet and BreakPolicy with nullable Ids Fix PayRuleSet and BreakPolicy deserialization and nested entity persistence Feb 18, 2026
Copilot AI changed the title Fix PayRuleSet and BreakPolicy deserialization and nested entity persistence Fix PayRuleSet and BreakPolicy JSON deserialization and nested entity persistence Feb 18, 2026
Copilot AI changed the title Fix PayRuleSet and BreakPolicy JSON deserialization and nested entity persistence Fix PayRuleSet and BreakPolicy CRUD with nested entity persistence and schema alignment Feb 18, 2026
… DayOfWeek field

Co-authored-by: renemadsen <76994+renemadsen@users.noreply.github.com>
Copilot AI changed the title Fix PayRuleSet and BreakPolicy CRUD with nested entity persistence and schema alignment Implement PayRuleSet and BreakPolicy CRUD with nested entity persistence Feb 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

🚀 Feature: Extend Rule Engine for Advanced Overtime & Holiday Logic (Non‑Breaking + API CRUD + Tests)

2 participants

Comments