Skip to content

Fix/general issues#36

Merged
emilwojtaszek merged 16 commits into
mainfrom
fix/general-issues
Feb 11, 2026
Merged

Fix/general issues#36
emilwojtaszek merged 16 commits into
mainfrom
fix/general-issues

Conversation

@emilwojtaszek

@emilwojtaszek emilwojtaszek commented Feb 11, 2026

Copy link
Copy Markdown
Member

Summary by CodeRabbit

  • New Features

    • HTML/PDF generation accepts metadata (KSeF number); sales date now shown in invoice rendering
    • Invoice import now distinguishes inserted vs updated so re-synced invoices aren’t counted as new
  • Bug Fixes

    • Improved token refresh/error handling; stale sync job errors hidden after successful completion
  • UI/UX Improvements

    • Toasts moved to bottom; invoice list/detail layout and preview sizing updated
    • Team members and pending invitations merged into a single management view
  • Chores

    • Role label renamed: "Invoice Reviewer" → "Reviewer" (data and UI updated)

emilwojtaszek and others added 10 commits February 11, 2026 21:05
…yncs

- upsert_invoice now returns {:ok, invoice, :inserted | :updated} so the
  sync counter only counts genuinely new invoices instead of all processed
  (including re-synced) ones.
- trigger_manual_sync checks for available/scheduled/executing job states,
  preventing duplicate jobs when tapping "Sync Now" rapidly.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…tion buttons

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…en refresh errors

- All KSeF API calls now have 30s receive_timeout and Req transient
  retry (2 retries with 1s delay) to handle intermittent timeouts.
- TokenManager.do_refresh distinguishes network errors (retryable) from
  auth rejections (reauth_required) so transient failures don't
  permanently cancel sync jobs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add mb-2 to Invite button to align with input fields in the form.
- Rename "invoice_reviewer" role to "reviewer" across schemas,
  validation, UI, and tests.
- Add data migration to update existing rows in memberships and
  invitations tables.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…eldset structure

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Merge the separate "Pending invitations" and "Members" tables into one
table with columns: Email, Name, Role, Status, Expires, Action.
Pending invitations show em-dash for name, "pending" badge in status,
and expiry date. Members show em-dash for expires.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove buyer column, reorder to Number/Date/Type/Seller/Gross/Status,
prevent date wrapping. Capitalize team table headers to match .table component.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fetch and adapt official FA(3) stylesheet from crd.gov.pl with local
  imports and XSD lookups patched for --nonet usage
- Fix Req multipart tuple format for Gotenberg (was 3-tuple, needs 2-tuple)
- Pass invoice metadata (ksef_number) through PDF pipeline via xsltproc
  --stringparam and fallback template
- Extract sales_date (P_6) in parser for fallback template
- Update scripts/update-ksef-stylesheet.sh to handle real gov.pl URLs,
  auto-download shared templates and XSD files, inject ksef_number param

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Use 1/3 + 2/3 grid layout instead of 50/50. Replace .list component
with dense table, shorter labels, taller preview iframe (600px).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Oban's job.errors is append-only and never cleared, so completed jobs
that failed on a previous attempt still showed the old error message.
Now only show job.errors for non-completed states.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Feb 11, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

Rename role invoice_reviewerreviewer; invoice upsert now returns {:ok, invoice, :inserted | :updated}; metadata is threaded through PDF/XSLT pipeline; HTTP client options and delays standardized; sync error handling refined; many XSL/XSD assets and a migration added; tests and UI adjusted.

Changes

Cohort / File(s) Summary
Role rename & migration
lib/ksef_hub/companies/membership.ex, lib/ksef_hub/invitations/invitation.ex, priv/repo/migrations/20260211202008_rename_invoice_reviewer_to_reviewer.exs, test/...
Replaced invoice_reviewer with reviewer in code, tests, and DB via migration.
Invoice upsert & sync
lib/ksef_hub/invoices.ex, lib/ksef_hub/sync/invoice_fetcher.ex, test/ksef_hub/invoices_test.exs, test/ksef_hub/sync/invoice_fetcher_test.exs
Upsert returns triple `{:ok, invoice, :inserted
PDF/XSLT metadata flow
lib/ksef_hub/pdf.ex, lib/ksef_hub/pdf/behaviour.ex, lib/ksef_hub/pdf/fallback_template.ex, lib/ksef_hub/pdf/xsltproc.ex, lib/ksef_hub/pdf/gotenberg.ex, lib/ksef_hub_web/controllers/..., test/.../show_test.exs
Added optional metadata param across PDF pipeline (generate_html/2, transform/2); fallback template uses metadata (ksef_number, sales_date); Gotenberg multipart encoding adjusted; controllers and tests updated to pass metadata.
HTTP client & token handling
lib/ksef_hub/ksef_client/live.ex, lib/ksef_hub/ksef_client/token_manager.ex, test/ksef_hub/ksef_client/token_manager_test.exs
Standardized Req request options (timeouts, retry settings), added query/download delays, and refined token refresh error handling distinguishing network vs auth errors; tests added.
Sync history & job errors
lib/ksef_hub/sync/history.ex, test/ksef_hub/sync/history_test.exs
Broadened manual-sync blocking states (available/scheduled/executing) and added extract_error/1 to suppress stale errors for completed jobs; tests added.
UI & live views
lib/ksef_hub_web/components/core_components.ex, lib/ksef_hub_web/live/..., related tests
Flash moved from top→bottom; invoice list/show layout/table changes (date column, iframe sizing); team view merged pending invitations into members table and role label updated; many live tests adapted.
Invoice parser
lib/ksef_hub/invoices/parser.ex
Added sales_date extracted from P_6 to parsed invoice map.
XSL / XSD assets & script
priv/xsl/... (many), scripts/update-ksef-stylesheet.sh
Added/updated numerous XSL/XSD files (new centralized XSLT, multiple XSDs, placeholders), removed old shared template, and enhanced stylesheet fetch/patch script (injects ksef_number param, downloads/patches shared template and XSDs).
Rate limiter removal
lib/ksef_hub/ksef_client/rate_limiter.ex, test/.../rate_limiter_test.exs
Removed RateLimiter GenServer and its tests (module and tests deleted).
Tests & small fixes
test/... (various)
Updated many tests for role rename, generate_html/2 arity, upsert return tags, token refresh behaviors, and UI selector changes.

Sequence Diagram(s)

sequenceDiagram
  rect rgba(200,200,255,0.5)
  participant Controller
  end
  rect rgba(200,255,200,0.5)
  participant PdfMod as PDF Module
  end
  rect rgba(255,200,200,0.5)
  participant Xsltproc
  end
  rect rgba(255,255,200,0.5)
  participant Gotenberg
  end

  Controller->>PdfMod: generate_html(xml_content, metadata)
  PdfMod->>Xsltproc: transform(xml_content, metadata)
  Xsltproc-->>PdfMod: {:ok, html}
  PdfMod->>Gotenberg: generate_pdf(html)
  Gotenberg-->>PdfMod: {:ok, pdf_binary}
  PdfMod-->>Controller: {:ok, html} / {:ok, pdf_binary}
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

🐇 I hopped through code and nudged a role to "reviewer",
Upserts now say inserted or updated — clear and truer.
KSeF numbers tucked in XSL and HTML bright,
Retries hum, timeouts wait, PDFs print just right.
A rabbit cheers: the pipeline's snug tonight!

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 27.27% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'Fix/general issues' is vague and generic, failing to convey what specific changes or issues are being addressed in this substantial changeset. Use a more descriptive title that reflects the main objective, such as 'Rename invoice_reviewer role to reviewer and enhance invoice metadata' or 'Refactor roles, add sales date metadata, and improve PDF generation'.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/general-issues

No actionable comments were generated in the recent review. 🎉


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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (4)
lib/ksef_hub/sync/invoice_fetcher.ex (1)

141-159: ⚠️ Potential issue | 🟡 Minor

Update download_and_upsert/3 spec to match new tuple shape.

It now returns the :inserted | :updated tag from Invoices.upsert_invoice/1, so the spec should reflect that.

📌 Suggested update
-  `@spec` download_and_upsert(map(), String.t() | nil, map()) ::
-          {:ok, Invoices.Invoice.t()} | {:error, term()}
+  `@spec` download_and_upsert(map(), String.t() | nil, map()) ::
+          {:ok, Invoices.Invoice.t(), :inserted | :updated} | {:error, term()}
test/ksef_hub_web/live/team_live_test.exs (1)

93-103: ⚠️ Potential issue | 🟡 Minor

Avoid asserting role text; prefer structural selectors.

The updated assertion checks the badge text "reviewer", which makes the test brittle. Consider a data-testid/data-role attribute on the badge and assert on that instead.

🧩 Example adjustment (requires a data-role attribute in the template)
-      assert has_element?(view, "[data-testid='pending-invitations'] .badge", "reviewer")
+      assert has_element?(view, "[data-testid='pending-invitations'] .badge[data-role='reviewer']")

Based on learnings, Instead of relying on testing text content which can change, favor testing for the presence of key elements in LiveView tests.

lib/ksef_hub/ksef_client/live.ex (1)

34-60: ⚠️ Potential issue | 🟠 Major

Disable retries for non-idempotent KSeF auth and token endpoints.

KSeF API v2 does not define idempotency for /auth/xades-signature, /auth/token/redeem, and /auth/token/refresh. Currently, retry: :transient in req_options() (lines 20–28) applies to all endpoints including these non-idempotent POSTs, risking duplicate side effects:

  • /auth/xades-signature: Retrying on transient errors (500, 502, etc.) creates multiple authentication operations with different reference numbers.
  • /auth/token/redeem: Tokens are redeemable only once; a transient error followed by automatic retry will fail with 400/21302 if the initial request succeeded.
  • /auth/token/refresh: Each retry generates a new access token; automatic retries can create unintended duplicates.

Scope retry: :transient to idempotent endpoints (GETs like /auth/{referenceNumber}, /invoices/query/metadata, /invoices/ksef/{ksef_number}) or disable retries for auth/token operations and handle retries explicitly at the call site. Alternatively, use retry: false on non-idempotent operations and rely on Req's transient defaults only for safe methods.

Also applies to: lines 87 (poll_auth_status—idempotent GET), 143 (refresh_access_token), 208 (download_invoice—idempotent GET), 229 (terminate_session—has side effects).

lib/ksef_hub/pdf.ex (1)

14-28: 🛠️ Refactor suggestion | 🟠 Major

Add @doc/@SPEC for the public API.

generate_html/2 is public and now part of the updated interface—please document it and add type specs (same for generate_pdf/1 while you’re here).

✅ Proposed update
+  `@doc` "Generates HTML from FA(3) XML using xsltproc with fallback."
+  `@spec` generate_html(String.t(), map()) :: {:ok, String.t()} | {:error, term()}
   def generate_html(xml_content, metadata \\ %{}) do
     case Xsltproc.transform(xml_content, metadata) do
       {:ok, html} ->
         {:ok, html}
@@
         Logger.debug("Xsltproc failed, using fallback template")
         FallbackTemplate.render(xml_content, metadata)
     end
   end

+  `@doc` "Converts HTML to PDF via Gotenberg."
+  `@spec` generate_pdf(String.t()) :: {:ok, binary()} | {:error, term()}
   def generate_pdf(html) do
     Gotenberg.convert(html)
   end
As per coding guidelines, "Every public function must have `@doc` documentation" and "Every function (public and private) must have `@spec` type specification".
🤖 Fix all issues with AI agents
In `@lib/ksef_hub_web/live/invoice_live/show.ex`:
- Around line 198-200: The file has formatting issues causing CI to fail; run
the Elixir formatter (mix format) on the InvoiceLive.Show module
(lib/ksef_hub_web/live/invoice_live/show.ex) to correct whitespace/indentation
and trailing HTML fragments (e.g., the render/0 or render/1 template that
contains the closing divs), then commit the formatted file so CI passes; ensure
the module name InvoiceLive.Show and its render function are formatted
consistently with project style.

In `@lib/ksef_hub/invoices.ex`:
- Around line 69-110: The pre-check using Repo.exists? in upsert_invoice creates
a TOCTOU race; remove the existed? check and instead determine inserted vs
updated from the single DB-returned row after Repo.insert (which already uses
conflict_target and returning: true) by comparing timestamp fields on the
returned Invoice (e.g., compare invoice.inserted_at and invoice.updated_at or
check whether updated_at changed) to decide :inserted or :updated; alternatively
wrap the operation in a Repo.transaction and use the returned invoice within the
same transaction to ensure atomicity—update the branch that matches on
Repo.insert/2 to compute the atom from the returned invoice timestamps rather
than from existed?.

In `@lib/ksef_hub/ksef_client/token_manager.ex`:
- Around line 194-200: The warning logs raw API response bodies in the {:error,
reason} branch; change it to avoid leaking sensitive response bodies by
pattern-matching known KSeF error tuples and logging only the status (e.g.,
match {:ksef_error, status, _} and call Logger.warning("Token refresh failed,
re-auth required: status=#{status}")), and for any other reason log a generic
message without interpolating the full reason (e.g., Logger.warning("Token
refresh failed, re-auth required")). Ensure the clause still returns {:error,
:reauth_required} as shown and keep the existing {:error, {:request_failed, _}}
branch behavior.

In `@priv/xsl/WspolneSzablonyWizualizacji_v12-0E.xsl`:
- Around line 699-722: There are two identical templates matching
"*[local-name()='Naglowek']/*[local-name()='KodUrzedu'] |
*[local-name()='Naglowek']/*[local-name()='PoprzedniNaczelnikUS']" causing a
duplicate; either remove the unintended duplicate or consolidate them into one
template that chooses between $schema-urzedow and $schema-urzedowexwus (or
between 'TKodUS' and 'TKodUS1') before calling the named template
ZnajdzWEnumeracji, or give each template a distinct mode and update callers to
use that mode; modify the template(s) to pass the correct schema/typ based on a
clear condition or mode so only one matching template applies at runtime.
- Around line 7-8: The schema-walut parameter ('schema-walut') points to a
remote XSD URL which will break the document() call inside the ZnajdzWEnumeracji
template (referenced at lines where ZnajdzWEnumeracji is called and document()
is used); fix by ensuring KodyWalut_v1-0E.xsd is available locally and change
the schema-walut parameter to reference the local filename (or run the
update-ksef-stylesheet.sh end-to-end so it downloads and patches the path); keep
the parameter name 'schema-walut' and ensure the local path matches what
ZnajdzWEnumeracji/document() expects.
🧹 Nitpick comments (3)
lib/ksef_hub/invoices.ex (1)

75-111: Consider extracting helpers to keep upsert_invoice/1 compact.

The function now mixes query, changeset construction, conflict fields, and result tagging; a couple of small helpers would improve readability and align with the size guideline.

As per coding guidelines, Keep functions small and focused (< 15 lines ideally) in Elixir.

scripts/update-ksef-stylesheet.sh (1)

28-40: Inconsistent curl options in XSD download loop.

The XSD download loop at line 31 uses hardcoded timeout values instead of the CURL_OPTS variable defined at line 12. Consider using ${CURL_OPTS} for consistency.

Suggested fix
   for xsd_url in $(grep -oP "select=\"'\\Khttps?://[^']*\\.xsd" "${XSL_DIR}/${SHARED_FILENAME}" || true); do
     xsd_file=$(basename "${xsd_url}")
     echo "  Downloading ${xsd_file}..."
-    if curl --connect-timeout 10 --max-time 30 -fsSL "${xsd_url}" -o "${XSL_DIR}/${xsd_file}" 2>/dev/null; then
+    if curl ${CURL_OPTS} "${xsd_url}" -o "${XSL_DIR}/${xsd_file}" 2>/dev/null; then
       echo "    OK"
lib/ksef_hub_web/live/team_live.ex (1)

214-214: Consider updating data-testid to reflect merged table content.

The data-testid="pending-invitations" on the table is misleading since it now contains both members and pending invitations. Consider renaming to something like "team-table" or "members-and-invitations".

Suggested fix
-          <table class="table table-sm" data-testid="pending-invitations">
+          <table class="table table-sm" data-testid="team-table">

Comment thread lib/ksef_hub_web/live/invoice_live/show.ex Outdated
Comment thread lib/ksef_hub/invoices.ex Outdated
Comment thread lib/ksef_hub/ksef_client/token_manager.ex
Comment thread priv/xsl/WspolneSzablonyWizualizacji_v12-0E.xsl Outdated
Comment thread priv/xsl/WspolneSzablonyWizualizacji_v12-0E.xsl
emilwojtaszek and others added 4 commits February 11, 2026 23:30
…non-idempotent KSeF endpoints

- Correct download_and_upsert/3 @SPEC to match 3-element ok tuple
- Add data-role attribute to invitation badge, assert on it in test
- Introduce req_options_no_retry/0 for non-idempotent KSeF API calls
  (get_challenge, authenticate_xades, redeem_tokens, refresh_access_token,
  terminate_session) to prevent duplicate side effects on transient errors

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…and remote URLs

- Remove invoice_exists? check before upsert; determine insert vs update
  by comparing inserted_at/updated_at timestamps on the returned row
- Sanitize token_manager logging to avoid leaking sensitive API response
  bodies in the catch-all error branch
- Consolidate duplicate KodUrzedu/PoprzedniNaczelnikUS XSL templates
  into one with primary/fallback lookup
- Replace remote XSD URLs in XSL params with local filenames and add
  placeholder XSD files for KodyWalut and KodyNaczelnikow
- Fix formatting in show.ex (CI blocker)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…URL_OPTS

- Add @doc and @SPEC to generate_html/2 and generate_pdf/1 in Pdf module
  to satisfy project documentation conventions
- Rename data-testid from "pending-invitations" to "team-table" since the
  table contains all members, not just pending invitations
- Update team_live_test selectors to match renamed testid
- Use $CURL_OPTS variable in update-ksef-stylesheet.sh instead of
  hardcoded curl flags for consistency

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
lib/ksef_hub/ksef_client/live.ex (1)

213-231: ⚠️ Potential issue | 🔴 Critical

Implement proactive rate limiting per coding guidelines.

The code relies only on reactive 429 handling, but the coding guidelines require proactive rate limiting: 8 req/s for invoice downloads (Process.sleep(125) between requests) and 2 req/s for KSeF queries (Process.sleep(500) between queries). Both download_invoice and query_invoice_metadata are called in loops without rate limiting delays, causing unnecessary API errors. The orphaned RateLimiter module exists but is unused and not integrated.

🤖 Fix all issues with AI agents
In `@priv/xsl/KodyWalut_v1-0E.xsd`:
- Around line 1-2: The empty XSD priv/xsl/KodyWalut_v1-0E.xsd is referenced by
the XSLT template ZnajdzWEnumeracji to enumerate values for the type TKodWaluty
but defines no types, causing runtime failures; fix by either adding an
explanatory comment matching the pattern used in KodyUrzedowSkarbowych_v8-0E.xsd
(stating this is a placeholder because the authoritative schema couldn’t be
downloaded) or by implementing the missing TKodWaluty enumeration/type
definitions (or adding an xs:import to the real schema) so that
ZnajdzWEnumeracji can successfully load and enumerate currency codes.

In `@scripts/update-ksef-stylesheet.sh`:
- Around line 56-66: Make the ksef_number injections idempotent by checking for
existing fragments before inserting: test for an existing <xsl:param
name="ksef_number"> (grep -q '<xsl:param name="ksef_number"' fa3-styl.xsl) and
only run the sed that adds the param if that check fails, and likewise test for
the injected block (grep -q 'Numer KSeF' or the exact '<xsl:if
test="$ksef_number' ... 'Numer KSeF'>' snippet) and only run the sed that
appends the NaglowekTytulowyKSeF + Numer KSeF block if not present; keep the
same inserted content and preserve the .bak/remove steps but guard both
insertions with these existence checks so reruns do not duplicate the param or
the display block.

Comment on lines +1 to +2
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"/>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, locate and verify the file exists and show its actual contents
find . -name "KodyWalut_v1-0E.xsd" -type f

Repository: appunite/appunite-ksef-ex

Length of output: 99


🏁 Script executed:

# Check the actual file size and contents
if [ -f "priv/xsl/KodyWalut_v1-0E.xsd" ]; then
  echo "=== File exists ===" && \
  wc -l priv/xsl/KodyWalut_v1-0E.xsd && \
  cat -n priv/xsl/KodyWalut_v1-0E.xsd
fi

Repository: appunite/appunite-ksef-ex

Length of output: 229


🏁 Script executed:

# Search for references to this schema file in the codebase
rg "KodyWalut_v1-0E" --type-list

Repository: appunite/appunite-ksef-ex

Length of output: 458


🏁 Script executed:

# Search for XSD schema imports, references, or validations
rg -i "KodyWalut|xsd.*schema|schema.*xsd" -t xml -t xsl -t py -t js

Repository: appunite/appunite-ksef-ex

Length of output: 96


🏁 Script executed:

# Check for related XSD files in the same directory
ls -la priv/xsl/*.xsd 2>/dev/null || echo "No XSD files found"

Repository: appunite/appunite-ksef-ex

Length of output: 517


🏁 Script executed:

# Check git history for this file (commit message and changes)
git log --oneline -n 20 -- "priv/xsl/KodyWalut_v1-0E.xsd" 2>/dev/null || echo "No git history available"

Repository: appunite/appunite-ksef-ex

Length of output: 119


🏁 Script executed:

# Check content of other small XSD files to see if they're also empty
echo "=== KodyNaczelnikowUrzedowSkarbowych_v4-0E.xsd ===" && \
cat priv/xsl/KodyNaczelnikowUrzedowSkarbowych_v4-0E.xsd && \
echo -e "\n=== KodyUrzedowSkarbowychExWUS_v8-0E.xsd ===" && \
cat priv/xsl/KodyUrzedowSkarbowychExWUS_v8-0E.xsd && \
echo -e "\n=== KodyUrzedowSkarbowych_v8-0E.xsd ===" && \
cat priv/xsl/KodyUrzedowSkarbowych_v8-0E.xsd

Repository: appunite/appunite-ksef-ex

Length of output: 660


🏁 Script executed:

# Search for references to KodyWalut or schema imports in XML files
rg "KodyWalut" -t xml -t html

Repository: appunite/appunite-ksef-ex

Length of output: 181


🏁 Script executed:

# Search for schema validation or XSD references in the codebase
rg "schema" -t xml -t html -A 2 -B 2

Repository: appunite/appunite-ksef-ex

Length of output: 6073


🏁 Script executed:

# Look for any validation logic in code files
rg -i "validate|xsd|schema" -t py --max-count 20

Repository: appunite/appunite-ksef-ex

Length of output: 217


🏁 Script executed:

# Check if there are any XSLT or processing instructions referencing this schema
rg "schemaLocation|import|include" -t xml

Repository: appunite/appunite-ksef-ex

Length of output: 209


Add explanatory comment to empty currency codes schema, or implement the missing type definitions.

This XSD is actively referenced in WspolneSzablonyWizualizacji_v12-0E.xsl where the XSLT template ZnajdzWEnumeracji attempts to load it via document() and enumerate values for type TKodWaluty. Since the schema defines no types, currency code lookups will fail at runtime.

Compare with similar placeholder schemas in the same directory (e.g., KodyUrzedowSkarbowych_v8-0E.xsd), which include comments explaining they are placeholders that "could not download from gov.pl." Either add a similar explanatory comment to document this limitation, or include the actual currency code type definitions or an xs:import reference.

🤖 Prompt for AI Agents
In `@priv/xsl/KodyWalut_v1-0E.xsd` around lines 1 - 2, The empty XSD
priv/xsl/KodyWalut_v1-0E.xsd is referenced by the XSLT template
ZnajdzWEnumeracji to enumerate values for the type TKodWaluty but defines no
types, causing runtime failures; fix by either adding an explanatory comment
matching the pattern used in KodyUrzedowSkarbowych_v8-0E.xsd (stating this is a
placeholder because the authoritative schema couldn’t be downloaded) or by
implementing the missing TKodWaluty enumeration/type definitions (or adding an
xs:import to the real schema) so that ZnajdzWEnumeracji can successfully load
and enumerate currency codes.

Comment on lines +56 to +66
# Add ksef_number param (not in gov stylesheet, injected by our system)
echo "Adding ksef_number parameter..."
sed -i.bak '/<xsl:output/a\
<xsl:param name="ksef_number" select="'\'''\''"/>
' "${XSL_DIR}/fa3-styl.xsl"
rm -f "${XSL_DIR}/fa3-styl.xsl.bak"

# Add KSeF number display after NaglowekTytulowyKSeF call
sed -i.bak 's|<xsl:call-template name="NaglowekTytulowyKSeF"/>|<xsl:call-template name="NaglowekTytulowyKSeF"/>\
<xsl:if test="$ksef_number != '\'''\''"><div style="text-align:right; margin-bottom:0.5em; font-size:0.9em;">Numer KSeF: <b><xsl:value-of select="$ksef_number"/></b></div></xsl:if>|' "${XSL_DIR}/fa3-styl.xsl"
rm -f "${XSL_DIR}/fa3-styl.xsl.bak"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Make the ksef_number injection idempotent.

Re-running the script will append duplicate <xsl:param name="ksef_number"> entries and repeated “Numer KSeF” blocks, which can break validation or render duplicates. Guard the inserts so reruns are safe.

🛠️ Suggested fix (idempotent guards)
 # Add ksef_number param (not in gov stylesheet, injected by our system)
 echo "Adding ksef_number parameter..."
-sed -i.bak '/<xsl:output/a\
-	<xsl:param name="ksef_number" select="'"''"'"/>
-' "${XSL_DIR}/fa3-styl.xsl"
-rm -f "${XSL_DIR}/fa3-styl.xsl.bak"
+if ! grep -q 'name="ksef_number"' "${XSL_DIR}/fa3-styl.xsl"; then
+  sed -i.bak '/<xsl:output/a\
+	<xsl:param name="ksef_number" select="'"''"'"/>
+' "${XSL_DIR}/fa3-styl.xsl"
+  rm -f "${XSL_DIR}/fa3-styl.xsl.bak"
+fi
 
 # Add KSeF number display after NaglowekTytulowyKSeF call
-sed -i.bak 's|<xsl:call-template name="NaglowekTytulowyKSeF"/>|<xsl:call-template name="NaglowekTytulowyKSeF"/>\
-			<xsl:if test="$ksef_number != '"'"''"'"'"><div style="text-align:right; margin-bottom:0.5em; font-size:0.9em;">Numer KSeF: <b><xsl:value-of select="$ksef_number"/></b></div></xsl:if>|' "${XSL_DIR}/fa3-styl.xsl"
-rm -f "${XSL_DIR}/fa3-styl.xsl.bak"
+if ! grep -q 'Numer KSeF:' "${XSL_DIR}/fa3-styl.xsl"; then
+  sed -i.bak 's|<xsl:call-template name="NaglowekTytulowyKSeF"/>|<xsl:call-template name="NaglowekTytulowyKSeF"/>\
+			<xsl:if test="$ksef_number != '"'"''"'"'"><div style="text-align:right; margin-bottom:0.5em; font-size:0.9em;">Numer KSeF: <b><xsl:value-of select="$ksef_number"/></b></div></xsl:if>|' "${XSL_DIR}/fa3-styl.xsl"
+  rm -f "${XSL_DIR}/fa3-styl.xsl.bak"
+fi
🤖 Prompt for AI Agents
In `@scripts/update-ksef-stylesheet.sh` around lines 56 - 66, Make the ksef_number
injections idempotent by checking for existing fragments before inserting: test
for an existing <xsl:param name="ksef_number"> (grep -q '<xsl:param
name="ksef_number"' fa3-styl.xsl) and only run the sed that adds the param if
that check fails, and likewise test for the injected block (grep -q 'Numer KSeF'
or the exact '<xsl:if test="$ksef_number' ... 'Numer KSeF'>' snippet) and only
run the sed that appends the NaglowekTytulowyKSeF + Numer KSeF block if not
present; keep the same inserted content and preserve the .bak/remove steps but
guard both insertions with these existence checks so reruns do not duplicate the
param or the display block.

emilwojtaszek and others added 2 commits February 12, 2026 00:20
Add Process.sleep delays before query_invoice_metadata (500ms, 2 req/s)
and download_invoice (125ms, 8 req/s) in the Live client per KSeF rate
limit guidelines. Use RateLimiter.handle_rate_limit/1 for reactive 429
handling in InvoiceFetcher with jitter.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The GenServer was never started in the supervision tree and never called.
Proactive rate limiting uses simple Process.sleep delays in the Live
client; reactive 429 handling uses inline sleep with jitter in
InvoiceFetcher.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@emilwojtaszek emilwojtaszek merged commit 0c12996 into main Feb 11, 2026
3 checks passed
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.

1 participant