Skip to content

feat(eet): report sales to eet 2.0, with settings, status and a sandbox - #99

Merged
pepakriz merged 7 commits into
finitoapp:mainfrom
i-am-fatik:feat/eet2-sales-reporting
Sep 29, 2026
Merged

pepakriz merged 7 commits into
finitoapp:mainfrom
i-am-fatik:feat/eet2-sales-reporting

Conversation

@i-am-fatik

@i-am-fatik i-am-fatik commented Sep 27, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Closes #24.

  • Reporting. Every payment received while EET is enabled gets one sale record, frozen at creation so a resend describes the same sale. A background job sends it and retries with backoff until a signed POK arrives. EET never changes a payment or bill status: a sale EET has not confirmed stays paid. The job runs in the native app and the browser, not in the CLI, which has no terminal device.
  • Protocol. Built on @finitoapp/eet-client, which builds, signs and verifies the EET 2.0 messages. Payky owns the records, the queue and reading the .p12 certificate.
  • Status. The payment detail shows the POK, warnings and the last error with a manual resend. Every payment row of the bill detail carries a status badge.
  • Settings. EET is off by default. A merchant imports the cash-register certificate, enters the establishment number, picks the environment, sends a verification-mode test and sees unconfirmed sales. In the sandbox the official test certificates are one tap away through api/eet/playground-certificates, because the tax administrator's server sends no CORS headers. No test key is committed.
  • Tips. The settings ask whether tips belong to the business or to employees, and explain why next to the choice. A tip is a reported sale only when it is the business's income, so with tips belonging to employees a sale is reported without its tip. The business stays the default, which is the behavior before this choice and always allowed. The rule comes from the tax administrator's seminar for developers, not from the binding interface specification.
  • Sandbox marking. With the playground selected, a banner on every terminal screen and a note on the paid screen show that sales are not reported to the tax administrator.
  • Production endpoint. It comes from VITE_PAYKY_EET_PRODUCTION_URL. A build without it offers only the playground.

Test plan

  • bun run check passes on every commit (844 tests on the last). Under a load average of about 10, two runs timed out on expect.poll in eet-reporting-job.test.ts and passed on rerun.
  • e2e/eet.spec.ts passes 11/11 with --workers=2, against a fake EET responder and a generated certificate, including a 10 % tip left out of celk_trzba when tips belong to employees
  • vite build keeps the certificate parsing in a lazy chunk, and fflate stays out of the client bundle

🤖 Generated with Claude Code

@vercel

vercel Bot commented Sep 27, 2026

Copy link
Copy Markdown

@i-am-fatik is attempting to deploy a commit to the Josef K's projects Team on Vercel.

A member of the Team first needs to authorize it.

@vercel

vercel Bot commented Sep 28, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
payky Ready Ready Preview Sep 29, 2026 8:48am UTC

Comment thread src/core/background-jobs/background-jobs.ts
Comment thread src/core/background-jobs/jobs/eet-reporting-job.ts
@pepakriz pepakriz added the run-e2e Runs the Playwright e2e suite (production build) in CI for this PR label Sep 29, 2026
EET 2.0 takes the sale total with the currency's full fraction digits,
"250.00", while minorUnitsToDecimalString trims it to "250" for display.
EET 2.0 obliges a Czech merchant to report every in-person sale whatever
the payment form, and production accepts sales from 1 November 2026.
Each payment received while EET is enabled gets one sale record, frozen
at creation so every resend describes the same sale, and the job resends
it with backoff until a signed POK arrives. A payment stays paid
whatever EET answers.

The protocol comes from @finitoapp/eet-client, Payky owns only the
records, the queue and reading the certificate. The job runs in the
native app and the browser but not in the CLI, which has no terminal
device to report from, so the CLI list is now cliBackgroundJobs. The
production endpoint comes from VITE_PAYKY_EET_PRODUCTION_URL, and a
build without it offers only the playground.
…etail

Staff need to see whether EET confirmed a sale, and to resend one it
refused without waiting for the next automatic retry. The payment detail
shows the POK, warnings and the last error with a manual resend, and
every payment row of the bill detail carries the status badge.
…s a tap away

A merchant turns EET on, imports the cash-register certificate, enters
the establishment number, picks the environment, sends a test in
verification mode and sees the sales EET has not confirmed yet. It stays
off by default. The official playground certificates come through
api/eet/playground-certificates, because the tax administrator's server
sends no CORS headers, so no test key is ever committed.
With the playground selected every sale is still sent, just never to the
tax administrator, so a banner on every terminal screen and a note on
the paid screen keep staff from taking a sandbox sale for a reported
one. Layouts make room for the banner through --terminal-banner-height.
The spec answers from a fake EET responder with a generated certificate,
never the shared playground ones. Payments made through the e2e bridge
now carry the terminal device, since the job reports only its own
device's payments, and both the dev server and the preview build get an
.invalid production URL so the production path runs too.
…sale

A tip is a reported EET sale only when it is the business's income. A
tip that belongs to employees is not subject to EET, and only employees'
tips can be exempt from income tax, so a restaurant whose staff keep the
tips needs its sales reported without them. Payky cannot know who a tip
belongs to, so the EET settings now ask, with the reasons spelled out
next to the choice. The business stays the default, which is today's
behavior and always allowed, since employees' tips may be reported
voluntarily. The choice is read once when a sale is frozen, so it never
rewrites a sale already created.

The rule comes from the tax administrator's seminar for developers, not
from the binding interface specification.
@pepakriz
pepakriz force-pushed the feat/eet2-sales-reporting branch from 80711ca to f21d46a Compare September 29, 2026 09:09
@pepakriz pepakriz removed the run-e2e Runs the Playwright e2e suite (production build) in CI for this PR label Sep 29, 2026
@pepakriz
pepakriz merged commit a49a60a into finitoapp:main Sep 29, 2026
2 of 3 checks passed
@i-am-fatik
i-am-fatik deleted the feat/eet2-sales-reporting branch September 29, 2026 15:48
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.

Add Czech EET 2.0 integration

2 participants