diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 7723619..15718f2 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -6,10 +6,6 @@ on: types: [published] jobs: - analysis: - uses: ./.github/workflows/sonarcloud.yml - secrets: inherit - build: uses: ./.github/workflows/build.yml @@ -17,6 +13,11 @@ jobs: needs: build uses: ./.github/workflows/test.yml secrets: inherit + + analysis: + needs: test + uses: ./.github/workflows/sonarcloud.yml + secrets: inherit publish-npm: needs: [test, analysis] diff --git a/.github/workflows/pr-check-suite.yml b/.github/workflows/pr-check-suite.yml index 112fda6..3808744 100644 --- a/.github/workflows/pr-check-suite.yml +++ b/.github/workflows/pr-check-suite.yml @@ -13,10 +13,6 @@ permissions: pull-requests: write jobs: - analysis: - uses: ./.github/workflows/sonarcloud.yml - secrets: inherit - build: uses: ./.github/workflows/build.yml @@ -24,4 +20,9 @@ jobs: needs: build uses: ./.github/workflows/test.yml secrets: inherit + + analysis: + needs: test + uses: ./.github/workflows/sonarcloud.yml + secrets: inherit diff --git a/.github/workflows/sonarcloud.yml b/.github/workflows/sonarcloud.yml index 82eee80..884e56d 100644 --- a/.github/workflows/sonarcloud.yml +++ b/.github/workflows/sonarcloud.yml @@ -14,9 +14,19 @@ jobs: SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} with: fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis + + - name: Download coverage artifact + if: env.SONAR_TOKEN + uses: actions/download-artifact@v4 + env: + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + with: + name: coverage + path: coverage/ + - name: SonarCloud Scan if: env.SONAR_TOKEN - uses: SonarSource/sonarcloud-github-action@master + uses: SonarSource/sonarqube-scan-action@master env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 7c0aa00..ee7ade2 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -45,4 +45,11 @@ jobs: token: ${{ secrets.CODECOV_TOKEN }} files: ./coverage/coverage-final.json flags: unittests - name: codecov-umbrella \ No newline at end of file + name: codecov-umbrella + + - name: Upload coverage artifact + uses: actions/upload-artifact@v4 + with: + name: coverage + path: coverage/ + retention-days: 1 \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index b41f327..069e319 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,35 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.0.3] - 2025-12-03 + +### Changed +- **BREAKING:** `DailyClosure` type structure completely rewritten to match actual Satispay API response + - Now returns `shop_daily_closure` and `device_daily_closure` objects + - Each closure includes: `id`, `type`, `customer_uid`, `gross_amount_unit`, `refund_amount_unit`, `amount_unit`, `currency` +- **BREAKING:** Removed non-existent fields from `DailyClosure` type: + - Removed `date` field (use `shop_daily_closure.id` instead) + - Removed `total_amount_unit` field (use `shop_daily_closure.amount_unit` instead) + - Removed `payments_count` field (not provided by Satispay API) +- `DailyClosure.get()` now accepts `Date` objects in addition to string dates (YYYYMMDD format) +- Updated documentation with correct API response structure and `Date` object usage examples + +### Added +- `DailyClosureDetail` type for structured closure information +- `DateUtils.formatToYYYYMMDD()` utility function for date formatting +- Comprehensive E2E tests for daily closure functionality (5 test cases) +- Unit tests for `Date` object support in `DailyClosure.get()` +- Enhanced examples showing multiple ways to retrieve daily closures + +### Fixed +- `DailyClosure` type now accurately reflects Satispay's actual API response +- Corrected documentation to match real API behavior verified through testing + +## [0.0.2] - 2025-12-01 + +### Fixed +- add bin `satispay-keygen` to build configuration + ## [0.0.1] - 2025-12-01 ### Added @@ -37,4 +66,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Example files for all major operations (payments, reports, sessions, webhooks, etc.) - Runtime-specific examples for Node.js, Deno, and Bun +[0.0.3]: https://github.com/volverjs/zod-vue-i18n/compare/v0.0.2...v0.0.3 +[0.0.2]: https://github.com/volverjs/zod-vue-i18n/compare/v0.0.1...v0.0.2 [0.0.1]: https://github.com/volverjs/satispay-node-sdk/releases/tag/v0.0.1 diff --git a/README.md b/README.md index c22dacd..ac2faa4 100644 --- a/README.md +++ b/README.md @@ -231,12 +231,18 @@ import { DailyClosure } from '@volverjs/satispay-node-sdk'; // Today's closure const closure = await DailyClosure.get(); -// Specific date (YYYYMMDD format) -const closureByDate = await DailyClosure.get('20240115'); +// Specific date using Date object (recommended) +const yesterday = new Date(); +yesterday.setDate(yesterday.getDate() - 1); +const closureByDate = await DailyClosure.get(yesterday); + +// Or using YYYYMMDD string format +const closureByString = await DailyClosure.get('20240115'); -console.log('Date:', closure.date); -console.log('Total:', closure.total_amount_unit / 100, closure.currency); -console.log('Payments:', closure.payments_count); +console.log('Date:', closure.shop_daily_closure.id); +console.log('Total:', closure.shop_daily_closure.amount_unit / 100, closure.shop_daily_closure.currency); +console.log('Gross:', closure.shop_daily_closure.gross_amount_unit / 100); +console.log('Refunds:', closure.shop_daily_closure.refund_amount_unit / 100); ``` ### Pre-Authorized Payment Tokens diff --git a/package.json b/package.json index 5196598..dfe5a7e 100644 --- a/package.json +++ b/package.json @@ -63,16 +63,16 @@ "devDependencies": { "@eslint/js": "^9.39.1", "@types/node": "^24.10.1", - "@vitest/coverage-v8": "^4.0.14", - "@vitest/ui": "^4.0.14", + "@vitest/coverage-v8": "^4.0.15", + "@vitest/ui": "^4.0.15", "dotenv": "^17.2.3", "eslint": "^9.39.1", "eslint-plugin-vitest": "^0.5.4", - "prettier": "^3.7.3", + "prettier": "^3.7.4", "typescript": "^5.9.3", - "typescript-eslint": "^8.48.0", + "typescript-eslint": "^8.48.1", "vite": "^7.2.6", "vite-plugin-dts": "^4.5.4", - "vitest": "^4.0.14" + "vitest": "^4.0.15" } } \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d866d4b..74720be 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -15,11 +15,11 @@ importers: specifier: ^24.10.1 version: 24.10.1 '@vitest/coverage-v8': - specifier: ^4.0.14 - version: 4.0.14(vitest@4.0.14) + specifier: ^4.0.15 + version: 4.0.15(vitest@4.0.15) '@vitest/ui': - specifier: ^4.0.14 - version: 4.0.14(vitest@4.0.14) + specifier: ^4.0.15 + version: 4.0.15(vitest@4.0.15) dotenv: specifier: ^17.2.3 version: 17.2.3 @@ -28,16 +28,16 @@ importers: version: 9.39.1 eslint-plugin-vitest: specifier: ^0.5.4 - version: 0.5.4(eslint@9.39.1)(typescript@5.9.3)(vitest@4.0.14) + version: 0.5.4(eslint@9.39.1)(typescript@5.9.3)(vitest@4.0.15) prettier: - specifier: ^3.7.3 - version: 3.7.3 + specifier: ^3.7.4 + version: 3.7.4 typescript: specifier: ^5.9.3 version: 5.9.3 typescript-eslint: - specifier: ^8.48.0 - version: 8.48.0(eslint@9.39.1)(typescript@5.9.3) + specifier: ^8.48.1 + version: 8.48.1(eslint@9.39.1)(typescript@5.9.3) vite: specifier: ^7.2.6 version: 7.2.6(@types/node@24.10.1) @@ -45,8 +45,8 @@ importers: specifier: ^4.5.4 version: 4.5.4(@types/node@24.10.1)(rollup@4.53.2)(typescript@5.9.3)(vite@7.2.6(@types/node@24.10.1)) vitest: - specifier: ^4.0.14 - version: 4.0.14(@types/node@24.10.1)(@vitest/ui@4.0.14) + specifier: ^4.0.15 + version: 4.0.15(@types/node@24.10.1)(@vitest/ui@4.0.15) packages: @@ -497,23 +497,23 @@ packages: '@types/node@24.10.1': resolution: {integrity: sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==} - '@typescript-eslint/eslint-plugin@8.48.0': - resolution: {integrity: sha512-XxXP5tL1txl13YFtrECECQYeZjBZad4fyd3cFV4a19LkAY/bIp9fev3US4S5fDVV2JaYFiKAZ/GRTOLer+mbyQ==} + '@typescript-eslint/eslint-plugin@8.48.1': + resolution: {integrity: sha512-X63hI1bxl5ohelzr0LY5coufyl0LJNthld+abwxpCoo6Gq+hSqhKwci7MUWkXo67mzgUK6YFByhmaHmUcuBJmA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': ^8.48.0 + '@typescript-eslint/parser': ^8.48.1 eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/parser@8.48.0': - resolution: {integrity: sha512-jCzKdm/QK0Kg4V4IK/oMlRZlY+QOcdjv89U2NgKHZk1CYTj82/RVSx1mV/0gqCVMJ/DA+Zf/S4NBWNF8GQ+eqQ==} + '@typescript-eslint/parser@8.48.1': + resolution: {integrity: sha512-PC0PDZfJg8sP7cmKe6L3QIL8GZwU5aRvUFedqSIpw3B+QjRSUZeeITC2M5XKeMXEzL6wccN196iy3JLwKNvDVA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/project-service@8.48.0': - resolution: {integrity: sha512-Ne4CTZyRh1BecBf84siv42wv5vQvVmgtk8AuiEffKTUo3DrBaGYZueJSxxBZ8fjk/N3DrgChH4TOdIOwOwiqqw==} + '@typescript-eslint/project-service@8.48.1': + resolution: {integrity: sha512-HQWSicah4s9z2/HifRPQ6b6R7G+SBx64JlFQpgSSHWPKdvCZX57XCbszg/bapbRsOEv42q5tayTYcEFpACcX1w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' @@ -522,18 +522,18 @@ packages: resolution: {integrity: sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA==} engines: {node: ^18.18.0 || >=20.0.0} - '@typescript-eslint/scope-manager@8.48.0': - resolution: {integrity: sha512-uGSSsbrtJrLduti0Q1Q9+BF1/iFKaxGoQwjWOIVNJv0o6omrdyR8ct37m4xIl5Zzpkp69Kkmvom7QFTtue89YQ==} + '@typescript-eslint/scope-manager@8.48.1': + resolution: {integrity: sha512-rj4vWQsytQbLxC5Bf4XwZ0/CKd362DkWMUkviT7DCS057SK64D5lH74sSGzhI6PDD2HCEq02xAP9cX68dYyg1w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/tsconfig-utils@8.48.0': - resolution: {integrity: sha512-WNebjBdFdyu10sR1M4OXTt2OkMd5KWIL+LLfeH9KhgP+jzfDV/LI3eXzwJ1s9+Yc0Kzo2fQCdY/OpdusCMmh6w==} + '@typescript-eslint/tsconfig-utils@8.48.1': + resolution: {integrity: sha512-k0Jhs4CpEffIBm6wPaCXBAD7jxBtrHjrSgtfCjUvPp9AZ78lXKdTR8fxyZO5y4vWNlOvYXRtngSZNSn+H53Jkw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/type-utils@8.48.0': - resolution: {integrity: sha512-zbeVaVqeXhhab6QNEKfK96Xyc7UQuoFWERhEnj3mLVnUWrQnv15cJNseUni7f3g557gm0e46LZ6IJ4NJVOgOpw==} + '@typescript-eslint/type-utils@8.48.1': + resolution: {integrity: sha512-1jEop81a3LrJQLTf/1VfPQdhIY4PlGDBc/i67EVWObrtvcziysbLN3oReexHOM6N3jyXgCrkBsZpqwH0hiDOQg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 @@ -543,8 +543,8 @@ packages: resolution: {integrity: sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==} engines: {node: ^18.18.0 || >=20.0.0} - '@typescript-eslint/types@8.48.0': - resolution: {integrity: sha512-cQMcGQQH7kwKoVswD1xdOytxQR60MWKM1di26xSUtxehaDs/32Zpqsu5WJlXTtTTqyAVK8R7hvsUnIXRS+bjvA==} + '@typescript-eslint/types@8.48.1': + resolution: {integrity: sha512-+fZ3LZNeiELGmimrujsDCT4CRIbq5oXdHe7chLiW8qzqyPMnn1puNstCrMNVAqwcl2FdIxkuJ4tOs/RFDBVc/Q==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@typescript-eslint/typescript-estree@7.18.0': @@ -556,8 +556,8 @@ packages: typescript: optional: true - '@typescript-eslint/typescript-estree@8.48.0': - resolution: {integrity: sha512-ljHab1CSO4rGrQIAyizUS6UGHHCiAYhbfcIZ1zVJr5nMryxlXMVWS3duFPSKvSUbFPwkXMFk1k0EMIjub4sRRQ==} + '@typescript-eslint/typescript-estree@8.48.1': + resolution: {integrity: sha512-/9wQ4PqaefTK6POVTjJaYS0bynCgzh6ClJHGSBj06XEHjkfylzB+A3qvyaXnErEZSaxhIo4YdyBgq6j4RysxDg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' @@ -568,8 +568,8 @@ packages: peerDependencies: eslint: ^8.56.0 - '@typescript-eslint/utils@8.48.0': - resolution: {integrity: sha512-yTJO1XuGxCsSfIVt1+1UrLHtue8xz16V8apzPYI06W0HbEbEWHxHXgZaAgavIkoh+GeV6hKKd5jm0sS6OYxWXQ==} + '@typescript-eslint/utils@8.48.1': + resolution: {integrity: sha512-fAnhLrDjiVfey5wwFRwrweyRlCmdz5ZxXz2G/4cLn0YDLjTapmN4gcCsTBR1N2rWnZSDeWpYtgLDsJt+FpmcwA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 @@ -579,24 +579,24 @@ packages: resolution: {integrity: sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==} engines: {node: ^18.18.0 || >=20.0.0} - '@typescript-eslint/visitor-keys@8.48.0': - resolution: {integrity: sha512-T0XJMaRPOH3+LBbAfzR2jalckP1MSG/L9eUtY0DEzUyVaXJ/t6zN0nR7co5kz0Jko/nkSYCBRkz1djvjajVTTg==} + '@typescript-eslint/visitor-keys@8.48.1': + resolution: {integrity: sha512-BmxxndzEWhE4TIEEMBs8lP3MBWN3jFPs/p6gPm/wkv02o41hI6cq9AuSmGAaTTHPtA1FTi2jBre4A9rm5ZmX+Q==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@vitest/coverage-v8@4.0.14': - resolution: {integrity: sha512-EYHLqN/BY6b47qHH7gtMxAg++saoGmsjWmAq9MlXxAz4M0NcHh9iOyKhBZyU4yxZqOd8Xnqp80/5saeitz4Cng==} + '@vitest/coverage-v8@4.0.15': + resolution: {integrity: sha512-FUJ+1RkpTFW7rQITdgTi93qOCWJobWhBirEPCeXh2SW2wsTlFxy51apDz5gzG+ZEYt/THvWeNmhdAoS9DTwpCw==} peerDependencies: - '@vitest/browser': 4.0.14 - vitest: 4.0.14 + '@vitest/browser': 4.0.15 + vitest: 4.0.15 peerDependenciesMeta: '@vitest/browser': optional: true - '@vitest/expect@4.0.14': - resolution: {integrity: sha512-RHk63V3zvRiYOWAV0rGEBRO820ce17hz7cI2kDmEdfQsBjT2luEKB5tCOc91u1oSQoUOZkSv3ZyzkdkSLD7lKw==} + '@vitest/expect@4.0.15': + resolution: {integrity: sha512-Gfyva9/GxPAWXIWjyGDli9O+waHDC0Q0jaLdFP1qPAUUfo1FEXPXUfUkp3eZA0sSq340vPycSyOlYUeM15Ft1w==} - '@vitest/mocker@4.0.14': - resolution: {integrity: sha512-RzS5NujlCzeRPF1MK7MXLiEFpkIXeMdQ+rN3Kk3tDI9j0mtbr7Nmuq67tpkOJQpgyClbOltCXMjLZicJHsH5Cg==} + '@vitest/mocker@4.0.15': + resolution: {integrity: sha512-CZ28GLfOEIFkvCFngN8Sfx5h+Se0zN+h4B7yOsPVCcgtiO7t5jt9xQh2E1UkFep+eb9fjyMfuC5gBypwb07fvQ==} peerDependencies: msw: ^2.4.9 vite: ^6.0.0 || ^7.0.0-0 @@ -606,25 +606,25 @@ packages: vite: optional: true - '@vitest/pretty-format@4.0.14': - resolution: {integrity: sha512-SOYPgujB6TITcJxgd3wmsLl+wZv+fy3av2PpiPpsWPZ6J1ySUYfScfpIt2Yv56ShJXR2MOA6q2KjKHN4EpdyRQ==} + '@vitest/pretty-format@4.0.15': + resolution: {integrity: sha512-SWdqR8vEv83WtZcrfLNqlqeQXlQLh2iilO1Wk1gv4eiHKjEzvgHb2OVc3mIPyhZE6F+CtfYjNlDJwP5MN6Km7A==} - '@vitest/runner@4.0.14': - resolution: {integrity: sha512-BsAIk3FAqxICqREbX8SetIteT8PiaUL/tgJjmhxJhCsigmzzH8xeadtp7LRnTpCVzvf0ib9BgAfKJHuhNllKLw==} + '@vitest/runner@4.0.15': + resolution: {integrity: sha512-+A+yMY8dGixUhHmNdPUxOh0la6uVzun86vAbuMT3hIDxMrAOmn5ILBHm8ajrqHE0t8R9T1dGnde1A5DTnmi3qw==} - '@vitest/snapshot@4.0.14': - resolution: {integrity: sha512-aQVBfT1PMzDSA16Y3Fp45a0q8nKexx6N5Amw3MX55BeTeZpoC08fGqEZqVmPcqN0ueZsuUQ9rriPMhZ3Mu19Ag==} + '@vitest/snapshot@4.0.15': + resolution: {integrity: sha512-A7Ob8EdFZJIBjLjeO0DZF4lqR6U7Ydi5/5LIZ0xcI+23lYlsYJAfGn8PrIWTYdZQRNnSRlzhg0zyGu37mVdy5g==} - '@vitest/spy@4.0.14': - resolution: {integrity: sha512-JmAZT1UtZooO0tpY3GRyiC/8W7dCs05UOq9rfsUUgEZEdq+DuHLmWhPsrTt0TiW7WYeL/hXpaE07AZ2RCk44hg==} + '@vitest/spy@4.0.15': + resolution: {integrity: sha512-+EIjOJmnY6mIfdXtE/bnozKEvTC4Uczg19yeZ2vtCz5Yyb0QQ31QWVQ8hswJ3Ysx/K2EqaNsVanjr//2+P3FHw==} - '@vitest/ui@4.0.14': - resolution: {integrity: sha512-fvDz8o7SQpFLoSBo6Cudv+fE85/fPCkwTnLAN85M+Jv7k59w2mSIjT9Q5px7XwGrmYqqKBEYxh/09IBGd1E7AQ==} + '@vitest/ui@4.0.15': + resolution: {integrity: sha512-sxSyJMaKp45zI0u+lHrPuZM1ZJQ8FaVD35k+UxVrha1yyvQ+TZuUYllUixwvQXlB7ixoDc7skf3lQPopZIvaQw==} peerDependencies: - vitest: 4.0.14 + vitest: 4.0.15 - '@vitest/utils@4.0.14': - resolution: {integrity: sha512-hLqXZKAWNg8pI+SQXyXxWCTOpA3MvsqcbVeNgSi8x/CSN2wi26dSzn1wrOhmCmFjEvN9p8/kLFRHa6PI8jHazw==} + '@vitest/utils@4.0.15': + resolution: {integrity: sha512-HXjPW2w5dxhTD0dLwtYHDnelK3j8sR8cWIaLxr22evTyY6q8pRCjZSmhRWVjBaOVXChQd6AwMzi9pucorXCPZA==} '@volar/language-core@2.4.23': resolution: {integrity: sha512-hEEd5ET/oSmBC6pi1j6NaNYRWoAiDhINbT8rmwtINugR39loROSlufGdYMF9TaKGfz+ViGs1Idi3mAhnuPcoGQ==} @@ -1192,8 +1192,8 @@ packages: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} - prettier@3.7.3: - resolution: {integrity: sha512-QgODejq9K3OzoBbuyobZlUhznP5SKwPqp+6Q6xw6o8gnhr4O85L2U915iM2IDcfF2NPXVaM9zlo9tdwipnYwzg==} + prettier@3.7.4: + resolution: {integrity: sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA==} engines: {node: '>=14'} hasBin: true @@ -1301,8 +1301,9 @@ packages: tinybench@2.9.0: resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} - tinyexec@0.3.2: - resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} + tinyexec@1.0.2: + resolution: {integrity: sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==} + engines: {node: '>=18'} tinyglobby@0.2.15: resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} @@ -1336,8 +1337,8 @@ packages: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} - typescript-eslint@8.48.0: - resolution: {integrity: sha512-fcKOvQD9GUn3Xw63EgiDqhvWJ5jsyZUaekl3KVpGsDJnN46WJTe3jWxtQP9lMZm1LJNkFLlTaWAxK2vUQR+cqw==} + typescript-eslint@8.48.1: + resolution: {integrity: sha512-FbOKN1fqNoXp1hIl5KYpObVrp0mCn+CLgn479nmu2IsRMrx2vyv74MmsBLVlhg8qVwNFGbXSp8fh1zp8pEoC2A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 @@ -1415,18 +1416,18 @@ packages: yaml: optional: true - vitest@4.0.14: - resolution: {integrity: sha512-d9B2J9Cm9dN9+6nxMnnNJKJCtcyKfnHj15N6YNJfaFHRLua/d3sRKU9RuKmO9mB0XdFtUizlxfz/VPbd3OxGhw==} + vitest@4.0.15: + resolution: {integrity: sha512-n1RxDp8UJm6N0IbJLQo+yzLZ2sQCDyl1o0LeugbPWf8+8Fttp29GghsQBjYJVmWq3gBFfe9Hs1spR44vovn2wA==} engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} hasBin: true peerDependencies: '@edge-runtime/vm': '*' '@opentelemetry/api': ^1.9.0 '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 - '@vitest/browser-playwright': 4.0.14 - '@vitest/browser-preview': 4.0.14 - '@vitest/browser-webdriverio': 4.0.14 - '@vitest/ui': 4.0.14 + '@vitest/browser-playwright': 4.0.15 + '@vitest/browser-preview': 4.0.15 + '@vitest/browser-webdriverio': 4.0.15 + '@vitest/ui': 4.0.15 happy-dom: '*' jsdom: '*' peerDependenciesMeta: @@ -1822,14 +1823,14 @@ snapshots: dependencies: undici-types: 7.16.0 - '@typescript-eslint/eslint-plugin@8.48.0(@typescript-eslint/parser@8.48.0(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(typescript@5.9.3)': + '@typescript-eslint/eslint-plugin@8.48.1(@typescript-eslint/parser@8.48.1(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.48.0(eslint@9.39.1)(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.48.0 - '@typescript-eslint/type-utils': 8.48.0(eslint@9.39.1)(typescript@5.9.3) - '@typescript-eslint/utils': 8.48.0(eslint@9.39.1)(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.48.0 + '@typescript-eslint/parser': 8.48.1(eslint@9.39.1)(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.48.1 + '@typescript-eslint/type-utils': 8.48.1(eslint@9.39.1)(typescript@5.9.3) + '@typescript-eslint/utils': 8.48.1(eslint@9.39.1)(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.48.1 eslint: 9.39.1 graphemer: 1.4.0 ignore: 7.0.5 @@ -1839,22 +1840,22 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.48.0(eslint@9.39.1)(typescript@5.9.3)': + '@typescript-eslint/parser@8.48.1(eslint@9.39.1)(typescript@5.9.3)': dependencies: - '@typescript-eslint/scope-manager': 8.48.0 - '@typescript-eslint/types': 8.48.0 - '@typescript-eslint/typescript-estree': 8.48.0(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.48.0 + '@typescript-eslint/scope-manager': 8.48.1 + '@typescript-eslint/types': 8.48.1 + '@typescript-eslint/typescript-estree': 8.48.1(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.48.1 debug: 4.4.3 eslint: 9.39.1 typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.48.0(typescript@5.9.3)': + '@typescript-eslint/project-service@8.48.1(typescript@5.9.3)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.48.0(typescript@5.9.3) - '@typescript-eslint/types': 8.48.0 + '@typescript-eslint/tsconfig-utils': 8.48.1(typescript@5.9.3) + '@typescript-eslint/types': 8.48.1 debug: 4.4.3 typescript: 5.9.3 transitivePeerDependencies: @@ -1865,20 +1866,20 @@ snapshots: '@typescript-eslint/types': 7.18.0 '@typescript-eslint/visitor-keys': 7.18.0 - '@typescript-eslint/scope-manager@8.48.0': + '@typescript-eslint/scope-manager@8.48.1': dependencies: - '@typescript-eslint/types': 8.48.0 - '@typescript-eslint/visitor-keys': 8.48.0 + '@typescript-eslint/types': 8.48.1 + '@typescript-eslint/visitor-keys': 8.48.1 - '@typescript-eslint/tsconfig-utils@8.48.0(typescript@5.9.3)': + '@typescript-eslint/tsconfig-utils@8.48.1(typescript@5.9.3)': dependencies: typescript: 5.9.3 - '@typescript-eslint/type-utils@8.48.0(eslint@9.39.1)(typescript@5.9.3)': + '@typescript-eslint/type-utils@8.48.1(eslint@9.39.1)(typescript@5.9.3)': dependencies: - '@typescript-eslint/types': 8.48.0 - '@typescript-eslint/typescript-estree': 8.48.0(typescript@5.9.3) - '@typescript-eslint/utils': 8.48.0(eslint@9.39.1)(typescript@5.9.3) + '@typescript-eslint/types': 8.48.1 + '@typescript-eslint/typescript-estree': 8.48.1(typescript@5.9.3) + '@typescript-eslint/utils': 8.48.1(eslint@9.39.1)(typescript@5.9.3) debug: 4.4.3 eslint: 9.39.1 ts-api-utils: 2.1.0(typescript@5.9.3) @@ -1888,7 +1889,7 @@ snapshots: '@typescript-eslint/types@7.18.0': {} - '@typescript-eslint/types@8.48.0': {} + '@typescript-eslint/types@8.48.1': {} '@typescript-eslint/typescript-estree@7.18.0(typescript@5.9.3)': dependencies: @@ -1905,12 +1906,12 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/typescript-estree@8.48.0(typescript@5.9.3)': + '@typescript-eslint/typescript-estree@8.48.1(typescript@5.9.3)': dependencies: - '@typescript-eslint/project-service': 8.48.0(typescript@5.9.3) - '@typescript-eslint/tsconfig-utils': 8.48.0(typescript@5.9.3) - '@typescript-eslint/types': 8.48.0 - '@typescript-eslint/visitor-keys': 8.48.0 + '@typescript-eslint/project-service': 8.48.1(typescript@5.9.3) + '@typescript-eslint/tsconfig-utils': 8.48.1(typescript@5.9.3) + '@typescript-eslint/types': 8.48.1 + '@typescript-eslint/visitor-keys': 8.48.1 debug: 4.4.3 minimatch: 9.0.5 semver: 7.7.3 @@ -1931,12 +1932,12 @@ snapshots: - supports-color - typescript - '@typescript-eslint/utils@8.48.0(eslint@9.39.1)(typescript@5.9.3)': + '@typescript-eslint/utils@8.48.1(eslint@9.39.1)(typescript@5.9.3)': dependencies: '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1) - '@typescript-eslint/scope-manager': 8.48.0 - '@typescript-eslint/types': 8.48.0 - '@typescript-eslint/typescript-estree': 8.48.0(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.48.1 + '@typescript-eslint/types': 8.48.1 + '@typescript-eslint/typescript-estree': 8.48.1(typescript@5.9.3) eslint: 9.39.1 typescript: 5.9.3 transitivePeerDependencies: @@ -1947,15 +1948,15 @@ snapshots: '@typescript-eslint/types': 7.18.0 eslint-visitor-keys: 3.4.3 - '@typescript-eslint/visitor-keys@8.48.0': + '@typescript-eslint/visitor-keys@8.48.1': dependencies: - '@typescript-eslint/types': 8.48.0 + '@typescript-eslint/types': 8.48.1 eslint-visitor-keys: 4.2.1 - '@vitest/coverage-v8@4.0.14(vitest@4.0.14)': + '@vitest/coverage-v8@4.0.15(vitest@4.0.15)': dependencies: '@bcoe/v8-coverage': 1.0.2 - '@vitest/utils': 4.0.14 + '@vitest/utils': 4.0.15 ast-v8-to-istanbul: 0.3.8 istanbul-lib-coverage: 3.2.2 istanbul-lib-report: 3.0.1 @@ -1965,58 +1966,58 @@ snapshots: obug: 2.1.1 std-env: 3.10.0 tinyrainbow: 3.0.3 - vitest: 4.0.14(@types/node@24.10.1)(@vitest/ui@4.0.14) + vitest: 4.0.15(@types/node@24.10.1)(@vitest/ui@4.0.15) transitivePeerDependencies: - supports-color - '@vitest/expect@4.0.14': + '@vitest/expect@4.0.15': dependencies: '@standard-schema/spec': 1.0.0 '@types/chai': 5.2.3 - '@vitest/spy': 4.0.14 - '@vitest/utils': 4.0.14 + '@vitest/spy': 4.0.15 + '@vitest/utils': 4.0.15 chai: 6.2.1 tinyrainbow: 3.0.3 - '@vitest/mocker@4.0.14(vite@7.2.6(@types/node@24.10.1))': + '@vitest/mocker@4.0.15(vite@7.2.6(@types/node@24.10.1))': dependencies: - '@vitest/spy': 4.0.14 + '@vitest/spy': 4.0.15 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: vite: 7.2.6(@types/node@24.10.1) - '@vitest/pretty-format@4.0.14': + '@vitest/pretty-format@4.0.15': dependencies: tinyrainbow: 3.0.3 - '@vitest/runner@4.0.14': + '@vitest/runner@4.0.15': dependencies: - '@vitest/utils': 4.0.14 + '@vitest/utils': 4.0.15 pathe: 2.0.3 - '@vitest/snapshot@4.0.14': + '@vitest/snapshot@4.0.15': dependencies: - '@vitest/pretty-format': 4.0.14 + '@vitest/pretty-format': 4.0.15 magic-string: 0.30.21 pathe: 2.0.3 - '@vitest/spy@4.0.14': {} + '@vitest/spy@4.0.15': {} - '@vitest/ui@4.0.14(vitest@4.0.14)': + '@vitest/ui@4.0.15(vitest@4.0.15)': dependencies: - '@vitest/utils': 4.0.14 + '@vitest/utils': 4.0.15 fflate: 0.8.2 flatted: 3.3.3 pathe: 2.0.3 sirv: 3.0.2 tinyglobby: 0.2.15 tinyrainbow: 3.0.3 - vitest: 4.0.14(@types/node@24.10.1)(@vitest/ui@4.0.14) + vitest: 4.0.15(@types/node@24.10.1)(@vitest/ui@4.0.15) - '@vitest/utils@4.0.14': + '@vitest/utils@4.0.15': dependencies: - '@vitest/pretty-format': 4.0.14 + '@vitest/pretty-format': 4.0.15 tinyrainbow: 3.0.3 '@volar/language-core@2.4.23': @@ -2216,12 +2217,12 @@ snapshots: escape-string-regexp@4.0.0: {} - eslint-plugin-vitest@0.5.4(eslint@9.39.1)(typescript@5.9.3)(vitest@4.0.14): + eslint-plugin-vitest@0.5.4(eslint@9.39.1)(typescript@5.9.3)(vitest@4.0.15): dependencies: '@typescript-eslint/utils': 7.18.0(eslint@9.39.1)(typescript@5.9.3) eslint: 9.39.1 optionalDependencies: - vitest: 4.0.14(@types/node@24.10.1)(@vitest/ui@4.0.14) + vitest: 4.0.15(@types/node@24.10.1)(@vitest/ui@4.0.15) transitivePeerDependencies: - supports-color - typescript @@ -2600,7 +2601,7 @@ snapshots: prelude-ls@1.2.1: {} - prettier@3.7.3: {} + prettier@3.7.4: {} punycode@2.3.1: {} @@ -2700,7 +2701,7 @@ snapshots: tinybench@2.9.0: {} - tinyexec@0.3.2: {} + tinyexec@1.0.2: {} tinyglobby@0.2.15: dependencies: @@ -2727,12 +2728,12 @@ snapshots: dependencies: prelude-ls: 1.2.1 - typescript-eslint@8.48.0(eslint@9.39.1)(typescript@5.9.3): + typescript-eslint@8.48.1(eslint@9.39.1)(typescript@5.9.3): dependencies: - '@typescript-eslint/eslint-plugin': 8.48.0(@typescript-eslint/parser@8.48.0(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(typescript@5.9.3) - '@typescript-eslint/parser': 8.48.0(eslint@9.39.1)(typescript@5.9.3) - '@typescript-eslint/typescript-estree': 8.48.0(typescript@5.9.3) - '@typescript-eslint/utils': 8.48.0(eslint@9.39.1)(typescript@5.9.3) + '@typescript-eslint/eslint-plugin': 8.48.1(@typescript-eslint/parser@8.48.1(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(typescript@5.9.3) + '@typescript-eslint/parser': 8.48.1(eslint@9.39.1)(typescript@5.9.3) + '@typescript-eslint/typescript-estree': 8.48.1(typescript@5.9.3) + '@typescript-eslint/utils': 8.48.1(eslint@9.39.1)(typescript@5.9.3) eslint: 9.39.1 typescript: 5.9.3 transitivePeerDependencies: @@ -2783,15 +2784,15 @@ snapshots: '@types/node': 24.10.1 fsevents: 2.3.3 - vitest@4.0.14(@types/node@24.10.1)(@vitest/ui@4.0.14): + vitest@4.0.15(@types/node@24.10.1)(@vitest/ui@4.0.15): dependencies: - '@vitest/expect': 4.0.14 - '@vitest/mocker': 4.0.14(vite@7.2.6(@types/node@24.10.1)) - '@vitest/pretty-format': 4.0.14 - '@vitest/runner': 4.0.14 - '@vitest/snapshot': 4.0.14 - '@vitest/spy': 4.0.14 - '@vitest/utils': 4.0.14 + '@vitest/expect': 4.0.15 + '@vitest/mocker': 4.0.15(vite@7.2.6(@types/node@24.10.1)) + '@vitest/pretty-format': 4.0.15 + '@vitest/runner': 4.0.15 + '@vitest/snapshot': 4.0.15 + '@vitest/spy': 4.0.15 + '@vitest/utils': 4.0.15 es-module-lexer: 1.7.0 expect-type: 1.2.2 magic-string: 0.30.21 @@ -2800,14 +2801,14 @@ snapshots: picomatch: 4.0.3 std-env: 3.10.0 tinybench: 2.9.0 - tinyexec: 0.3.2 + tinyexec: 1.0.2 tinyglobby: 0.2.15 tinyrainbow: 3.0.3 vite: 7.2.6(@types/node@24.10.1) why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 24.10.1 - '@vitest/ui': 4.0.14(vitest@4.0.14) + '@vitest/ui': 4.0.15(vitest@4.0.15) transitivePeerDependencies: - jiti - less diff --git a/sonar-project.properties b/sonar-project.properties index 24455c3..3b8809c 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -1,5 +1,8 @@ sonar.projectKey=volverjs_satispay-node-sdk sonar.organization=volverjs -sonar.coverage.exclusions=tests/** sonar.sources=src -sonar.exclusions=tests/** \ No newline at end of file +sonar.tests=tests +sonar.exclusions=tests/**,**/*.config.*,**/node_modules/**,dist/**,examples/** +sonar.test.exclusions=tests/** +sonar.coverage.exclusions=tests/**,**/*.config.*,src/index.ts,src/types.ts,src/bin/** +sonar.javascript.lcov.reportPaths=coverage/lcov.info \ No newline at end of file diff --git a/src/DailyClosure.ts b/src/DailyClosure.ts index 9a934d4..0eb50b4 100644 --- a/src/DailyClosure.ts +++ b/src/DailyClosure.ts @@ -1,5 +1,6 @@ import { Request } from './Request.js' import { DailyClosure as DailyClosureType, DailyClosureQueryParams } from './types.js' +import { DateUtils } from './utils.js' /** * DailyClosure class for retrieving daily closure information @@ -10,24 +11,26 @@ export class DailyClosure { /** * Get daily closure * @see https://developers.satispay.com/reference/retrieve-daily-closure - * @param date Date in format YYYYMMDD (default: today) + * @param date Date object, date in format YYYYMMDD, or undefined for today * @param query Query parameters (optional) * @param headers Custom headers (optional) */ static async get( - date?: string, + date?: string | Date, query: DailyClosureQueryParams = {}, headers: Record = {} ): Promise { + let dateString: string + if (!date) { - const today = new Date() - const year = today.getFullYear() - const month = String(today.getMonth() + 1).padStart(2, '0') - const day = String(today.getDate()).padStart(2, '0') - date = `${year}${month}${day}` + dateString = DateUtils.formatToYYYYMMDD(new Date()) + } else if (date instanceof Date) { + dateString = DateUtils.formatToYYYYMMDD(date) + } else { + dateString = date } - let path = `${this.apiPath}/${date}` + let path = `${this.apiPath}/${dateString}` if (Object.keys(query).length > 0) { const queryParams = new URLSearchParams() diff --git a/src/types.ts b/src/types.ts index 49b7959..69e2f54 100644 --- a/src/types.ts +++ b/src/types.ts @@ -193,13 +193,24 @@ export type Consumer = { } /** - * Daily closure interface + * Daily closure detail */ -export type DailyClosure = { - date: string - total_amount_unit: number +export type DailyClosureDetail = { + id: string + type: string + customer_uid: string + gross_amount_unit: number + refund_amount_unit: number + amount_unit: number currency: string - payments_count: number +} + +/** + * Daily closure response + */ +export type DailyClosure = { + shop_daily_closure: DailyClosureDetail + device_daily_closure: DailyClosureDetail } /** diff --git a/src/utils.ts b/src/utils.ts index b1a6287..4aff4c0 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -89,6 +89,20 @@ export const DateUtils = { return d.toISOString().split('T')[0] }, + /** + * Format date to YYYYMMDD format (for daily closure) + * @param date Date object or ISO string + * @returns Formatted date string (YYYYMMDD) + * @example DateUtils.formatToYYYYMMDD(new Date('2024-01-15')) // "20240115" + */ + formatToYYYYMMDD(date: Date | string): string { + const d = typeof date === 'string' ? new Date(date) : date + const year = d.getFullYear() + const month = String(d.getMonth() + 1).padStart(2, '0') + const day = String(d.getDate()).padStart(2, '0') + return `${year}${month}${day}` + }, + /** * Parse Satispay date string to Date object * @param dateString Date string from API diff --git a/tests/DailyClosure.test.ts b/tests/DailyClosure.test.ts index d00c5fe..50d50a5 100644 --- a/tests/DailyClosure.test.ts +++ b/tests/DailyClosure.test.ts @@ -12,10 +12,24 @@ vi.mock('../src/Request', () => ({ describe('DailyClosure', () => { const mockDailyClosure: DailyClosureType = { - date: '2025-11-18', - total_amount_unit: 15000, - currency: 'EUR', - payments_count: 25, + shop_daily_closure: { + id: '20251118', + type: 'SHOP_ONLINE', + customer_uid: '2c544020-2cfb-45ea-b22e-1a0302c54b11', + gross_amount_unit: 15000, + refund_amount_unit: 0, + amount_unit: 15000, + currency: 'EUR', + }, + device_daily_closure: { + id: '20251118', + type: 'DEVICE', + customer_uid: '8c061458-e634-440c-8770-86b36eb9d1d6', + gross_amount_unit: 0, + refund_amount_unit: 0, + amount_unit: 0, + currency: 'EUR', + }, } beforeEach(() => { @@ -63,5 +77,29 @@ describe('DailyClosure', () => { const callArg = vi.mocked(Request.get).mock.calls[0][0] expect(callArg).toMatch(/^\/g_business\/v1\/daily_closure\/\d{8}/) }) + + it('should accept Date object', async () => { + const date = new Date('2025-11-18') + vi.mocked(Request.get).mockResolvedValue(mockDailyClosure) + + await DailyClosure.get(date) + + expect(Request.get).toHaveBeenCalledWith('/g_business/v1/daily_closure/20251118', { + headers: {}, + sign: true, + }) + }) + + it('should accept string date in YYYYMMDD format', async () => { + const dateString = '20251118' + vi.mocked(Request.get).mockResolvedValue(mockDailyClosure) + + await DailyClosure.get(dateString) + + expect(Request.get).toHaveBeenCalledWith('/g_business/v1/daily_closure/20251118', { + headers: {}, + sign: true, + }) + }) }) }) diff --git a/tests/e2e/daily-closure.e2e.test.ts b/tests/e2e/daily-closure.e2e.test.ts new file mode 100644 index 0000000..eb253b4 --- /dev/null +++ b/tests/e2e/daily-closure.e2e.test.ts @@ -0,0 +1,112 @@ +import { describe, it, expect } from 'vitest' +import { DailyClosure } from '../../src/DailyClosure' +import { canRunE2ETests, hasAuthenticationKeys } from '../setup' + +/** + * E2E tests for Daily Closure with Satispay + * + * These tests require: + * - SATISPAY_PUBLIC_KEY, SATISPAY_PRIVATE_KEY, SATISPAY_KEY_ID configured + * - Staging or test environment + */ + +describe.skipIf(!canRunE2ETests() || !hasAuthenticationKeys())('E2E: Daily Closure', () => { + describe('Get Daily Closure', () => { + it('should get today\'s daily closure', async () => { + const closure = await DailyClosure.get() + + expect(closure).toBeDefined() + expect(closure.shop_daily_closure).toBeDefined() + expect(closure.device_daily_closure).toBeDefined() + + // Validate shop_daily_closure structure + expect(closure.shop_daily_closure.id).toBeDefined() + expect(closure.shop_daily_closure.type).toBeDefined() + expect(closure.shop_daily_closure.customer_uid).toBeDefined() + expect(typeof closure.shop_daily_closure.amount_unit).toBe('number') + expect(typeof closure.shop_daily_closure.gross_amount_unit).toBe('number') + expect(typeof closure.shop_daily_closure.refund_amount_unit).toBe('number') + expect(closure.shop_daily_closure.currency).toBe('EUR') + + // Validate device_daily_closure structure + expect(closure.device_daily_closure.id).toBeDefined() + expect(closure.device_daily_closure.type).toBeDefined() + expect(closure.device_daily_closure.customer_uid).toBeDefined() + expect(typeof closure.device_daily_closure.amount_unit).toBe('number') + expect(typeof closure.device_daily_closure.gross_amount_unit).toBe('number') + expect(typeof closure.device_daily_closure.refund_amount_unit).toBe('number') + expect(closure.device_daily_closure.currency).toBe('EUR') + + console.log('\nšŸ“Š Today\'s Daily Closure:') + console.log(`Date: ${closure.shop_daily_closure.id}`) + console.log(`Shop Amount: ${closure.shop_daily_closure.amount_unit / 100} ${closure.shop_daily_closure.currency}`) + console.log(`Device Amount: ${closure.device_daily_closure.amount_unit / 100} ${closure.device_daily_closure.currency}`) + }, 30000) + + it('should get daily closure using Date object', async () => { + const today = new Date() + const closure = await DailyClosure.get(today) + + expect(closure).toBeDefined() + expect(closure.shop_daily_closure).toBeDefined() + expect(closure.device_daily_closure).toBeDefined() + + // Verify the date matches today's format (YYYYMMDD) + const expectedDate = `${today.getFullYear()}${String(today.getMonth() + 1).padStart(2, '0')}${String(today.getDate()).padStart(2, '0')}` + expect(closure.shop_daily_closure.id).toBe(expectedDate) + + console.log('\nšŸ“Š Daily Closure (using Date object):') + console.log(`Date: ${closure.shop_daily_closure.id}`) + console.log(`Shop Amount: ${closure.shop_daily_closure.amount_unit / 100} ${closure.shop_daily_closure.currency}`) + }, 30000) + + it('should get daily closure using string date (YYYYMMDD)', async () => { + const today = new Date() + const dateString = `${today.getFullYear()}${String(today.getMonth() + 1).padStart(2, '0')}${String(today.getDate()).padStart(2, '0')}` + + const closure = await DailyClosure.get(dateString) + + expect(closure).toBeDefined() + expect(closure.shop_daily_closure).toBeDefined() + expect(closure.shop_daily_closure.id).toBe(dateString) + + console.log('\nšŸ“Š Daily Closure (using string date):') + console.log(`Date: ${closure.shop_daily_closure.id}`) + console.log(`Shop Amount: ${closure.shop_daily_closure.amount_unit / 100} ${closure.shop_daily_closure.currency}`) + }, 30000) + + it('should get yesterday\'s daily closure', async () => { + const yesterday = new Date() + yesterday.setDate(yesterday.getDate() - 1) + + const closure = await DailyClosure.get(yesterday) + + expect(closure).toBeDefined() + expect(closure.shop_daily_closure).toBeDefined() + + const expectedDate = `${yesterday.getFullYear()}${String(yesterday.getMonth() + 1).padStart(2, '0')}${String(yesterday.getDate()).padStart(2, '0')}` + expect(closure.shop_daily_closure.id).toBe(expectedDate) + + console.log('\nšŸ“Š Yesterday\'s Daily Closure:') + console.log(`Date: ${closure.shop_daily_closure.id}`) + console.log(`Shop Amount: ${closure.shop_daily_closure.amount_unit / 100} ${closure.shop_daily_closure.currency}`) + console.log(`Shop Gross: ${closure.shop_daily_closure.gross_amount_unit / 100}`) + console.log(`Shop Refunds: ${closure.shop_daily_closure.refund_amount_unit / 100}`) + }, 30000) + + it('should validate amounts calculation', async () => { + const closure = await DailyClosure.get() + + // Verify that amount_unit = gross_amount_unit - refund_amount_unit + const shopCalculated = closure.shop_daily_closure.gross_amount_unit - closure.shop_daily_closure.refund_amount_unit + expect(closure.shop_daily_closure.amount_unit).toBe(shopCalculated) + + const deviceCalculated = closure.device_daily_closure.gross_amount_unit - closure.device_daily_closure.refund_amount_unit + expect(closure.device_daily_closure.amount_unit).toBe(deviceCalculated) + + console.log('\nāœ… Amount calculation verified:') + console.log(`Shop: ${closure.shop_daily_closure.gross_amount_unit} - ${closure.shop_daily_closure.refund_amount_unit} = ${closure.shop_daily_closure.amount_unit}`) + console.log(`Device: ${closure.device_daily_closure.gross_amount_unit} - ${closure.device_daily_closure.refund_amount_unit} = ${closure.device_daily_closure.amount_unit}`) + }, 30000) + }) +}) diff --git a/tests/utils.test.ts b/tests/utils.test.ts index 5d6941a..34967cc 100644 --- a/tests/utils.test.ts +++ b/tests/utils.test.ts @@ -81,6 +81,22 @@ describe('DateUtils', () => { }) }) + describe('formatToYYYYMMDD', () => { + it('should format Date object to YYYYMMDD', () => { + const date = new Date('2024-01-15T10:30:00Z') + expect(DateUtils.formatToYYYYMMDD(date)).toBe('20240115') + }) + + it('should format ISO string to YYYYMMDD', () => { + expect(DateUtils.formatToYYYYMMDD('2024-01-15T10:30:00Z')).toBe('20240115') + }) + + it('should pad single digit months and days', () => { + const date = new Date('2024-03-05T10:30:00Z') + expect(DateUtils.formatToYYYYMMDD(date)).toBe('20240305') + }) + }) + describe('parseFromApi', () => { it('should parse date string', () => { const date = DateUtils.parseFromApi('2024-01-15T10:30:00Z')