Skip to content

entity-service: time-card search filters + create/update write path - #989

Merged
Rashmika998 merged 2 commits into
wso2-open-operations:v2from
rksk:time-card-filters-and-write
Jun 30, 2026
Merged

entity-service: time-card search filters + create/update write path#989
Rashmika998 merged 2 commits into
wso2-open-operations:v2from
rksk:time-card-filters-and-write

Conversation

@rksk

@rksk rksk commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

What

Search filters on POST /time-cards/search: add caseId, userId, approverId (eligible approver), and approvedById (actual approver) filters. State filtering already worked. UUIDs are mapped to ServiceNow sysids; the approver fields map to multi-value (glide_list) columns matched with CONTAINS downstream.

Write path (ServiceNow data source; no schema change):

  • POST /time-cards — create a time card in the submitted state. Submitter is taken from the session, never the payload. Caller supplies approverIds (eligible approvers).
  • PATCH /time-cards/{id} — one endpoint for both field edits (submitter, while submitted) and state transitions: {"state":"approved"}, or {"state":"rejected","leadComment":"..."}. Authorization (submitter vs eligible approver) is enforced by the downstream ServiceNow integration service.

This follows the existing cases/call-requests convention where state transitions go through the resource PATCH rather than action sub-resources.

Layers

Domain types, service methods (+ interface), handlers, routes, and openapi.yaml updated. go build, go vet clean.

Notes

  • The matching downstream ServiceNow scripted-API change is tracked separately.
  • Authorization parity for create (case/project access check) is a documented follow-up.

Summary by CodeRabbit

  • New Features
    • Added create and update actions for time cards (POST /time-cards, PATCH /time-cards/{id}).
    • Time-card search now supports additional filters for case, user, approver, and approved-by.
    • Updated API documentation with the new time-card endpoints and request/response schemas.
  • Bug Fixes
    • Strengthened validation for time-card updates, including correct state-transition rules and required rejection comments.
    • Added safeguards to reject invalid UUIDs and non-negative time/duration values.

…path

Search: add caseId (task), userId (user), approverId (approver_list, eligible),
and approvedById (approved_by, actual) filters to POST /time-cards/search; state
filtering already existed. UUIDs map to SN sysids; approver fields are glide_lists
matched with CONTAINS on the SN side.

Write path (SN data source, no schema change): add POST /time-cards (create,
state=submitted, caller-supplied approverIds) and PATCH /time-cards/{id}. The
PATCH carries either editable fields (submitter, while submitted) or a state
transition (state=approved, or state=rejected with leadComment) for an eligible
approver in approver_list; SN enforces authorization. Submitter is taken from
the session. Domain types, service, handlers, routes, and openapi documented.
@coderabbitai

coderabbitai Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: bc40667d-e747-4747-b2af-1c443bd60772

📥 Commits

Reviewing files that changed from the base of the PR and between 1af7bad and 1b193ec.

📒 Files selected for processing (2)
  • entity-service/internal/service/sn_time_card_service.go
  • entity-service/openapi.yaml
🚧 Files skipped from review as they are similar to previous changes (2)
  • entity-service/internal/service/sn_time_card_service.go
  • entity-service/openapi.yaml

📝 Walkthrough

Walkthrough

Adds POST /time-cards and PATCH /time-cards/{id} endpoints to the entity service, plus new time-card DTOs, expanded search filters, SN service handling, route wiring, and OpenAPI definitions.

Changes

Time Card Create/Update API

Layer / File(s) Summary
Domain DTOs and service interface
entity-service/internal/domain/entity.go, entity-service/internal/service/interfaces.go, entity-service/openapi.yaml
Adds CreateTimeCardRequest, UpdateTimeCardRequest, and TimeCardMutationResponse; extends SearchTimeCardsFilters with caseId, userId, approverId, and approvedById; declares CreateTimeCard and UpdateTimeCard on TimeCardService; adds matching OpenAPI schemas and operations.
SearchTimeCards filter extension
entity-service/internal/service/sn_time_card_service.go
Extends snTimeCardFilters with four new optional fields, validates the new UUID filters in SearchTimeCards, and maps them into the SN request payload.
SN service create/update flow
entity-service/internal/service/sn_time_card_service.go
Adds SN mutation payload/response types, parseTimeCardMutation, and nonNegativeMinutes; implements CreateTimeCard and UpdateTimeCard with required-field checks, UUID/state/duration validation, payload mapping, and POST/PATCH calls.
HTTP handlers and route registration
entity-service/internal/handler/time_card_handler.go, entity-service/internal/server/routes.go
Adds CreateTimeCard and UpdateTimeCard handlers with request decoding and JSON responses; registers POST /time-cards and PATCH /time-cards/{id}; conditions GET /products/vulnerabilities/{id} on the handler check.
Cosmetic formatting
entity-service/internal/domain/entity.go
Reformatting only for SearchCasesFilters, CreateCaseRequest, SearchCaseCommentsRequest, and Attachment.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • wso2-open-operations/cs-tools#964: Introduces the time-cards search contract and /time-cards/search wiring that this PR extends with additional filters and mutation endpoints.

Suggested labels

Type/Improvement, Area/Backend, Entity Service

Suggested reviewers

  • Rashmika998
  • cloby99

Poem

🐇 Hop, hop — time cards take their flight,
Filters grow and payloads write.
Patch and post beneath the moon,
A rabbit stamps the work real soon,
With approver hops and tidy code delight.

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description is missing most required template sections, including Purpose, Goals, Approach, tests, docs, and release details. Rewrite it using the full template and add the missing sections with concrete links, test evidence, security checks, and release notes.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: new time-card search filters and create/update write paths.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 golangci-lint (2.12.2)

level=error msg="[linters_context] typechecking error: pattern ./...: directory prefix . does not contain main module or its selected dependencies"


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
entity-service/internal/service/sn_time_card_service.go (1)

374-409: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

UpdateTimeCard accepts a no-op request (no state and no editable fields).

After ID validation, if State is nil and none of the editable fields/approverIds are set, the method builds an empty payload and PATCHes ServiceNow with nothing to change. Consider rejecting requests that carry neither a state transition nor any editable field, to fail fast with a clear validation error.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@entity-service/internal/service/sn_time_card_service.go` around lines 374 -
409, UpdateTimeCard currently allows a no-op update when State is nil and no
editable fields or approverIds are provided, resulting in an empty PATCH payload
to ServiceNow. Add a validation check in snTimeCardService.UpdateTimeCard after
the existing ID/state/field validation to reject requests with neither a state
transition nor any mutable field set. Use the existing request fields in
domain.UpdateTimeCardRequest and return a clear apierror.ValidationError when
the update would otherwise be empty.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@entity-service/openapi.yaml`:
- Around line 3536-3573: Update the UpdateTimeCardRequest schema to enforce the
documented PATCH contract by preventing empty bodies and separating state
transitions from editable-field updates. In entity-service/openapi.yaml, add
validation such as minProperties: 1 and, if appropriate, a oneOf that
distinguishes the state/leadComment shape from the edit fields shape for
UpdateTimeCardRequest. Also add a corresponding server-side guard in the time
card update path so the implementation rejects no-op requests consistently with
the schema.
- Around line 1440-1464: The PATCH /time-cards/{id} response list is missing the
UnauthorizedError case documented for create; update the OpenAPI definition for
UpdateTimeCard in openapi.yaml to include a 401 response alongside the existing
200/400/404/500 entries, using the same ErrorResponse schema pattern used by
POST /time-cards.

---

Nitpick comments:
In `@entity-service/internal/service/sn_time_card_service.go`:
- Around line 374-409: UpdateTimeCard currently allows a no-op update when State
is nil and no editable fields or approverIds are provided, resulting in an empty
PATCH payload to ServiceNow. Add a validation check in
snTimeCardService.UpdateTimeCard after the existing ID/state/field validation to
reject requests with neither a state transition nor any mutable field set. Use
the existing request fields in domain.UpdateTimeCardRequest and return a clear
apierror.ValidationError when the update would otherwise be empty.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: c96acbec-0a5b-41c4-b8a1-826598217a0b

📥 Commits

Reviewing files that changed from the base of the PR and between 193bbc1 and 1af7bad.

📒 Files selected for processing (6)
  • entity-service/internal/domain/entity.go
  • entity-service/internal/handler/time_card_handler.go
  • entity-service/internal/server/routes.go
  • entity-service/internal/service/interfaces.go
  • entity-service/internal/service/sn_time_card_service.go
  • entity-service/openapi.yaml

Comment thread entity-service/openapi.yaml
Comment thread entity-service/openapi.yaml
…+ minProperties

Address CodeRabbit review on wso2-open-operations#989:
- UpdateTimeCard rejects a body with neither a state transition nor any editable
  field (no-op PATCH), and rejects combining a transition with field edits (the
  transition path ignores edits downstream, which would silently drop them).
- openapi: UpdateTimeCardRequest gets minProperties: 1; PATCH /time-cards/{id}
  documents the 401 response (parity with POST /time-cards).
@coderabbitai

coderabbitai Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Tip

For best results, initiate chat on the files or code changes.

@rksk Thanks for the update — that addresses my concerns.

The UpdateTimeCard guard against empty/no-op requests and mixed transition+edit payloads makes the behavior much clearer, and adding the 401 for PATCH /time-cards/{id} brings it in line with POST /time-cards. I’m also good with skipping oneOf here since the explicit server-side validation plus minProperties: 1 enforces the contract without extra schema complexity.

🐇✨


✏️ Learnings added
Learnt from: rksk
URL: https://github.com/wso2-open-operations/cs-tools/pull/989

Timestamp: 2026-06-30T15:46:13.621Z
Learning: In the `entity-service` time-card API, the `PATCH /time-cards/{id}` contract is intentionally enforced with `minProperties: 1` in `entity-service/openapi.yaml` plus explicit server-side validation in the update path to reject empty bodies and mixed state-transition-plus-field-edit requests, instead of modeling the request with OpenAPI `oneOf`.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


If you found this review helpful, would you consider giving us a shout-out on X?

Thank you for using CodeRabbit!

rksk added a commit to rksk/os-cs-tools that referenced this pull request Jun 30, 2026
Parity with the entity-service contract (wso2-open-operations#989): reject an empty/no-op PATCH body
in the spec; the entity service enforces it and this BFF passes the body through.
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.

2 participants