Compare commits

...

242 Commits
4.x ... 6.x

Author SHA1 Message Date
dependabot[bot]
a7baf9f7a0 Bump actions/cache from 4.3.0 to 5.0.1 in /.github/workflows
Bumps [actions/cache](https://github.com/actions/cache) from 4.3.0 to 5.0.1.
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](0057852bfa...9255dc7a25)

---
updated-dependencies:
- dependency-name: actions/cache
  dependency-version: 5.0.1
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-12-25 17:11:46 +01:00
dependabot[bot]
18af858930 Bump softprops/action-gh-release in /.github/workflows
Bumps [softprops/action-gh-release](https://github.com/softprops/action-gh-release) from 2.4.2 to 2.5.0.
- [Release notes](https://github.com/softprops/action-gh-release/releases)
- [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md)
- [Commits](5be0e66d93...a06a81a03e)

---
updated-dependencies:
- dependency-name: softprops/action-gh-release
  dependency-version: 2.5.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-12-12 15:06:04 +01:00
dependabot[bot]
1db3592baf Bump zizmorcore/zizmor-action from 0.2.0 to 0.3.0 in /.github/workflows
Bumps [zizmorcore/zizmor-action](https://github.com/zizmorcore/zizmor-action) from 0.2.0 to 0.3.0.
- [Release notes](https://github.com/zizmorcore/zizmor-action/releases)
- [Commits](e673c3917a...e639db9933)

---
updated-dependencies:
- dependency-name: zizmorcore/zizmor-action
  dependency-version: 0.3.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-12-12 15:05:31 +01:00
BitcoinMitchell
cc2cef162f dev: Fix comments with pinact 2025-11-28 15:09:35 +01:00
BitcoinMitchell
9dc2f2cedd Update validate.yml 2025-11-28 15:09:35 +01:00
BitcoinMitchell
12ea23fd7d Update security.yml 2025-11-28 15:09:35 +01:00
BitcoinMitchell
12bb7e853c dev: Use hash for actions/checkout 2025-11-28 15:09:35 +01:00
dependabot[bot]
df87beb4e3 Bump actions/checkout from 5.0.0 to 6.0.0 in /.github/workflows
Bumps [actions/checkout](https://github.com/actions/checkout) from 5.0.0 to 6.0.0.
- [Release notes](https://github.com/actions/checkout/releases)
- [Commits](https://github.com/actions/checkout/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: 6.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-11-28 15:09:35 +01:00
BitcoinMitchell
bf71d966a6 dev: Set cooldown for dependabot 2025-11-28 15:01:40 +01:00
BitcoinMitchell
cb98dafc12 dev: Lockdown pipelines 2025-11-28 15:01:40 +01:00
dependabot[bot]
411ff22a98 Bump actions/checkout from 5 to 6 in /.github/workflows
Bumps [actions/checkout](https://github.com/actions/checkout) from 5 to 6.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-11-21 15:20:28 +01:00
dependabot[bot]
f9e10eddbe Bump dealerdirect/phpcodesniffer-composer-installer from 1.1.2 to 1.2.0
Bumps [dealerdirect/phpcodesniffer-composer-installer](https://github.com/PHPCSStandards/composer-installer) from 1.1.2 to 1.2.0.
- [Release notes](https://github.com/PHPCSStandards/composer-installer/releases)
- [Changelog](https://github.com/PHPCSStandards/composer-installer/blob/main/CHANGELOG.md)
- [Commits](https://github.com/PHPCSStandards/composer-installer/compare/v1.1.2...v1.2.0)

---
updated-dependencies:
- dependency-name: dealerdirect/phpcodesniffer-composer-installer
  dependency-version: 1.2.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-11-21 15:17:33 +01:00
dependabot[bot]
bd5100461c Bump symfony/http-foundation from 5.4.46 to 5.4.50 in /modules/btcpay
Bumps [symfony/http-foundation](https://github.com/symfony/http-foundation) from 5.4.46 to 5.4.50.
- [Release notes](https://github.com/symfony/http-foundation/releases)
- [Changelog](https://github.com/symfony/http-foundation/blob/7.3/CHANGELOG.md)
- [Commits](https://github.com/symfony/http-foundation/compare/v5.4.46...v5.4.50)

---
updated-dependencies:
- dependency-name: symfony/http-foundation
  dependency-version: 5.4.50
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-11-21 15:16:51 +01:00
dependabot[bot]
5caa02768c Bump composer/semver from 3.4.3 to 3.4.4 in /modules/btcpay
Bumps [composer/semver](https://github.com/composer/semver) from 3.4.3 to 3.4.4.
- [Release notes](https://github.com/composer/semver/releases)
- [Changelog](https://github.com/composer/semver/blob/main/CHANGELOG.md)
- [Commits](https://github.com/composer/semver/compare/3.4.3...3.4.4)

---
updated-dependencies:
- dependency-name: composer/semver
  dependency-version: 3.4.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-11-21 15:09:26 +01:00
dependabot[bot]
bc4a5744e8 Bump ergebnis/composer-normalize in /modules/btcpay
Bumps [ergebnis/composer-normalize](https://github.com/ergebnis/composer-normalize) from 2.45.0 to 2.48.2.
- [Release notes](https://github.com/ergebnis/composer-normalize/releases)
- [Changelog](https://github.com/ergebnis/composer-normalize/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ergebnis/composer-normalize/compare/2.45.0...2.48.2)

---
updated-dependencies:
- dependency-name: ergebnis/composer-normalize
  dependency-version: 2.48.2
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-11-21 15:06:26 +01:00
dependabot[bot]
27a97c56b1 Bump stechstudio/backoff from 1.5 to 1.6 in /modules/btcpay
Bumps [stechstudio/backoff](https://github.com/stechstudio/backoff) from 1.5 to 1.6.
- [Release notes](https://github.com/stechstudio/backoff/releases)
- [Commits](https://github.com/stechstudio/backoff/compare/1.5...1.6)

---
updated-dependencies:
- dependency-name: stechstudio/backoff
  dependency-version: '1.6'
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-11-21 15:06:13 +01:00
BitcoinMitchell
0a15854dab
Update validate.yml (#204) 2025-09-22 11:28:17 +02:00
BitcoinMitchell
1bf5e7ce81 Prepare for v6.3.1
Some checks failed
Release / Release a new ZIP (push) Has been cancelled
2025-09-19 10:09:41 +02:00
BitcoinMitchell
55b3fcf3c8 fix: Ensure currency is properly displayed when using BTCPay Server v2 2025-09-19 10:09:41 +02:00
BitcoinMitchell
bf39f3d622 fix: Ensure icons work on PS 9 2025-09-19 10:09:41 +02:00
BitcoinMitchell
466a38f7c1 fix: Only call parent::__construct(); for PS 8.0 2025-09-19 10:09:41 +02:00
BitcoinMitchell
1dd151bcf2 fix: redirectLink is deprecated 2025-09-19 10:09:41 +02:00
BitcoinMitchell
a2609ff54c fix: Actually log error when caught 2025-09-19 10:09:41 +02:00
dependabot[bot]
f47b9964da Bump actions/checkout from 4 to 5 in /.github/workflows
Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 5.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-16 21:24:45 +02:00
dependabot[bot]
fd891f545e Bump dealerdirect/phpcodesniffer-composer-installer from 1.1.0 to 1.1.2
Bumps [dealerdirect/phpcodesniffer-composer-installer](https://github.com/PHPCSStandards/composer-installer) from 1.1.0 to 1.1.2.
- [Release notes](https://github.com/PHPCSStandards/composer-installer/releases)
- [Changelog](https://github.com/PHPCSStandards/composer-installer/blob/main/CHANGELOG.md)
- [Commits](https://github.com/PHPCSStandards/composer-installer/compare/v1.1.0...v1.1.2)

---
updated-dependencies:
- dependency-name: dealerdirect/phpcodesniffer-composer-installer
  dependency-version: 1.1.2
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-16 21:22:46 +02:00
dependabot[bot]
ed50d43628 Bump phpoffice/phpspreadsheet from 1.29.9 to 1.30.0
Bumps [phpoffice/phpspreadsheet](https://github.com/PHPOffice/PhpSpreadsheet) from 1.29.9 to 1.30.0.
- [Release notes](https://github.com/PHPOffice/PhpSpreadsheet/releases)
- [Changelog](https://github.com/PHPOffice/PhpSpreadsheet/blob/1.30.0/CHANGELOG.md)
- [Commits](https://github.com/PHPOffice/PhpSpreadsheet/compare/1.29.9...1.30.0)

---
updated-dependencies:
- dependency-name: phpoffice/phpspreadsheet
  dependency-version: 1.30.0
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-16 21:19:55 +02:00
dependabot[bot]
0253f05742 Bump ergebnis/composer-normalize from 2.47.0 to 2.48.2
Bumps [ergebnis/composer-normalize](https://github.com/ergebnis/composer-normalize) from 2.47.0 to 2.48.2.
- [Release notes](https://github.com/ergebnis/composer-normalize/releases)
- [Changelog](https://github.com/ergebnis/composer-normalize/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ergebnis/composer-normalize/compare/2.47.0...2.48.2)

---
updated-dependencies:
- dependency-name: ergebnis/composer-normalize
  dependency-version: 2.48.2
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-16 21:18:03 +02:00
dependabot[bot]
599a382869 Bump dealerdirect/phpcodesniffer-composer-installer from 1.0.0 to 1.1.0
Bumps [dealerdirect/phpcodesniffer-composer-installer](https://github.com/PHPCSStandards/composer-installer) from 1.0.0 to 1.1.0.
- [Release notes](https://github.com/PHPCSStandards/composer-installer/releases)
- [Changelog](https://github.com/PHPCSStandards/composer-installer/blob/main/.github_changelog_generator)
- [Commits](https://github.com/PHPCSStandards/composer-installer/compare/v1.0.0...v1.1.0)

---
updated-dependencies:
- dependency-name: dealerdirect/phpcodesniffer-composer-installer
  dependency-version: 1.1.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-30 12:50:14 +02:00
dependabot[bot]
651e3eaff5 Bump squizlabs/php_codesniffer from 3.13.1 to 3.13.2
Bumps [squizlabs/php_codesniffer](https://github.com/PHPCSStandards/PHP_CodeSniffer) from 3.13.1 to 3.13.2.
- [Release notes](https://github.com/PHPCSStandards/PHP_CodeSniffer/releases)
- [Changelog](https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/CHANGELOG.md)
- [Commits](https://github.com/PHPCSStandards/PHP_CodeSniffer/compare/3.13.1...3.13.2)

---
updated-dependencies:
- dependency-name: squizlabs/php_codesniffer
  dependency-version: 3.13.2
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-30 12:48:58 +02:00
dependabot[bot]
7af60e0ed6 Bump squizlabs/php_codesniffer from 3.13.0 to 3.13.1
Bumps [squizlabs/php_codesniffer](https://github.com/PHPCSStandards/PHP_CodeSniffer) from 3.13.0 to 3.13.1.
- [Release notes](https://github.com/PHPCSStandards/PHP_CodeSniffer/releases)
- [Changelog](https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/CHANGELOG.md)
- [Commits](https://github.com/PHPCSStandards/PHP_CodeSniffer/compare/3.13.0...3.13.1)

---
updated-dependencies:
- dependency-name: squizlabs/php_codesniffer
  dependency-version: 3.13.1
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-13 15:24:37 +02:00
dependabot[bot]
d6030dc3df Bump squizlabs/php_codesniffer from 3.12.2 to 3.13.0
Bumps [squizlabs/php_codesniffer](https://github.com/PHPCSStandards/PHP_CodeSniffer) from 3.12.2 to 3.13.0.
- [Release notes](https://github.com/PHPCSStandards/PHP_CodeSniffer/releases)
- [Changelog](https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/CHANGELOG.md)
- [Commits](https://github.com/PHPCSStandards/PHP_CodeSniffer/compare/3.12.2...3.13.0)

---
updated-dependencies:
- dependency-name: squizlabs/php_codesniffer
  dependency-version: 3.13.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-12 16:02:02 +02:00
dependabot[bot]
f9d6f2fd7a Bump ergebnis/composer-normalize from 2.46.0 to 2.47.0
Bumps [ergebnis/composer-normalize](https://github.com/ergebnis/composer-normalize) from 2.46.0 to 2.47.0.
- [Release notes](https://github.com/ergebnis/composer-normalize/releases)
- [Changelog](https://github.com/ergebnis/composer-normalize/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ergebnis/composer-normalize/compare/2.46.0...2.47.0)

---
updated-dependencies:
- dependency-name: ergebnis/composer-normalize
  dependency-version: 2.47.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-15 16:03:51 +02:00
dependabot[bot]
b5d3a66ccc Bump squizlabs/php_codesniffer from 3.12.1 to 3.12.2
Bumps [squizlabs/php_codesniffer](https://github.com/PHPCSStandards/PHP_CodeSniffer) from 3.12.1 to 3.12.2.
- [Release notes](https://github.com/PHPCSStandards/PHP_CodeSniffer/releases)
- [Changelog](https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/CHANGELOG.md)
- [Commits](https://github.com/PHPCSStandards/PHP_CodeSniffer/compare/3.12.1...3.12.2)

---
updated-dependencies:
- dependency-name: squizlabs/php_codesniffer
  dependency-version: 3.12.2
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-14 15:41:45 +02:00
dependabot[bot]
ac3d652500 Bump ergebnis/composer-normalize from 2.45.0 to 2.46.0
Bumps [ergebnis/composer-normalize](https://github.com/ergebnis/composer-normalize) from 2.45.0 to 2.46.0.
- [Release notes](https://github.com/ergebnis/composer-normalize/releases)
- [Changelog](https://github.com/ergebnis/composer-normalize/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ergebnis/composer-normalize/compare/2.45.0...2.46.0)

---
updated-dependencies:
- dependency-name: ergebnis/composer-normalize
  dependency-version: 2.46.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-14 10:16:48 +02:00
dependabot[bot]
c0d91bee7c Bump squizlabs/php_codesniffer from 3.12.0 to 3.12.1
Bumps [squizlabs/php_codesniffer](https://github.com/PHPCSStandards/PHP_CodeSniffer) from 3.12.0 to 3.12.1.
- [Release notes](https://github.com/PHPCSStandards/PHP_CodeSniffer/releases)
- [Changelog](https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/CHANGELOG.md)
- [Commits](https://github.com/PHPCSStandards/PHP_CodeSniffer/compare/3.12.0...3.12.1)

---
updated-dependencies:
- dependency-name: squizlabs/php_codesniffer
  dependency-version: 3.12.1
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-08 12:22:16 +02:00
dependabot[bot]
e7c39dc951 Bump squizlabs/php_codesniffer from 3.11.3 to 3.12.0
Bumps [squizlabs/php_codesniffer](https://github.com/PHPCSStandards/PHP_CodeSniffer) from 3.11.3 to 3.12.0.
- [Release notes](https://github.com/PHPCSStandards/PHP_CodeSniffer/releases)
- [Changelog](https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/CHANGELOG.md)
- [Commits](https://github.com/PHPCSStandards/PHP_CodeSniffer/compare/3.11.3...3.12.0)

---
updated-dependencies:
- dependency-name: squizlabs/php_codesniffer
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-18 15:00:13 +01:00
dependabot[bot]
05dbfcd026 Bump stechstudio/backoff from 1.4 to 1.5 in /modules/btcpay
Bumps [stechstudio/backoff](https://github.com/stechstudio/backoff) from 1.4 to 1.5.
- [Release notes](https://github.com/stechstudio/backoff/releases)
- [Commits](https://github.com/stechstudio/backoff/compare/1.4...1.5)

---
updated-dependencies:
- dependency-name: stechstudio/backoff
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-10 14:35:58 +01:00
dependabot[bot]
cdaa853138 Bump phpoffice/phpspreadsheet from 1.29.8 to 1.29.9
Bumps [phpoffice/phpspreadsheet](https://github.com/PHPOffice/PhpSpreadsheet) from 1.29.8 to 1.29.9.
- [Release notes](https://github.com/PHPOffice/PhpSpreadsheet/releases)
- [Changelog](https://github.com/PHPOffice/PhpSpreadsheet/blob/1.29.9/CHANGELOG.md)
- [Commits](https://github.com/PHPOffice/PhpSpreadsheet/compare/1.29.8...1.29.9)

---
updated-dependencies:
- dependency-name: phpoffice/phpspreadsheet
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-03 18:06:48 +01:00
dependabot[bot]
2c2bfcc456 Bump phpoffice/phpspreadsheet from 1.29.7 to 1.29.8
Bumps [phpoffice/phpspreadsheet](https://github.com/PHPOffice/PhpSpreadsheet) from 1.29.7 to 1.29.8.
- [Release notes](https://github.com/PHPOffice/PhpSpreadsheet/releases)
- [Changelog](https://github.com/PHPOffice/PhpSpreadsheet/blob/1.29.8/CHANGELOG.md)
- [Commits](https://github.com/PHPOffice/PhpSpreadsheet/compare/1.29.7...1.29.8)

---
updated-dependencies:
- dependency-name: phpoffice/phpspreadsheet
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-27 17:05:46 +01:00
dependabot[bot]
27f6f6939f Bump squizlabs/php_codesniffer from 3.11.2 to 3.11.3
Bumps [squizlabs/php_codesniffer](https://github.com/PHPCSStandards/PHP_CodeSniffer) from 3.11.2 to 3.11.3.
- [Release notes](https://github.com/PHPCSStandards/PHP_CodeSniffer/releases)
- [Changelog](https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/CHANGELOG.md)
- [Commits](https://github.com/PHPCSStandards/PHP_CodeSniffer/compare/3.11.2...3.11.3)

---
updated-dependencies:
- dependency-name: squizlabs/php_codesniffer
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-27 17:03:32 +01:00
BitcoinMitchell
fcb52555aa Updated to 2025 2025-01-03 19:39:56 +01:00
dependabot[bot]
a81a5463a0 Bump phpoffice/phpspreadsheet from 1.29.4 to 1.29.7
Bumps [phpoffice/phpspreadsheet](https://github.com/PHPOffice/PhpSpreadsheet) from 1.29.4 to 1.29.7.
- [Release notes](https://github.com/PHPOffice/PhpSpreadsheet/releases)
- [Changelog](https://github.com/PHPOffice/PhpSpreadsheet/blob/1.29.7/CHANGELOG.md)
- [Commits](https://github.com/PHPOffice/PhpSpreadsheet/compare/1.29.4...1.29.7)

---
updated-dependencies:
- dependency-name: phpoffice/phpspreadsheet
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-03 19:29:25 +01:00
dependabot[bot]
3350cd7d22 Bump squizlabs/php_codesniffer from 3.11.1 to 3.11.2
Bumps [squizlabs/php_codesniffer](https://github.com/PHPCSStandards/PHP_CodeSniffer) from 3.11.1 to 3.11.2.
- [Release notes](https://github.com/PHPCSStandards/PHP_CodeSniffer/releases)
- [Changelog](https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/CHANGELOG.md)
- [Commits](https://github.com/PHPCSStandards/PHP_CodeSniffer/compare/3.11.1...3.11.2)

---
updated-dependencies:
- dependency-name: squizlabs/php_codesniffer
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-27 21:08:31 +01:00
dependabot[bot]
e82faa3163 Bump tecnickcom/tcpdf from 6.7.7 to 6.8.0
Bumps [tecnickcom/tcpdf](https://github.com/tecnickcom/TCPDF) from 6.7.7 to 6.8.0.
- [Changelog](https://github.com/tecnickcom/TCPDF/blob/main/CHANGELOG.TXT)
- [Commits](https://github.com/tecnickcom/TCPDF/compare/6.7.7...6.8.0)

---
updated-dependencies:
- dependency-name: tecnickcom/tcpdf
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-27 21:07:22 +01:00
dependabot[bot]
5fda99976f Bump ergebnis/composer-normalize from 2.44.0 to 2.45.0
Bumps [ergebnis/composer-normalize](https://github.com/ergebnis/composer-normalize) from 2.44.0 to 2.45.0.
- [Release notes](https://github.com/ergebnis/composer-normalize/releases)
- [Changelog](https://github.com/ergebnis/composer-normalize/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ergebnis/composer-normalize/compare/2.44.0...2.45.0)

---
updated-dependencies:
- dependency-name: ergebnis/composer-normalize
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-05 15:57:22 +01:00
dependabot[bot]
56f204d744 Bump ergebnis/composer-normalize in /modules/btcpay
Bumps [ergebnis/composer-normalize](https://github.com/ergebnis/composer-normalize) from 2.44.0 to 2.45.0.
- [Release notes](https://github.com/ergebnis/composer-normalize/releases)
- [Changelog](https://github.com/ergebnis/composer-normalize/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ergebnis/composer-normalize/compare/2.44.0...2.45.0)

---
updated-dependencies:
- dependency-name: ergebnis/composer-normalize
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-05 15:55:07 +01:00
dependabot[bot]
fef984c483 Bump tecnickcom/tcpdf from 6.7.5 to 6.7.7
Bumps [tecnickcom/tcpdf](https://github.com/tecnickcom/TCPDF) from 6.7.5 to 6.7.7.
- [Changelog](https://github.com/tecnickcom/TCPDF/blob/main/CHANGELOG.TXT)
- [Commits](https://github.com/tecnickcom/TCPDF/compare/6.7.5...6.7.7)

---
updated-dependencies:
- dependency-name: tecnickcom/tcpdf
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-27 15:01:09 +01:00
BitcoinMitchell
0142dd0c4d Ensure BTCPayServer 2.0 compatibility
Some checks failed
Release / Release a new ZIP (push) Has been cancelled
2024-11-25 15:52:36 +01:00
dependabot[bot]
712219bd23 Bump btcpayserver/btcpayserver-greenfield-php in /modules/btcpay
Bumps [btcpayserver/btcpayserver-greenfield-php](https://github.com/btcpayserver/btcpayserver-greenfield-php) from 2.8.0 to 2.8.1.
- [Release notes](https://github.com/btcpayserver/btcpayserver-greenfield-php/releases)
- [Commits](https://github.com/btcpayserver/btcpayserver-greenfield-php/compare/v2.8.0...v2.8.1)

---
updated-dependencies:
- dependency-name: btcpayserver/btcpayserver-greenfield-php
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-25 15:17:38 +01:00
dependabot[bot]
b2ebded790 Bump phpoffice/phpspreadsheet from 1.29.2 to 1.29.4
Bumps [phpoffice/phpspreadsheet](https://github.com/PHPOffice/PhpSpreadsheet) from 1.29.2 to 1.29.4.
- [Release notes](https://github.com/PHPOffice/PhpSpreadsheet/releases)
- [Changelog](https://github.com/PHPOffice/PhpSpreadsheet/blob/1.29.4/CHANGELOG.md)
- [Commits](https://github.com/PHPOffice/PhpSpreadsheet/compare/1.29.2...1.29.4)

---
updated-dependencies:
- dependency-name: phpoffice/phpspreadsheet
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-18 21:45:47 +01:00
dependabot[bot]
d30a0b205b Bump squizlabs/php_codesniffer from 3.11.0 to 3.11.1
Bumps [squizlabs/php_codesniffer](https://github.com/PHPCSStandards/PHP_CodeSniffer) from 3.11.0 to 3.11.1.
- [Release notes](https://github.com/PHPCSStandards/PHP_CodeSniffer/releases)
- [Changelog](https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/CHANGELOG.md)
- [Commits](https://github.com/PHPCSStandards/PHP_CodeSniffer/compare/3.11.0...3.11.1)

---
updated-dependencies:
- dependency-name: squizlabs/php_codesniffer
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-18 21:40:36 +01:00
dependabot[bot]
218427da0b Bump squizlabs/php_codesniffer from 3.10.3 to 3.11.0
Bumps [squizlabs/php_codesniffer](https://github.com/PHPCSStandards/PHP_CodeSniffer) from 3.10.3 to 3.11.0.
- [Release notes](https://github.com/PHPCSStandards/PHP_CodeSniffer/releases)
- [Changelog](https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/CHANGELOG.md)
- [Commits](https://github.com/PHPCSStandards/PHP_CodeSniffer/compare/3.10.3...3.11.0)

---
updated-dependencies:
- dependency-name: squizlabs/php_codesniffer
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-13 10:04:07 +01:00
BitcoinMitchell
48c26171ba Updated README.md 2024-11-08 20:36:43 +01:00
BitcoinMitchell
29cad33c1b Delete .github/workflows/dependencies.yml
Local PHP Security Checker is outdated. Will replace with different check later
2024-11-06 22:11:07 +01:00
dependabot[bot]
2a3ea675b5 Bump btcpayserver/btcpayserver-greenfield-php in /modules/btcpay
Bumps [btcpayserver/btcpayserver-greenfield-php](https://github.com/btcpayserver/btcpayserver-greenfield-php) from 2.7.1 to 2.8.0.
- [Release notes](https://github.com/btcpayserver/btcpayserver-greenfield-php/releases)
- [Commits](https://github.com/btcpayserver/btcpayserver-greenfield-php/compare/v2.7.1...v2.8.0)

---
updated-dependencies:
- dependency-name: btcpayserver/btcpayserver-greenfield-php
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-06 21:50:48 +01:00
dependabot[bot]
51177d0ca9 Bump twig/twig from 3.11.1 to 3.11.2
Bumps [twig/twig](https://github.com/twigphp/Twig) from 3.11.1 to 3.11.2.
- [Changelog](https://github.com/twigphp/Twig/blob/v3.11.2/CHANGELOG)
- [Commits](https://github.com/twigphp/Twig/compare/v3.11.1...v3.11.2)

---
updated-dependencies:
- dependency-name: twig/twig
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-06 21:50:37 +01:00
dependabot[bot]
895fe2a450 Bump twig/twig from 3.11.1 to 3.11.2 in /modules/btcpay
Bumps [twig/twig](https://github.com/twigphp/Twig) from 3.11.1 to 3.11.2.
- [Changelog](https://github.com/twigphp/Twig/blob/v3.11.2/CHANGELOG)
- [Commits](https://github.com/twigphp/Twig/compare/v3.11.1...v3.11.2)

---
updated-dependencies:
- dependency-name: twig/twig
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-06 21:50:30 +01:00
dependabot[bot]
07e4112ebf Bump symfony/http-foundation from 5.4.42 to 5.4.46 in /modules/btcpay
Bumps [symfony/http-foundation](https://github.com/symfony/http-foundation) from 5.4.42 to 5.4.46.
- [Release notes](https://github.com/symfony/http-foundation/releases)
- [Changelog](https://github.com/symfony/http-foundation/blob/7.1/CHANGELOG.md)
- [Commits](https://github.com/symfony/http-foundation/compare/v5.4.42...v5.4.46)

---
updated-dependencies:
- dependency-name: symfony/http-foundation
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-06 21:50:21 +01:00
dependabot[bot]
35b1a0bbea Bump ergebnis/composer-normalize from 2.43.0 to 2.44.0
Bumps [ergebnis/composer-normalize](https://github.com/ergebnis/composer-normalize) from 2.43.0 to 2.44.0.
- [Release notes](https://github.com/ergebnis/composer-normalize/releases)
- [Changelog](https://github.com/ergebnis/composer-normalize/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ergebnis/composer-normalize/compare/2.43.0...2.44.0)

---
updated-dependencies:
- dependency-name: ergebnis/composer-normalize
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-07 17:24:30 +02:00
dependabot[bot]
9f0ecff2f8 Bump ergebnis/composer-normalize in /modules/btcpay
Bumps [ergebnis/composer-normalize](https://github.com/ergebnis/composer-normalize) from 2.43.0 to 2.44.0.
- [Release notes](https://github.com/ergebnis/composer-normalize/releases)
- [Changelog](https://github.com/ergebnis/composer-normalize/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ergebnis/composer-normalize/compare/2.43.0...2.44.0)

---
updated-dependencies:
- dependency-name: ergebnis/composer-normalize
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-07 17:23:04 +02:00
dependabot[bot]
f550891a60 Bump phpoffice/phpspreadsheet from 1.29.1 to 1.29.2
Bumps [phpoffice/phpspreadsheet](https://github.com/PHPOffice/PhpSpreadsheet) from 1.29.1 to 1.29.2.
- [Release notes](https://github.com/PHPOffice/PhpSpreadsheet/releases)
- [Changelog](https://github.com/PHPOffice/PhpSpreadsheet/blob/1.29.2/CHANGELOG.md)
- [Commits](https://github.com/PHPOffice/PhpSpreadsheet/compare/1.29.1...1.29.2)

---
updated-dependencies:
- dependency-name: phpoffice/phpspreadsheet
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-07 17:21:03 +02:00
BitcoinMitchell
31efe2d408 Update btcpay.php to v6.2.1
Some checks failed
Release / Release a new ZIP (push) Has been cancelled
2024-09-20 22:06:15 +02:00
dependabot[bot]
1527d8c098 Bump composer/semver from 3.4.2 to 3.4.3 in /modules/btcpay
Bumps [composer/semver](https://github.com/composer/semver) from 3.4.2 to 3.4.3.
- [Release notes](https://github.com/composer/semver/releases)
- [Changelog](https://github.com/composer/semver/blob/main/CHANGELOG.md)
- [Commits](https://github.com/composer/semver/compare/3.4.2...3.4.3)

---
updated-dependencies:
- dependency-name: composer/semver
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-20 15:32:07 +02:00
dependabot[bot]
1c07520f6a Bump squizlabs/php_codesniffer from 3.10.2 to 3.10.3
Bumps [squizlabs/php_codesniffer](https://github.com/PHPCSStandards/PHP_CodeSniffer) from 3.10.2 to 3.10.3.
- [Release notes](https://github.com/PHPCSStandards/PHP_CodeSniffer/releases)
- [Changelog](https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/CHANGELOG.md)
- [Commits](https://github.com/PHPCSStandards/PHP_CodeSniffer/compare/3.10.2...3.10.3)

---
updated-dependencies:
- dependency-name: squizlabs/php_codesniffer
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-18 15:43:43 +02:00
BitcoinMitchell
fd3410b3eb Update README.md 2024-09-17 13:55:55 +02:00
dependabot[bot]
9cbad690bb Bump btcpayserver/btcpayserver-greenfield-php in /modules/btcpay
Bumps [btcpayserver/btcpayserver-greenfield-php](https://github.com/btcpayserver/btcpayserver-greenfield-php) from 2.7.0 to 2.7.1.
- [Release notes](https://github.com/btcpayserver/btcpayserver-greenfield-php/releases)
- [Commits](https://github.com/btcpayserver/btcpayserver-greenfield-php/compare/v2.7.0...v2.7.1)

---
updated-dependencies:
- dependency-name: btcpayserver/btcpayserver-greenfield-php
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-17 12:18:12 +02:00
BitcoinMitchell
cabf7c2ee8 Updated all dependencies
Some checks failed
Release / Release a new ZIP (push) Has been cancelled
2024-09-16 22:35:33 +02:00
dependabot[bot]
1505153bbc Bump btcpayserver/btcpayserver-greenfield-php in /modules/btcpay
Bumps [btcpayserver/btcpayserver-greenfield-php](https://github.com/btcpayserver/btcpayserver-greenfield-php) from 2.6.0 to 2.7.0.
- [Release notes](https://github.com/btcpayserver/btcpayserver-greenfield-php/releases)
- [Commits](https://github.com/btcpayserver/btcpayserver-greenfield-php/compare/v2.6.0...v2.7.0)

---
updated-dependencies:
- dependency-name: btcpayserver/btcpayserver-greenfield-php
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-16 15:43:35 +02:00
dependabot[bot]
db6cd92f78 Bump twig/twig from 3.10.3 to 3.11.1 in /modules/btcpay
Bumps [twig/twig](https://github.com/twigphp/Twig) from 3.10.3 to 3.11.1.
- [Changelog](https://github.com/twigphp/Twig/blob/v3.11.1/CHANGELOG)
- [Commits](https://github.com/twigphp/Twig/compare/v3.10.3...v3.11.1)

---
updated-dependencies:
- dependency-name: twig/twig
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-10 19:49:50 +02:00
dependabot[bot]
5f1a1dbfa9 Bump twig/twig from 3.10.3 to 3.11.1
Bumps [twig/twig](https://github.com/twigphp/Twig) from 3.10.3 to 3.11.1.
- [Changelog](https://github.com/twigphp/Twig/blob/v3.11.1/CHANGELOG)
- [Commits](https://github.com/twigphp/Twig/compare/v3.10.3...v3.11.1)

---
updated-dependencies:
- dependency-name: twig/twig
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-10 19:35:00 +02:00
dependabot[bot]
2a6578bdb8 Bump stechstudio/backoff from 1.3 to 1.4 in /modules/btcpay
Bumps [stechstudio/backoff](https://github.com/stechstudio/backoff) from 1.3 to 1.4.
- [Release notes](https://github.com/stechstudio/backoff/releases)
- [Commits](https://github.com/stechstudio/backoff/compare/1.3...1.4)

---
updated-dependencies:
- dependency-name: stechstudio/backoff
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-08-30 16:06:08 +02:00
dependabot[bot]
c66c49e30b Bump squizlabs/php_codesniffer from 3.10.1 to 3.10.2
Bumps [squizlabs/php_codesniffer](https://github.com/PHPCSStandards/PHP_CodeSniffer) from 3.10.1 to 3.10.2.
- [Release notes](https://github.com/PHPCSStandards/PHP_CodeSniffer/releases)
- [Changelog](https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/CHANGELOG.md)
- [Commits](https://github.com/PHPCSStandards/PHP_CodeSniffer/compare/3.10.1...3.10.2)

---
updated-dependencies:
- dependency-name: squizlabs/php_codesniffer
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-07-22 19:16:17 +02:00
dependabot[bot]
019f297b94 Bump composer/semver from 3.4.0 to 3.4.2 in /modules/btcpay
Bumps [composer/semver](https://github.com/composer/semver) from 3.4.0 to 3.4.2.
- [Release notes](https://github.com/composer/semver/releases)
- [Changelog](https://github.com/composer/semver/blob/main/CHANGELOG.md)
- [Commits](https://github.com/composer/semver/compare/3.4.0...3.4.2)

---
updated-dependencies:
- dependency-name: composer/semver
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-07-12 15:52:45 +02:00
BitcoinMitchell
86efeb7422 [Configuration] Ensure ConfigureController works on PS 8.0
Some checks failed
Release / Release a new ZIP (push) Has been cancelled
2024-07-05 09:27:17 +02:00
dependabot[bot]
3915ebd46f Bump ergebnis/composer-normalize from 2.42.0 to 2.43.0
Bumps [ergebnis/composer-normalize](https://github.com/ergebnis/composer-normalize) from 2.42.0 to 2.43.0.
- [Release notes](https://github.com/ergebnis/composer-normalize/releases)
- [Changelog](https://github.com/ergebnis/composer-normalize/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ergebnis/composer-normalize/compare/2.42.0...2.43.0)

---
updated-dependencies:
- dependency-name: ergebnis/composer-normalize
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-17 15:43:15 +02:00
dependabot[bot]
c503994389 Bump ergebnis/composer-normalize in /modules/btcpay
Bumps [ergebnis/composer-normalize](https://github.com/ergebnis/composer-normalize) from 2.42.0 to 2.43.0.
- [Release notes](https://github.com/ergebnis/composer-normalize/releases)
- [Changelog](https://github.com/ergebnis/composer-normalize/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ergebnis/composer-normalize/compare/2.42.0...2.43.0)

---
updated-dependencies:
- dependency-name: ergebnis/composer-normalize
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-17 15:09:20 +02:00
dependabot[bot]
65d7a5db87 Bump symfony/debug-bundle from 5.4.39 to 5.4.40 in /modules/btcpay
Bumps [symfony/debug-bundle](https://github.com/symfony/debug-bundle) from 5.4.39 to 5.4.40.
- [Release notes](https://github.com/symfony/debug-bundle/releases)
- [Changelog](https://github.com/symfony/debug-bundle/blob/7.1/CHANGELOG.md)
- [Commits](https://github.com/symfony/debug-bundle/compare/v5.4.39...v5.4.40)

---
updated-dependencies:
- dependency-name: symfony/debug-bundle
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-03 16:01:55 +02:00
dependabot[bot]
c17acb2ed8 Bump symfony/var-dumper from 5.4.39 to 5.4.40 in /modules/btcpay
Bumps [symfony/var-dumper](https://github.com/symfony/var-dumper) from 5.4.39 to 5.4.40.
- [Release notes](https://github.com/symfony/var-dumper/releases)
- [Changelog](https://github.com/symfony/var-dumper/blob/7.1/CHANGELOG.md)
- [Commits](https://github.com/symfony/var-dumper/compare/v5.4.39...v5.4.40)

---
updated-dependencies:
- dependency-name: symfony/var-dumper
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-03 16:01:42 +02:00
dependabot[bot]
7b793d1acf Bump smarty/smarty from 4.5.2 to 4.5.3
Bumps [smarty/smarty](https://github.com/smarty-php/smarty) from 4.5.2 to 4.5.3.
- [Release notes](https://github.com/smarty-php/smarty/releases)
- [Changelog](https://github.com/smarty-php/smarty/blob/v4.5.3/CHANGELOG.md)
- [Commits](https://github.com/smarty-php/smarty/compare/v4.5.2...v4.5.3)

---
updated-dependencies:
- dependency-name: smarty/smarty
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-29 20:48:13 +02:00
dependabot[bot]
eb57c0b117 Bump squizlabs/php_codesniffer from 3.10.0 to 3.10.1
Bumps [squizlabs/php_codesniffer](https://github.com/PHPCSStandards/PHP_CodeSniffer) from 3.10.0 to 3.10.1.
- [Release notes](https://github.com/PHPCSStandards/PHP_CodeSniffer/releases)
- [Changelog](https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/CHANGELOG.md)
- [Commits](https://github.com/PHPCSStandards/PHP_CodeSniffer/compare/3.10.0...3.10.1)

---
updated-dependencies:
- dependency-name: squizlabs/php_codesniffer
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-23 15:44:57 +02:00
dependabot[bot]
4a95f790d2 Bump prestashop/php-dev-tools from 4.3.0 to 5
Bumps [prestashop/php-dev-tools](https://github.com/PrestaShop/php-dev-tools) from 4.3.0 to 5.
- [Release notes](https://github.com/PrestaShop/php-dev-tools/releases)
- [Commits](https://github.com/PrestaShop/php-dev-tools/compare/v4.3.0...v5)

---
updated-dependencies:
- dependency-name: prestashop/php-dev-tools
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-23 15:43:27 +02:00
dependabot[bot]
8e035725d7 Bump squizlabs/php_codesniffer from 3.9.2 to 3.10.0
Bumps [squizlabs/php_codesniffer](https://github.com/PHPCSStandards/PHP_CodeSniffer) from 3.9.2 to 3.10.0.
- [Release notes](https://github.com/PHPCSStandards/PHP_CodeSniffer/releases)
- [Changelog](https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/CHANGELOG.md)
- [Commits](https://github.com/PHPCSStandards/PHP_CodeSniffer/compare/3.9.2...3.10.0)

---
updated-dependencies:
- dependency-name: squizlabs/php_codesniffer
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-20 15:38:07 +02:00
BitcoinMitchell
e6f0f4cf88 Removed feature-request.yml 2024-05-06 00:06:09 +02:00
BitcoinMitchell
a635a5ba2e Update config.yml 2024-05-06 00:06:09 +02:00
BitcoinMitchell
5400690620 Update README.md 2024-05-06 00:06:09 +02:00
dependabot[bot]
68c91cd773 Bump symfony/debug-bundle from 4.4.37 to 5.4.39 in /modules/btcpay
Bumps [symfony/debug-bundle](https://github.com/symfony/debug-bundle) from 4.4.37 to 5.4.39.
- [Release notes](https://github.com/symfony/debug-bundle/releases)
- [Changelog](https://github.com/symfony/debug-bundle/blob/7.0/CHANGELOG.md)
- [Commits](https://github.com/symfony/debug-bundle/compare/v4.4.37...v5.4.39)

---
updated-dependencies:
- dependency-name: symfony/debug-bundle
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-29 15:38:40 +02:00
dependabot[bot]
a4ff72ab3d Bump btcpayserver/btcpayserver-greenfield-php in /modules/btcpay
Bumps [btcpayserver/btcpayserver-greenfield-php](https://github.com/btcpayserver/btcpayserver-greenfield-php) from 2.5.0 to 2.6.0.
- [Release notes](https://github.com/btcpayserver/btcpayserver-greenfield-php/releases)
- [Commits](https://github.com/btcpayserver/btcpayserver-greenfield-php/compare/v2.5.0...v2.6.0)

---
updated-dependencies:
- dependency-name: btcpayserver/btcpayserver-greenfield-php
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-25 21:10:39 +02:00
dependabot[bot]
f4ed7e3dce Bump squizlabs/php_codesniffer from 3.9.1 to 3.9.2
Bumps [squizlabs/php_codesniffer](https://github.com/PHPCSStandards/PHP_CodeSniffer) from 3.9.1 to 3.9.2.
- [Release notes](https://github.com/PHPCSStandards/PHP_CodeSniffer/releases)
- [Changelog](https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/CHANGELOG.md)
- [Commits](https://github.com/PHPCSStandards/PHP_CodeSniffer/compare/3.9.1...3.9.2)

---
updated-dependencies:
- dependency-name: squizlabs/php_codesniffer
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-24 15:45:28 +02:00
BitcoinMitchell
18c71a2ba1 [DX] Use mailpit over mailhog 2024-04-10 16:08:16 +02:00
BitcoinMitchell
0ea3887f25 [Core] Version bump
Some checks failed
Release / Release a new ZIP (push) Has been cancelled
2024-04-08 14:31:29 +02:00
BitcoinMitchell
f4570c3576 [Core] Updated dependencies 2024-04-08 14:31:29 +02:00
BitcoinMitchell
1a9b2eece9 [Core] Ensure module warnings do not error out when configuration is invalid 2024-04-08 14:31:29 +02:00
BitcoinMitchell
a13be64da8 [UX] Added button to go to Dashboard 2024-04-08 14:31:29 +02:00
BitcoinMitchell
0ee632af25 [UX] When clicking on the linked store, go to the actual store instead of the the instance homepage 2024-04-08 14:31:29 +02:00
BitcoinMitchell
33b52d97a2 [UX] Improved API key error message slightly 2024-04-08 14:31:29 +02:00
BitcoinMitchell
b713c4a0fd [DX] Added an validator error typehint 2024-04-08 14:31:29 +02:00
BitcoinMitchell
2c60973224 [Configure] Get the store as soon as possible 2024-04-08 14:31:29 +02:00
BitcoinMitchell
6740d86cb1 [Configuration] Reset the API key if it is invalid 2024-04-08 14:31:29 +02:00
dependabot[bot]
9e876d325d Bump symfony/var-dumper from 4.4.47 to 5.4.38 in /modules/btcpay
Bumps [symfony/var-dumper](https://github.com/symfony/var-dumper) from 4.4.47 to 5.4.38.
- [Release notes](https://github.com/symfony/var-dumper/releases)
- [Changelog](https://github.com/symfony/var-dumper/blob/7.0/CHANGELOG.md)
- [Commits](https://github.com/symfony/var-dumper/compare/v4.4.47...v5.4.38)

---
updated-dependencies:
- dependency-name: symfony/var-dumper
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-04 19:35:29 +02:00
dependabot[bot]
9efc69dcd8 Bump btcpayserver/btcpayserver-greenfield-php in /modules/btcpay
Bumps [btcpayserver/btcpayserver-greenfield-php](https://github.com/btcpayserver/btcpayserver-greenfield-php) from 2.4.0 to 2.5.0.
- [Release notes](https://github.com/btcpayserver/btcpayserver-greenfield-php/releases)
- [Commits](https://github.com/btcpayserver/btcpayserver-greenfield-php/compare/v2.4.0...v2.5.0)

---
updated-dependencies:
- dependency-name: btcpayserver/btcpayserver-greenfield-php
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-03 15:09:58 +02:00
dependabot[bot]
b002e106e7 Bump squizlabs/php_codesniffer from 3.9.0 to 3.9.1
Bumps [squizlabs/php_codesniffer](https://github.com/PHPCSStandards/PHP_CodeSniffer) from 3.9.0 to 3.9.1.
- [Release notes](https://github.com/PHPCSStandards/PHP_CodeSniffer/releases)
- [Changelog](https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/CHANGELOG.md)
- [Commits](https://github.com/PHPCSStandards/PHP_CodeSniffer/compare/3.9.0...3.9.1)

---
updated-dependencies:
- dependency-name: squizlabs/php_codesniffer
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-01 16:00:20 +02:00
dependabot[bot]
8550a91500 Bump stechstudio/backoff from 1.2.1 to 1.3 in /modules/btcpay
Bumps [stechstudio/backoff](https://github.com/stechstudio/backoff) from 1.2.1 to 1.3.
- [Release notes](https://github.com/stechstudio/backoff/releases)
- [Commits](https://github.com/stechstudio/backoff/compare/1.2.1...1.3)

---
updated-dependencies:
- dependency-name: stechstudio/backoff
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-03-29 14:25:24 +01:00
dependabot[bot]
f9b2914c14 Bump btcpayserver/btcpayserver-greenfield-php in /modules/btcpay
Bumps [btcpayserver/btcpayserver-greenfield-php](https://github.com/btcpayserver/btcpayserver-greenfield-php) from 2.3.0 to 2.4.0.
- [Release notes](https://github.com/btcpayserver/btcpayserver-greenfield-php/releases)
- [Commits](https://github.com/btcpayserver/btcpayserver-greenfield-php/compare/v2.3.0...v2.4.0)

---
updated-dependencies:
- dependency-name: btcpayserver/btcpayserver-greenfield-php
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-03-27 14:25:29 +01:00
dependabot[bot]
2259d61806 Bump php-parallel-lint/php-parallel-lint from 1.3.2 to 1.4.0
Bumps [php-parallel-lint/php-parallel-lint](https://github.com/php-parallel-lint/PHP-Parallel-Lint) from 1.3.2 to 1.4.0.
- [Release notes](https://github.com/php-parallel-lint/PHP-Parallel-Lint/releases)
- [Changelog](https://github.com/php-parallel-lint/PHP-Parallel-Lint/blob/v1.4.0/CHANGELOG.md)
- [Commits](https://github.com/php-parallel-lint/PHP-Parallel-Lint/compare/v1.3.2...v1.4.0)

---
updated-dependencies:
- dependency-name: php-parallel-lint/php-parallel-lint
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-03-27 14:23:20 +01:00
BitcoinMitchell
b37761e103 [Versioning] Re-use the existing CurlClient for version checking
Some checks failed
Release / Release a new ZIP (push) Has been cancelled
Less depedencies, more better
2024-03-14 11:55:46 +01:00
BitcoinMitchell
26c0c168f7 Update README.md 2024-03-12 22:52:48 +01:00
dependabot[bot]
14e8f40f98 Bump softprops/action-gh-release from 1 to 2 in /.github/workflows
Bumps [softprops/action-gh-release](https://github.com/softprops/action-gh-release) from 1 to 2.
- [Release notes](https://github.com/softprops/action-gh-release/releases)
- [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md)
- [Commits](https://github.com/softprops/action-gh-release/compare/v1...v2)

---
updated-dependencies:
- dependency-name: softprops/action-gh-release
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-03-11 15:22:30 +01:00
dependabot[bot]
873f3225f9 Bump stechstudio/backoff from 1.2 to 1.2.1 in /modules/btcpay
Bumps [stechstudio/backoff](https://github.com/stechstudio/backoff) from 1.2 to 1.2.1.
- [Release notes](https://github.com/stechstudio/backoff/releases)
- [Commits](https://github.com/stechstudio/backoff/compare/1.2...1.2.1)

---
updated-dependencies:
- dependency-name: stechstudio/backoff
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-03-10 23:23:59 +01:00
BitcoinMitchell
93a32d7ddd [GitHub] Use github.ref_name instead of github.ref 2024-02-28 22:18:55 +01:00
BitcoinMitchell
7e4336095a [Core] Version bump
Some checks failed
Release / Release a new ZIP (push) Has been cancelled
2024-02-28 22:10:06 +01:00
BitcoinMitchell
caa5289ac6 [Core] Add the README.md to /docs as well 2024-02-28 22:10:06 +01:00
BitcoinMitchell
b948ad38e5 [Core] Ensure all TPL variables are escaped 2024-02-28 22:10:06 +01:00
BitcoinMitchell
da640a7c36 [Core] Ensure all folders have index.php 2024-02-28 22:10:06 +01:00
BitcoinMitchell
8ed68bc353 [Core] Ensure all PHP files contain defined('_PS_VERSION_') 2024-02-28 22:10:06 +01:00
BitcoinMitchell
85ff776e7f [Core] Added our module key 2024-02-28 22:10:06 +01:00
BitcoinMitchell
28fc02d9a7 Update README.md 2024-02-27 14:02:44 +01:00
BitcoinMitchell
596d4fa01c [Core] Ensure relevant polyfills are replaced
Executed `composer normalize` as well
2024-02-22 15:18:58 +01:00
BitcoinMitchell
8b64109de3 [Core] Lock Symfony to 4.4.* 2024-02-22 14:57:54 +01:00
dependabot[bot]
4a8f9942ac Bump actions/checkout from 2 to 4 in /.github/workflows
Bumps [actions/checkout](https://github.com/actions/checkout) from 2 to 4.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v2...v4)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-22 14:54:03 +01:00
dependabot[bot]
3325af8ec4 Bump actions/cache from 3 to 4 in /.github/workflows
Bumps [actions/cache](https://github.com/actions/cache) from 3 to 4.
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](https://github.com/actions/cache/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/cache
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-22 14:52:36 +01:00
BitcoinMitchell
270c17984e Update dependencies.yml
[GitHub] Ensure logical name for dependencies workflow
2024-02-22 14:50:11 +01:00
BitcoinMitchell
7584858250 Updated GitHub relevant files 2024-02-22 14:39:40 +01:00
BitcoinMitchell
daac5df679
[Core] Resolve installation failure (#101)
Some checks failed
Release / Release a new ZIP (push) Has been cancelled
2024-02-22 00:35:09 +01:00
BitcoinMitchell
5497847d6e Updated README/LICENSE to 2024 2024-02-21 22:36:44 +01:00
BitcoinMitchell
51196354b4 [Core] Ensure sane repositories
Some checks failed
Release / Release a new ZIP (push) Has been cancelled
2024-02-21 20:42:43 +01:00
BitcoinMitchell
73ef8ceb3f [Order] Show payment info if order was created via BTCPay Server 2024-02-21 20:42:43 +01:00
BitcoinMitchell
4d8d0c48c7 [Versioning] Show module warning for latest version if no other warnings set 2024-02-21 20:42:43 +01:00
BitcoinMitchell
776a08bea5 [OrderStates] Ensure customers can download the invoice when marked as paid 2024-02-21 20:42:43 +01:00
BitcoinMitchell
e11f8c8f7b [Processor] Improved order handling, add payments, ensure clear warnings 2024-02-21 20:42:43 +01:00
BitcoinMitchell
480881538e [Order] Protect order status changes when already paid
Enabled by default
2024-02-21 20:42:43 +01:00
BitcoinMitchell
4ffeafbb3e [Developer] Added missing bcmath dependency 2024-02-21 20:42:43 +01:00
BitcoinMitchell
79011fa65c [Developer] Added simple bitcoin-cli script for bitcoind inside docker
Only accepts the commands you really need
2024-02-21 20:42:43 +01:00
BitcoinMitchell
dac5503784 [Developer] Use docker-compose.override.yml instead of .dist 2024-02-21 20:42:43 +01:00
dependabot[bot]
72a798226e
Bump squizlabs/php_codesniffer from 3.8.1 to 3.9.0 (#97)
Bumps [squizlabs/php_codesniffer](https://github.com/PHPCSStandards/PHP_CodeSniffer) from 3.8.1 to 3.9.0.
- [Release notes](https://github.com/PHPCSStandards/PHP_CodeSniffer/releases)
- [Changelog](https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/CHANGELOG.md)
- [Commits](https://github.com/PHPCSStandards/PHP_CodeSniffer/compare/3.8.1...3.9.0)

---
updated-dependencies:
- dependency-name: squizlabs/php_codesniffer
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-20 20:23:27 +01:00
BitcoinMitchell
fc0713a022 Removed unused code 2024-02-19 16:43:19 +01:00
BitcoinMitchell
eda842fe9c Updated module warnings 2024-02-19 16:43:19 +01:00
BitcoinMitchell
0367537a2b Improved the configuration page 2024-02-19 16:43:19 +01:00
BitcoinMitchell
ef3a93aa28 Improved configuration layout 2024-02-19 16:43:19 +01:00
BitcoinMitchell
d9fbbbe478 Upgraded to latest dependencies
Some checks failed
Release / Release a new ZIP (push) Has been cancelled
2024-02-19 14:54:18 +01:00
dependabot[bot]
87d41f086c Bump ergebnis/composer-normalize from 2.31.0 to 2.42.0
Bumps [ergebnis/composer-normalize](https://github.com/ergebnis/composer-normalize) from 2.31.0 to 2.42.0.
- [Release notes](https://github.com/ergebnis/composer-normalize/releases)
- [Changelog](https://github.com/ergebnis/composer-normalize/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ergebnis/composer-normalize/compare/2.31.0...2.42.0)

---
updated-dependencies:
- dependency-name: ergebnis/composer-normalize
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-08 19:40:38 +01:00
dependabot[bot]
5026f592f9 Bump squizlabs/php_codesniffer from 3.8.0 to 3.8.1
Bumps [squizlabs/php_codesniffer](https://github.com/PHPCSStandards/PHP_CodeSniffer) from 3.8.0 to 3.8.1.
- [Release notes](https://github.com/PHPCSStandards/PHP_CodeSniffer/releases)
- [Changelog](https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/CHANGELOG.md)
- [Commits](https://github.com/PHPCSStandards/PHP_CodeSniffer/compare/3.8.0...3.8.1)

---
updated-dependencies:
- dependency-name: squizlabs/php_codesniffer
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-12 14:28:13 +01:00
dependabot[bot]
f3d0e0c88b Bump squizlabs/php_codesniffer from 3.7.2 to 3.8.0
Bumps [squizlabs/php_codesniffer](https://github.com/squizlabs/PHP_CodeSniffer) from 3.7.2 to 3.8.0.
- [Release notes](https://github.com/squizlabs/PHP_CodeSniffer/releases)
- [Commits](https://github.com/squizlabs/PHP_CodeSniffer/commits)

---
updated-dependencies:
- dependency-name: squizlabs/php_codesniffer
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-08 23:40:55 +01:00
Mitchell
70f263b5fa Removed the displayPaymentEU hook
Some checks failed
Release / Release a new ZIP (push) Has been cancelled
2023-11-15 21:54:44 +01:00
Mitchell
c9eecba5b5 FIX: Ensure client is available in validation.php
Some checks failed
Release / Release a new ZIP (push) Has been cancelled
2023-11-15 21:47:37 +01:00
dependabot[bot]
05f4108874 Bump symfony/symfony from 4.4.50 to 4.4.51
Bumps [symfony/symfony](https://github.com/symfony/symfony) from 4.4.50 to 4.4.51.
- [Release notes](https://github.com/symfony/symfony/releases)
- [Changelog](https://github.com/symfony/symfony/blob/v4.4.51/CHANGELOG-4.4.md)
- [Commits](https://github.com/symfony/symfony/compare/v4.4.50...v4.4.51)

---
updated-dependencies:
- dependency-name: symfony/symfony
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-11-12 17:21:15 +01:00
dependabot[bot]
c0fe58ddd6 Bump symfony/twig-bridge from 5.4.22 to 5.4.31 in /modules/btcpay
Bumps [symfony/twig-bridge](https://github.com/symfony/twig-bridge) from 5.4.22 to 5.4.31.
- [Release notes](https://github.com/symfony/twig-bridge/releases)
- [Changelog](https://github.com/symfony/twig-bridge/blob/6.3/CHANGELOG.md)
- [Commits](https://github.com/symfony/twig-bridge/compare/v5.4.22...v5.4.31)

---
updated-dependencies:
- dependency-name: symfony/twig-bridge
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-11-12 17:18:32 +01:00
Mitchell
5a36fd0b28 Show more information
Some checks failed
Release / Release a new ZIP (push) Has been cancelled
2023-07-14 13:24:01 +02:00
Mitchell
81cea88a6d Revert "Use a null check instead an empty check" 2023-07-14 13:24:01 +02:00
Mitchell
79499ae5a5 Use a null check instead an empty check 2023-07-14 13:24:01 +02:00
Mitchell
cdb08b59cf Remove the set API key if the store isn't fully ready yet
The API key is automatically saved once set, so we must manually remove it
2023-07-14 13:24:01 +02:00
Mitchell
f77e5a6e1b Valid clients can reach the server and the store 2023-07-14 13:24:01 +02:00
Mitchell
eeec2640a9 Use str_contains over strpos, since we require PHP8 2023-07-14 13:24:01 +02:00
Mitchell
27950d30d0 Log more errors and ensure all to have a proper level 2023-07-14 13:24:01 +02:00
Mitchell
62645b2a3e Always check for null after building the Client 2023-07-14 13:24:01 +02:00
ndeet
7e79e66c6d Fix stuff breaking on PS8 on install/uninstall and webhook creation flow causing exceptions. 2023-07-14 13:24:01 +02:00
Mitchell
ac3d5ad40d Updated dependencies 2023-07-14 13:24:01 +02:00
Mitchell
16c3b476ab Updated autocomplete.php 2023-07-14 13:24:01 +02:00
Mitchell
86179f5d58 Updated dependencies 2023-07-14 13:24:01 +02:00
Mitchell
e945c3f260 Ensure the upgrade can be run 2023-07-14 13:24:01 +02:00
Mitchell
359fbd5431 Require BTCPay Server 1.7.0 and up 2023-07-14 13:24:01 +02:00
Mitchell
88ec4142b4 Upgrade to PrestaShop 8.0 2023-07-14 13:24:01 +02:00
dependabot[bot]
020297d48c Bump smarty/smarty from 4.2.1 to 4.3.1
Bumps [smarty/smarty](https://github.com/smarty-php/smarty) from 4.2.1 to 4.3.1.
- [Release notes](https://github.com/smarty-php/smarty/releases)
- [Changelog](https://github.com/smarty-php/smarty/blob/master/CHANGELOG.md)
- [Commits](https://github.com/smarty-php/smarty/compare/v4.2.1...v4.3.1)

---
updated-dependencies:
- dependency-name: smarty/smarty
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-14 13:24:01 +02:00
dependabot[bot]
2b1411dded Bump squizlabs/php_codesniffer from 3.7.1 to 3.7.2
Bumps [squizlabs/php_codesniffer](https://github.com/squizlabs/PHP_CodeSniffer) from 3.7.1 to 3.7.2.
- [Release notes](https://github.com/squizlabs/PHP_CodeSniffer/releases)
- [Commits](https://github.com/squizlabs/PHP_CodeSniffer/compare/3.7.1...3.7.2)

---
updated-dependencies:
- dependency-name: squizlabs/php_codesniffer
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-14 13:24:01 +02:00
Mitchell
16cace9671 GitHub Workflow changes 2023-07-14 13:24:01 +02:00
dependabot[bot]
602ece9635 Bump symfony/http-kernel from 4.4.47 to 5.4.20 in /modules/btcpay
Bumps [symfony/http-kernel](https://github.com/symfony/http-kernel) from 4.4.47 to 5.4.20.
- [Release notes](https://github.com/symfony/http-kernel/releases)
- [Changelog](https://github.com/symfony/http-kernel/blob/6.2/CHANGELOG.md)
- [Commits](https://github.com/symfony/http-kernel/compare/v4.4.47...v5.4.20)

---
updated-dependencies:
- dependency-name: symfony/http-kernel
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-14 13:24:01 +02:00
Mitchell
1444e200a7 Try and resolve local-php-security-checker issues 2023-07-14 13:24:01 +02:00
dependabot[bot]
878f82d15c Bump symfony/symfony from 4.4.47 to 4.4.50
Bumps [symfony/symfony](https://github.com/symfony/symfony) from 4.4.47 to 4.4.50.
- [Release notes](https://github.com/symfony/symfony/releases)
- [Changelog](https://github.com/symfony/symfony/blob/v4.4.50/CHANGELOG-4.4.md)
- [Commits](https://github.com/symfony/symfony/compare/v4.4.47...v4.4.50)

---
updated-dependencies:
- dependency-name: symfony/symfony
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-14 13:24:01 +02:00
Mitchell
77c18cbd37 Added version checking for the module
Some checks failed
Release / Release a new ZIP (push) Has been cancelled
2023-01-16 01:56:41 +01:00
Mitchell
13018117d8 Updated README.md 2023-01-16 01:35:39 +01:00
dependabot[bot]
9ddf7aeef9 Bump prestashop/php-dev-tools from 4.2.1 to 4.3.0
Bumps [prestashop/php-dev-tools](https://github.com/PrestaShop/php-dev-tools) from 4.2.1 to 4.3.0.
- [Release notes](https://github.com/PrestaShop/php-dev-tools/releases)
- [Commits](https://github.com/PrestaShop/php-dev-tools/compare/v4.2.1...v4.3.0)

---
updated-dependencies:
- dependency-name: prestashop/php-dev-tools
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-10-19 17:33:35 +02:00
Mitchell
e96befdb95 Allow API key to be set, in case redirection fails
Some checks failed
Release / Release a new ZIP (push) Has been cancelled
2022-10-15 14:30:14 +02:00
Mitchell
2946d33316 Updated twig/twig to v3.4.3 2022-09-30 11:48:57 +02:00
dependabot[bot]
81fc413574 Bump smarty/smarty from 4.2.0 to 4.2.1
Bumps smarty/smarty from 4.2.0 to 4.2.1.

---
updated-dependencies:
- dependency-name: smarty/smarty
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-09-17 01:47:51 +02:00
Mitchell
0e804f9357 composer bump 2022-08-23 00:09:53 +02:00
Mitchell
9fabe66f44 Bump version
Some checks failed
Release / Release a new ZIP (push) Has been cancelled
2022-08-14 00:36:32 +02:00
Mitchell
1678d502cb Changed MAJOR to WARNING 2022-08-14 00:36:32 +02:00
dependabot[bot]
47952a6345 Bump guzzlehttp/guzzle from 7.4.4 to 7.4.5
Bumps [guzzlehttp/guzzle](https://github.com/guzzle/guzzle) from 7.4.4 to 7.4.5.
- [Release notes](https://github.com/guzzle/guzzle/releases)
- [Changelog](https://github.com/guzzle/guzzle/blob/master/CHANGELOG.md)
- [Commits](https://github.com/guzzle/guzzle/compare/7.4.4...7.4.5)

---
updated-dependencies:
- dependency-name: guzzlehttp/guzzle
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-21 23:28:46 +02:00
dependabot[bot]
a6efd7b97f Bump squizlabs/php_codesniffer from 3.7.0 to 3.7.1
Bumps [squizlabs/php_codesniffer](https://github.com/squizlabs/PHP_CodeSniffer) from 3.7.0 to 3.7.1.
- [Release notes](https://github.com/squizlabs/PHP_CodeSniffer/releases)
- [Commits](https://github.com/squizlabs/PHP_CodeSniffer/compare/3.7.0...3.7.1)

---
updated-dependencies:
- dependency-name: squizlabs/php_codesniffer
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-20 18:29:28 +02:00
dependabot[bot]
03e262c714 Bump squizlabs/php_codesniffer from 3.6.2 to 3.7.0
Bumps [squizlabs/php_codesniffer](https://github.com/squizlabs/PHP_CodeSniffer) from 3.6.2 to 3.7.0.
- [Release notes](https://github.com/squizlabs/PHP_CodeSniffer/releases)
- [Commits](https://github.com/squizlabs/PHP_CodeSniffer/compare/3.6.2...3.7.0)

---
updated-dependencies:
- dependency-name: squizlabs/php_codesniffer
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-13 20:46:28 +02:00
Mitchell
de5b78eff5 Bumped module version
Some checks failed
Release / Release a new ZIP (push) Has been cancelled
2022-06-12 23:10:48 +02:00
Mitchell
6d14bc15c4 Show message for Prestashop Security Popup 2022-06-12 23:06:38 +02:00
Mitchell
0bb2d9db6d Hide payment option if the server is down/not connected/still syncing 2022-06-12 23:06:38 +02:00
Mitchell
81c2d4f8eb Do not process a payment that doesn't have an order 2022-06-12 23:06:38 +02:00
dependabot[bot]
6fdb5bf58c Bump guzzlehttp/guzzle from 7.4.2 to 7.4.4
Bumps [guzzlehttp/guzzle](https://github.com/guzzle/guzzle) from 7.4.2 to 7.4.4.
- [Release notes](https://github.com/guzzle/guzzle/releases)
- [Changelog](https://github.com/guzzle/guzzle/blob/master/CHANGELOG.md)
- [Commits](https://github.com/guzzle/guzzle/compare/7.4.2...7.4.4)

---
updated-dependencies:
- dependency-name: guzzlehttp/guzzle
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-10 21:01:27 +02:00
dependabot[bot]
1e6dd28d89 Bump slevomat/coding-standard from 7.2.0 to 7.2.1
Bumps [slevomat/coding-standard](https://github.com/slevomat/coding-standard) from 7.2.0 to 7.2.1.
- [Release notes](https://github.com/slevomat/coding-standard/releases)
- [Commits](https://github.com/slevomat/coding-standard/compare/7.2.0...7.2.1)

---
updated-dependencies:
- dependency-name: slevomat/coding-standard
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-05-27 00:15:17 +02:00
dependabot[bot]
e396f57867 Bump smarty/smarty from 3.1.44 to 3.1.45
Bumps smarty/smarty from 3.1.44 to 3.1.45.

---
updated-dependencies:
- dependency-name: smarty/smarty
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-05-27 00:13:24 +02:00
dependabot[bot]
d8cf11fbe7 Bump slevomat/coding-standard from 7.1 to 7.2.0
Bumps [slevomat/coding-standard](https://github.com/slevomat/coding-standard) from 7.1 to 7.2.0.
- [Release notes](https://github.com/slevomat/coding-standard/releases)
- [Commits](https://github.com/slevomat/coding-standard/compare/7.1.0...7.2.0)

---
updated-dependencies:
- dependency-name: slevomat/coding-standard
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-05-06 17:33:43 +02:00
BitcoinMitchell
e76c5a284d Update README.md 2022-04-28 16:18:21 +02:00
Mitchell
bfaf21e81a Resolved getting an empty data object as webhook
Some checks failed
Release / Release a new ZIP (push) Has been cancelled
This affected webhook creation (as it never made one), resulting in the plugin not working
2022-04-28 16:09:59 +02:00
Mitchell
c0af983350 Upgraded dependencies 2022-04-28 16:09:59 +02:00
Mitchell
e84cea11aa Updated docker-compose to the latest versions 2022-04-28 16:09:59 +02:00
dependabot[bot]
68fedd5cea Bump slevomat/coding-standard from 7.0.19 to 7.1
Bumps [slevomat/coding-standard](https://github.com/slevomat/coding-standard) from 7.0.19 to 7.1.
- [Release notes](https://github.com/slevomat/coding-standard/releases)
- [Commits](https://github.com/slevomat/coding-standard/compare/7.0.19...7.1.0)

---
updated-dependencies:
- dependency-name: slevomat/coding-standard
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-30 11:32:11 +02:00
dependabot[bot]
efaf73c83f Bump guzzlehttp/psr7 from 2.1.0 to 2.2.1
Bumps [guzzlehttp/psr7](https://github.com/guzzle/psr7) from 2.1.0 to 2.2.1.
- [Release notes](https://github.com/guzzle/psr7/releases)
- [Changelog](https://github.com/guzzle/psr7/blob/master/CHANGELOG.md)
- [Commits](https://github.com/guzzle/psr7/compare/2.1.0...2.2.1)

---
updated-dependencies:
- dependency-name: guzzlehttp/psr7
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-30 11:30:33 +02:00
Mitchell
f908920c0c Brought back the order creation after payment option
Some checks failed
Release / Release a new ZIP (push) Has been cancelled
2022-03-19 16:41:22 +01:00
Mitchell
eccf86bb3f Upgraded module depedencies 2022-03-19 16:41:22 +01:00
Mitchell
f624bbc000 Use proper function and constants 2022-03-19 16:41:22 +01:00
BitcoinMitchell
fa9c781651 Update README.md 2022-03-18 23:23:12 +01:00
Mitchell
cb5e85eb25 Updated docker-compose.yml.dist 2022-03-16 22:55:54 +01:00
Mitchell
0d451e5462 Upgraded depedencies 2022-03-16 22:55:54 +01:00
Mitchell
34d2529a44 Only remove the configuration during reset/uninstall
Some checks failed
Release / Release a new ZIP (push) Has been cancelled
2022-03-09 00:13:45 +01:00
dependabot[bot]
db8164abbc Bump slevomat/coding-standard from 6.4.1 to 7.0.19
Bumps [slevomat/coding-standard](https://github.com/slevomat/coding-standard) from 6.4.1 to 7.0.19.
- [Release notes](https://github.com/slevomat/coding-standard/releases)
- [Commits](https://github.com/slevomat/coding-standard/compare/6.4.1...7.0.19)

---
updated-dependencies:
- dependency-name: slevomat/coding-standard
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-07 19:54:09 +01:00
BitcoinMitchell
308ed5e15f
Enable Dependabot (#37) 2022-03-07 18:52:24 +00:00
Mitchell
58a574c3a1 Updated version
Some checks failed
Release / Release a new ZIP (push) Has been cancelled
2022-03-07 19:30:15 +01:00
Mitchell
12b028e775 Do not remove order states when removing the module
This causes a lot of side effects that aren't fun.
2022-03-07 19:30:15 +01:00
Mitchell
5224a95887 Do not error out if invoice is not found 2022-03-07 19:30:15 +01:00
Mitchell
e21b958d5b Updated depedencies 2022-03-07 19:30:15 +01:00
Mitchell
ea086535c3 Use the new getSecret() from greenfield-php 2022-02-14 23:32:13 +01:00
Mitchell
59757d5ebc Show plugin version on the configure page 2022-02-14 23:32:13 +01:00
Mitchell
c613c01910 Made a few more codestyle changes
Some checks failed
Release / Release a new ZIP (push) Has been cancelled
2022-02-14 01:07:35 +01:00
Mitchell
f2888a65aa Upgraded btcpayserver/btcpayserver-greenfield-php 2022-02-14 01:07:35 +01:00
BitcoinMitchell
6bdeba362a Removed outdated documentation 2022-02-13 17:05:43 +01:00
BitcoinMitchell
09f4c71f18 Remove module version from README.md
It is no longer relevant as it's consistent with the release version
2022-02-13 16:49:45 +01:00
Mitchell
6d182ca991 Create order when the user is redirect to BTCPay Server
Some checks failed
Release / Release a new ZIP (push) Has been cancelled
Resolves #28
2022-02-13 16:40:55 +01:00
Mitchell
5896429500 Update docker images to the latest versions 2022-02-13 16:40:55 +01:00
Mitchell
497fe5a8cf Updated templates slightly 2022-02-13 16:40:55 +01:00
Mitchell
843a67a2f9 Updated codestyle rules to be more modern 2022-02-13 16:40:55 +01:00
Mitchell
ada445fa9a Use \Throwable instead of \Exception 2022-02-13 16:40:55 +01:00
Mitchell
ee4983df82 Improved errors in Webhook front controller 2022-02-13 16:40:55 +01:00
Mitchell
90fec5125d Improved error handling on payment page 2022-02-13 16:40:55 +01:00
dependabot[bot]
9c0fc5263b Bump twig/twig from 3.3.7 to 3.3.8
Bumps [twig/twig](https://github.com/twigphp/Twig) from 3.3.7 to 3.3.8.
- [Release notes](https://github.com/twigphp/Twig/releases)
- [Changelog](https://github.com/twigphp/Twig/blob/3.x/CHANGELOG)
- [Commits](https://github.com/twigphp/Twig/compare/v3.3.7...v3.3.8)

---
updated-dependencies:
- dependency-name: twig/twig
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-11 13:09:46 +01:00
Mitchell
71a5b15999 Updated all dependencies 2022-02-03 21:24:53 +01:00
Mitchell
191d08fde7 Updated all dependencies 2022-01-27 20:19:03 +01:00
BitcoinMitchell
5d15a68c78 Validate on PHP 8.1 as well 2022-01-27 20:19:03 +01:00
BitcoinMitchell
1498ced3b7 Updated Shields.io link 2022-01-27 19:50:36 +01:00
BitcoinMitchell
51550d6283 Resolve incorrect URL in README.md 2022-01-27 19:45:26 +01:00
BitcoinMitchell
da63e320d3 Create CONTRIBUTING.md 2022-01-27 19:26:23 +01:00
BitcoinMitchell
e4fc93b30e Updated year in LICENSE 2022-01-27 19:20:07 +01:00
dependabot[bot]
1432001ed2 Bump smarty/smarty from 3.1.40 to 3.1.43
Bumps smarty/smarty from 3.1.40 to 3.1.43.

---
updated-dependencies:
- dependency-name: smarty/smarty
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-01-13 22:14:43 +01:00
BitcoinMitchell
19d15fe07b Update README.md
Some checks failed
Release / Release a new ZIP (push) Has been cancelled
2021-11-25 22:26:47 +01:00
BitcoinMitchell
73839e37a9 Updated module version in the README.md 2021-11-25 22:26:47 +01:00
BitcoinMitchell
949592e4de Update the module version 2021-11-25 22:26:47 +01:00
Mitchell
82bec456d2 Only run the validation workflow for pull requests 2021-11-25 14:36:50 +01:00
Mitchell
a985077226 Check if storeID exists, before calling 'ensureWebhook' 2021-11-25 14:33:36 +01:00
Mitchell
c0ce763801 Removed pointless @noinspection statements
Some checks failed
Release / Release a new ZIP (push) Has been cancelled
Validate / Linting (PHP ${{ matrix.php-versions }}) (7.3) (push) Has been cancelled
Validate / Linting (PHP ${{ matrix.php-versions }}) (7.4) (push) Has been cancelled
Validate / Linting (PHP ${{ matrix.php-versions }}) (8.0) (push) Has been cancelled
2021-11-25 14:09:06 +01:00
Mitchell
4cb72c5763 Store webhook secret after creation 2021-11-25 14:09:06 +01:00
Mitchell
d9f86ca22b Only reset configuration 2021-11-25 14:09:06 +01:00
Mitchell
30369474fc Added option to share metadata with BTCPay Server 2021-11-25 14:09:06 +01:00
Mitchell
c1f662a919 Updated README.md with actually tested setup 2021-11-25 14:09:06 +01:00
Mitchell
88da987c88 Use provided 'isIncomingWebhookRequestValid' function 2021-11-25 14:09:06 +01:00
Mitchell
a79203fc5f Improved pull request template 2021-11-25 14:09:06 +01:00
Mitchell
be44357845 Refactor to new Greenfield API 2021-11-25 14:09:06 +01:00
Mitchell
9c923eb83b Include basic docker-compose 2021-11-25 14:09:06 +01:00
131 changed files with 14145 additions and 7082 deletions

3
.github/FUNDING.yml vendored
View File

@ -1,2 +1 @@
# These are supported funding model platforms
custom: https://foundation.btcpayserver.org
custom: https://btcpayserver.org/donate/

View File

@ -1,38 +0,0 @@
---
name: Bug report
about: File a bug report
title: ''
labels: ''
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Your BTCPay Environment (please complete the following information):**
- BTCPay Server Version [available in the right bottom corner of footer]
- Deployment Method: [e.g. Docker, Manual, Third-Party-hoist]
- Browser [e.g. chrome, safari]
**Logs (if applicable)**
Basic logs can be found in Server Settings > Logs. More logs https://docs.btcpayserver.org/Troubleshooting/#2-looking-through-the-logs
**Setup Parameters**
If you're reporting a deployment issue run `. btcpay-setup.sh -i` and paste your the parameters by obscuring private information.
**Additional context**
Add any other context about the problem here.

79
.github/ISSUE_TEMPLATE/bug-report.yml vendored Normal file
View File

@ -0,0 +1,79 @@
name: 🐛 Bug Report
description: File a bug report
title: "[Bug]: "
labels: ["bug"]
body:
- type: markdown
attributes:
value: |
### ❗️ Read this before submitting your bug report:
- **Provide as much detail as possible** - error logs, screenshots, your exact configuration. If the issue cannot be reproduced, it cannot be fixed.
- **Avoid reporting "error 500" or "white page" errors** - this is a universal error message that does not provide enough information to qualify the issue. Enable debug mode in the Performance section of PrestaShop or manually in `/config/defines.inc.php` and try again. You should get a proper error message.
- Thank you for taking the time to fill out this bug report!
- type: textarea
id: version
attributes:
label: What is your BTCPay Server version?
description: You can see the version in the footer's bottom right corner
placeholder: I'm running BTCPay v1.X.X.X
validations:
required: true
- type: textarea
id: deployment
attributes:
label: How did you deploy BTCPay Server?
description: Docker, manual, third-party host? Read more on deployment methods [here](https://docs.btcpayserver.org/Deployment/)
placeholder: I'm running BTCPay Server on a...
validations:
required: true
- type: textarea
id: module-version
attributes:
label: What is version of the PrestaShop plugin are you using?
description: You can see the version in the header of the configuration page or in the module list
placeholder: I'm running BTCPay v1.X.X.X
validations:
required: true
- type: textarea
id: what-happened
attributes:
label: What happened?
description: A clear and concise description of what the bug is.
placeholder: Tell us what you see!
validations:
required: true
- type: textarea
id: reproduce
attributes:
label: How did you encounter this bug?
description: Step by step describe how did you encounter the bug?
placeholder: 1. I clicked X 2. Then I clicked Y 3. See error
validations:
required: true
- type: textarea
id: logoutput
attributes:
label: Relevant log output
description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks. PrestaShop logs can be found in Advanced Parameters > Logs.
render: shell
- type: textarea
id: browser
attributes:
label: What browser do you use (if useful)?
description: Provide your browser and it's version. If you replicated issues on multiple browsers, let us know which ones.
placeholder: For example Safari 15.00, Chrome 10.0, Tor, Edge, etc
validations:
required: false
- type: textarea
id: additonal
attributes:
label: Additional information
description: Feel free to provide additional information. Screenshots are always helpful.
- type: checkboxes
id: terms
attributes:
label: Are you sure this is a bug report?
description: By submitting this report, you agree that this is not a support or a feature request. For general questions please read our [documentation](https://docs.btcpayserver.org). You can ask questions [on our community chat](https://chat.btcpayserver.org)
options:
- label: I confirm this is a bug report
required: true

View File

@ -1,5 +1,17 @@
blank_issues_enabled: false
blank_issues_enabled: true
contact_links:
- name: Community Support Chat
- name: 💡 Request a feature
url: https://github.com/btcpayserver/prestashop-plugin/discussions/categories/ideas-feature-requests
about: Submit a feature request or vote on ideas posted by others. Features with most upvotes become roadmap candidates
- name: 🧑‍💻 Ask a technical question
url: https://github.com/btcpayserver/prestashop-plugin/discussions/new?category=technical-support
about: If you're experiencing a technical problem post it to our community support forum
- name: 📝 Official Documentation
url: https://docs.btcpayserver.org
about: Check our documentation for answers to common questions
- name: 💬 Community Support Chat
url: https://chat.btcpayserver.org/
about: Ask general questions and get community support in real-time.
about: Ask general questions and get community support in real-time
- name: 🙏 PrestaShop Support
url: https://www.prestashop-project.org/support/
about: Read up on how you can get support for your PrestaShop store

View File

@ -1,23 +0,0 @@
---
name: Feature request
about: Suggest a new feature or enhancement
title: ''
labels: ''
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Sketch/Image/Wireframe/Mockup**
If applicable provide examples, wireframes, sketches or images to better explain your idea.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

View File

@ -1,19 +0,0 @@
<!-----------------------------------------------------------------------------
Thank you for contributing to the BTCPay plugin!
Please take the time to edit the "Answers" rows below with the necessary information.
Check out our contribution guidelines to find out how to complete it:
https://devdocs.prestashop.com/1.7/contribute/contribution-guidelines/#pull-requests
------------------------------------------------------------------------------>
| Questions | Answers
| ------------- | -------------------------------------------------------
| Description? | Please be specific when describing the PR. <br> Every detail helps: versions, browser/server configuration, specific module/theme, etc. Feel free to add more information below this table.
| Type? | bug fix / improvement / new feature / refacto / critical
| BC breaks? | yes / no
| Deprecations? | yes / no
| Fixed ticket? | Fixes btcpayserver/prestashop-plugin#{issue number here}.
| How to test? | Please indicate how to best verify that this PR is correct.
<!-- Click the form's "Preview" button to make sure the table is functional in GitHub. Thank you! -->

40
.github/dependabot.yml vendored Normal file
View File

@ -0,0 +1,40 @@
version: 2
updates:
# Ensure root composer is up-to-date
- package-ecosystem: composer
directory: /
schedule:
interval: daily
cooldown:
default-days: 7
open-pull-requests-limit: 5
reviewers:
- BitcoinMitchell
labels:
- dependencies
# Ensure module composer is up-to-date
- package-ecosystem: composer
directory: /modules/btcpay
schedule:
interval: daily
cooldown:
default-days: 7
open-pull-requests-limit: 5
reviewers:
- BitcoinMitchell
labels:
- dependencies
# Ensure workflows are up-to-date
- package-ecosystem: github-actions
directory: "/.github/workflows"
schedule:
interval: daily
cooldown:
default-days: 7
open-pull-requests-limit: 5
reviewers:
- BitcoinMitchell
labels:
- dependencies

35
.github/pull_request_template.md vendored Normal file
View File

@ -0,0 +1,35 @@
# Description
Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. List any dependencies that are required for this change.
- Fixes # (issue)
- Depends on # (issue or pr)
# Type of change
Please delete options that are not relevant.
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
- [ ] Refactor (non-breaking change which improves the codebase)
# How Has This Been Tested?
Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration
- [ ] Test A
- [ ] Test B
**Test Configuration**:
* BTCPay Server version:
* PrestaShop version:
* PHP version:
# Checklist:
- [ ] My code follows the style guidelines of this project
- [ ] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [ ] I have checked my code and corrected any misspellings

View File

@ -4,27 +4,33 @@ on:
push:
tags: [ 'v*' ] # Push events to matching v*, i.e. v1.0, v20.15.10
permissions: {}
jobs:
linting:
name: "Release a new ZIP"
runs-on: "ubuntu-latest"
steps:
- name: "Checkout"
uses: "actions/checkout@v2"
uses: "actions/checkout@c2d88d3ecc89a9ef08eebf45d9637801dcee7eb5" # v6.0.0
with:
persist-credentials: false
- name: "Setup PHP, with composer and extensions"
uses: "shivammathur/setup-php@v2" # https://github.com/shivammathur/setup-php
uses: "shivammathur/setup-php@44454db4f0199b8b9685a5d763dc37cbf79108e1" # v2.36.0
with:
php-version: "7.3"
php-version: "8.0"
extensions: "mbstring, xml, ctype, iconv, intl, gd"
tools: "composer:v2"
- name: "Get composer cache directory"
id: "composercache"
run: "echo '::set-output name=dir::$(composer config cache-files-dir)'"
id: "composer-cache"
run: 'echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT'
- name: "Cache composer dependencies"
uses: "actions/cache@v2"
uses: "actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb" # v5.0.1
with:
path: "${{ steps.composercache.outputs.dir }}"
path: "${{ steps.composer-cache.outputs.dir }}"
key: "${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}"
restore-keys: "${{ runner.os }}-composer-"
lookup-only: true
- name: "Validate composer"
run: "composer validate"
- name: "Install Composer dependencies"
@ -34,24 +40,14 @@ jobs:
- name: "Make zip"
run: "make"
# Make a release from the tag
# Make a release from the tag and upload the zip
- name: "Create Release"
id: "create_release"
uses: "actions/create-release@v1"
env:
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" # This token is provided by Actions, you do not need to create your own token
with:
tag_name: "${{ github.ref }}"
release_name: "Release ${{ github.ref }}"
# Upload the zip to the release
- name: "Upload Release Asset"
id: "upload-release-asset"
uses: "actions/upload-release-asset@v1"
uses: "softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b" # v2.5.0
env:
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
with:
upload_url: "${{ steps.create_release.outputs.upload_url }}" # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps
asset_path: "./build/btcpay.zip"
asset_name: "btcpay.zip"
asset_content_type: "application/zip"
name: "Release ${{ github.ref_name }}"
files: "./build/btcpay.zip"
fail_on_unmatched_files: true
generate_release_notes: true

26
.github/workflows/security.yml vendored Normal file
View File

@ -0,0 +1,26 @@
name: GitHub Actions Security Analysis with zizmor 🌈
on:
push:
branches: ["main"]
pull_request:
branches: ["**"]
permissions: {}
jobs:
zizmor:
name: Run zizmor 🌈
runs-on: ubuntu-latest
permissions:
security-events: write
contents: read # only needed for private repos
actions: read # only needed for private repos
steps:
- name: Checkout repository
uses: actions/checkout@c2d88d3ecc89a9ef08eebf45d9637801dcee7eb5 # v6.0.0
with:
persist-credentials: false
- name: Run zizmor 🌈
uses: zizmorcore/zizmor-action@e639db99335bc9038abc0e066dfcd72e23d26fb4 # v0.3.0

View File

@ -1,32 +1,43 @@
name: "Validate"
on: [ "push", "pull_request" ]
on:
push:
paths: [ 'modules/**' ]
branches: [ '6.x' ]
tags: [ 'v*' ]
pull_request:
paths: [ 'modules/**' ]
permissions: {}
jobs:
linting:
name: "Linting (PHP ${{ matrix.php-versions }})"
runs-on: "ubuntu-latest"
strategy:
fail-fast: false
matrix:
php-versions: [ '7.3', '7.4', '8.0' ]
php-versions: [ '8.0', '8.1' ]
steps:
- name: "Checkout"
uses: "actions/checkout@v2"
uses: "actions/checkout@c2d88d3ecc89a9ef08eebf45d9637801dcee7eb5" # v6.0.0
with:
persist-credentials: false
- name: "Setup PHP, with composer and extensions"
uses: "shivammathur/setup-php@v2" # https://github.com/shivammathur/setup-php
uses: "shivammathur/setup-php@44454db4f0199b8b9685a5d763dc37cbf79108e1" # v2.36.0
with:
php-version: "${{ matrix.php-versions }}"
extensions: "mbstring, xml, ctype, iconv, intl, gd"
tools: "composer:v2"
- name: "Get composer cache directory"
id: "composercache"
run: "echo '::set-output name=dir::$(composer config cache-files-dir)'"
id: "composer-cache"
run: 'echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT'
- name: "Cache composer dependencies"
uses: "actions/cache@v2"
uses: "actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb" # v5.0.1
with:
path: "${{ steps.composercache.outputs.dir }}"
path: "${{ steps.composer-cache.outputs.dir }}"
key: "${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}"
restore-keys: "${{ runner.os }}-composer-"
lookup-only: true
- name: "Validate composer"
run: "composer validate"
- name: "Install Composer dependencies"

5
.gitignore vendored
View File

@ -8,13 +8,18 @@ btcpay.zip
# Ignore php-cs-fixer cache
.php_cs.cache
.php-cs-fixer.cache
# Ignore phpcs cache
.phpcs-cache
# Ignore developer specific docker-compose
docker-compose.override.yml
# Ignore files in the module that are added via `make`
/modules/btcpay/LICENSE
/modules/btcpay/README.md
/modules/btcpay/docs/README.md
# We dont care about the lib/vendor folder
/modules/btcpay/lib/

View File

@ -16,6 +16,7 @@ return (new PhpCsFixer\Config())
'concat_space' => false,
'fopen_flags' => false,
'native_function_invocation' => false,
'native_constant_invocation' => false,
'phpdoc_summary' => false,
'protected_to_private' => false,
'psr_autoloading' => false,

1
.php-version Normal file
View File

@ -0,0 +1 @@
8.0

8
CONTRIBUTING.md Normal file
View File

@ -0,0 +1,8 @@
[![Twitter Follow](https://img.shields.io/twitter/follow/btcpayserver?color=brightgreen&label=Follow%20%40BTCPayServer&style=flat-square)](https://twitter.com/btcpayserver)
[![BTCPay Server Community](https://img.shields.io/badge/chat-mattermost-brightgreen?style=flat-square)](https://chat.btcpayserver.org/btcpayserver)
BTCPay is built and maintained entirely by volunteer contributors around the internet. We welcome and appreciate new contributions.
Contributors looking to help out, before opening a pull request, please [create an issue](https://github.com/btcpayserver/prestashop-plugin/issues/new/choose)
or join [our community chat](https://chat.btcpayserver.org) to get early feedback, discuss best ways to tackle the problem and to ensure there is no work duplication.

View File

@ -1,6 +1,6 @@
MIT License
Copyright (c) 2017-2021 btcpayserver
Copyright (c) 2017-2025 btcpayserver
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@ -3,22 +3,49 @@ MODULE_FOLDER := "./modules"
BUILD_FOLDER := "./build"
ZIP_NAME := "${MODULE}.zip"
ZIP_DEBUG_NAME := "${MODULE}_debug.zip"
MODULE_OUT := "${BUILD_FOLDER}/${ZIP_NAME}"
.PHONY: all deps build clean lint lint-fix
.PHONY: all build install update upgrade clean lint lint-fix
all: build
deps: ## Download and make all dependencies
build: ## Build the bastard binary file
# Installing all dependencies
@cd "$(MODULE_FOLDER)/$(MODULE)" \
&& composer install --no-dev
# Dump autoloader
@cd "$(MODULE_FOLDER)/$(MODULE)" \
&& composer dump-autoload -o --no-dev
# Removing the old ZIP if present
@rm -f $(MODULE_OUT)
# Make the build folder
@mkdir -p $(BUILD_FOLDER)
# Copy the license to the module
@cp ./LICENSE "$(MODULE_FOLDER)/$(MODULE)"
# Copy the README to the module root and docs
@cp ./README.md "$(MODULE_FOLDER)/$(MODULE)"
@cp ./README.md "$(MODULE_FOLDER)/$(MODULE)/docs"
# Zip the module
@cd $(MODULE_FOLDER) \
&& zip -r $(ZIP_NAME) $(MODULE) \
&& mv $(ZIP_NAME) "../$(BUILD_FOLDER)"
debug: ## Build the bastard binary file as debug file
# Installing all dependencies
@cd "$(MODULE_FOLDER)/$(MODULE)" \
&& composer install
# Dump autoloader
@cd "$(MODULE_FOLDER)/$(MODULE)" \
&& composer dump-autoload -o --no-dev
&& composer dump-autoload -o
build: deps ## Build the bastard binary file
# Removing the old ZIP if present
@rm -f $(MODULE_OUT)
@ -33,8 +60,40 @@ build: deps ## Build the bastard binary file
# Zip the module
@cd $(MODULE_FOLDER) \
&& zip -r $(ZIP_NAME) $(MODULE) \
&& mv $(ZIP_NAME) "../$(BUILD_FOLDER)"
&& zip -r $(ZIP_DEBUG_NAME) $(MODULE) \
&& mv $(ZIP_DEBUG_NAME) "../$(BUILD_FOLDER)"
bump: ## Bump all package versions
# Bump all root dependencies
@composer install
# Bump all module dependencies
@cd "$(MODULE_FOLDER)/$(MODULE)" \
&& composer install
install: ## Install everything for development
# Installing all root dependencies
@composer install
# Installing all module dependencies
@cd "$(MODULE_FOLDER)/$(MODULE)" \
&& composer install
update: ## Update all dependencies (including development)
# Upgrading all root dependencies
@composer update
# Upgrading all module dependencies
@cd "$(MODULE_FOLDER)/$(MODULE)" \
&& composer update
upgrade: ## Upgrade all dependencies (including development)
# Upgrading all root dependencies
@composer upgrade
# Upgrading all module dependencies
@cd "$(MODULE_FOLDER)/$(MODULE)" \
&& composer upgrade
clean: ## Remove previous builds
# Removing the ZIP
@ -51,14 +110,17 @@ lint: ## Lints the module
@./vendor/bin/php-cs-fixer fix --diff --dry-run -v
# Run PHPCS
@./vendor/bin/phpcs
@./vendor/bin/phpcs --cache -p
# Run PHP Parallel Lint
@./vendor/bin/parallel-lint --exclude ./modules/btcpay/vendor ./modules/btcpay
lint-fix: ## Resolves linter issues
# Run PHP CS Fixer
@./vendor/bin/php-cs-fixer fix -v
# Run PHPCBF
@./vendor/bin/phpcbf -p
@./vendor/bin/phpcbf --cache -p
help: ## Display this help screen
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'

105
README.md
View File

@ -1,71 +1,94 @@
# Prestashop Plugin
# BTCPay Server - Prestashop Plugin
[![Maintained](https://img.shields.io/maintenance/yes/2021?style=flat-square)](https://github.com/btcpayserver/prestashop-plugin/pulse)
[![GitHub Workflow Status](https://img.shields.io/github/workflow/status/btcpayserver/prestashop-plugin/Validate/master?style=flat-square)](https://github.com/btcpayserver/prestashop-plugin/actions)
[![GitHub License](https://img.shields.io/github/license/btcpayserver/prestashop-plugin?color=brightgreen&style=flat-square)](https://github.com/btcpayserver/prestashop-plugin/blob/master/LICENSE)
[![GitHub contributors](https://img.shields.io/github/contributors-anon/btcpayserver/prestashop-plugin?style=flat-square)](https://github.com/btcpayserver/prestashop-plugin/graphs/contributors)
![BTCPay Server](https://raw.githubusercontent.com/btcpayserver/btcpayserver/master/BTCPayServer/wwwroot/img/btc_pay_BG_twitter.png)
[![PrestaShop module version](https://img.shields.io/badge/module%20version-4.0.2-brightgreen?style=flat-square)](https://github.com/btcpayserver/prestashop-plugin/releases)
[![GitHub release (latest SemVer)](https://img.shields.io/github/v/release/btcpayserver/prestashop-plugin?sort=semver&style=flat-square)](https://github.com/btcpayserver/prestashop-plugin/releases)
[![GitHub all releases](https://img.shields.io/github/downloads/btcpayserver/prestashop-plugin/total?style=flat-square)](https://github.com/btcpayserver/prestashop-plugin/releases)
<h3 align="center">
Accept Bitcoin payments within PrestaShop
</h3>
<div align="center">
<p>
<a href="https://github.com/btcpayserver/prestashop-plugin/pulse"><img src="https://img.shields.io/maintenance/yes/2025?style=flat-square" alt="Maintained"/></a>
<a href="https://github.com/btcpayserver/prestashop-plugin/actions"><img src="https://img.shields.io/github/actions/workflow/status/btcpayserver/prestashop-plugin/validate.yml?style=flat-square" alt="GitHub Workflow Status"/></a>
<a href="https://github.com/btcpayserver/prestashop-plugin/blob/6.x/LICENSE"><img src="https://img.shields.io/github/license/btcpayserver/prestashop-plugin?color=brightgreen&amp;style=flat-square" alt="GitHub License"/></a>
<a href="https://github.com/btcpayserver/prestashop-plugin#contributing"><img src="https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square" alt="PRs are welcome"/></a>
<a href="https://github.com/btcpayserver/prestashop-plugin/graphs/contributors"><img src="https://img.shields.io/github/contributors-anon/btcpayserver/prestashop-plugin?style=flat-square" alt="GitHub contributors"/></a>
</p>
<p>
<a href="https://github.com/btcpayserver/prestashop-plugin/releases"><img src="https://img.shields.io/github/v/release/btcpayserver/prestashop-plugin?sort=semver&amp;style=flat-square" alt="GitHub release (latest SemVer)"/></a>
<a href="https://github.com/btcpayserver/prestashop-plugin/releases"><img src="https://img.shields.io/github/downloads/btcpayserver/prestashop-plugin/total?style=flat-square" alt="GitHub all releases"/></a>
</p>
</div>
This is a Bitcoin payment plugin for PrestaShop using BTCPay server. [BTCPay Server](https://btcpayserver.org) is a free and open source server for merchants wanting to accept Bitcoin for their business.
<div align="center">
<sub>"This is lies, my trust in you is broken, I will make you obsolete" 💚
</a>
</div>
<br/>
**Warning**: This version should be considered as beta. Use it at your own risk.
<p align="center">
<a href="https://github.com/btcpayserver/prestashop-plugin/issues/new/choose">Report a bug</a>
·
<a href="https://github.com/btcpayserver/prestashop-plugin/discussions/new/choose">Request a feature</a>
·
<a href="https://docs.btcpayserver.org/FAQ/">FAQ</a>
</p>
## Tested successfully
* Prestashop 1.7.7.x
* BTCPay server v1.0.6.4
---
**Note**: The legacy version can be found at [prestashop-plugin-legacy](https://github.com/btcpayserver/prestashop-plugin-legacy) and will not recieve any further support at this time.
## 🔧 Requirements
That said, this module has `v4` as it's module version and includes migration scripts to try and migrate your old module to this new version. The module name has been kept as is, so upgrading should be easy.
Please ensure that you meet the following requirements before installing this plugin.
## Internals
- You are using PHP 8.0 or higher
- Your PrestaShop is version 8.0/9.0 or higher.
- Your BTCPay Server is version 1.7.0 or higher
- The PDO, curl, gd, intl, json, and mbstring PHP extensions are available
- You have a BTCPay Server, either [self-hosted](https://docs.btcpayserver.org/Deployment/) or [hosted by a third party](https://docs.btcpayserver.org/Deployment/ThirdPartyHosting/)
- [You've a registered account on the instance](https://docs.btcpayserver.org/RegisterAccount)
- [You've a BTCPay store on the instance](https://docs.btcpayserver.org/CreateStore)
- [You've a wallet connected to your store](https://docs.btcpayserver.org/WalletSetup)
This plugin support creating orders before or after payment. That said the `before`-mode still requires a callback from the BTCPay server itself so that all relevant data is available during order creation.
### Tested successfully
- Prestashop v8.0, v8.0.1, v8.0.4, v8.1.0, v8.1.3, v8.1.4, v8.2.1, v9.0.0
- BTCPay server v1.7.0, v1.7.3.0, v1.12.5, v1.13.0, v1.13.5, v2.1.5, v2.2.1
- BTCPay server v2 is supported as of module version v6.3.0.
## Future improvements
There is a lot of improvements that can still be made:
* Create a docker container for testing
* Rewrite to use the new [Greenfield Invoice API](https://docs.btcpayserver.org/API/Greenfield/v1/).
### Multistore
## Documentation
As of right now the module is **not** compatible with Prestashop's multistore feature. Any help to resolve this is very much welcomed. Please see the relevant [discussion](https://github.com/btcpayserver/prestashop-plugin/discussions/130).
Please check out our [official website](https://btcpayserver.org/), our [complete documentation](https://docs.btcpayserver.org/) and [FAQ](https://docs.btcpayserver.org/FAQ/) for more details.
## 📗 Documentation
If you have trouble using BTCPay, consider joining [communities listed on official website](https://btcpayserver.org/#communityCTA) to get help from BTCPay community members. Only file [Github issue](https://github.com/btcpayserver/prestashop-plugin/issues) for technical issues you can't resolve through other channels or feature requests you've validated with other members of community.
Please check out our [official website](https://btcpayserver.org/), [complete documentation](https://docs.btcpayserver.org/) and [FAQ](https://docs.btcpayserver.org/FAQ/) for more details.
Main community chat is located on [Mattermost](https://chat.btcpayserver.org/).
If you have trouble using BTCPay Server, consider joining [communities listed on the official website](https://btcpayserver.org/#communityCTA) to get help from other contributors. Only create a [GitHub issue](https://github.com/btcpayserver/prestashop-plugin/issues/new/choose) for technical issues you can't resolve through other channels or feature requests you've validated with other members of the community.
### Quick Start Guide
## 🚀 Quick Start Guide
To get up and running with our plugin quickly, see the [PrestaShop Guide on our documentation website](https://docs.btcpayserver.org/PrestaShop/).
## Versioning
## 🧑‍💻 Versioning
We use [SemVer](http://semver.org/) for versioning. For the versions available, see the
[tags on this repository](https://github.com/BitcoinMitchell/docker-prestashop/tags).
We use [SemVer](http://semver.org/) for versioning. For the versions available, see the [releases within this repository](https://github.com/btcpayserver/prestashop-plugin/releases).
## Contributing
## 🤝 Contributing
[![Twitter Follow](https://img.shields.io/twitter/follow/btcpayserver?color=brightgreen&label=Follow%20%40BTCPayServer&style=flat-square)](https://twitter.com/btcpayserver)
[![BTCPay Server Community](https://img.shields.io/badge/chat-mattermost-brightgreen?style=flat-square)](https://chat.btcpayserver.org/btcpayserver)
BTCPay Server is built and maintained entirely by volunteer contributors around the internet. We welcome and appreciate new contributions.
BTCPay is built and maintained entirely by volunteer contributors around the internet. We welcome and appreciate new contributions.
Contributors looking to help out, before opening a pull request, please join [our community chat](https://chat.btcpayserver.org/) or [start a GitHub discussion](https://github.com/btcpayserver/btcpayserver/discussions) to get early feedback, discuss the best ways to tackle the problem, and ensure there is no work duplication.
Contributors looking to help out, before opening a pull request, please [create an issue](https://github.com/btcpayserver/prestashop-plugin/issues/new/choose)
or join [our community chat](https://chat.btcpayserver.org) to get early feedback, discuss best ways to tackle the problem and to ensure there is no work duplication.
### 🔧 Development
## PrestaShop Support
We recommend using [PrestaShop Kickstarter](https://github.com/PrestaShopCorp/docker-compose-kickstarter) (which supports [ngrok](https://ngrok.com/)) and a dockerized [BTCPay Server instance](https://github.com/btcpayserver/btcpayserver-docker/blob/master/Production/docker-compose.btc.yml) (or [an online testnet instance](https://testnet.demo.btcpayserver.org/)) for testing locally.
PrestaShop support can be found through it's official channels.
## 🏪 PrestaShop Support
* [Homepage](https://www.prestashop.com)
* [Documentation](https://doc.prestashop.com)
* [Support Forums](https://www.prestashop.com/forums)
PrestaShop support can be found through its official channels.
## License
* [Documentation](https://docs.prestashop-project.org/v.8-documentation) - contains answers to commonly asked questions and provides instructions for almost everything. Including setup, management, etc.
* [Support Forums](https://www.prestashop.com/forums) - the official Prestashop forum is a good place to find further answers and ask Prestashop related questions.
## 📝 License
BTCPay Server software, logo and designs are provided under [MIT License](LICENSE).

View File

@ -1,7 +1,74 @@
Security issues and bugs should be reported privately, via email. To report a security issue, please send an email to **security@btcpayserver.org** (not for support).
# Reporting a potential Vulnerability.
<!-- Short intro. -->
We take the security of our project seriously, and we encourage responsible disclosure of any vulnerabilities that may be found. To facilitate this process, we have established the following vulnerability reporting process.
You will receive a reply indicating the next steps in handling your report. If for some reason you do not receive a reply within 24 hours, please follow up via email to ensure the original message was received.
We appreciate your efforts to disclose your findings responsibly.
After the initial reply to your report, you will be informed of the progress towards a fix and full announcement. You may be asked to provide additional information or guidance.
##### 1. Reporting Channel
If you believe you have discovered a vulnerability in our project, please email us at `security@btcpayserver.org`. Alternatively, you may report the vulnerability to us through [huntr.dev](https://huntr.dev/repos/btcpayserver/btcpayserver/).
We appreciate your efforts to responsibly disclose your findings, and will make every effort to acknowledge your contributions.
Please allow for up to 2 business days for an acknowledgement of receipt. If you receive no response within 2 business days, please follow up via email to ensure the original message was received.
Upon review of your report, you may be asked to provide additional information or guidance.
<!--TODO: If available, add link to PGP key used to read security report emails.-->
##### 2. In-Scope
<!-- What's in scope? Any repo in our org for example. -->
We welcome reports of vulnerabilities in repositories owned by the [BTCPay Server GitHub Organization](https://github.com/btcpayserver). This includes any issues related to the confidentiality, integrity, or availability of systems or data in these systems.
##### 3. Out of Scope
<!-- What's out of scope? Thinking here about custom deployments, plugins that are not created by BTCPay (this includes kukks plugins that should be reported to him directly). -->
1. Any BTCPay Server deployment that has been customized in any way. To facilitate reproducibility, please verify that the BTCPay Server instance is based on the un-altered source-code or [Docker deployment](https://docs.btcpayserver.org/Docker/).
2. Any BTCPay Server plugin that is not authored by `btcpayserver` as stated by the author tag in-app.
##### 4. Preferred Reporting Template
<!-- Template example to guide reporter into including specific info that we'd appreciate be included in the report. -->
We encourage the use of a reporting template that includes a detailed description of the vulnerability, any evidence or proof of concept, and steps to reproduce the vulnerability.
Please find an example of an email template [at the end of this document](#7-reporting-template-example).
##### 5. Timeline for Remediation
<!-- Tentative 90 business day timeline for resolution. This is a typical industry standard, but have included wording to include the fact that we're a team of volunteers, and that we cannot guarantee it. -->
While we will work to remediate the reported vulnerability within 90 business days from the acknowledgment of the report, being a team of volunteers, we cannot guarantee this timeline to be accurate at all time.
We will provide regular updates to the reporter until the vulnerability is resolved.
##### 6. Timeline to Public Disclosure
<!-- No tentative timeline, given it can differ based on multiple criteria, but we have to take into account the fact that a public disclosure of a full year is too much. Security by obscurity is rarely beneficial, especially for the uninformed end-users. -->
We will work with the reporter to define a suitable timeline to public disclosure once the vulnerability is remediated.
<!--
##### 7. More information
For more information on our complete vulnerability response process, please see our [documentation]()
-->
##### 7. Reporting Template Example
<!-- Simple template for users to take as example for vulnerability reporting. Contains the basic minimum information that we need to assess promptly a report. -->
Feel free to use the below template to report a vulnerability.
```
Subject: Vulnerability Report - BTCPay Server
Dear BTCPay Server team,
I am writing to report a security vulnerability that I have identified in BTCPay Server. I believe this vulnerability poses a significant threat to the security of the project and its users.
Here are the details of the vulnerability:
* Vulnerability description: [Provide a clear and concise description of the vulnerability]
* Impact: [Describe the potential impact of the vulnerability, ie. any potential consequences for the project, its users, or any third parties]
* Affected version(s): [Specify which version(s) of the project are affected by the vulnerability]
* Steps to reproduce & Proof of Concept: [Provide a step-by-step guide to reproduce the vulnerability, including any screenshots and code snippets you feel would help]
* Severity: [Provide your assessment of the severity of the vulnerability, using a scale such as Warning/Low/Medium/High/Critical]
* Mitigation or Fix: [Provide your recommendation for a solution or mitigation strategy for the vulnerability]
If needed, I [agree/do not agree] to be invited into a Github private fork for the purpose of helping resolve this vulnerability. [Please include a link to your github profile]
Please let me know if you need any further information or if you would like to discuss this vulnerability in more detail.
Thank you for your attention to this matter.
Sincerely,
[Your Name/Handle]
```

40
UPGRADE-5.0.md Normal file
View File

@ -0,0 +1,40 @@
# Upgrading from 4.0 to 5.0
Prestashop modules come with an auto-upgrade feature which will be used to upgrade your currently running plugin. This documents serves as a reference for what has been changed.
## Requirements
The module requirements have been changed to:
- You are using PHP 7.3.0 or higher
- Your PrestaShop is version 1.7.7.0 or higher.
- Your BTCPay Server is version 1.3.0 or higher
## Database
We now fetch all invoice and payment data directly from BTCPay Server so the following columns will be removed from `bitcoin_payment` during the upgrade:
- `bitcoin_price`
- `bitcoin_paid`
- `bitcoin_address`
- `bitcoin_refund_address`
- `rate`
## Different PHP client
We switched from [`btcpayserver-php-client`] to the newer and actively supported [`btcpayserver-greenfield-php`]. This means that the old `IPN` has been replaced with an `webhook` based approach.
For you this means that **_you'll have to re-connect_** to your BTCPay Server instance.
## Invoice
On the front-end side of things we now show the customer how much they have transferred and via what payment.
### Order states
The order states have received a new translation so that they are more correct:
- `Awaiting Bitcoin payment` has been changed to `Awaiting crypto payment`.
- `Waiting for Bitcoin confirmations` has been changed to `Waiting for confirmations`.
- `Bitcoin transaction failed` has been changed to `Crypto transaction failed`.
- `Paid with Bitcoin` has been changed to `Paid with crypto`.
[`btcpayserver-php-client`]: https://github.com/btcpayserver/btcpayserver-php-client
[`btcpayserver-greenfield-php`]: https://github.com/btcpayserver/btcpayserver-greenfield-php

10
UPGRADE-6.0.md Normal file
View File

@ -0,0 +1,10 @@
# Upgrading from 5.0 to 6.0
Prestashop modules come with an auto-upgrade feature which will be used to upgrade your currently running plugin. This documents serves as a reference for what has been changed.
## Requirements
The module requirements have been changed to:
- You are using PHP 8.0 or higher
- Your PrestaShop is version 8.0 or higher.
- Your BTCPay Server is version 1.7.0 or higher

View File

@ -1,20 +1,28 @@
{
"name": "btcpay/prestashop-plugin",
"description": "BTCPay Server payment plugin for PrestaShop",
"license": "MIT",
"type": "prestashop-module",
"description": "BTCPay payment plugin for PrestaShop",
"keywords": [
"prestashop",
"plugin",
"payment",
"ecommerce",
"BTCPay",
"BTCPay Server",
"bitcoin",
"BTCPay"
"crypto",
"ecommerce",
"module",
"payment",
"plugin",
"prestashop"
],
"homepage": "https://github.com/btcpayserver/prestashop-plugin",
"license": "MIT",
"support": {
"issues": "https://github.com/btcpayserver/prestashop-plugin/issues",
"source": "https://github.com/btcpayserver/prestashop-plugin"
},
"require": {
"php": ">=7.3.0",
"php": ">=8.0",
"ext-PDO": "*",
"ext-bcmath": "*",
"ext-curl": "*",
"ext-dom": "*",
"ext-fileinfo": "*",
@ -24,25 +32,43 @@
"ext-json": "*",
"ext-mbstring": "*",
"ext-zip": "*",
"composer/installers": "^v1.9.0"
"composer/installers": "^1.12.0"
},
"require-dev": {
"dealerdirect/phpcodesniffer-composer-installer": "^1.0.0",
"ergebnis/composer-normalize": "^2.43.0",
"ezyang/htmlpurifier": "dev-master as 4.17.0",
"friendsofphp/php-cs-fixer": "^3.4.0",
"lcobucci/jwt": "dev-3.4.6-patch as 3.4.6",
"php-parallel-lint/php-console-highlighter": "^1.0",
"php-parallel-lint/php-parallel-lint": "^1.4.0",
"phpoffice/phpspreadsheet": "^1.29.1",
"prestashop/autoindex": "^2.1",
"prestashop/php-dev-tools": "^5",
"prestashop/prestashop": "^8.1.7",
"roave/security-advisories": "dev-latest",
"slevomat/coding-standard": "^8.15.0",
"squizlabs/php_codesniffer": "^3.10.2"
},
"replace": {
"prestashop/blockwishlist": "^2.0",
"prestashop/contactform": "^v4.3.0",
"prestashop/blockreassurance": "^5.1.4",
"prestashop/blockwishlist": "^3",
"prestashop/classic": "^2.0.0-beta",
"prestashop/contactform": "^4.3.0",
"prestashop/dashactivity": "^2",
"prestashop/dashgoals": "^2",
"prestashop/dashproducts": "^2",
"prestashop/dashtrends": "^2",
"prestashop/gamification": "^v2.4.0",
"prestashop/gamification": "^2.4.0",
"prestashop/graphnvd3": "^2",
"prestashop/gridhtml": "^2",
"prestashop/gsitemap": "^4",
"prestashop/pagesnotfound": "^2",
"prestashop/productcomments": "^v4.2.2",
"prestashop/productcomments": "^7.0",
"prestashop/ps_banner": "^2",
"prestashop/ps_bestsellers": "^1.0",
"prestashop/ps_brandlist": "^1.0",
"prestashop/ps_cashondelivery": "^1.0",
"prestashop/ps_cashondelivery": "^2.0",
"prestashop/ps_categoryproducts": "^1.0",
"prestashop/ps_categorytree": "^2",
"prestashop/ps_checkpayment": "^2",
@ -53,24 +79,28 @@
"prestashop/ps_customersignin": "^2",
"prestashop/ps_customtext": "^4",
"prestashop/ps_dataprivacy": "^2.0",
"prestashop/ps_emailsubscription": "^v2.7.0",
"prestashop/ps_facetedsearch": "^v3.7.1",
"prestashop/ps_distributionapiclient": "^1.0.1",
"prestashop/ps_emailalerts": "^3.0",
"prestashop/ps_emailsubscription": "^2.7.0",
"prestashop/ps_facetedsearch": "^3.7.1",
"prestashop/ps_faviconnotificationbo": "^2",
"prestashop/ps_featuredproducts": "^2",
"prestashop/ps_googleanalytics": "^5.0",
"prestashop/ps_imageslider": "^3",
"prestashop/ps_languageselector": "^2",
"prestashop/ps_linklist": "^5",
"prestashop/ps_linklist": "^6",
"prestashop/ps_mainmenu": "^2",
"prestashop/ps_newproducts": "^1.0",
"prestashop/ps_searchbar": "^2",
"prestashop/ps_sharebuttons": "^2",
"prestashop/ps_shoppingcart": "^2",
"prestashop/ps_shoppingcart": "^3",
"prestashop/ps_socialfollow": "^2",
"prestashop/ps_specials": "^1.0",
"prestashop/ps_supplierlist": "^1.0",
"prestashop/ps_themecusto": "^1",
"prestashop/ps_viewedproduct": "^1.2",
"prestashop/ps_wirepayment": "^2",
"prestashop/psgdpr": "^1.0",
"prestashop/statsbestcategories": "^2",
"prestashop/statsbestcustomers": "^2",
"prestashop/statsbestmanufacturers": "^2",
@ -88,28 +118,25 @@
"prestashop/statsregistrations": "^2",
"prestashop/statssales": "^2",
"prestashop/statssearch": "^2",
"prestashop/statsstock": "^2"
},
"require-dev": {
"dealerdirect/phpcodesniffer-composer-installer": "^0.7.0",
"ergebnis/composer-normalize": "^2.8",
"friendsofphp/php-cs-fixer": "^v2.16.4",
"johnkary/phpunit-speedtrap": "^v3.2.0",
"phpspec/prophecy-phpunit": "^2.0",
"prestashop/prestashop": "dev-develop",
"roave/security-advisories": "dev-latest",
"slevomat/coding-standard": "^6.3",
"squizlabs/php_codesniffer": "^3.5",
"symfony/phpunit-bridge": "^v3.4.43"
},
"config": {
"platform": {
"php": "7.3"
},
"preferred-install": "dist",
"prepend-autoloader": false,
"sort-packages": true
"prestashop/statsstock": "^2",
"symfony/polyfill-mbstring": "*",
"symfony/polyfill-php54": "*",
"symfony/polyfill-php55": "^1.10",
"symfony/polyfill-php56": "*",
"symfony/polyfill-php70": "*",
"symfony/polyfill-php71": "*",
"symfony/polyfill-php72": "*",
"symfony/polyfill-php73": "*",
"symfony/polyfill-php74": "*"
},
"repositories": [
{
"type": "vcs",
"url": "https://github.com/PrestaShop/jwt"
}
],
"minimum-stability": "dev",
"prefer-stable": true,
"autoload": {
"psr-4": {
"BTCPay\\": "modules/btcpay/src"
@ -118,7 +145,19 @@
"modules/btcpay/btcpay.php"
]
},
"minimum-stability": "stable",
"config": {
"allow-plugins": {
"composer/installers": true,
"dealerdirect/phpcodesniffer-composer-installer": true,
"ergebnis/composer-normalize": true
},
"platform": {
"php": "8.0"
},
"preferred-install": "dist",
"prepend-autoloader": false,
"sort-packages": true
},
"scripts": {
"post-install-cmd": [
"@install-codestandards"
@ -126,9 +165,5 @@
"install-codestandards": [
"Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin::run"
]
},
"support": {
"issues": "https://github.com/btcpayserver/prestashop-plugin/issues",
"source": "https://github.com/btcpayserver/prestashop-plugin"
}
}

7263
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
<?php
define('_DB_PREFIX_', 'PS_');
const _DB_PREFIX_ = 'ps_';
abstract class AbstractAssetManager extends AbstractAssetManagerCore
{
@ -55,6 +55,7 @@ abstract class ObjectModel extends ObjectModelCore
}
abstract class PaymentModule extends PaymentModuleCore
{
protected $is_eu_compatible;
}
abstract class ProductListingFrontController extends ProductListingFrontControllerCore
{
@ -92,27 +93,9 @@ class AddressFormat extends AddressFormatCore
class AdminAccessController extends AdminAccessControllerCore
{
}
class AdminAddonsCatalogController extends AdminAddonsCatalogControllerCore
{
}
class AdminAddressesController extends AdminAddressesControllerCore
{
}
class AdminAdminPreferencesController extends AdminAdminPreferencesControllerCore
{
}
class AdminAttachmentsController extends AdminAttachmentsControllerCore
{
}
class AdminAttributeGeneratorController extends AdminAttributeGeneratorControllerCore
{
}
class AdminAttributesGroupsController extends AdminAttributesGroupsControllerCore
{
}
class AdminBackupController extends AdminBackupControllerCore
{
}
class AdminCarriersController extends AdminCarriersControllerCore
{
}
@ -125,60 +108,24 @@ class AdminCartRulesController extends AdminCartRulesControllerCore
class AdminCartsController extends AdminCartsControllerCore
{
}
class AdminCategoriesController extends AdminCategoriesControllerCore
{
}
class AdminCmsCategoriesController extends AdminCmsCategoriesControllerCore
{
}
class AdminCmsContentController extends AdminCmsContentControllerCore
{
}
class AdminCmsController extends AdminCmsControllerCore
{
}
class AdminContactsController extends AdminContactsControllerCore
{
}
class AdminController extends AdminControllerCore
{
}
class AdminCountriesController extends AdminCountriesControllerCore
{
}
class AdminCurrenciesController extends AdminCurrenciesControllerCore
{
}
class AdminCustomerPreferencesController extends AdminCustomerPreferencesControllerCore
{
}
class AdminCustomersController extends AdminCustomersControllerCore
{
}
class AdminCustomerThreadsController extends AdminCustomerThreadsControllerCore
{
}
class AdminDashboardController extends AdminDashboardControllerCore
{
}
class AdminDeliverySlipController extends AdminDeliverySlipControllerCore
{
}
class AdminEmailsController extends AdminEmailsControllerCore
{
}
class AdminEmployeesController extends AdminEmployeesControllerCore
{
}
class AdminFeaturesController extends AdminFeaturesControllerCore
{
}
class AdminGendersController extends AdminGendersControllerCore
{
}
class AdminGeolocationController extends AdminGeolocationControllerCore
{
}
class AdminGroupsController extends AdminGroupsControllerCore
{
}
@ -188,36 +135,12 @@ class AdminImagesController extends AdminImagesControllerCore
class AdminImportController extends AdminImportControllerCore
{
}
class AdminInformationController extends AdminInformationControllerCore
{
}
class AdminInvoicesController extends AdminInvoicesControllerCore
{
}
class AdminLanguagesController extends AdminLanguagesControllerCore
{
}
class AdminLegacyLayoutController extends AdminLegacyLayoutControllerCore
{
}
class AdminLocalizationController extends AdminLocalizationControllerCore
{
}
class AdminLoginController extends AdminLoginControllerCore
{
}
class AdminLogsController extends AdminLogsControllerCore
{
}
class AdminMaintenanceController extends AdminMaintenanceControllerCore
{
}
class AdminManufacturersController extends AdminManufacturersControllerCore
{
}
class AdminMetaController extends AdminMetaControllerCore
{
}
class AdminModulesController extends AdminModulesControllerCore
{
}
@ -227,51 +150,15 @@ class AdminModulesPositionsController extends AdminModulesPositionsControllerCor
class AdminNotFoundController extends AdminNotFoundControllerCore
{
}
class AdminOrderMessageController extends AdminOrderMessageControllerCore
{
}
class AdminOrderPreferencesController extends AdminOrderPreferencesControllerCore
{
}
class AdminOrdersController extends AdminOrdersControllerCore
{
}
class AdminOutstandingController extends AdminOutstandingControllerCore
{
}
class AdminPatternsController extends AdminPatternsControllerCore
{
}
class AdminPaymentController extends AdminPaymentControllerCore
{
}
class AdminPaymentPreferencesController extends AdminPaymentPreferencesControllerCore
{
}
class AdminPdfController extends AdminPdfControllerCore
{
}
class AdminPerformanceController extends AdminPerformanceControllerCore
{
}
class AdminPPreferencesController extends AdminPPreferencesControllerCore
{
}
class AdminPreferencesController extends AdminPreferencesControllerCore
{
}
class AdminProductsController extends AdminProductsControllerCore
{
}
class AdminProfilesController extends AdminProfilesControllerCore
{
}
class AdminQuickAccessesController extends AdminQuickAccessesControllerCore
{
}
class AdminReferrersController extends AdminReferrersControllerCore
{
}
class AdminRequestSqlController extends AdminRequestSqlControllerCore
{
}
@ -284,12 +171,6 @@ class AdminSearchConfController extends AdminSearchConfControllerCore
class AdminSearchController extends AdminSearchControllerCore
{
}
class AdminSearchEnginesController extends AdminSearchEnginesControllerCore
{
}
class AdminShippingController extends AdminShippingControllerCore
{
}
class AdminShopController extends AdminShopControllerCore
{
}
@ -299,9 +180,6 @@ class AdminShopGroupController extends AdminShopGroupControllerCore
class AdminShopUrlController extends AdminShopUrlControllerCore
{
}
class AdminSlipController extends AdminSlipControllerCore
{
}
class AdminSpecificPriceRuleController extends AdminSpecificPriceRuleControllerCore
{
}
@ -314,63 +192,24 @@ class AdminStatsController extends AdminStatsControllerCore
class AdminStatusesController extends AdminStatusesControllerCore
{
}
class AdminStockConfigurationController extends AdminStockConfigurationControllerCore
{
}
class AdminStockCoverController extends AdminStockCoverControllerCore
{
}
class AdminStockInstantStateController extends AdminStockInstantStateControllerCore
{
}
class AdminStockManagementController extends AdminStockManagementControllerCore
{
}
class AdminStockMvtController extends AdminStockMvtControllerCore
{
}
class AdminStoresController extends AdminStoresControllerCore
{
}
class AdminSuppliersController extends AdminSuppliersControllerCore
{
}
class AdminSupplyOrdersController extends AdminSupplyOrdersControllerCore
{
}
class AdminTabsController extends AdminTabsControllerCore
{
}
class AdminTagsController extends AdminTagsControllerCore
{
}
class AdminTaxesController extends AdminTaxesControllerCore
{
}
class AdminTaxRulesGroupController extends AdminTaxRulesGroupControllerCore
{
}
class AdminThemesCatalogController extends AdminThemesCatalogControllerCore
{
}
class AdminThemesController extends AdminThemesControllerCore
{
}
class AdminTrackingController extends AdminTrackingControllerCore
{
}
class AdminTranslationsController extends AdminTranslationsControllerCore
{
}
class AdminWarehousesController extends AdminWarehousesControllerCore
{
}
class AdminWebserviceController extends AdminWebserviceControllerCore
{
}
class AdminZonesController extends AdminZonesControllerCore
{
}
class Alias extends AliasCore
{
}
@ -380,9 +219,6 @@ class Attachment extends AttachmentCore
class AttachmentController extends AttachmentControllerCore
{
}
class Attribute extends AttributeCore
{
}
class AttributeGroup extends AttributeGroupCore
{
}
@ -743,9 +579,6 @@ class OrderDetail extends OrderDetailCore
class OrderDetailController extends OrderDetailControllerCore
{
}
class OrderDiscount extends OrderDiscountCore
{
}
class OrderFollowController extends OrderFollowControllerCore
{
}
@ -815,9 +648,6 @@ class PhpEncryption extends PhpEncryptionCore
class PhpEncryptionEngine extends PhpEncryptionEngineCore
{
}
class PhpEncryptionLegacyEngine extends PhpEncryptionLegacyEngineCore
{
}
class PrestaShopBackup extends PrestaShopBackupCore
{
}
@ -872,9 +702,6 @@ class RangePrice extends RangePriceCore
class RangeWeight extends RangeWeightCore
{
}
class Referrer extends ReferrerCore
{
}
class RequestSql extends RequestSqlCore
{
}
@ -1064,15 +891,11 @@ class WebserviceSpecificManagementImages extends WebserviceSpecificManagementIma
class WebserviceSpecificManagementSearch extends WebserviceSpecificManagementSearchCore
{
}
class Windows extends WindowsCore
{
}
class Zone extends ZoneCore
{
}
/* Class aliases */
class Autoload extends PrestaShopAutoload
{
}

76
development/bitcoin-cli.sh Executable file
View File

@ -0,0 +1,76 @@
#!/bin/bash
# Helper to connect to the running bitcoind (by default running regtest).
# Function to show usage instructions
show_usage() {
cat <<EOF
Usage: bitcoin-cli-helper COMMAND [ARGS]
Commands:
getnewaddress Generate a new address
generatetoaddress BLOCKS ADDRESS Generate new blocks and send the reward to the specified address
generate NUM_BLOCKS Generate a specified number of blocks
settxfee FEE Set the transaction fee for this network
sendtoaddress ADDRESS AMOUNT Send funds to an address
EOF
}
# Check if a valid command is provided
validate_command() {
local valid_commands=("getnewaddress" "generatetoaddress" "generate" "settxfee" "sendtoaddress")
local command=$1
for valid_cmd in "${valid_commands[@]}"; do
if [ "$valid_cmd" = "$command" ]; then
return 0
fi
done
return 1
}
# Validate the number of arguments
if [ "$#" -lt 1 ]; then
echo "Error: Missing command."
show_usage
exit 1
fi
# Check if the provided command is valid
if ! validate_command "$1"; then
echo "Error: Invalid command."
show_usage
exit 1
fi
# Execute the command with docker
if [ "$1" = "generate" ]; then
if [ "$#" -lt 2 ]; then
echo "Error: Missing number of blocks to generate."
show_usage
exit 1
fi
# Execute it right away, as we must pass `-`
docker exec prestashop_bitcoind bitcoin-cli -datadir="/data" -generate "$2"
exit 0
elif [ "$1" = "generatetoaddress" ]; then
if [ "$#" -lt 3 ]; then
echo "Error: Missing blocks to mine and/or address."
show_usage
exit 1
fi
elif [ "$1" = "settxfee" ]; then
if [ "$#" -lt 2 ]; then
echo "Error: Missing transaction fee value."
show_usage
exit 1
fi
elif [ "$1" = "sendtoaddress" ]; then
if [ "$#" -lt 3 ]; then
echo "Error: Missing address and/or amount to send."
show_usage
exit 1
fi
fi
# Execute the command with docker
docker exec prestashop_bitcoind bitcoin-cli -datadir="/data" "$@"

14
modules/btcpay/.htaccess Normal file
View File

@ -0,0 +1,14 @@
# Apache 2.2
<IfModule !mod_authz_core.c>
<Files *.php>
order allow,deny
deny from all
</Files>
</IfModule>
# Apache 2.4
<IfModule mod_authz_core.c>
<Files *.php>
Require all denied
</Files>
</IfModule>

View File

@ -1,13 +1,19 @@
<?php
use BTCPay\Constants;
use BTCPay\Github\Versioning;
use BTCPay\Installer\Config;
use BTCPay\Installer\Hooks;
use BTCPay\Installer\OrderStates;
use BTCPay\Installer\Tables;
use BTCPay\LegacyOrderBitcoinRepository;
use BTCPay\Installer\Webhook;
use BTCPay\Repository\BitcoinPaymentRepository;
use BTCPay\Repository\TableRepository;
use BTCPay\Server\Client;
use BTCPayServer\Exception\BTCPayException;
use BTCPayServer\Exception\RequestException;
use PrestaShop\PrestaShop\Adapter\Configuration;
use PrestaShop\PrestaShop\Adapter\Presenter\Order\OrderPresenter;
use PrestaShop\PrestaShop\Adapter\SymfonyContainer;
use PrestaShop\PrestaShop\Core\Payment\PaymentOption;
if (!defined('_PS_VERSION_')) {
@ -20,41 +26,54 @@ if (!file_exists(__DIR__ . '/vendor/autoload.php')) {
require_once __DIR__ . '/vendor/autoload.php';
/** @noinspection AutoloadingIssuesInspection */
class BTCPay extends PaymentModule
{
/**
* @var BitcoinPaymentRepository
*/
private $repository;
public $tabs = [
[
'name' => 'BTCPay',
'name' => 'BTCPay Server',
'visible' => true,
'class_name' => 'AdminConfigureBTCPay',
'parent_class_name' => 'AdminParentPayment',
],
];
/**
* @var Configuration
*/
private $configuration;
/**
* @var Versioning
*/
private $versioning;
public function __construct()
{
$this->name = 'btcpay';
$this->tab = 'payments_gateways';
$this->version = '4.0.2';
$this->author = 'BTCPayServer';
$this->ps_versions_compliancy = ['min' => '1.7.7', 'max' => _PS_VERSION_];
$this->controllers = ['payment', 'validation', 'ipn'];
$this->version = '6.3.1';
$this->author = 'BTCPay Server';
$this->ps_versions_compliancy = ['min' => Constants::MINIMUM_PS_VERSION, 'max' => _PS_VERSION_];
$this->controllers = ['payment', 'validation', 'webhook'];
$this->is_eu_compatible = true;
$this->bootstrap = true;
$this->module_key = 'aec3ab8084e8e626bdcbda75d2ab39ee';
$this->currencies = true;
$this->currencies_mode = 'radio';
parent::__construct();
$this->displayName = $this->trans('BTCPay', [], 'Modules.Btcpay.Admin');
$this->description = $this->trans('Accepts Bitcoin payments via BTCPay.', [], 'Modules.Btcpay.Front');
$this->confirmUninstall = $this->trans('Are you sure you want to delete your details?', [], 'Modules.Btcpay.Front');
$this->displayName = $this->trans('BTCPay Server', [], 'Modules.Btcpay.Admin');
$this->description = $this->trans('Accept crypto payments via BTCPay Server.', [], 'Modules.Btcpay.Front');
$this->confirmUninstall = $this->trans('Are you sure that you want to uninstall this module? Past purchases and order states will be kept, but your configuration will be removed.', [], 'Modules.Btcpay.Front');
$this->configuration = new Configuration();
$this->versioning = new Versioning();
// Process any and all alerts/warnings
$this->displayModuleWarnings();
}
public function install(): bool
@ -63,12 +82,26 @@ class BTCPay extends PaymentModule
return false;
}
if (null === ($repository = $this->getRepository())) {
if (version_compare(\PHP_VERSION, Constants::MINIMUM_PHP_VERSION, '<')) {
$this->addModuleErrors([
[
'key' => sprintf('PHP version is too low. Expected %s or higher, received %s.', Constants::MINIMUM_PHP_VERSION, \PHP_VERSION),
'parameters' => [],
'domain' => 'Admin.Modules.Notification',
],
]);
return false;
}
if (!empty($errors = (new Config())->install())) {
$this->addModuleErrors($errors);
if (version_compare(_PS_VERSION_, Constants::MINIMUM_PS_VERSION, '<')) {
$this->addModuleErrors([
[
'key' => sprintf('PrestaShop version is too low. Expected %s or higher, received %s.', Constants::MINIMUM_PS_VERSION, _PS_VERSION_),
'parameters' => [],
'domain' => 'Admin.Modules.Notification',
],
]);
return false;
}
@ -79,6 +112,14 @@ class BTCPay extends PaymentModule
return false;
}
if (!empty($errors = (new Config())->install())) {
$this->addModuleErrors($errors);
return false;
}
// Create required tables
$repository = new TableRepository($this->get('doctrine.dbal.default_connection'));
if (!empty($errors = (new Tables($repository))->install())) {
$this->addModuleErrors($errors);
$this->uninstall();
@ -96,10 +137,13 @@ class BTCPay extends PaymentModule
return true;
}
/**
* When uninstalling, only remove the configuration and webhook. This way, order states and payment links are not lost.
*/
public function uninstall(): bool
{
if (null === ($repository = $this->getRepository())) {
return false;
if (!empty($errors = (new Webhook())->uninstall())) {
$this->addModuleErrors($errors);
}
if (!empty($errors = (new Config())->uninstall())) {
@ -108,28 +152,24 @@ class BTCPay extends PaymentModule
return false;
}
if (!empty($errors = (new Tables($repository))->uninstall())) {
$this->addModuleErrors($errors);
return false;
}
if (!empty($errors = (new OrderStates($this->name))->uninstall())) {
$this->addModuleErrors($errors);
return false;
}
return parent::uninstall();
}
/**
* When resetting, only deal with the configuration. This way, order states and payment links are not lost.
*/
public function reset(): bool
{
if (!$this->uninstall()) {
$config = new Config();
if (!empty($errors = $config->uninstall())) {
$this->addModuleErrors($errors);
return false;
}
if (!$this->install()) {
if (!empty($errors = $config->install())) {
$this->addModuleErrors($errors);
return false;
}
@ -146,7 +186,12 @@ class BTCPay extends PaymentModule
Tools::redirectAdmin($this->context->link->getAdminLink('AdminConfigureBTCPay'));
}
// Hooks on prestashop invoice
/**
* Hooks on prestashop invoice
*
* @throws PrestaShopDatabaseException
* @throws JsonException
*/
public function hookDisplayAdminOrderMainBottom($params): ?string
{
// If the module is not active, abort
@ -160,43 +205,77 @@ class BTCPay extends PaymentModule
}
// Get BTCPay URL or abort
if (empty($serverUrl = Configuration::get('BTCPAY_URL'))) {
if (empty($serverUrl = $this->configuration->get(Constants::CONFIGURATION_BTCPAY_HOST))) {
return null;
}
// Get legacy repository
$repository = new LegacyOrderBitcoinRepository();
// Ensure the client is ready for use
if (null === ($client = Client::createFromConfiguration($this->configuration)) || false === $client->isValid()) {
return null;
}
// Get the order
if (null === ($orderBitcoin = $repository->getOneByOrderID($params['id_order']))) {
if (null === ($bitcoinPayment = BitcoinPaymentRepository::getOneByOrderID($params['id_order']))) {
return null;
}
// Check if it has an invoice ID
if (null === ($invoiceId = $orderBitcoin->getInvoiceId()) || empty($invoiceId)) {
if (null === ($invoiceId = $bitcoinPayment->getInvoiceId()) || empty($invoiceId)) {
return null;
}
// Get the cart
if (false === ($cart = Cart::getCartByOrderId($orderBitcoin->getOrderId()))) {
if (false === ($cart = Cart::getCartByOrderId($bitcoinPayment->getOrderId()))) {
return null;
}
// Get the currency from our cart
$currency = Currency::getCurrencyInstance((int) $cart->id_currency);
// Get the store ID
$storeID = $this->configuration->get(Constants::CONFIGURATION_BTCPAY_STORE_ID);
// Prepare smarty
$this->context->smarty->assign([
'server_url' => $serverUrl,
'currency_sign' => $currency->getSymbol(),
'payment_details' => $orderBitcoin->toArray(),
'server_url' => $serverUrl,
'storeCurrency' => Currency::getCurrencyInstance($cart->id_currency)->getSymbol(),
]);
return $this->display(__FILE__, 'views/templates/admin/invoice_block.tpl');
try {
// Get the invoice and its payments
$invoice = $client->invoice()->getInvoice($storeID, $invoiceId);
// Filter out methods without payments
$paymentMethods = array_filter($client->invoice()->getPaymentMethods($storeID, $invoiceId), static function ($method) {
return !empty($method->getPayments());
});
// Has any payment been received
$paymentReceived = array_reduce($paymentMethods, static function ($carry, $method) {
return empty($method->getPayments()) ? $carry : true;
}, false);
// Add more information to smarty
$this->context->smarty->assign([
'invoice' => $invoice,
'paymentMethods' => $paymentMethods,
'paymentReceived' => $paymentReceived,
]);
return $this->display(__FILE__, 'views/templates/admin/invoice_block.tpl');
} catch (RequestException $exception) {
// Log the exception
PrestaShopLogger::addLog(\sprintf('[WARNING] Tried to load BTCPay Server invoice in hookDisplayAdminOrderMainBottom: %s', $exception->getMessage()), \PrestaShopLogger::LOG_SEVERITY_LEVEL_WARNING, $exception->getCode(), 'Order', $bitcoinPayment->getOrderId());
// Show that the invoice was not found
return $this->display(__FILE__, 'views/templates/admin/invoice_missing_block.tpl');
}
}
// Hooks on prestashop order details in frontend
public function hookDisplayOrderDetail($params): ?string
/**
* Hooks on prestashop order details in frontend
*
* @throws JsonException
* @throws PrestaShopDatabaseException
*/
public function hookDisplayOrderDetail(array $params): ?string
{
// If the module is not active, abort
if (!$this->active) {
@ -208,65 +287,70 @@ class BTCPay extends PaymentModule
return null;
}
// Get BTCPay URL or abort
if (empty($serverUrl = Configuration::get('BTCPAY_URL'))) {
return null;
}
// Check if we actually have an order
$order = $params['order'];
if (!$order instanceof Order) {
return null;
}
// Check if we actually have an order
// If created by another module, return
if ($order->module !== $this->name) {
return false;
}
// Check if we actually have an cart
$cart = $params['cart'];
if (!$cart instanceof Cart) {
return null;
}
// Get legacy repository
$repository = new LegacyOrderBitcoinRepository();
// Get BTCPay URL or abort
if (empty($serverUrl = $this->configuration->get(Constants::CONFIGURATION_BTCPAY_HOST))) {
return null;
}
// Ensure the client is ready for use
if (null === ($client = Client::createFromConfiguration($this->configuration)) || false === $client->isValid()) {
return null;
}
// Get the order
if (null === ($orderBitcoin = $repository->getOneByOrderID($order->id))) {
if (null === ($bitcoinPayment = BitcoinPaymentRepository::getOneByOrderID($order->id))) {
return null;
}
// Check if it has an invoice ID
if (null === ($invoiceId = $orderBitcoin->getInvoiceId()) || empty($invoiceId)) {
if (null === ($invoiceId = $bitcoinPayment->getInvoiceId()) || empty($invoiceId)) {
return null;
}
// Get the currency from our cart
$currency = Currency::getCurrencyInstance((int) $cart->id_currency);
// Get the store ID
$storeID = $this->configuration->get(Constants::CONFIGURATION_BTCPAY_STORE_ID);
// Prepare smarty
$this->context->smarty->assign(
[
'server_url' => $serverUrl,
'currency_sign' => $currency->sign,
'payment_details' => $orderBitcoin->toArray(),
]
);
try {
// Prepare smarty
$this->context->smarty->assign([
'serverURL' => $serverUrl,
'storeCurrency' => Currency::getCurrencyInstance($cart->id_currency)->getSymbol(),
'invoice' => $client->invoice()->getInvoice($storeID, $invoiceId),
'paymentMethods' => $client->invoice()->getPaymentMethods($storeID, $invoiceId),
]);
return $this->display(__FILE__, 'views/templates/hooks/order_detail.tpl');
}
return $this->display(__FILE__, 'views/templates/hooks/order_detail.tpl');
} catch (RequestException $exception) {
// Log the exception
PrestaShopLogger::addLog(\sprintf('[WARNING] Tried to load BTCPay Server invoice in hookDisplayOrderDetail: %s', $exception->getMessage()), \PrestaShopLogger::LOG_SEVERITY_LEVEL_WARNING, $exception->getCode(), 'Order', $order->id);
public function hookDisplayPaymentEU(): array
{
if (!$this->active) {
return [];
// If the invoice is gone just return null
return null;
}
return [
'cta_text' => $this->name,
'logo' => Media::getMediaPath(_PS_MODULE_DIR_ . $this->name . '/views/images/bitcoin.png'),
'action' => $this->context->link->getModuleLink($this->name, 'payment', [], true),
];
}
// Hooks on prestashop payment returns
/**
* Hooks on prestashop payment returns
*
* @throws Exception
*/
public function hookPaymentReturn($params): ?string
{
// If the module is not active, abort
@ -285,38 +369,75 @@ class BTCPay extends PaymentModule
return null;
}
// Get the order
if (null === ($bitcoinPayment = BitcoinPaymentRepository::getOneByOrderID($order->id))) {
return null;
}
// Prepare smarty to present order details
$this->context->smarty->assign(
[
'presenter' => (new OrderPresenter())->present($order),
'order_state' => $order->getCurrentState(),
'os_waiting' => (string) Configuration::get('BTCPAY_OS_WAITING'),
'os_confirming' => (string) Configuration::get('BTCPAY_OS_CONFIRMING'),
'os_failed' => (string) Configuration::get('BTCPAY_OS_FAILED'),
'os_paid' => (string) Configuration::get('BTCPAY_OS_PAID'),
]
);
$this->context->smarty->assign([
'presenter' => (new OrderPresenter())->present($order),
'bitcoinPayment' => $bitcoinPayment,
'order_state' => $order->getCurrentState(),
'os_waiting' => $this->configuration->getInt(Constants::CONFIGURATION_ORDER_STATE_WAITING),
'os_confirming' => $this->configuration->getInt(Constants::CONFIGURATION_ORDER_STATE_CONFIRMING),
'os_failed' => $this->configuration->getInt(Constants::CONFIGURATION_ORDER_STATE_FAILED),
'os_paid' => $this->configuration->getInt(Constants::CONFIGURATION_ORDER_STATE_PAID),
]);
return $this->display(__FILE__, 'views/templates/hooks/payment_return.tpl');
}
// Hooks on prestashop payment options
/**
* Hooks on prestashop payment options
*
* @throws SmartyException
* @throws JsonException
*/
public function hookPaymentOptions(): array
{
// If the module is not active, abort
if (!$this->active) {
return [];
}
$paymentOption = new PaymentOption();
$paymentOption->setLogo(Media::getMediaPath(_PS_MODULE_DIR_ . $this->name . '/views/images/bitcoin.png'));
$paymentOption->setModuleName($this->name);
$paymentOption->setCallToActionText($this->trans('Pay with Bitcoin', [], 'Modules.Btcpay.Front'));
$paymentOption->setAction($this->context->link->getModuleLink($this->name, 'payment', [], true));
// Ensure the client is ready for use
if (null === ($client = Client::createFromConfiguration($this->configuration)) || false === $client->isValid()) {
return [];
}
return [$paymentOption];
// Get the store ID
$storeID = $this->configuration->get(Constants::CONFIGURATION_BTCPAY_STORE_ID);
try {
// If the server is not fully synced, do not show the option
if (!$client->server()->getInfo()->isFullySynced()) {
return [];
}
return [
(new PaymentOption())
->setModuleName($this->name)
->setLogo(Media::getMediaPath(_PS_MODULE_DIR_ . $this->name . '/views/images/payment.png'))
->setAction($this->context->link->getModuleLink($this->name, 'payment', [], true))
->setCallToActionText($this->trans('Pay with BTCPay Server', [], 'Modules.Btcpay.Front'))
->setAdditionalInformation($this->context->smarty->fetch('module:btcpay/views/templates/hooks/payment_option.tpl')),
];
} catch (BTCPayException $exception) {
// Log the exception
PrestaShopLogger::addLog(\sprintf('[WARNING] Could not load payments options from server: %s', $exception->getMessage()), \PrestaShopLogger::LOG_SEVERITY_LEVEL_WARNING, $exception->getCode());
return [];
}
}
// Hooks on prestashop cart changes
/**
* Hooks on prestashop cart changes
*
* @throws JsonException
* @throws PrestaShopDatabaseException
* @throws PrestaShopException
*/
public function hookActionCartSave(array $params): void
{
// If the module is not active, abort
@ -340,16 +461,18 @@ class BTCPay extends PaymentModule
}
// Get the order
if (null === ($orderBitcoin = (new LegacyOrderBitcoinRepository())->getOneByCartID($cart->id))) {
if (null === ($bitcoinPayment = BitcoinPaymentRepository::getOneByCartID($cart->id))) {
return;
}
PrestaShopLogger::addLog('[WARNING] Order has changed for cart: ' . $cart->id . '. Cancelling....', 2);
PrestaShopLogger::addLog('[INFO] Order has changed for cart. Cancelling....', \PrestaShopLogger::LOG_SEVERITY_LEVEL_WARNING, null, 'Cart', $cart->id);
// Try to remove the order
if (false === $orderBitcoin->delete()) {
PrestaShopLogger::addLog('[ERROR] Expected to remove the order, but failed to do so', 3);
throw new \PrestaShopDatabaseException('Expected to remove the order, but failed to do so');
if (false === $bitcoinPayment->delete()) {
$error = \sprintf('[ERROR] Expected to remove the order %s, but failed to do so', $bitcoinPayment->getOrderId());
PrestaShopLogger::addLog($error, \PrestaShopLogger::LOG_SEVERITY_LEVEL_ERROR, null, 'BitcoinPayment', $bitcoinPayment->getId());
throw new \PrestaShopDatabaseException($error);
}
}
@ -360,21 +483,47 @@ class BTCPay extends PaymentModule
}
}
private function getRepository(): ?BitcoinPaymentRepository
private function displayModuleWarnings(): void
{
if (null === $this->repository) {
try {
$this->repository = $this->get('prestashop.module.btcpay.repository');
} catch (Throwable $e) {
if (null !== ($container = SymfonyContainer::getInstance())) {
$this->repository = new BitcoinPaymentRepository(
$container->get('doctrine.dbal.default_connection'),
$container->getParameter('database_prefix')
);
}
// Try and create the client
$client = Client::createFromConfiguration($this->configuration);
try {
// Show warning if API key is missing or if we're not yet fully synced
if (null === $client || empty($this->configuration->get(Constants::CONFIGURATION_BTCPAY_API_KEY))) {
$this->warning = $this->trans('Your BTCPay Server store has not yet been linked, payment option is unavailable.', [], 'Modules.Btcpay.Admin');
} elseif (!$client->server()->getInfo()->isFullySynced()) {
$this->warning = $this->trans('One (or more) coins are not yet synced, payment option will be unavailable until the sync has finished.', [], 'Modules.Btcpay.Admin');
}
} catch (BTCPayException $exception) {
// Log the exception
PrestaShopLogger::addLog(\sprintf('[WARNING] BTCPay Server configuration is no longer valid, resetting host and API key. Error: %s', $exception->getMessage()), \PrestaShopLogger::LOG_SEVERITY_LEVEL_WARNING, $exception->getCode());
// Show a warning
$this->warning = $this->trans('Your BTCPay Server configuration is no longer valid, please setup module again.', [], 'Modules.Btcpay.Admin');
// Reset configuration
$this->configuration->set(Constants::CONFIGURATION_BTCPAY_HOST, Constants::CONFIGURATION_DEFAULT_HOST);
$this->configuration->set(Constants::CONFIGURATION_BTCPAY_API_KEY, null);
// Bail
return;
} catch (\Throwable $exception) {
// Log the exception
PrestaShopLogger::addLog(\sprintf('[WARNING] Could not parse server information: %s', $exception->getMessage()), \PrestaShopLogger::LOG_SEVERITY_LEVEL_WARNING, $exception->getCode());
// Bail
return;
}
return $this->repository;
// API key/sync warnings are more important than a new version, if a warning is set, return now
if (!empty($this->warning)) {
return;
}
// Otherwise, add a warning on version upgrade
if (null !== ($latest = $this->versioning->latest()) && $latest->newer($this->version)) {
$this->warning = $this->trans(\sprintf('There is a new version available for this plugin: %s.', $latest->getTagName()), [], 'Modules.Btcpay.Admin');
}
}
}

View File

@ -1,7 +1,8 @@
{
"name": "btcpay/prestashop",
"type": "prestashop-module",
"description": "BTCPay payment plugin for PrestaShop",
"license": "MIT",
"type": "prestashop-module",
"keywords": [
"prestashop",
"plugin",
@ -11,30 +12,41 @@
"BTCPay"
],
"homepage": "https://github.com/btcpayserver/prestashop-plugin",
"license": "MIT",
"support": {
"issues": "https://github.com/btcpayserver/prestashop-plugin/issues",
"source": "https://github.com/btcpayserver/prestashop-plugin"
},
"require": {
"php": ">=7.3.0",
"php": ">=8.0",
"ext-PDO": "*",
"ext-bcmath": "*",
"ext-curl": "*",
"ext-gd": "*",
"ext-intl": "*",
"ext-json": "*",
"ext-mbstring": "*",
"btcpayserver/btcpayserver-php-client": "^v1.0.1",
"stechstudio/backoff": "^1.2"
"btcpayserver/btcpayserver-greenfield-php": "^2.8.1",
"composer/semver": "^3.4.2",
"stechstudio/backoff": "^1.4"
},
"require-dev": {
"ergebnis/composer-normalize": "^2.15",
"roave/security-advisories": "dev-latest"
"ergebnis/composer-normalize": "^2.43",
"roave/security-advisories": "dev-latest",
"symfony/debug-bundle": "~5.4.40",
"symfony/var-dumper": "~5.4.43"
},
"config": {
"platform": {
"php": "7.3"
},
"preferred-install": "dist",
"prepend-autoloader": false,
"sort-packages": true
"replace": {
"symfony/polyfill-mbstring": "*",
"symfony/polyfill-php54": "*",
"symfony/polyfill-php55": "^1.10",
"symfony/polyfill-php56": "*",
"symfony/polyfill-php70": "*",
"symfony/polyfill-php71": "*",
"symfony/polyfill-php72": "*",
"symfony/polyfill-php73": "*",
"symfony/polyfill-php74": "*"
},
"minimum-stability": "stable",
"autoload": {
"psr-4": {
"BTCPay\\": "src/"
@ -44,9 +56,16 @@
],
"exclude-from-classmap": []
},
"minimum-stability": "stable",
"support": {
"issues": "https://github.com/btcpayserver/prestashop-plugin/issues",
"source": "https://github.com/btcpayserver/prestashop-plugin"
"config": {
"allow-plugins": {
"ergebnis/composer-normalize": true,
"php-http/discovery": true
},
"platform": {
"php": "8.0"
},
"preferred-install": "dist",
"prepend-autoloader": false,
"sort-packages": true
}
}

File diff suppressed because it is too large Load Diff

12
modules/btcpay/config.xml Normal file
View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8" ?>
<module>
<name>btcpay</name>
<displayName><![CDATA[BTCPay Server]]></displayName>
<version><![CDATA[6.1.0]]></version>
<description><![CDATA[Accept crypto payments via BTCPay Server.]]></description>
<author><![CDATA[BTCPay Server]]></author>
<tab><![CDATA[payments_gateways]]></tab>
<confirmUninstall><![CDATA[Are you sure that you want to uninstall this module? Past purchases and order states will be kept, but your configuration will be removed.]]></confirmUninstall>
<is_configurable>1</is_configurable>
<need_instance>1</need_instance>
</module>

View File

@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@ -2,13 +2,31 @@ admin_btcpay_configure:
path: /btcpay/configure
methods: [GET]
defaults:
_controller: 'BTCPay\Controller\Admin\Improve\Payment\ConfigureController::editAction'
_controller: 'BTCPay\Controller\Admin\Improve\Payment\ConfigureController::viewAction'
_legacy_controller: AdminConfigureBTCPay
_legacy_link: AdminConfigureBTCPay
_disable_module_prefix: true
admin_btcpay_configure_process:
admin_btcpay_configure_server_process:
path: /btcpay/configure
methods: [POST]
methods: [GET, POST]
defaults:
_controller: 'BTCPay\Controller\Admin\Improve\Payment\ConfigureController::editProcessAction'
_controller: 'BTCPay\Controller\Admin\Improve\Payment\ConfigureController::editServerSettingsAction'
_legacy_controller: AdminConfigureBTCPay
_disable_module_prefix: true
admin_btcpay_configure_general_process:
path: /btcpay/configure/general
methods: [GET, POST]
defaults:
_controller: 'BTCPay\Controller\Admin\Improve\Payment\ConfigureController::editGeneralSettingsAction'
_legacy_controller: AdminConfigureBTCPay
_disable_module_prefix: true
admin_btcpay_validate:
path: /btcpay/api-key/validate
methods: [GET, POST]
defaults:
_controller: 'BTCPay\Controller\Admin\Improve\Payment\ConfigureController::validateAPIKeyAction'
_legacy_controller: AdminConfigureBTCPay
_disable_module_prefix: true

View File

@ -2,31 +2,63 @@ services:
_defaults:
public: true
prestashop.module.btcpay.repository:
class: BTCPay\Repository\BitcoinPaymentRepository
# Module
prestashop.module.btcpay:
class: BTCPay
# Repositories
prestashop.module.btcpay.repository.install:
class: BTCPay\Repository\TableRepository
arguments:
$connection: '@doctrine.dbal.default_connection'
$prefix: '%database_prefix%'
- '@doctrine.dbal.default_connection'
- '%database_prefix%'
# BTCPay form data provider
prestashop.module.btcpay.form.configure.provider:
class: BTCPay\Form\ConfigureFormDataProvider
# Controllers
BTCPay\Controller\Admin\Improve\Payment\ConfigureController:
class: BTCPay\Controller\Admin\Improve\Payment\ConfigureController
arguments:
- '@prestashop.module.btcpay'
- '@validator'
- '@prestashop.module.btcpay.form_handler.server'
- '@prestashop.module.btcpay.form_handler.general'
# Form types
prestashop.module.btcpay.form.type.configure:
class: BTCPay\Form\Type\ConfigureType
# Form data provider
prestashop.module.btcpay.form.server.provider:
class: BTCPay\Form\ServerFormDataProvider
prestashop.module.btcpay.form.general.provider:
class: BTCPay\Form\GeneralFormDataProvider
# Form type
prestashop.module.btcpay.form.type.server:
class: BTCPay\Form\Type\ServerType
parent: 'form.type.translatable.aware'
public: true
tags:
- { name: form.type }
tags: [{ name: form.type }]
# BTCPay form handler
prestashop.module.btcpay.form_handler:
class: 'PrestaShop\PrestaShop\Core\Form\FormHandler'
prestashop.module.btcpay.form.type.general:
class: BTCPay\Form\Type\GeneralType
parent: 'form.type.translatable.aware'
public: true
tags: [{ name: form.type }]
# Form handler
prestashop.module.btcpay.form_handler.server:
class: PrestaShop\PrestaShop\Core\Form\Handler
arguments:
$formBuilder: '@=service("form.factory").createBuilder()'
$formFactory: '@Symfony\Component\Form\FormFactoryInterface'
$hookDispatcher: '@prestashop.core.hook.dispatcher'
$formDataProvider: '@prestashop.module.btcpay.form.configure.provider'
$formTypes:
'btcpay': 'BTCPay\Form\Type\ConfigureType'
$hookName: 'AdminConfigureBTCPay'
$formDataProvider: '@prestashop.module.btcpay.form.server.provider'
$form: 'BTCPay\Form\Type\ServerType'
$hookName: 'ServerType'
$formName: 'server-form'
# Form handler
prestashop.module.btcpay.form_handler.general:
class: PrestaShop\PrestaShop\Core\Form\Handler
arguments:
$formFactory: '@Symfony\Component\Form\FormFactoryInterface'
$hookDispatcher: '@prestashop.core.hook.dispatcher'
$formDataProvider: '@prestashop.module.btcpay.form.general.provider'
$form: 'BTCPay\Form\Type\GeneralType'
$hookName: 'GeneralType'
$formName: 'general-form'

View File

@ -1,22 +1,23 @@
<?php
if (!defined('_PS_VERSION_')) {
exit;
}
class AdminConfigureBTCPayController extends ModuleAdminController
{
/**
* BTCpay module instance. It's assigned automatically by PrestaShop infrastructure.
*
* @var BTCPay
*/
public $module;
/**
* Configure the administration controller and define some sane defaults.
*
* {@inheritdoc}
*/
public function __construct()
{
$this->bootstrap = true;
$this->display = 'view';
parent::__construct();
if (!$this->module->active) {
@ -25,7 +26,7 @@ class AdminConfigureBTCPayController extends ModuleAdminController
}
/**
* Redirect to the configuration screen of this module.
* Redirect to the actual configuration screen of this module.
*
* {@inheritdoc}
*/

View File

@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@ -1,55 +0,0 @@
<?php
use BTCPay\LegacyOrderBitcoinRepository;
use BTCPay\Server\IPN;
use Symfony\Component\HttpFoundation\Request;
/** @noinspection AutoloadingIssuesInspection */
class BTCPayIpnModuleFrontController extends \ModuleFrontController
{
/**
* Enable SSL only.
*
* @var bool
*/
public $ssl = true;
/**
* @var BTCPay
*/
public $module;
/**
* @var IPN
*/
private $ipn;
public function __construct()
{
parent::__construct();
$this->ipn = new IPN(new LegacyOrderBitcoinRepository());
}
/**
* We don't want to show anything, so just don't render anything.
*
* {@inheritdoc}
*/
public function display(): bool
{
return true;
}
/**
* {@inheritdoc}
*/
public function postProcess(): void
{
try {
$this->ipn->process($this->module, Request::createFromGlobals());
} catch (\Exception $e) {
throw new LogicException('Could not process', 1, $e);
}
}
}

View File

@ -1,9 +1,13 @@
<?php
use BTCPay\LegacyOrderBitcoinRepository;
use BTCPay\Constants;
use BTCPay\Server\Factory;
use PrestaShop\PrestaShop\Adapter\Configuration;
if (!defined('_PS_VERSION_')) {
exit;
}
/** @noinspection AutoloadingIssuesInspection */
class BTCPayPaymentModuleFrontController extends ModuleFrontController
{
/**
@ -13,32 +17,54 @@ class BTCPayPaymentModuleFrontController extends ModuleFrontController
*/
public $ssl = true;
/**
* @var BTCPay
*/
public $module;
/**
* @var Factory
*/
private $factory;
/**
* @var Configuration
*/
private $configuration;
public function __construct()
{
parent::__construct();
$this->factory = new Factory(new LegacyOrderBitcoinRepository(), new \Link(), $this->module->name);
$this->factory = new Factory($this->module, $this->context);
$this->configuration = new Configuration();
}
/**
* {@inheritdoc}
*/
public function initContent(): void
{
parent::initContent();
if (null !== ($redirect = $this->factory->createPaymentRequest($this->context->customer, $this->context->cart))) {
Tools::redirectLink($redirect);
if (null === $this->configuration->get(Constants::CONFIGURATION_BTCPAY_STORE_ID)) {
$this->warning[] = $this->context->getTranslator()->trans('Payment method has not yet been setup properly. Please try again or contact us.', [], 'Modules.Btcpay.Front');
$this->redirectWithNotifications($this->context->link->getPageLink('cart', $this->ssl));
return;
}
$this->warning[] = $this->context->getTranslator()->trans('We are having issues with our BTCPayServer backend. Please try again or contact us.', [], 'Modules.Btcpay.Front');
$this->redirectWithNotifications($this->context->link->getPageLink('cart', $this->ssl));
try {
if (null !== ($redirect = $this->factory->createPaymentRequest($this->context->customer, $this->context->cart))) {
Tools::redirect($redirect);
return;
}
$this->warning[] = $this->context->getTranslator()->trans('We could not create a payment request via BTCPay Server. Please try again or contact us.', [], 'Modules.Btcpay.Front');
$this->redirectWithNotifications($this->context->link->getPageLink('cart', $this->ssl));
} catch (\Throwable $throwable) {
PrestaShopLogger::addLog(\sprintf('[ERROR] An error occurred during payment creation: %s', $throwable), PrestaShopLogger::LOG_SEVERITY_LEVEL_ERROR, $throwable->getCode());
$this->warning[] = $this->context->getTranslator()->trans('We are having issues with our BTCPay Server backend. Please try again or contact us.', [], 'Modules.Btcpay.Front');
$this->redirectWithNotifications($this->context->link->getPageLink('cart', $this->ssl));
}
}
}

View File

@ -1,8 +1,15 @@
<?php
use BTCPay\LegacyOrderBitcoinRepository;
use BTCPay\Constants;
use BTCPay\Invoice\Processor;
use BTCPay\Repository\BitcoinPaymentRepository;
use BTCPay\Server\Client;
use PrestaShop\PrestaShop\Adapter\Configuration;
if (!defined('_PS_VERSION_')) {
exit;
}
/** @noinspection AutoloadingIssuesInspection */
class BTCPayValidationModuleFrontController extends ModuleFrontController
{
/**
@ -13,19 +20,26 @@ class BTCPayValidationModuleFrontController extends ModuleFrontController
public $ssl = true;
/**
* @var LegacyOrderBitcoinRepository
* @var \BTCPay
*/
private $repository;
public $module;
/**
* @var Configuration
*/
private $configuration;
public function __construct()
{
parent::__construct();
$this->repository = new LegacyOrderBitcoinRepository();
$this->configuration = new Configuration();
}
/**
* {@inheritdoc}
* @throws JsonException
* @throws PrestaShopDatabaseException
* @throws PrestaShopException
*/
public function postProcess(): void
{
@ -39,20 +53,21 @@ class BTCPayValidationModuleFrontController extends ModuleFrontController
// Get the translator so we can translate our errors
if (null === ($translator = $this->getTranslator())) {
throw new \RuntimeException('Expected the translator to be available');
throw new RuntimeException('Expected the translator to be available');
}
// Check if our payment option is still valid
$authorized = false;
$paymentAvailable = false;
foreach (Module::getPaymentModules() as $module) {
if ($module['name'] === $this->module->name) {
$authorized = true;
$paymentAvailable = true;
break;
}
}
// If it's no longer valid, redirect the customer.
if (!$authorized) {
if (!$paymentAvailable) {
$this->warning[] = $translator->trans('This payment method is not available.', [], 'Modules.Btcpay.Front');
$this->redirectWithNotifications($this->context->link->getPageLink('cart', $this->ssl));
@ -61,27 +76,45 @@ class BTCPayValidationModuleFrontController extends ModuleFrontController
// Get the passed invoice reference, which we can then use to get the actual order
$invoiceReference = Tools::getValue('invoice_reference', 0);
if (null === ($orderBitcoin = $this->repository->getOneByInvoiceReference($invoiceReference))) {
$this->warning[] = $translator->trans('There is no order that we can validate.', [], 'Modules.Btcpay.Front');
if (null === ($bitcoinPayment = BitcoinPaymentRepository::getOneByInvoiceReference($invoiceReference))) {
$this->warning[] = $translator->trans('The passed invoice reference is not valid.', [], 'Modules.Btcpay.Front');
$this->redirectWithNotifications($this->context->link->getPageLink('cart', $this->ssl));
return;
}
// Get the order and validate it
$order = Order::getByCartId($orderBitcoin->getCartId());
if (null === $order || 0 === $order->id || (int) $order->id_customer !== (int) $this->context->customer->id) {
$this->warning[] = $translator->trans('There is no order that we can process.', [], 'Modules.Btcpay.Front');
$this->redirectWithNotifications($this->context->link->getPageLink('cart', $this->ssl));
// Grab the current order mode
$orderMode = $this->configuration->get(Constants::CONFIGURATION_ORDER_MODE);
return;
// Get the order and validate it
$order = Order::getByCartId($bitcoinPayment->getCartId());
if (null === $order || 0 === $order->id || (int) $order->id_customer !== (int) $this->context->customer->id) {
// The order must exist when using the `before` order mode
if (Constants::ORDER_MODE_BEFORE === $orderMode) {
$this->warning[] = $translator->trans('There is no order that we can process.', [], 'Modules.Btcpay.Front');
$this->redirectWithNotifications($this->context->link->getPageLink('cart', $this->ssl));
return;
}
// Ensure the client is ready for use
if (null === ($client = Client::createFromConfiguration($this->configuration)) || false === $client->isValid()) {
throw new RuntimeException('Expected the client to be available');
}
// User was quicker than the callback, so we deal with the actual invoice now
$processor = new Processor($this->module, $this->context, $this->configuration, $client);
$processor->paymentReceivedCreateAfter($bitcoinPayment);
// Grab the (now existing) order
$order = Order::getByCartId($bitcoinPayment->getCartId());
}
// Get the customer so we can do a fancy redirect
$customer = new Customer((int) $cart->id_customer);
// If it's a guest, sent them to guest tracking
if (Cart::isGuestCartByCartId($orderBitcoin->getCartId())) {
if (Cart::isGuestCartByCartId($bitcoinPayment->getCartId())) {
Tools::redirect($this->context->link->getPageLink('guest-tracking', $this->ssl, null, ['order_reference' => $order->reference, 'email' => $customer->email]));
return;

View File

@ -0,0 +1,94 @@
<?php
use BTCPay\Constants;
use BTCPay\Server\Client;
use BTCPay\Server\WebhookHandler;
use PrestaShop\PrestaShop\Adapter\Configuration;
use Symfony\Component\HttpFoundation\Request;
if (!defined('_PS_VERSION_')) {
exit;
}
class BTCPayWebhookModuleFrontController extends \ModuleFrontController
{
/**
* Enable SSL only.
*
* @var bool
*/
public $ssl = true;
/**
* @var BTCPay
*/
public $module;
/**
* @var Configuration
*/
private $configuration;
/**
* @var Client|null
*/
private $client;
/**
* @var WebhookHandler
*/
private $handler;
public function __construct()
{
parent::__construct();
$this->configuration = new Configuration();
$this->client = Client::createFromConfiguration($this->configuration);
$this->handler = new WebhookHandler($this->module, $this->context, $this->client);
}
/**
* We don't want to show anything, so just don't render anything.
*
* {@inheritdoc}
*/
public function display(): bool
{
return true;
}
/**
* {@inheritdoc}
*
* @throws Exception
*/
public function postProcess(): void
{
$request = Request::createFromGlobals();
// If the module is inactive, or we don't receive a signature, or we don't have the webhook secret, just return
if (!$this->module->active
|| null === ($signature = $request->headers->get(Constants::BTCPAY_HEADER_SIG))
|| false === ($secret = $this->configuration->get(Constants::CONFIGURATION_BTCPAY_WEBHOOK_SECRET))) {
return;
}
// Ensure the client is ready for use, if not, just return
if (null === $this->client || false === $this->client->isValid()) {
return;
}
// Ensure our webhook is actually valid
if (false === $this->client->webhook()->isIncomingWebhookRequestValid($request->getContent(), $signature, $secret)) {
$error = 'Invalid BTCPay Server payment notification message received - signature did not match.';
\PrestaShopLogger::addLog($error, \PrestaShopLogger::LOG_SEVERITY_LEVEL_ERROR);
throw new \Exception($error);
}
$this->handler->process($request);
echo 'OK';
}
}

View File

@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

File diff suppressed because it is too large Load Diff

View File

@ -2,19 +2,70 @@
namespace BTCPay;
use BTCPayServer\Invoice;
use BTCPayServer\Client\InvoiceCheckoutOptions;
if (!\defined('_PS_VERSION_')) {
exit;
}
class Constants
{
/**
* All possible transaction speeds as defined by BTCPay server
*/
public const TRANSACTION_SPEEDS = [Invoice::TRANSACTION_SPEED_LOW, Invoice::TRANSACTION_SPEED_MEDIUM, Invoice::TRANSACTION_SPEED_HIGH];
// Version information
public const MINIMUM_BTCPAY_VERSION = '1.7.0';
public const MINIMUM_PS_VERSION = '8.0.0';
public const MINIMUM_PHP_VERSION = '8.0.0';
/**
* All possible options for order creation (before or after payment)
*/
// Cache configuration
public const LASTEST_VERSION_CACHE_KEY = 'BTCPAY_LATEST_VERSION';
public const LASTEST_VERSION_CACHE_EXPIRATION = 60 * 60 * 24 * 7; // 7 days
// GitHub API endpoint for releases
public const GITHUB_API_LATEST_ENDPOINT = 'https://api.github.com/repos/btcpayserver/prestashop-plugin/releases/latest';
// BTCPay Server webhook header
public const BTCPAY_HEADER_SIG = 'Btcpay-Sig';
// BTCPay required permissions
public const BTCPAY_PERMISSIONS = [
'btcpay.store.canmodifystoresettings',
'btcpay.store.webhooks.canmodifywebhooks',
'btcpay.store.canviewstoresettings',
'btcpay.store.cancreateinvoice',
'btcpay.store.canviewinvoices',
'btcpay.store.canmodifyinvoices',
];
// BTCPay Server configuration
public const CONFIGURATION_BTCPAY_HOST = 'BTCPAY_URL';
public const CONFIGURATION_BTCPAY_API_KEY = 'BTCPAY_API_KEY';
public const CONFIGURATION_BTCPAY_STORE_ID = 'BTCPAY_STORE_ID';
public const CONFIGURATION_BTCPAY_WEBHOOK_ID = 'BTCPAY_WEBHOOK_ID';
public const CONFIGURATION_BTCPAY_WEBHOOK_SECRET = 'BTCPAY_WEBHOOK_SECRET';
// Default values
public const CONFIGURATION_DEFAULT_HOST = 'https://testnet.demo.btcpayserver.org';
// Order (creation) related configuration
public const CONFIGURATION_ORDER_MODE = 'BTCPAY_ORDERMODE';
// Order states
public const CONFIGURATION_ORDER_STATE_WAITING = 'BTCPAY_OS_WAITING';
public const CONFIGURATION_ORDER_STATE_CONFIRMING = 'BTCPAY_OS_CONFIRMING';
public const CONFIGURATION_ORDER_STATE_FAILED = 'BTCPAY_OS_FAILED';
public const CONFIGURATION_ORDER_STATE_PAID = 'BTCPAY_OS_PAID';
// Do we want to protect order states from getting changed by webhook
public const CONFIGURATION_PROTECT_ORDERS = 'BTCPAY_PROTECT_ORDERS';
// Do we want to share personal details with BTCPay Server
public const CONFIGURATION_SHARE_METADATA = 'BTCPAY_SHARE_METADATA';
// All possible transaction speeds as defined by BTCPay server
public const CONFIGURATION_SPEED_MODE = 'BTCPAY_TXSPEED';
public const TRANSACTION_SPEEDS = [InvoiceCheckoutOptions::SPEED_HIGH, InvoiceCheckoutOptions::SPEED_MEDIUM, InvoiceCheckoutOptions::SPEED_LOW];
// All possible options for order creation (before or after payment)
public const ORDER_MODES = [self::ORDER_MODE_BEFORE, self::ORDER_MODE_AFTER];
public const ORDER_MODE_BEFORE = 'beforepayment';
public const ORDER_MODE_AFTER = 'afterpayment';
public const ORDER_MODE_BEFORE = 'before_payment';
public const ORDER_MODE_AFTER = 'after_payment';
}

View File

@ -2,31 +2,97 @@
namespace BTCPay\Controller\Admin\Improve\Payment;
use BTCPay;
use BTCPay\Constants;
use BTCPay\Form\Data\General;
use BTCPay\Form\Data\Server;
use BTCPay\Github\Versioning;
use BTCPay\Server\Client;
use BTCPay\Server\Data\ValidateApiKey;
use BTCPayServer\Client\ApiKey;
use Exception;
use PrestaShop\PrestaShop\Core\Domain\Configuration\ShopConfigurationInterface;
use PrestaShop\PrestaShop\Core\Form\FormHandlerInterface;
use PrestaShopBundle\Controller\Admin\FrameworkBundleAdminController;
use PrestaShopBundle\Security\Annotation\AdminSecurity;
use PrestaShopBundle\Security\Annotation\ModuleActivated;
use PrestaShopLogger;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\ParameterBag;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Validator\ConstraintViolationInterface;
use Symfony\Component\Validator\Validator\ValidatorInterface;
use Throwable;
if (!\defined('_PS_VERSION_')) {
exit;
}
/**
* @ModuleActivated(moduleName="btcpay", redirectRoute="admin_module_manage")
*/
class ConfigureController extends FrameworkBundleAdminController
{
/**
* @var BTCPay
*/
private $module;
/**
* @var ValidatorInterface
*/
private $validator;
/**
* @var FormHandlerInterface
*/
private $serverFormHandler;
/**
* @var FormHandlerInterface
*/
private $generalFormHandler;
/**
* @var Versioning
*/
private $versioning;
public function __construct(BTCPay $module, ValidatorInterface $validator, FormHandlerInterface $serverFormHandler, FormHandlerInterface $generalFormHandler)
{
// Fallback in case 8.0 is used // TODO: Remove once we make 9.0 the minimum
if (\version_compare(\_PS_VERSION_, '8.1.0', '<')) {
parent::__construct();
}
$this->module = $module;
$this->validator = $validator;
$this->serverFormHandler = $serverFormHandler;
$this->generalFormHandler = $generalFormHandler;
$this->versioning = new Versioning();
}
/**
* @AdminSecurity("is_granted('read', request.get('_legacy_controller'))", message="Access denied.")
*
* @throws \Exception
* @throws Exception
*/
public function editAction(Request $request): Response
public function viewAction(Request $request): Response
{
return $this->render('@Modules/btcpay/views/templates/admin/configure.html.twig', [
'form' => $this->get('prestashop.module.btcpay.form_handler')->getForm()->createView(),
'help_link' => $this->generateSidebarLink($request->attributes->get('_legacy_controller')),
'enableSidebar' => true,
]);
// Build the client
$client = Client::createFromConfiguration($this->getConfiguration());
// Create the authorization URL (without redirect)
$authorizeUrl = ApiKey::getAuthorizeUrl($this->getConfiguration()->get(Constants::CONFIGURATION_BTCPAY_HOST), Constants::BTCPAY_PERMISSIONS, $this->module->name, true, true, null, $this->module->name);
// Ensure we always have a webhook
if (null !== $client && $client->isValid()) {
$client->webhook()->ensureWebhook($this->getConfiguration()->get(Constants::CONFIGURATION_BTCPAY_STORE_ID));
}
return $this->getResponse($request, $this->serverFormHandler->getForm(), $this->generalFormHandler->getForm(), $authorizeUrl, $client);
}
/**
@ -34,31 +100,349 @@ class ConfigureController extends FrameworkBundleAdminController
*
* @return RedirectResponse|Response
*
* @throws \Exception
* @throws Exception
*/
public function editProcessAction(Request $request): Response
public function editServerSettingsAction(Request $request): Response
{
/** @var FormHandlerInterface $formHandler */
$formHandler = $this->get('prestashop.module.btcpay.form_handler');
$form = $formHandler->getForm();
$form->handleRequest($request);
// Get configuration container
$shopConfiguration = $this->getConfiguration();
if ($form->isSubmitted() && $form->isValid()) {
$data = $form->getData();
$saveErrors = $formHandler->save($data);
// Get current configuration, before processing everything
$currentConfiguration = Server::create($shopConfiguration);
if (0 === \count($saveErrors)) {
$this->addFlash('success', $this->trans('Successful update.', 'Admin.Notifications.Success'));
$serverForm = $this->serverFormHandler->getForm();
$serverForm->handleRequest($request);
// Just show the boring configuration field on no submit/invalid form
if (!$serverForm->isSubmitted() || !$serverForm->isValid()) {
// Try and create the client
$client = Client::createFromConfiguration($this->getConfiguration());
// Create the authorization URL (without redirect)
$authorizeUrl = ApiKey::getAuthorizeUrl($this->getConfiguration()->get(Constants::CONFIGURATION_BTCPAY_HOST), Constants::BTCPAY_PERMISSIONS, $this->module->name, true, true, null, $this->module->name);
return $this->getResponse($request, $serverForm, $this->generalFormHandler->getForm(), $authorizeUrl, $client);
}
/** @var Server $submittedConfiguration */
$submittedConfiguration = $serverForm->getData();
// If there are errors in the form, error out here
if (0 !== \count($saveErrors = $this->serverFormHandler->save($submittedConfiguration->toArray()))) {
$this->flashErrors($saveErrors);
return $this->redirectToRoute('admin_btcpay_configure');
}
// If the configuration is the same, just stop
if ($submittedConfiguration->equals($currentConfiguration)) {
$this->addFlash('success', 'BTCPay Server Plugin: Settings have not changed.');
return $this->redirectToRoute('admin_btcpay_configure');
}
// If we are just removing the API key, do that and return
if (null === $submittedConfiguration->getApiKey() && !empty($currentConfiguration->getApiKey())) {
// Remove the current webhook to prevent issues in the future
if (false === (new Client($shopConfiguration->get(Constants::CONFIGURATION_BTCPAY_HOST), $currentConfiguration->getApiKey()))->webhook()->removeCurrent()) {
$this->addFlash('error', 'BTCPay Server Plugin: Could not remove webhook from the server. Please double check it is actually gone.');
}
$shopConfiguration->set(Constants::CONFIGURATION_BTCPAY_API_KEY, null);
$shopConfiguration->set(Constants::CONFIGURATION_BTCPAY_STORE_ID, null);
$shopConfiguration->set(Constants::CONFIGURATION_BTCPAY_WEBHOOK_ID, null);
$shopConfiguration->set(Constants::CONFIGURATION_BTCPAY_WEBHOOK_SECRET, null);
$this->addFlash('success', 'BTCPay Server plugin: API key has been removed');
return $this->redirectToRoute('admin_btcpay_configure');
}
// Before processing anything further, make sure any webhook that exists is removed
(new Client($currentConfiguration->getHost(), $currentConfiguration->getApiKey()))->webhook()->removeCurrent();
// If an API key is set, use that
if (null !== $submittedConfiguration->getApiKey()) {
return $this->processApiKey($submittedConfiguration);
}
// If nothing has been set, redirect to the host
return $this->processRedirect($request, $submittedConfiguration);
}
/**
* @AdminSecurity("is_granted('update', request.get('_legacy_controller'))", message="Access denied.")
*
* @return RedirectResponse|Response
*
* @throws Exception
*/
public function editGeneralSettingsAction(Request $request): Response
{
// Get current configuration, before processing everything
$currentConfiguration = General::create($this->getConfiguration());
$generalForm = $this->generalFormHandler->getForm();
$generalForm->handleRequest($request);
// Just show the boring configuration field on no submit/invalid form
if (!$generalForm->isSubmitted() || !$generalForm->isValid()) {
// Try and create the client
$client = Client::createFromConfiguration($this->getConfiguration());
// Create the authorization URL (without redirect)
$authorizeUrl = ApiKey::getAuthorizeUrl($this->getConfiguration()->get(Constants::CONFIGURATION_BTCPAY_HOST), Constants::BTCPAY_PERMISSIONS, $this->module->name, true, true, null, $this->module->name);
return $this->getResponse($request, $this->serverFormHandler->getForm(), $generalForm, $authorizeUrl, $client);
}
/** @var General $general */
$general = $generalForm->getData();
// If there are errors in the form, error out here
if (0 !== \count($saveErrors = $this->generalFormHandler->save($general->toArray()))) {
$this->flashErrors($saveErrors);
return $this->redirectToRoute('admin_btcpay_configure');
}
// If the configuration is the same, just stop
if ($general->equals($currentConfiguration)) {
$this->addFlash('success', 'BTCPay Server Plugin: Settings have not changed.');
return $this->redirectToRoute('admin_btcpay_configure');
}
// Return home
$this->addFlash('success', 'BTCPay Server Plugin: Settings have been saved.');
return $this->redirectToRoute('admin_btcpay_configure');
}
/**
* @return RedirectResponse|Response
*
* @throws Exception
*/
public function validateAPIKeyAction(Request $request): Response
{
// If we received an empty post we probably hit the PrestaShop security check
if (empty($request->request->all())) {
$this->addFlash('error', 'Did not receive data from BTCPay Server. If you received an <strong>Invalid Token</strong> page, make sure to properly setup PrestaShop and BTCPay Server (publicly accessible and HTTPS enabled). Please try again once done or use the API key option.');
// Make sure to reset the API key
$this->getConfiguration()->set(Constants::CONFIGURATION_BTCPAY_API_KEY, null);
return $this->redirectToRoute('admin_btcpay_configure');
}
// Validate incoming request and return any errors we encounter
$validateRequest = new ValidateApiKey($request->request);
if (0 !== \count($errors = $this->validator->validate($validateRequest))) {
/** @var ConstraintViolationInterface $error */
foreach ($errors as $error) {
$this->addFlash('error', $error->getMessage());
}
// Make sure to reset the API key
$this->getConfiguration()->set(Constants::CONFIGURATION_BTCPAY_API_KEY, null);
return $this->redirectToRoute('admin_btcpay_configure');
}
// Build the client
$client = new Client($this->getConfiguration()->get(Constants::CONFIGURATION_BTCPAY_HOST), $validateRequest->getApiKey());
// Get the store ID
$storeId = $validateRequest->getStoreID();
try {
// Ensure we have a valid BTCPay Server version
if (null !== ($info = $client->server()->getInfo()) && \version_compare($info->getVersion(), Constants::MINIMUM_BTCPAY_VERSION, '<')) {
$this->addFlash('error', \sprintf('BTCPay server version is too low. Expected %s or higher, received %s.', Constants::MINIMUM_BTCPAY_VERSION, $info->getVersion()));
PrestaShopLogger::addLog(\sprintf('[ERROR] BTCPay server version is too low. Expected %s or higher, received %s.', Constants::MINIMUM_BTCPAY_VERSION, $info->getVersion()), PrestaShopLogger::LOG_SEVERITY_LEVEL_ERROR);
// Make sure to reset the API key
$this->getConfiguration()->set(Constants::CONFIGURATION_BTCPAY_API_KEY, null);
return $this->redirectToRoute('admin_btcpay_configure');
}
$this->flashErrors($saveErrors);
// Ensure we have a payment methods setup
if (empty($client->payment()->getPaymentMethods($storeId))) {
$this->addFlash('error', \sprintf("This plugin expects a payment method to have been setup for store '%s'.", $client->store()->getStore($storeId)->offsetGet('name')));
PrestaShopLogger::addLog(\sprintf("[ERROR] This plugin expects a payment method to have been setup for store '%s'.", $client->store()->getStore($storeId)->offsetGet('name')), PrestaShopLogger::LOG_SEVERITY_LEVEL_ERROR);
// Make sure to reset the API key
$this->getConfiguration()->set(Constants::CONFIGURATION_BTCPAY_API_KEY, null);
return $this->redirectToRoute('admin_btcpay_configure');
}
// Ensure we have a webhook
$client->webhook()->ensureWebhook($storeId);
} catch (Throwable $throwable) {
$this->addFlash('error', \sprintf('BTCPay Server plugin: %s', $throwable->getMessage()));
PrestaShopLogger::addLog(\sprintf('[ERROR] An error occurred during configuration validation: %s', $throwable), PrestaShopLogger::LOG_SEVERITY_LEVEL_ERROR, $throwable->getCode());
return $this->redirectToRoute('admin_btcpay_configure');
}
// Store the API key and store ID we received
$this->getConfiguration()->set(Constants::CONFIGURATION_BTCPAY_API_KEY, $validateRequest->getApiKey());
$this->getConfiguration()->set(Constants::CONFIGURATION_BTCPAY_STORE_ID, $storeId);
$this->addFlash('success', 'BTCPay Server plugin: Your store and server have been linked!');
return $this->redirectToRoute('admin_btcpay_configure');
}
protected function getConfiguration(): ShopConfigurationInterface
{
// Fallback in case 8.0 is used // TODO: Remove once we make 9.0 the minimum
if (\version_compare(\_PS_VERSION_, '8.1.0', '<')) {
return $this->configuration;
}
return parent::getConfiguration();
}
/**
* @throws Exception
*/
private function processApiKey(Server $configuration): RedirectResponse
{
// Get configuration container
$shopConfiguration = $this->getConfiguration();
// Build the client
$client = new Client($configuration->getHost(), $configuration->getApiKey());
try {
// Validate created API key and return any errors we encounter
$validateKey = new ValidateApiKey(new ParameterBag($client->apiKey()->getCurrent()->getData()));
if (0 !== \count($errors = $this->validator->validate($validateKey))) {
/** @var ConstraintViolationInterface $error */
foreach ($errors as $error) {
$this->addFlash('error', $error->getMessage());
}
// Make sure to reset the API key
$shopConfiguration->set(Constants::CONFIGURATION_BTCPAY_API_KEY, null);
return $this->redirectToRoute('admin_btcpay_configure');
}
// Get the store ID
$storeId = $validateKey->getStoreID();
// Grab the store
$store = $client->store()->getStore($storeId);
// Ensure we have a valid BTCPay Server version
if (null !== ($info = $client->server()->getInfo()) && \version_compare($info->getVersion(), Constants::MINIMUM_BTCPAY_VERSION, '<')) {
$this->addFlash('error', \sprintf('BTCPay server version is too low. Expected %s or higher, received %s.', Constants::MINIMUM_BTCPAY_VERSION, $info->getVersion()));
PrestaShopLogger::addLog(\sprintf('[ERROR] BTCPay server version is too low. Expected %s or higher, received %s.', Constants::MINIMUM_BTCPAY_VERSION, $info->getVersion()), PrestaShopLogger::LOG_SEVERITY_LEVEL_ERROR);
// Make sure to reset the API key
$shopConfiguration->set(Constants::CONFIGURATION_BTCPAY_API_KEY, null);
return $this->redirectToRoute('admin_btcpay_configure');
}
// Ensure we have a payment methods setup
if (empty($client->payment()->getPaymentMethods($storeId))) {
$this->addFlash('error', \sprintf("This plugin expects a payment method to have been setup for store '%s'.", $store->offsetGet('name')));
PrestaShopLogger::addLog(\sprintf("[ERROR] This plugin expects a payment method to have been setup for store '%s'.", $store->offsetGet('name')), PrestaShopLogger::LOG_SEVERITY_LEVEL_ERROR);
// Make sure to reset the API key
$shopConfiguration->set(Constants::CONFIGURATION_BTCPAY_API_KEY, null);
return $this->redirectToRoute('admin_btcpay_configure');
}
// Save the new store ID
$shopConfiguration->set(Constants::CONFIGURATION_BTCPAY_STORE_ID, $storeId);
// Ensure we have a webhook
$client->webhook()->ensureWebhook($storeId);
} catch (Throwable $throwable) {
$this->addFlash('error', \sprintf('BTCPay Server plugin: %s', $throwable->getMessage()));
PrestaShopLogger::addLog(\sprintf('[ERROR] An error occurred during setup: %s', $throwable), PrestaShopLogger::LOG_SEVERITY_LEVEL_ERROR, $throwable->getCode());
// Ensure nothing is saved
$shopConfiguration->set(Constants::CONFIGURATION_BTCPAY_API_KEY, null);
$shopConfiguration->set(Constants::CONFIGURATION_BTCPAY_STORE_ID, null);
$shopConfiguration->set(Constants::CONFIGURATION_BTCPAY_WEBHOOK_ID, null);
$shopConfiguration->set(Constants::CONFIGURATION_BTCPAY_WEBHOOK_SECRET, null);
return $this->redirectToRoute('admin_btcpay_configure');
}
// Store the API key and store ID we received
$shopConfiguration->set(Constants::CONFIGURATION_BTCPAY_API_KEY, $validateKey->getApiKey());
$shopConfiguration->set(Constants::CONFIGURATION_BTCPAY_STORE_ID, $storeId);
$this->addFlash('success', 'BTCPay Server plugin: Your store and server have been linked!');
// Return home
return $this->redirectToRoute('admin_btcpay_configure');
}
/**
* @throws Exception
*/
private function processRedirect(Request $request, Server $configuration): RedirectResponse
{
// Get the store name and build the redirect URL
$storeName = $this->getContext()->shop->name;
$redirectUrl = $request->getSchemeAndHttpHost() . $this->getAdminLink('btcpay', ['route' => 'admin_btcpay_validate'], true);
// Create the authorization URL (with redirect)
$authorizeUrl = ApiKey::getAuthorizeUrl($configuration->getHost(), Constants::BTCPAY_PERMISSIONS, $storeName, true, true, $redirectUrl, $storeName);
// If there is no API key, redirect no matter what
if (empty($apiKey = $this->getConfiguration()->get(Constants::CONFIGURATION_BTCPAY_API_KEY))) {
return $this->redirect($authorizeUrl);
}
// If we have an apiKey, check if it's valid by fetching the storeId
try {
$client = new Client($configuration->getHost(), $apiKey);
// If we don't have a store ID, abort right away
if (null === ($storeID = $this->getConfiguration()->get(Constants::CONFIGURATION_BTCPAY_STORE_ID))) {
return $this->redirect($authorizeUrl);
}
// Ensure we have a webhook
$client->webhook()->ensureWebhook($storeID);
} catch (Throwable) {
// Reset BTCPay details
$this->getConfiguration()->set(Constants::CONFIGURATION_BTCPAY_API_KEY, null);
$this->getConfiguration()->set(Constants::CONFIGURATION_BTCPAY_WEBHOOK_ID, null);
$this->getConfiguration()->set(Constants::CONFIGURATION_BTCPAY_WEBHOOK_SECRET, null);
// Redirect away to get proper details
return $this->redirect($authorizeUrl);
}
// Return home
return $this->redirectToRoute('admin_btcpay_configure');
}
private function getResponse(Request $request, FormInterface $serverForm, FormInterface $generalForm, string $authorizeUrl, ?Client $client): Response
{
return $this->render('@Modules/btcpay/views/templates/admin/configure.html.twig', [
'form' => $form->createView(),
'server_form' => $serverForm->createView(),
'general_form' => $generalForm->createView(),
'help_link' => $this->generateSidebarLink($request->attributes->get('_legacy_controller')),
'storeId' => $this->getConfiguration()->get(Constants::CONFIGURATION_BTCPAY_STORE_ID),
'webhookId' => $this->getConfiguration()->get(Constants::CONFIGURATION_BTCPAY_WEBHOOK_ID),
'latestVersion' => $this->versioning->latest(),
'moduleVersion' => $this->module->version,
'authorizeUrl' => $authorizeUrl,
'client' => $client,
'enableSidebar' => true,
]);
}

View File

@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@ -2,6 +2,10 @@
namespace BTCPay\Entity;
if (!\defined('_PS_VERSION_')) {
exit;
}
/**
* phpcs:disable Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
*/
@ -42,55 +46,21 @@ class BitcoinPayment extends \ObjectModel
*/
public $amount;
/**
* @var string|null
*/
public $bitcoin_price;
/**
* @var string|null
*/
public $bitcoin_paid;
/**
* @var string|null
*/
public $bitcoin_address;
/**
* @var string|null
*/
public $bitcoin_refund_address;
/**
* @var string|null
*/
public $redirect;
/**
* @var string|null
*/
public $rate;
/**
* {@inheritdoc}
*/
public static $definition = [
'table' => 'bitcoin_payment',
'primary' => 'id',
'fields' => [
'cart_id' => ['type' => self::TYPE_INT, 'required' => true, 'validate' => 'isUnsignedInt'],
'order_id' => ['type' => self::TYPE_INT, 'validate' => 'isUnsignedInt'],
'status' => ['type' => self::TYPE_STRING, 'required' => true, 'validate' => 'isString'],
'invoice_id' => ['type' => self::TYPE_STRING, 'validate' => 'isString'],
'invoice_reference' => ['type' => self::TYPE_STRING, 'validate' => 'isString'],
'amount' => ['type' => self::TYPE_STRING, 'validate' => 'isString'],
'bitcoin_price' => ['type' => self::TYPE_STRING, 'validate' => 'isString'],
'bitcoin_paid' => ['type' => self::TYPE_STRING, 'validate' => 'isString'],
'bitcoin_address' => ['type' => self::TYPE_STRING, 'validate' => 'isString'],
'bitcoin_refund_address' => ['type' => self::TYPE_STRING, 'validate' => 'isString'],
'redirect' => ['type' => self::TYPE_STRING, 'validate' => 'isUrl'],
'rate' => ['type' => self::TYPE_STRING, 'validate' => 'isString'],
'cart_id' => ['type' => self::TYPE_INT, 'required' => true, 'validate' => 'isUnsignedInt'],
'order_id' => ['type' => self::TYPE_INT, 'validate' => 'isUnsignedInt'],
'status' => ['type' => self::TYPE_STRING, 'required' => true, 'validate' => 'isString'],
'invoice_id' => ['type' => self::TYPE_STRING, 'validate' => 'isString'],
'invoice_reference' => ['type' => self::TYPE_STRING, 'validate' => 'isString'],
'redirect' => ['type' => self::TYPE_STRING, 'validate' => 'isUrl'],
],
];
@ -124,6 +94,11 @@ class BitcoinPayment extends \ObjectModel
$this->order_id = $order_id;
}
public function hasOrder(): bool
{
return false === empty($this->order_id);
}
public function getStatus(): string
{
return $this->status;
@ -134,6 +109,10 @@ class BitcoinPayment extends \ObjectModel
$this->status = $status;
}
/**
* @throws \PrestaShopDatabaseException
* @throws \PrestaShopException
*/
public function getStatusName(): string
{
$name = $this->getStatus();
@ -144,7 +123,7 @@ class BitcoinPayment extends \ObjectModel
}
if (\is_array($orderState->name) && !empty($orderState->name)) {
return array_pop($orderState->name);
return \array_pop($orderState->name);
}
}
@ -181,46 +160,6 @@ class BitcoinPayment extends \ObjectModel
$this->amount = $amount;
}
public function getBitcoinPrice(): ?string
{
return $this->bitcoin_price;
}
public function setBitcoinPrice(?string $bitcoin_price): void
{
$this->bitcoin_price = $bitcoin_price;
}
public function getBitcoinPaid(): ?string
{
return $this->bitcoin_paid;
}
public function setBitcoinPaid(?string $bitcoin_paid): void
{
$this->bitcoin_paid = $bitcoin_paid;
}
public function getBitcoinAddress(): ?string
{
return $this->bitcoin_address;
}
public function setBitcoinAddress(?string $bitcoin_address): void
{
$this->bitcoin_address = $bitcoin_address;
}
public function getBitcoinRefundAddress(): ?string
{
return $this->bitcoin_refund_address;
}
public function setBitcoinRefundAddress(?string $bitcoin_refund_address): void
{
$this->bitcoin_refund_address = $bitcoin_refund_address;
}
public function getRedirect(): ?string
{
return $this->redirect;
@ -231,16 +170,6 @@ class BitcoinPayment extends \ObjectModel
$this->redirect = $redirect;
}
public function getRate(): ?string
{
return $this->rate;
}
public function setRate(?string $rate): void
{
$this->rate = $rate;
}
public function toArray(): array
{
return [
@ -251,12 +180,7 @@ class BitcoinPayment extends \ObjectModel
'invoice_id' => $this->getInvoiceId(),
'invoice_reference' => $this->getInvoiceReference(),
'amount' => $this->getAmount(),
'btc_price' => $this->getBitcoinPrice(),
'btc_paid' => $this->getBitcoinPaid(),
'btc_address' => $this->getBitcoinAddress(),
'btc_refundaddress' => $this->getBitcoinRefundAddress(),
'redirect' => $this->getRedirect(),
'rate' => $this->getRate(),
];
}
}

View File

@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@ -2,6 +2,10 @@
namespace BTCPay\Exception;
if (!\defined('_PS_VERSION_')) {
exit;
}
class BTCPayException extends \RuntimeException
{
}

View File

@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@ -0,0 +1,49 @@
<?php
namespace BTCPay\Factory;
use BTCPay\Repository\CustomerThreadRepository;
if (!\defined('_PS_VERSION_')) {
exit;
}
class CustomerMessage
{
/**
* @throws \PrestaShopDatabaseException
* @throws \PrestaShopException
*/
public static function create(\CustomerThread $ct, string $message): \CustomerMessage
{
// Create a customer message
$cm = new \CustomerMessage();
$cm->id_customer_thread = $ct->id;
$cm->id_employee = 0;
$cm->message = $message;
$cm->private = true;
$cm->read = true;
// Ensure it is actually created
$cm->add();
return $cm;
}
/**
* @throws \PrestaShopDatabaseException
* @throws \PrestaShopException
*/
public static function addToOrder(\Shop $shop, \Order $order, string $message): void
{
// Find or create the customer thread
$ct = CustomerThreadRepository::fetchOrCreate($shop, $order);
// Ensure the thread is open
$ct->status = 'open';
$ct->update();
// Create the message
self::create($ct, $message);
}
}

View File

@ -0,0 +1,36 @@
<?php
namespace BTCPay\Factory;
if (!\defined('_PS_VERSION_')) {
exit;
}
class CustomerThread
{
/**
* @throws \PrestaShopException
* @throws \PrestaShopDatabaseException
*/
public static function create(\Shop $shop, \Order $order): \CustomerThread
{
// Grab the customer from the order
$customer = $order->getCustomer();
// Create a customer thread
$ct = new \CustomerThread();
$ct->id_contact = 0;
$ct->id_customer = $order->id_customer;
$ct->id_shop = (int) $shop->id;
$ct->id_order = (int) $order->id;
$ct->id_lang = \Language::getIdByIso('en');
$ct->email = $customer->email;
$ct->status = 'open';
$ct->token = \Tools::passwdGen(12);
// Ensure it is actually created
$ct->add();
return $ct;
}
}

View File

@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@ -1,143 +0,0 @@
<?php
namespace BTCPay\Form;
use BTCPay\Form\Data\Configuration;
use BTCPay\Server\Client;
use BTCPayServer\PrivateKey;
use BTCPayServer\PublicKey;
use BTCPayServer\SinKey;
use PrestaShop\PrestaShop\Core\Form\FormDataProviderInterface;
class ConfigureFormDataProvider implements FormDataProviderInterface
{
/**
* @return Configuration[]
*/
public function getData(): array
{
// Get BTCPay URL or use sane default
$serverUrl = \Configuration::get('BTCPAY_URL');
if (true === empty($serverUrl)) {
$serverUrl = 'https://testnet.demo.btcpayserver.org';
}
$configuration = new Configuration(
$serverUrl,
\Configuration::get('BTCPAY_TXSPEED'),
\Configuration::get('BTCPAY_ORDERMODE'),
\Configuration::get('BTCPAY_PAIRINGCODE')
);
return ['btcpay' => $configuration];
}
public function setData(array $data): array
{
/** @var Configuration $configuration */
$configuration = $data['btcpay'];
\Configuration::updateValue('BTCPAY_URL', rtrim($configuration->getUrl(), '/\\'));
\Configuration::updateValue('BTCPAY_TXSPEED', $configuration->getTransactionSpeed());
\Configuration::updateValue('BTCPAY_ORDERMODE', $configuration->getOrderMode());
// Only update the pairing code if it's different
if (\Configuration::get('BTCPAY_PAIRINGCODE') === $configuration->getPairingCode()) {
return [];
}
// Try and update the pairing code
if (!empty($errors = $this->processPairingCode($configuration->getUrl(), $configuration->getPairingCode()))) {
return $errors;
}
\Configuration::updateValue('BTCPAY_PAIRINGCODE', $configuration->getPairingCode());
return [];
}
private function processPairingCode(string $serverUrl, string $pairing_code): ?array
{
// Generate Private Key for api security
$privateKey = new PrivateKey();
$privateKey->generate();
// Generate Public Key
$publicKey = new PublicKey();
$publicKey->setPrivateKey($privateKey);
$publicKey->generate();
// Get SIN Key
$sinKey = new SinKey();
$sinKey->setPublicKey($publicKey);
$sinKey->generate();
// Create an API Client
$client = new Client();
$client->setUri(Client::getURI($serverUrl));
$client->setPrivateKey($privateKey);
$client->setPublicKey($publicKey);
$label = \Configuration::get('PS_SHOP_NAME');
try {
// Ignore notices and warnings for now
$old_error_reporting = error_reporting();
error_reporting(\E_ALL & ~\E_NOTICE & ~\E_STRICT & ~\E_DEPRECATED & ~\E_WARNING);
$token = $client->createToken(
[
'id' => (string) $sinKey,
'pairingCode' => $pairing_code,
'label' => $label,
]
);
error_reporting($old_error_reporting);
} catch (\Exception $e) {
\PrestaShopLogger::addLog('[ERROR] Issue creating token:' . $e->getMessage(), 3);
return [
[
'key' => sprintf('Failed to create token: %s', $e->getMessage()),
'domain' => 'Admin.Catalog.Notification',
'parameters' => [],
],
];
}
if (false === isset($token)) {
return [
[
'key' => 'Failed to create token, you are maybe using an already activated pairing code.',
'domain' => 'Admin.Catalog.Notification',
'parameters' => [],
],
];
}
// Encrypt or return errors
if (\is_array($pubEncrypted = $client->getEncryption()->encrypt($publicKey))) {
return $pubEncrypted;
}
// Encrypt or return errors
if (\is_array($tokenEncrypted = $client->getEncryption()->encrypt($token))) {
return $tokenEncrypted;
}
// Encrypt or return errors
if (\is_array($keyEncrypted = $client->getEncryption()->encrypt($privateKey))) {
return $keyEncrypted;
}
// Update our configuration with the new data
\Configuration::updateValue('BTCPAY_LABEL', $label);
\Configuration::updateValue('BTCPAY_PUB', (string) $pubEncrypted);
\Configuration::updateValue('BTCPAY_SIN', (string) $sinKey);
\Configuration::updateValue('BTCPAY_TOKEN', (string) $tokenEncrypted);
\Configuration::updateValue('BTCPAY_KEY', (string) $keyEncrypted);
return null;
}
}

View File

@ -1,91 +0,0 @@
<?php
namespace BTCPay\Form\Data;
use Symfony\Component\Validator\Constraints as Assert;
class Configuration
{
/**
* @Assert\Url()
* @Assert\NotNull()
* @Assert\NotBlank()
*
* @var string
*/
private $url;
/**
* @Assert\NotNull()
* @Assert\NotBlank()
* @Assert\Choice(choices=\BTCPay\Constants::TRANSACTION_SPEEDS, message="Invalid transaction speed")
*
* @var string
*/
private $transactionSpeed;
/**
* @Assert\NotNull()
* @Assert\NotBlank()
* @Assert\Choice(choices=\BTCPay\Constants::ORDER_MODES, message="Invalid order mode")
*
* @var string
*/
private $orderMode;
/**
* @Assert\NotBlank()
* @Assert\Regex(pattern="/^[a-zA-Z0-9]{7}$/", message="Invalid pairing code")
*
* @var string|null
*/
private $pairingCode;
public function __construct(string $url, string $transactionSpeed, string $orderMode, ?string $pairingCode)
{
$this->url = $url;
$this->transactionSpeed = $transactionSpeed;
$this->orderMode = $orderMode;
$this->pairingCode = $pairingCode;
}
public function getUrl(): string
{
return $this->url;
}
public function setUrl(string $url): void
{
$this->url = $url;
}
public function getTransactionSpeed(): string
{
return $this->transactionSpeed;
}
public function setTransactionSpeed(string $transaction_speed): void
{
$this->transactionSpeed = $transaction_speed;
}
public function getOrderMode(): string
{
return $this->orderMode;
}
public function setOrderMode(string $order_mode): void
{
$this->orderMode = $order_mode;
}
public function getPairingCode(): ?string
{
return $this->pairingCode;
}
public function setPairingCode(?string $pairing_code): void
{
$this->pairingCode = $pairing_code;
}
}

View File

@ -0,0 +1,124 @@
<?php
namespace BTCPay\Form\Data;
use BTCPay\Constants;
use BTCPayServer\Client\InvoiceCheckoutOptions;
use PrestaShop\PrestaShop\Core\Domain\Configuration\ShopConfigurationInterface;
use Symfony\Component\Validator\Constraints as Assert;
if (!\defined('_PS_VERSION_')) {
exit;
}
class General
{
/**
* @Assert\NotBlank()
* @Assert\Choice(choices=\BTCPay\Constants::TRANSACTION_SPEEDS, message="Invalid transaction speed")
*
* @var string
*/
private $speed;
/**
* @Assert\NotBlank()
* @Assert\Choice(choices=\BTCPay\Constants::ORDER_MODES, message="Invalid order mode")
*
* @var string
*/
private $orderMode;
/**
* @Assert\Choice(choices={true, false})
*/
private $protectOrders;
/**
* @Assert\Choice(choices={true, false})
*/
private $shareMetadata;
public function __construct(string $speed, string $orderMode, bool $protectOrders, bool $shareMetadata)
{
$this->speed = $speed;
$this->orderMode = $orderMode;
$this->protectOrders = $protectOrders;
$this->shareMetadata = $shareMetadata;
}
public static function create(ShopConfigurationInterface $configuration): self
{
return new self(
$configuration->get(Constants::CONFIGURATION_SPEED_MODE, InvoiceCheckoutOptions::SPEED_MEDIUM),
$configuration->get(Constants::CONFIGURATION_ORDER_MODE, Constants::ORDER_MODE_BEFORE),
(bool) $configuration->get(Constants::CONFIGURATION_PROTECT_ORDERS, true),
(bool) $configuration->get(Constants::CONFIGURATION_SHARE_METADATA, false),
);
}
public static function fromArray(array $data): self
{
return new self(
$data['speed'],
$data['orderMode'],
$data['protectOrders'],
$data['shareMetadata'],
);
}
public function getSpeed(): string
{
return $this->speed;
}
public function setSpeed(string $speed): void
{
$this->speed = $speed;
}
public function getOrderMode(): string
{
return $this->orderMode;
}
public function setOrderMode(string $order_mode): void
{
$this->orderMode = $order_mode;
}
public function getProtectOrders(): bool
{
return $this->protectOrders;
}
public function setProtectOrders(bool $protectOrders): void
{
$this->protectOrders = $protectOrders;
}
public function shareMetadata(): bool
{
return $this->shareMetadata;
}
public function setShareMetadata(bool $shareMetadata): void
{
$this->shareMetadata = $shareMetadata;
}
public function equals(self $general): bool
{
return $this->toArray() === $general->toArray();
}
public function toArray(): array
{
return [
'speed' => $this->speed,
'orderMode' => $this->orderMode,
'protectOrders' => $this->protectOrders,
'shareMetadata' => $this->shareMetadata,
];
}
}

View File

@ -0,0 +1,84 @@
<?php
namespace BTCPay\Form\Data;
use BTCPay\Constants;
use PrestaShop\PrestaShop\Core\Domain\Configuration\ShopConfigurationInterface;
use Symfony\Component\Validator\Constraints as Assert;
if (!\defined('_PS_VERSION_')) {
exit;
}
class Server
{
/**
* @Assert\Url()
* @Assert\NotBlank()
*
* @var string|null
*/
private $host;
/**
* @Assert\Type(type="alnum")
*
* @var string|null
*/
private $apiKey;
public function __construct(string $host, string $apiKey = null)
{
$this->host = $host;
$this->apiKey = $apiKey;
}
public static function create(ShopConfigurationInterface $configuration): self
{
return new self(
$configuration->get(Constants::CONFIGURATION_BTCPAY_HOST, Constants::CONFIGURATION_DEFAULT_HOST),
$configuration->get(Constants::CONFIGURATION_BTCPAY_API_KEY, null),
);
}
public static function fromArray(array $data): self
{
return new self(
$data['host'],
$data['apiKey'],
);
}
public function getHost(): ?string
{
return $this->host;
}
public function setHost(?string $host): void
{
$this->host = $host;
}
public function getApiKey(): ?string
{
return $this->apiKey;
}
public function setApiKey(?string $apiKey): void
{
$this->apiKey = $apiKey;
}
public function equals(self $configuration): bool
{
return $this->toArray() === $configuration->toArray();
}
public function toArray(): array
{
return [
'host' => $this->host,
'apiKey' => $this->apiKey,
];
}
}

View File

@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@ -0,0 +1,54 @@
<?php
namespace BTCPay\Form;
use BTCPay\Constants;
use BTCPay\Form\Data\General;
use PrestaShop\PrestaShop\Adapter\Configuration as PrestaShopConfiguration;
use PrestaShop\PrestaShop\Core\Form\FormDataProviderInterface;
if (!\defined('_PS_VERSION_')) {
exit;
}
class GeneralFormDataProvider implements FormDataProviderInterface
{
/**
* @var PrestaShopConfiguration
*/
private $configuration;
public function __construct()
{
$this->configuration = new PrestaShopConfiguration();
}
public function getData(): General
{
return General::create($this->configuration);
}
/**
* @throws \Exception
*/
public function setData(array $data): array
{
// Re-create configuration element with form data
$configuration = General::fromArray($data);
if ($this->configuration->get(Constants::CONFIGURATION_SPEED_MODE) !== ($speedMode = $configuration->getSpeed()) && !empty($speedMode)) {
$this->configuration->set(Constants::CONFIGURATION_SPEED_MODE, $speedMode);
}
if ($this->configuration->get(Constants::CONFIGURATION_ORDER_MODE) !== ($orderMode = $configuration->getOrderMode()) && !empty($orderMode)) {
$this->configuration->set(Constants::CONFIGURATION_ORDER_MODE, $orderMode);
}
if ($this->configuration->get(Constants::CONFIGURATION_SHARE_METADATA) !== ($shareMetadata = $configuration->shareMetadata())) {
$this->configuration->set(Constants::CONFIGURATION_SHARE_METADATA, $shareMetadata);
}
// All is fine
return [];
}
}

View File

@ -0,0 +1,50 @@
<?php
namespace BTCPay\Form;
use BTCPay\Constants;
use BTCPay\Form\Data\Server;
use PrestaShop\PrestaShop\Adapter\Configuration as PrestaShopConfiguration;
use PrestaShop\PrestaShop\Core\Form\FormDataProviderInterface;
if (!\defined('_PS_VERSION_')) {
exit;
}
class ServerFormDataProvider implements FormDataProviderInterface
{
/**
* @var PrestaShopConfiguration
*/
private $configuration;
public function __construct()
{
$this->configuration = new PrestaShopConfiguration();
}
public function getData(): Server
{
return Server::create($this->configuration);
}
/**
* @throws \Exception
*/
public function setData(array $data): array
{
// Re-create configuration element with form data
$configuration = Server::fromArray($data);
if ($this->configuration->get(Constants::CONFIGURATION_BTCPAY_HOST) !== \rtrim(\trim(($host = $configuration->getHost())), '/\\') && !empty($host)) {
$this->configuration->set(Constants::CONFIGURATION_BTCPAY_HOST, \rtrim(\trim($host), '/\\'));
}
if ($this->configuration->get(Constants::CONFIGURATION_BTCPAY_API_KEY) !== \rtrim(\trim(($apiKey = $configuration->getApiKey())), '/\\') && !empty($apiKey)) {
$this->configuration->set(Constants::CONFIGURATION_BTCPAY_API_KEY, \rtrim(\trim($apiKey), '/\\'));
}
// All is fine
return [];
}
}

View File

@ -1,62 +0,0 @@
<?php
namespace BTCPay\Form\Type;
use BTCPay\Constants;
use BTCPay\Form\Data\Configuration;
use BTCPayServer\Invoice;
use PrestaShopBundle\Form\Admin\Type\TranslatorAwareType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\UrlType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class ConfigureType extends TranslatorAwareType
{
/**
* {@inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('url', UrlType::class, [
'label' => $this->trans('BTCPay server url', 'Modules.Btcpay.Admin'),
])
->add('transaction_speed', ChoiceType::class, [
'choices' => [
$this->trans('Low', 'Modules.Btcpay.Admin') => Invoice::TRANSACTION_SPEED_LOW,
$this->trans('Medium', 'Modules.Btcpay.Admin') => Invoice::TRANSACTION_SPEED_MEDIUM,
$this->trans('High', 'Modules.Btcpay.Admin') => Invoice::TRANSACTION_SPEED_HIGH,
],
'label' => $this->trans('Transaction speed', 'Modules.Btcpay.Admin'),
])
->add('order_mode', ChoiceType::class, [
'choices' => [
$this->trans('Order before payment', 'Modules.Btcpay.Admin') => Constants::ORDER_MODE_BEFORE,
$this->trans('Order after payment', 'Modules.Btcpay.Admin') => Constants::ORDER_MODE_AFTER,
],
'label' => $this->trans('Order mode', 'Modules.Btcpay.Admin'),
])
->add('pairing_code', TextType::class, [
'label' => $this->trans('Pairing code', 'Modules.Btcpay.Admin'),
'required' => false,
]);
}
/**
* {@inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults(['data_class' => Configuration::class]);
}
/**
* {@inheritdoc}
*/
public function getBlockPrefix(): string
{
return 'module_btcpay';
}
}

View File

@ -0,0 +1,68 @@
<?php
namespace BTCPay\Form\Type;
use BTCPay\Constants;
use BTCPay\Form\Data\General;
use BTCPayServer\Client\InvoiceCheckoutOptions;
use PrestaShopBundle\Form\Admin\Type\TranslatorAwareType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
if (!\defined('_PS_VERSION_')) {
exit;
}
class GeneralType extends TranslatorAwareType
{
/**
* {@inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('speed', ChoiceType::class, [
'choices' => [
$this->trans('Low', 'Modules.Btcpay.Admin') => InvoiceCheckoutOptions::SPEED_LOW,
$this->trans('Medium', 'Modules.Btcpay.Admin') => InvoiceCheckoutOptions::SPEED_MEDIUM,
$this->trans('High', 'Modules.Btcpay.Admin') => InvoiceCheckoutOptions::SPEED_HIGH,
],
'label' => $this->trans('Transaction speed', 'Modules.Btcpay.Admin'),
'help' => $this->trans('Determines the transaction fee that we recommend to the customer.', 'Modules.Btcpay.Admin'),
'empty_data' => InvoiceCheckoutOptions::SPEED_MEDIUM,
])
->add('orderMode', ChoiceType::class, [
'choices' => [
$this->trans('Order before payment', 'Modules.Btcpay.Admin') => Constants::ORDER_MODE_BEFORE,
$this->trans('Order after payment', 'Modules.Btcpay.Admin') => Constants::ORDER_MODE_AFTER,
],
'label' => $this->trans('Order creation method', 'Modules.Btcpay.Admin'),
'help' => $this->trans('Will we create the order as soon as the user gets redirect to BTCPay Server or do we wait for the webhook.', 'Modules.Btcpay.Admin'),
'empty_data' => Constants::ORDER_MODE_BEFORE,
])
->add('protectOrders', ChoiceType::class, [
'choices' => [
$this->trans('Yes', 'Modules.Btcpay.Admin') => true,
$this->trans('No', 'Modules.Btcpay.Admin') => false,
],
'label' => $this->trans('Protect order status', 'Modules.Btcpay.Admin'),
'help' => $this->trans('Will protect the order status from changing to "failed" if it already has a "paid" order state. This will protect an order from being cancelled via webhook, if it was paid via a different payment gateway.', 'Modules.Btcpay.Admin'),
'empty_data' => true,
])
->add('shareMetadata', ChoiceType::class, [
'choices' => [
$this->trans('Yes', 'Modules.Btcpay.Admin') => true,
$this->trans('No', 'Modules.Btcpay.Admin') => false,
],
'label' => $this->trans('Send customer data to BTCPay Server', 'Modules.Btcpay.Admin'),
'help' => $this->trans('If you want customer email, address, etc. sent to BTCPay Server enable this option. By default for privacy and GDPR reasons this is disabled.', 'Modules.Btcpay.Admin'),
'empty_data' => false,
]);
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults(['data_class' => General::class]);
}
}

View File

@ -0,0 +1,56 @@
<?php
namespace BTCPay\Form\Type;
use BTCPay\Form\Data\Server;
use PrestaShop\PrestaShop\Adapter\Configuration;
use PrestaShopBundle\Form\Admin\Type\TranslatorAwareType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\UrlType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Contracts\Translation\TranslatorInterface;
if (!\defined('_PS_VERSION_')) {
exit;
}
class ServerType extends TranslatorAwareType
{
public function __construct(TranslatorInterface $translator, array $locales)
{
parent::__construct($translator, $locales);
}
/**
* {@inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options): void
{
/** @var Server $data */
$data = $builder->getData() ?? Server::create(new Configuration());
$builder
->add('host', UrlType::class, [
'label' => $this->trans('BTCPay Server URL', 'Modules.Btcpay.Admin'),
'help' => $this->trans('The URL/host to your BTCPay Server instance. Make sure your node is reachable from the internet.', 'Modules.Btcpay.Admin'),
'required' => true,
])
->add('apiKey', TextType::class, [
'label' => $this->trans('BTCPay Server API key', 'Modules.Btcpay.Admin'),
'attr' => [
'pattern' => '[a-zA-Z0-9]+',
'placeholder' => empty($data->getApiKey())
? $this->trans('Keep blank to be redirected for authentication', 'Modules.Btcpay.Admin')
: $this->trans('Removing the API key will disconnect your store', 'Modules.Btcpay.Admin'),
],
'required' => false,
'empty_data' => null,
]);
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults(['data_class' => Server::class]);
}
}

View File

@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@ -0,0 +1,84 @@
<?php
namespace BTCPay\Github;
use Composer\Semver\Comparator;
if (!\defined('_PS_VERSION_')) {
exit;
}
class Latest
{
/**
* @var int
*/
private $id;
/**
* @var string
*/
private $name;
/**
* @var string
*/
private $tagName;
/**
* @var string
*/
private $commit;
/**
* @var string
*/
private $url;
public function __construct(int $id, string $name, string $tagName, string $commit, string $url)
{
$this->id = $id;
$this->name = $name;
$this->tagName = $tagName;
$this->commit = $commit;
$this->url = $url;
}
public static function create(array $data): self
{
return new self($data['id'], $data['name'], $data['tag_name'], $data['target_commitish'], $data['html_url']);
}
public function getId(): int
{
return $this->id;
}
public function getName(): string
{
return $this->name;
}
public function getTagName(): string
{
return $this->tagName;
}
public function getCommit(): string
{
return $this->commit;
}
public function getUrl(): string
{
return $this->url;
}
public function newer(string $currentVersion): bool
{
return Comparator::greaterThan(
\str_replace('v', '', $this->getTagName()),
\str_replace('v', '', $currentVersion)
);
}
}

View File

@ -0,0 +1,80 @@
<?php
namespace BTCPay\Github;
use BTCPay\Constants;
use BTCPay\Server\CurlAdapter;
use Symfony\Component\Cache\Adapter\FilesystemAdapter;
use Symfony\Component\HttpFoundation\Request;
if (!\defined('_PS_VERSION_')) {
exit;
}
class Versioning
{
private const HEADERS = [
'Accept' => 'application/json',
'Content-Type' => 'application/json',
'User-Agent' => 'btcpayserver/prestashop-plugin',
];
/**
* @var FilesystemAdapter
*/
private $cache;
/**
* @var CurlAdapter
*/
private $client;
public function __construct()
{
$this->cache = new FilesystemAdapter();
$this->client = new CurlAdapter();
}
public function latest(): ?Latest
{
try {
// Check if we have a recent check cached
$cachedUpdate = $this->cache->getItem(Constants::LASTEST_VERSION_CACHE_KEY);
if ($cachedUpdate->isHit() && !empty($cachedData = $cachedUpdate->get())) {
return Latest::create($cachedData);
}
// Fetch the latest version
$response = $this->client->request(Request::METHOD_GET, Constants::GITHUB_API_LATEST_ENDPOINT, self::HEADERS);
// If the request failed, stop bothering
if (200 !== $response->getStatus()) {
\PrestaShopLogger::addLog(\sprintf('[WARNING] Could not check for latest version, received status: %s', $response->getBody()), \PrestaShopLogger::LOG_SEVERITY_LEVEL_WARNING, $response->getStatus());
return null;
}
// Decode JSON response
$data = \json_decode($response->getBody(), true, 512, \JSON_THROW_ON_ERROR);
// If the data is empty (or the request failed), return null
if (empty($data) || false === \array_key_exists('tag_name', $data) || (\array_key_exists('message', $data) && 'Not Found' === $data['message'])) {
return null;
}
// Set updated data
$cachedUpdate->expiresAfter(Constants::LASTEST_VERSION_CACHE_EXPIRATION);
$cachedUpdate->set($data);
// Save updated data
$this->cache->save($cachedUpdate);
// Finally, return the data
return Latest::create($cachedUpdate->get());
} catch (\Throwable $exception) {
\PrestaShopLogger::addLog(\sprintf('[INFO] Could not check for latest version, caught exception: %s', $exception->getMessage()), \PrestaShopLogger::LOG_SEVERITY_LEVEL_INFORMATIVE, $exception->getCode());
return null;
}
}
}

View File

@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@ -2,22 +2,40 @@
namespace BTCPay\Installer;
use Configuration;
use BTCPay\Constants;
use BTCPayServer\Client\InvoiceCheckoutOptions;
use PrestaShop\PrestaShop\Adapter\Configuration;
if (!\defined('_PS_VERSION_')) {
exit;
}
class Config
{
/**
* @var Configuration
*/
private $configuration;
public function __construct()
{
$this->configuration = new Configuration();
}
/**
* @throws \Exception
*/
public function install(): array
{
// Init clear configurations
if (!Configuration::updateValue('BTCPAY_URL', null)
|| !Configuration::updateValue('BTCPAY_LABEL', null)
|| !Configuration::updateValue('BTCPAY_PAIRINGCODE', null)
|| !Configuration::updateValue('BTCPAY_KEY', null)
|| !Configuration::updateValue('BTCPAY_PUB', null)
|| !Configuration::updateValue('BTCPAY_SIN', null)
|| !Configuration::updateValue('BTCPAY_TOKEN', null)
|| !Configuration::updateValue('BTCPAY_TXSPEED', null)
|| !Configuration::updateValue('BTCPAY_ORDERMODE', null)) {
// Ensure sane defaults
if (!$this->configuration->set(Constants::CONFIGURATION_BTCPAY_HOST, Constants::CONFIGURATION_DEFAULT_HOST)
|| !$this->configuration->set(Constants::CONFIGURATION_SPEED_MODE, InvoiceCheckoutOptions::SPEED_MEDIUM)
|| !$this->configuration->set(Constants::CONFIGURATION_ORDER_MODE, Constants::ORDER_MODE_BEFORE)
|| !$this->configuration->set(Constants::CONFIGURATION_BTCPAY_API_KEY, null)
|| !$this->configuration->set(Constants::CONFIGURATION_BTCPAY_STORE_ID, null)
|| !$this->configuration->set(Constants::CONFIGURATION_BTCPAY_WEBHOOK_ID, null)
|| !$this->configuration->set(Constants::CONFIGURATION_BTCPAY_WEBHOOK_SECRET, null)
|| !$this->configuration->set(Constants::CONFIGURATION_SHARE_METADATA, false)) {
return [
[
'key' => 'Could not init configuration',
@ -30,18 +48,20 @@ class Config
return [];
}
/**
* @throws \Exception
*/
public function uninstall(): array
{
// Remove configuration
if (!Configuration::deleteByName('BTCPAY_URL')
|| !Configuration::deleteByName('BTCPAY_LABEL')
|| !Configuration::deleteByName('BTCPAY_PAIRINGCODE')
|| !Configuration::deleteByName('BTCPAY_KEY')
|| !Configuration::deleteByName('BTCPAY_PUB')
|| !Configuration::deleteByName('BTCPAY_SIN')
|| !Configuration::deleteByName('BTCPAY_TOKEN')
|| !Configuration::deleteByName('BTCPAY_TXSPEED')
|| !Configuration::deleteByName('BTCPAY_ORDERMODE')) {
if (!$this->configuration->remove(Constants::CONFIGURATION_BTCPAY_HOST)
|| !$this->configuration->remove(Constants::CONFIGURATION_SPEED_MODE)
|| !$this->configuration->remove(Constants::CONFIGURATION_ORDER_MODE)
|| !$this->configuration->remove(Constants::CONFIGURATION_BTCPAY_API_KEY)
|| !$this->configuration->remove(Constants::CONFIGURATION_BTCPAY_STORE_ID)
|| !$this->configuration->remove(Constants::CONFIGURATION_BTCPAY_WEBHOOK_ID)
|| !$this->configuration->remove(Constants::CONFIGURATION_BTCPAY_WEBHOOK_SECRET)
|| !$this->configuration->remove(Constants::CONFIGURATION_SHARE_METADATA)) {
return [
[
'key' => 'Could not clear configuration',

View File

@ -4,6 +4,10 @@ namespace BTCPay\Installer;
use BTCPay;
if (!\defined('_PS_VERSION_')) {
exit;
}
class Hooks
{
/**
@ -20,8 +24,6 @@ class Hooks
{
if (!$this->module->registerHook('displayAdminOrderMainBottom')
|| !$this->module->registerHook('displayOrderDetail')
|| !$this->module->registerHook('displayPaymentEU')
|| !$this->module->registerHook('payment')
|| !$this->module->registerHook('paymentReturn')
|| !$this->module->registerHook('paymentOptions')
|| !$this->module->registerHook('actionCartSave')) {

View File

@ -2,10 +2,14 @@
namespace BTCPay\Installer;
use Configuration;
use BTCPay\Constants;
use Language;
use OrderState;
use PrestaShopCollection;
use PrestaShop\PrestaShop\Adapter\Configuration;
if (!\defined('_PS_VERSION_')) {
exit;
}
class OrderStates
{
@ -14,20 +18,32 @@ class OrderStates
*/
private $moduleName;
/**
* @var Configuration
*/
private $configuration;
public function __construct(string $moduleName)
{
$this->moduleName = $moduleName;
$this->moduleName = $moduleName;
$this->configuration = new Configuration();
}
/**
* @throws \PrestaShopDatabaseException
* @throws \PrestaShopException
* @throws \Exception
*/
public function install(): array
{
$errors = [];
// Check and insert "awaiting payment" if needed.
if (!Configuration::get('BTCPAY_OS_WAITING') || !\Validate::isLoadedObject(new OrderState(Configuration::get('BTCPAY_OS_WAITING')))) {
if (false === ($this->installAwaiting())) {
if (!$this->configuration->get(Constants::CONFIGURATION_ORDER_STATE_WAITING)
|| !\Validate::isLoadedObject(new OrderState($this->configuration->get(Constants::CONFIGURATION_ORDER_STATE_WAITING)))) {
if (false === $this->installAwaiting()) {
$errors[] = [
'key' => 'Could not add new order state: BTCPAY_OS_WAITING',
'key' => \sprintf('Could not add new order state: %s', Constants::CONFIGURATION_ORDER_STATE_WAITING),
'parameters' => [],
'domain' => 'Admin.Modules.Notification',
];
@ -35,10 +51,11 @@ class OrderStates
}
// Check and insert "confirming payment" if needed.
if (!Configuration::get('BTCPAY_OS_CONFIRMING') || !\Validate::isLoadedObject(new OrderState(Configuration::get('BTCPAY_OS_CONFIRMING')))) {
if (false === ($this->installConfirming())) {
if (!$this->configuration->get(Constants::CONFIGURATION_ORDER_STATE_CONFIRMING)
|| !\Validate::isLoadedObject(new OrderState($this->configuration->get(Constants::CONFIGURATION_ORDER_STATE_CONFIRMING)))) {
if (false === $this->installConfirming()) {
$errors[] = [
'key' => 'Could not add new order state: BTCPAY_OS_CONFIRMING',
'key' => \sprintf('Could not add new order state: %s', Constants::CONFIGURATION_ORDER_STATE_CONFIRMING),
'parameters' => [],
'domain' => 'Admin.Modules.Notification',
];
@ -46,10 +63,11 @@ class OrderStates
}
// Check and insert "failed payment" if needed.
if (!Configuration::get('BTCPAY_OS_FAILED') || !\Validate::isLoadedObject(new OrderState(Configuration::get('BTCPAY_OS_FAILED')))) {
if (false === ($this->installFailed())) {
if (!$this->configuration->get(Constants::CONFIGURATION_ORDER_STATE_FAILED)
|| !\Validate::isLoadedObject(new OrderState($this->configuration->get(Constants::CONFIGURATION_ORDER_STATE_FAILED)))) {
if (false === $this->installFailed()) {
$errors[] = [
'key' => 'Could not add new order state: BTCPAY_OS_FAILED',
'key' => \sprintf('Could not add new order state: %s', Constants::CONFIGURATION_ORDER_STATE_FAILED),
'parameters' => [],
'domain' => 'Admin.Modules.Notification',
];
@ -57,35 +75,11 @@ class OrderStates
}
// Check and insert "payment succeeded" if needed.
if (!Configuration::get('BTCPAY_OS_PAID') || !\Validate::isLoadedObject(new OrderState(Configuration::get('BTCPAY_OS_PAID')))) {
if (false === ($this->installPaid())) {
if (!$this->configuration->get(Constants::CONFIGURATION_ORDER_STATE_PAID)
|| !\Validate::isLoadedObject(new OrderState($this->configuration->get(Constants::CONFIGURATION_ORDER_STATE_PAID)))) {
if (false === $this->installPaid()) {
$errors[] = [
'key' => 'Could not add new order state: BTCPAY_OS_PAID',
'parameters' => [],
'domain' => 'Admin.Modules.Notification',
];
}
}
return $errors;
}
public function uninstall(): array
{
$collection = new PrestaShopCollection('OrderState');
$collection->where('module_name', '=', $this->moduleName);
if (empty($orderStates = $collection->getResults())) {
return [];
}
$errors = [];
/** @var OrderState $orderState */
foreach ($orderStates as $orderState) {
if (false === $orderState->delete()) {
$errors[] = [
'key' => 'Could not delete order state ' . $orderState->name,
'key' => \sprintf('Could not add new order state: %s', Constants::CONFIGURATION_ORDER_STATE_PAID),
'parameters' => [],
'domain' => 'Admin.Modules.Notification',
];
@ -95,6 +89,11 @@ class OrderStates
return $errors;
}
/**
* @throws \PrestaShopException
* @throws \PrestaShopDatabaseException
* @throws \Exception
*/
private function installAwaiting(): bool
{
$order_state = new OrderState();
@ -104,7 +103,7 @@ class OrderStates
$order_state->module_name = $this->moduleName;
foreach (Language::getLanguages(true, false, true) as $languageId) {
$order_state->name[$languageId] = 'Awaiting Bitcoin payment';
$order_state->name[$languageId] = 'Awaiting crypto payment';
}
if (false === $order_state->add()) {
@ -112,11 +111,16 @@ class OrderStates
}
$this->installImage($order_state, 'os_bitcoin_waiting.png');
Configuration::updateValue('BTCPAY_OS_WAITING', (int) $order_state->id);
$this->configuration->set(Constants::CONFIGURATION_ORDER_STATE_WAITING, (int) $order_state->id);
return true;
}
/**
* @throws \PrestaShopException
* @throws \PrestaShopDatabaseException
* @throws \Exception
*/
private function installConfirming(): bool
{
$order_state = new OrderState();
@ -126,7 +130,7 @@ class OrderStates
$order_state->module_name = $this->moduleName;
foreach (Language::getLanguages(true, false, true) as $languageId) {
$order_state->name[$languageId] = 'Waiting for Bitcoin confirmations';
$order_state->name[$languageId] = 'Waiting for confirmations';
}
if (false === $order_state->add()) {
@ -134,11 +138,16 @@ class OrderStates
}
$this->installImage($order_state, 'os_bitcoin_confirming.png');
Configuration::updateValue('BTCPAY_OS_CONFIRMING', (int) $order_state->id);
$this->configuration->set(Constants::CONFIGURATION_ORDER_STATE_CONFIRMING, (int) $order_state->id);
return true;
}
/**
* @throws \PrestaShopDatabaseException
* @throws \PrestaShopException
* @throws \Exception
*/
private function installFailed(): bool
{
$order_state = new OrderState();
@ -151,7 +160,7 @@ class OrderStates
$order_state->module_name = $this->moduleName;
foreach (Language::getLanguages(true, false, true) as $languageId) {
$order_state->name[$languageId] = 'Bitcoin transaction failed';
$order_state->name[$languageId] = 'Crypto transaction failed';
}
if (false === $order_state->add()) {
@ -159,11 +168,16 @@ class OrderStates
}
$this->installImage($order_state, 'os_bitcoin_failed.png');
Configuration::updateValue('BTCPAY_OS_FAILED', (int) $order_state->id);
$this->configuration->set(Constants::CONFIGURATION_ORDER_STATE_FAILED, (int) $order_state->id);
return true;
}
/**
* @throws \PrestaShopException
* @throws \PrestaShopDatabaseException
* @throws \Exception
*/
private function installPaid(): bool
{
$order_state = new OrderState();
@ -175,10 +189,11 @@ class OrderStates
$order_state->color = '#108510';
$order_state->logable = true;
$order_state->unremovable = true;
$order_state->invoice = true;
$order_state->module_name = $this->moduleName;
foreach (Language::getLanguages(true, false, true) as $languageId) {
$order_state->name[$languageId] = 'Paid with Bitcoin';
$order_state->name[$languageId] = 'Paid with crypto';
}
if (false === $order_state->add()) {
@ -186,15 +201,15 @@ class OrderStates
}
$this->installImage($order_state, 'os_bitcoin_paid.png');
Configuration::updateValue('BTCPAY_OS_PAID', (int) $order_state->id);
$this->configuration->set(Constants::CONFIGURATION_ORDER_STATE_PAID, (int) $order_state->id);
return true;
}
private function installImage(OrderState $order_state, string $image_name): void
{
$source = _PS_MODULE_DIR_ . $this->moduleName . '/views/images/' . $image_name;
$destination = _PS_ROOT_DIR_ . '/img/os/' . (int) $order_state->id . '.gif';
copy($source, $destination);
$source = \_PS_MODULE_DIR_ . $this->moduleName . '/views/images/' . $image_name;
$destination = \_PS_ROOT_DIR_ . '/img/os/' . (int) $order_state->id . '.gif';
\copy($source, $destination);
}
}

View File

@ -2,27 +2,39 @@
namespace BTCPay\Installer;
use BTCPay\Repository\BitcoinPaymentRepository;
use BTCPay\Repository\TableRepository;
if (!\defined('_PS_VERSION_')) {
exit;
}
class Tables
{
/**
* @var BitcoinPaymentRepository
* @var TableRepository
*/
private $repository;
private $tableRepository;
public function __construct(BitcoinPaymentRepository $repository)
public function __construct(TableRepository $repository)
{
$this->repository = $repository;
$this->tableRepository = $repository;
}
/**
* @throws \JsonException
* @throws \Doctrine\DBAL\Exception
*/
public function install(): array
{
return $this->repository->createTables();
return $this->tableRepository->createTables();
}
/**
* @throws \JsonException
* @throws \Doctrine\DBAL\Exception
*/
public function uninstall(): array
{
return $this->repository->dropTables();
return $this->tableRepository->dropTables();
}
}

View File

@ -0,0 +1,50 @@
<?php
namespace BTCPay\Installer;
use BTCPay\Server\Client;
use PrestaShop\PrestaShop\Adapter\Configuration;
if (!\defined('_PS_VERSION_')) {
exit;
}
class Webhook
{
/**
* @var Configuration
*/
private $configuration;
public function __construct()
{
$this->configuration = new Configuration();
}
/**
* @throws \Exception
*/
public function uninstall(): array
{
// Build the client from our stored configuration
$client = Client::createFromConfiguration($this->configuration);
// If there is no client, return now
if (null === $client) {
return [];
}
// Remove the current webhook to prevent issues in the future.
if (false === ($client->webhook()->removeCurrent())) {
return [
[
'key' => 'Could not remove webhook from the server. Please double check it is actually gone.',
'parameters' => [],
'domain' => 'Admin.Modules.Notification',
],
];
}
return [];
}
}

View File

@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@ -0,0 +1,352 @@
<?php
namespace BTCPay\Invoice;
use BTCPay\Constants;
use BTCPay\Entity\BitcoinPayment;
use BTCPay\Repository\OrderPaymentRepository;
use BTCPay\Server\Client;
use BTCPayServer\Result\Invoice;
use PrestaShop\PrestaShop\Adapter\Configuration;
if (!\defined('_PS_VERSION_')) {
exit;
}
class Processor
{
/**
* @var \BTCPay
*/
private $module;
/**
* @var \Context
*/
private $context;
/**
* @var Client
*/
private $client;
/**
* @var Configuration
*/
private $configuration;
public function __construct(\BTCPay $module, \Context $context, Configuration $configuration, Client $client)
{
$this->module = $module;
$this->context = $context;
$this->configuration = $configuration;
$this->client = $client;
}
/**
* @throws \JsonException
* @throws \PrestaShopDatabaseException
* @throws \PrestaShopException
*/
public function invoiceSettled(BitcoinPayment $bitcoinPayment): void
{
// Get the order
$order = new \Order($bitcoinPayment->getOrderId());
// Set the default status to be the current status
$orderStatus = $order->current_state;
// Get the store ID
$storeID = $this->configuration->get(Constants::CONFIGURATION_BTCPAY_STORE_ID);
// Grab the invoice from the server
$invoice = $this->client->invoice()->getInvoice($storeID, $bitcoinPayment->getInvoiceId());
// Ensure the invoice is not processing
if ($invoice->isProcessing()) {
\PrestaShopLogger::addLog(\sprintf("[ERROR] Invoice '%s' should not be processing when 'InvoiceSettled' has been received", $invoice->getId()), \PrestaShopLogger::LOG_SEVERITY_LEVEL_ERROR, null, 'Order', $order->id);
return;
}
// Change state if it's settled
if ($invoice->isSettled()) {
$orderStatus = (string) $this->configuration->get(Constants::CONFIGURATION_ORDER_STATE_PAID);
}
// Transaction was marked completed via BTCPay Server
if ($invoice->isMarked()) {
$orderStatus = (string) $this->configuration->get(Constants::CONFIGURATION_ORDER_STATE_PAID);
}
// If nothing changed, return
if ((string) $order->current_state === $orderStatus) {
\PrestaShopLogger::addLog('[INFO] The state is the same as the one received', \PrestaShopLogger::LOG_SEVERITY_LEVEL_INFORMATIVE, null, 'Order', $order->id);
return;
}
// Store the updated status
$this->updateOrderStatus($bitcoinPayment, $orderStatus);
}
/**
* @throws \JsonException
* @throws \PrestaShopDatabaseException
* @throws \PrestaShopException
*/
public function invoiceFailed(BitcoinPayment $bitcoinPayment): void
{
// Get the order
$order = new \Order($bitcoinPayment->getOrderId());
// Set the default status to be the current status
$orderStatus = $order->current_state;
// Get the store ID
$storeID = $this->configuration->get(Constants::CONFIGURATION_BTCPAY_STORE_ID);
// Grab the invoice from the server
$invoice = $this->client->invoice()->getInvoice($storeID, $bitcoinPayment->getInvoiceId());
// Change the order status if needed
if ($invoice->isInvalid() || $invoice->isExpired()) {
// Expiration for the invoice has passed, so mark it failed
$orderStatus = (string) $this->configuration->get(Constants::CONFIGURATION_ORDER_STATE_FAILED);
}
// Transaction was marked as invalid via BTCPay Server
if ($invoice->isMarked()) {
$orderStatus = (string) $this->configuration->get(Constants::CONFIGURATION_ORDER_STATE_FAILED);
}
// If nothing changed, return
if ((string) $order->current_state === $orderStatus) {
\PrestaShopLogger::addLog('[INFO] The state is the same as the one received', \PrestaShopLogger::LOG_SEVERITY_LEVEL_INFORMATIVE, null, 'Order', $order->id);
return;
}
// Update the status
$this->updateOrderStatus($bitcoinPayment, $orderStatus);
}
/**
* @throws \JsonException
* @throws \PrestaShopDatabaseException
* @throws \PrestaShopException
*/
public function paymentReceived(BitcoinPayment $bitcoinPayment): void
{
// Get the order
$order = new \Order($bitcoinPayment->getOrderId());
// Get the store ID
$storeID = $this->configuration->get(Constants::CONFIGURATION_BTCPAY_STORE_ID);
// Grab the invoice from the server
$invoice = $this->client->invoice()->getInvoice($storeID, $bitcoinPayment->getInvoiceId());
// Set the default status to be the current status
$orderStatus = $order->current_state;
// If partially paid, we are still waiting for more
if ($invoice->isPartiallyPaid()) {
$orderStatus = (string) $this->configuration->get(Constants::CONFIGURATION_ORDER_STATE_WAITING);
}
// Transaction received, but we have to wait some confirmation
if ($invoice->isProcessing()) {
$orderStatus = (string) $this->configuration->get(Constants::CONFIGURATION_ORDER_STATE_CONFIRMING);
}
// Transaction received, but paid late
if ($invoice->isPaidLate()) {
// Transaction received but we have to wait some confirmation
$orderStatus = (string) $this->configuration->get(Constants::CONFIGURATION_ORDER_STATE_CONFIRMING);
}
// Transaction received, but overpaid
if ($invoice->isOverpaid()) {
// Transaction received but we have to wait some confirmation
$orderStatus = (string) $this->configuration->get(Constants::CONFIGURATION_ORDER_STATE_CONFIRMING);
}
// Invoice confirmed on the network
if ($invoice->isSettled()) {
// Transaction received and already confirmed
$orderStatus = (string) $this->configuration->get(Constants::CONFIGURATION_ORDER_STATE_PAID);
}
// If nothing changed, return
if ((string) $order->current_state === $orderStatus) {
\PrestaShopLogger::addLog(\sprintf("[INFO] The state is the same as the one received for invoice '%s'", $invoice->getId()), \PrestaShopLogger::LOG_SEVERITY_LEVEL_INFORMATIVE, null, 'Order', $order->id);
return;
}
// Store the updated status
$this->updateOrderStatus($bitcoinPayment, $orderStatus);
}
/**
* @throws \JsonException
* @throws \PrestaShopDatabaseException
* @throws \PrestaShopException
*/
public function paymentReceivedCreateAfter(BitcoinPayment $bitcoinPayment): void
{
// Generate an order only if there is not another one with this cart
if (null !== \Order::getByCartId($bitcoinPayment->getCartId())) {
// We already have an order, so process as normal
$this->paymentReceived($bitcoinPayment);
return;
}
// Get the store ID
$storeID = $this->configuration->get(Constants::CONFIGURATION_BTCPAY_STORE_ID);
// Grab the invoice from the server
$invoice = $this->client->invoice()->getInvoice($storeID, $bitcoinPayment->getInvoiceId());
// Set an initial state
$orderStatus = (string) $this->configuration->get(Constants::CONFIGURATION_ORDER_STATE_WAITING);
// If partially paid, we are still waiting for more
if ($invoice->isPartiallyPaid()) {
$orderStatus = (string) $this->configuration->get(Constants::CONFIGURATION_ORDER_STATE_WAITING);
}
// Transaction received, but we have to wait some confirmation
if ($invoice->isProcessing()) {
$orderStatus = (string) $this->configuration->get(Constants::CONFIGURATION_ORDER_STATE_CONFIRMING);
}
// Transaction received, but paid late
if ($invoice->isPaidLate()) {
// Transaction received but we have to wait some confirmation
$orderStatus = (string) $this->configuration->get(Constants::CONFIGURATION_ORDER_STATE_CONFIRMING);
// Add a regular log
\PrestaShopLogger::addLog(\sprintf("[INFO] User paid after expiration for this invoice '%s'", $invoice->getId()), \PrestaShopLogger::LOG_SEVERITY_LEVEL_INFORMATIVE);
}
// Transaction received, but overpaid
if ($invoice->isOverpaid()) {
// Transaction received but we have to wait some confirmation
$orderStatus = (string) $this->configuration->get(Constants::CONFIGURATION_ORDER_STATE_CONFIRMING);
}
// Invoice confirmed on the network
if ($invoice->isSettled()) {
// Transaction received and already confirmed
$orderStatus = (string) $this->configuration->get(Constants::CONFIGURATION_ORDER_STATE_PAID);
}
// Fetch the secure key, which is used to check if the order has been made from this store
if (null === ($invoiceData = $invoice->getData()) || !\array_key_exists('metadata', $invoiceData) || !\array_key_exists('posData', $invoiceData['metadata'])) {
\PrestaShopLogger::addLog('[ERROR] Secure key was not defined', \PrestaShopLogger::LOG_SEVERITY_LEVEL_ERROR);
return;
}
// Grab the secure key
$secureKey = $invoiceData['metadata']['posData'];
\PrestaShopLogger::addLog(\sprintf("[INFO] Creating actual order for invoice '%s'", $invoice->getId()), \PrestaShopLogger::LOG_SEVERITY_LEVEL_INFORMATIVE, null, 'BitcoinPayment', $bitcoinPayment->getId());
$this->module->validateOrder(
$bitcoinPayment->getCartId(),
$orderStatus,
$bitcoinPayment->getAmount(),
$this->module->displayName,
null,
[],
null,
false,
$secureKey,
$this->context->shop
);
// Get the new order ID
$order = \Order::getByCartId($bitcoinPayment->getCartId());
// Store the new order ID and set the proper status
$bitcoinPayment->setOrderId($order->id);
$bitcoinPayment->setStatus($orderStatus);
// Update the object
if (false === $bitcoinPayment->update(true)) {
$error = \sprintf('[ERROR] Could not update bitcoin_payment: %s', \Db::getInstance()->getMsgError());
\PrestaShopLogger::addLog($error, \PrestaShopLogger::LOG_SEVERITY_LEVEL_ERROR, null, 'BitcoinPayment', $bitcoinPayment->getId());
throw new \RuntimeException($error);
}
}
/**
* @throws \JsonException
* @throws \PrestaShopDatabaseException
* @throws \PrestaShopException
*/
public function paymentSettled(BitcoinPayment $bitcoinPayment): void
{
// Get the order
$order = new \Order($bitcoinPayment->getOrderId());
// Get the store ID
$storeID = $this->configuration->get(Constants::CONFIGURATION_BTCPAY_STORE_ID);
// Grab the payments from the server
$paymentMethods = $this->client->invoice()->getPaymentMethods($storeID, $bitcoinPayment->getInvoiceId());
// Process all payments
foreach ($paymentMethods as $paymentMethod) {
// Grab all payments per payment method
$payments = $paymentMethod->getPayments();
// Process all payments
foreach ($payments as $payment) {
// Payment is not yet settled, continue
if (Invoice::STATUS_SETTLED !== $payment->getStatus()) {
continue;
}
// Payment is known, continue
if (OrderPaymentRepository::hasPayment($order, $payment)) {
continue;
}
// Add the payment
$order->addOrderPayment(\bcmul($payment->getValue(), $paymentMethod->getRate()), null, $payment->getTransactionId());
}
}
}
/**
* @throws \PrestaShopDatabaseException
* @throws \PrestaShopException
*/
private function updateOrderStatus(BitcoinPayment $bitcoinPayment, string $orderStatus): void
{
// Set the status
$bitcoinPayment->setStatus($orderStatus);
// Update the object
if (false === $bitcoinPayment->update(true)) {
$error = \sprintf('[ERROR] Could not update bitcoin_payment: %s', \Db::getInstance()->getMsgError());
\PrestaShopLogger::addLog($error, \PrestaShopLogger::LOG_SEVERITY_LEVEL_ERROR, null, 'BitcoinPayment', $bitcoinPayment->getId());
throw new \RuntimeException($error);
}
// Add the order change to the order history table
$orderHistory = new \OrderHistory();
$orderHistory->id_order = $bitcoinPayment->getOrderId();
// Store the change and make sure to create an invoice using existing payments (in case the status is changed to 'paid with crypto')
$orderHistory->changeIdOrderState($orderStatus, $bitcoinPayment->getOrderId(), true);
$orderHistory->add();
}
}

View File

@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@ -1,116 +0,0 @@
<?php
namespace BTCPay;
use BTCPay\Entity\BitcoinPayment;
class LegacyOrderBitcoinRepository
{
/**
* @var \Db
*/
private $connection;
public function __construct()
{
$this->connection = \Db::getInstance();
}
public function create(int $cartId, string $status, string $invoiceId): BitcoinPayment
{
$orderBitcoin = new BitcoinPayment();
$orderBitcoin->setCartId($cartId);
$orderBitcoin->setStatus($status);
$orderBitcoin->setInvoiceId($invoiceId);
if (false === $orderBitcoin->save(true)) {
\PrestaShopLogger::addLog('[ERROR] Could not store bitcoin_payment', 3);
throw new \RuntimeException('[ERROR] Could not store bitcoin_payment');
}
\PrestaShopLogger::addLog('Created bitcoin_payment for invoice ' . $invoiceId);
return $orderBitcoin;
}
public function getOneByInvoiceID(string $invoiceId): ?BitcoinPayment
{
$query = new \DbQuery();
$query->select('bp.*')
->from('bitcoin_payment', 'bp')
->where(sprintf('bp.invoice_id = "%s"', $invoiceId))
->limit(1);
$result = $this->connection->query($query);
if (0 !== ($errorCode = (int) $result->errorCode())) {
throw new \PrestaShopDatabaseException(json_encode($result->errorInfo()), $errorCode);
}
if (false === ($object = $result->fetchObject(BitcoinPayment::class))) {
return null;
}
return $object;
}
public function getOneByInvoiceReference(string $invoiceReference): ?BitcoinPayment
{
$query = new \DbQuery();
$query->select('bp.*')
->from('bitcoin_payment', 'bp')
->where(sprintf('bp.invoice_reference = "%s"', $invoiceReference))
->limit(1);
$result = $this->connection->query($query);
if (0 !== ($errorCode = (int) $result->errorCode())) {
throw new \PrestaShopDatabaseException(json_encode($result->errorInfo()), $errorCode);
}
if (false === ($object = $result->fetchObject(BitcoinPayment::class))) {
return null;
}
return $object;
}
public function getOneByCartID(int $cartID): ?BitcoinPayment
{
$query = new \DbQuery();
$query->select('bp.*')
->from('bitcoin_payment', 'bp')
->where(sprintf('bp.cart_id = "%s"', $cartID))
->limit(1);
$result = $this->connection->query($query);
if (0 !== ($errorCode = (int) $result->errorCode())) {
throw new \PrestaShopDatabaseException(json_encode($result->errorInfo()), $errorCode);
}
if (false === ($object = $result->fetchObject(BitcoinPayment::class))) {
return null;
}
return $object;
}
public function getOneByOrderID(int $orderID): ?BitcoinPayment
{
$query = new \DbQuery();
$query->select('bp.*')
->from('bitcoin_payment', 'bp')
->where(sprintf('bp.order_id = "%s"', $orderID))
->limit(1);
$result = $this->connection->query($query);
if (0 !== ($errorCode = (int) $result->errorCode())) {
throw new \PrestaShopDatabaseException(json_encode($result->errorInfo()), $errorCode);
}
if (false === ($object = \Db::getInstance()->query($query)->fetchObject(BitcoinPayment::class))) {
return null;
}
return $object;
}
}

View File

@ -2,88 +2,128 @@
namespace BTCPay\Repository;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\DBALException;
use BTCPay\Entity\BitcoinPayment;
if (!\defined('_PS_VERSION_')) {
exit;
}
class BitcoinPaymentRepository
{
/**
* @var Connection
* @throws \PrestaShopException
*/
private $connection;
/**
* @var string
*/
private $prefix;
public function __construct(Connection $connection, string $prefix)
public static function create(int $cartId, string $status, string $invoiceId): BitcoinPayment
{
$this->connection = $connection;
$this->prefix = $prefix;
$bitcoinPayment = new BitcoinPayment();
$bitcoinPayment->setCartId($cartId);
$bitcoinPayment->setStatus($status);
$bitcoinPayment->setInvoiceId($invoiceId);
if (false === $bitcoinPayment->save(true)) {
\PrestaShopLogger::addLog('[ERROR] Could not store bitcoin_payment', \PrestaShopLogger::LOG_SEVERITY_LEVEL_ERROR);
throw new \RuntimeException('[ERROR] Could not store bitcoin_payment');
}
\PrestaShopLogger::addLog('[INFO] Created bitcoin_payment for invoice ' . $invoiceId, \PrestaShopLogger::LOG_SEVERITY_LEVEL_INFORMATIVE, null, 'BitcoinPayment', $bitcoinPayment->getId());
return $bitcoinPayment;
}
/**
* @throws DBALException
* @throws \PrestaShopDatabaseException
* @throws \JsonException
*/
public function createTables(): array
public static function getOneByInvoiceID(string $invoiceId): ?BitcoinPayment
{
$errors = [];
$engine = _MYSQL_ENGINE_;
$query = new \DbQuery();
$query->select('bp.*')
->from('bitcoin_payment', 'bp')
->where(\sprintf('bp.invoice_id = "%s"', $invoiceId))
->limit(1);
$queries = [
"CREATE TABLE IF NOT EXISTS `{$this->prefix}bitcoin_payment`(
`id` int(11) NOT NULL AUTO_INCREMENT,
`cart_id` int(11) NOT NULL,
`order_id` int(11),
`status` varchar(255) NOT NULL,
`invoice_id` varchar(255),
`invoice_reference` varchar(255),
`amount` varchar(255),
`bitcoin_price` varchar(255),
`bitcoin_paid` varchar(255),
`bitcoin_address` varchar(255),
`bitcoin_refund_address` varchar(255),
`redirect` varchar(255),
`rate` varchar(255),
PRIMARY KEY (`id`),
UNIQUE KEY `invoice_id` (`invoice_id`)
) ENGINE=$engine DEFAULT CHARSET=utf8",
];
foreach ($queries as $query) {
// Execute query
$statement = $this->connection->executeQuery($query);
if (0 !== (int) $statement->errorCode()) {
$errors[] = [
'key' => json_encode($statement->errorInfo()),
'parameters' => [],
'domain' => 'Admin.Modules.Notification',
];
}
$result = \Db::getInstance()->query($query);
if (0 !== ($errorCode = (int) $result->errorCode())) {
throw new \PrestaShopDatabaseException(\json_encode($result->errorInfo(), \JSON_THROW_ON_ERROR), $errorCode);
}
return $errors;
if (false === ($object = $result->fetchObject(BitcoinPayment::class))) {
return null;
}
return $object;
}
/**
* @throws DBALException
* @throws \PrestaShopDatabaseException
* @throws \JsonException
*/
public function dropTables(): array
public static function getOneByInvoiceReference(string $invoiceReference): ?BitcoinPayment
{
$errors = [];
$query = "DROP TABLE IF EXISTS `{$this->prefix}bitcoin_payment`";
$query = new \DbQuery();
$query->select('bp.*')
->from('bitcoin_payment', 'bp')
->where(\sprintf('bp.invoice_reference = "%s"', $invoiceReference))
->limit(1);
// Execute query
$statement = $this->connection->executeQuery($query);
if (0 !== (int) $statement->errorCode()) {
$errors[] = [
'key' => json_encode($statement->errorInfo()),
'parameters' => [],
'domain' => 'Admin.Modules.Notification',
];
$result = \Db::getInstance()->query($query);
if (0 !== ($errorCode = (int) $result->errorCode())) {
throw new \PrestaShopDatabaseException(\json_encode($result->errorInfo(), \JSON_THROW_ON_ERROR), $errorCode);
}
return $errors;
if (false === ($object = $result->fetchObject(BitcoinPayment::class))) {
return null;
}
return $object;
}
/**
* @throws \PrestaShopDatabaseException
* @throws \JsonException
*/
public static function getOneByCartID(int $cartID): ?BitcoinPayment
{
$query = new \DbQuery();
$query->select('bp.*')
->from('bitcoin_payment', 'bp')
->where(\sprintf('bp.cart_id = "%s"', $cartID))
->limit(1);
$result = \Db::getInstance()->query($query);
if (0 !== ($errorCode = (int) $result->errorCode())) {
throw new \PrestaShopDatabaseException(\json_encode($result->errorInfo(), \JSON_THROW_ON_ERROR), $errorCode);
}
if (false === ($object = $result->fetchObject(BitcoinPayment::class))) {
return null;
}
return $object;
}
/**
* @throws \PrestaShopDatabaseException
* @throws \JsonException
*/
public static function getOneByOrderID(int $orderID): ?BitcoinPayment
{
$query = new \DbQuery();
$query->select('bp.*')
->from('bitcoin_payment', 'bp')
->where(\sprintf('bp.order_id = "%s"', $orderID))
->limit(1);
$result = \Db::getInstance()->query($query);
if (0 !== ($errorCode = (int) $result->errorCode())) {
throw new \PrestaShopDatabaseException(\json_encode($result->errorInfo(), \JSON_THROW_ON_ERROR), $errorCode);
}
if (false === ($object = $result->fetchObject(BitcoinPayment::class))) {
return null;
}
return $object;
}
}

View File

@ -0,0 +1,30 @@
<?php
namespace BTCPay\Repository;
use BTCPay\Factory\CustomerThread;
if (!\defined('_PS_VERSION_')) {
exit;
}
class CustomerThreadRepository
{
/**
* @throws \PrestaShopException
* @throws \PrestaShopDatabaseException
*/
public static function fetchOrCreate(\Shop $shop, \Order $order): \CustomerThread
{
// Get the customer
$customer = $order->getCustomer();
// Check if we need to create a thread, if so, create it and return it
if (false === ($threadId = \CustomerThread::getIdCustomerThreadByEmailAndIdOrder($customer->email, $order->id))) {
return CustomerThread::create($shop, $order);
}
// Return the existing thread
return new \CustomerThread((int) $threadId);
}
}

View File

@ -0,0 +1,25 @@
<?php
namespace BTCPay\Repository;
use BTCPayServer\Result\InvoicePayment;
use PrestaShopCollection;
if (!\defined('_PS_VERSION_')) {
exit;
}
class OrderPaymentRepository
{
/**
* @throws \PrestaShopException
*/
public static function hasPayment(\Order $order, InvoicePayment $payment): bool
{
$order_payments = new PrestaShopCollection(\OrderPayment::class);
$order_payments->where('order_reference', '=', $order->reference);
$order_payments->where('transaction_id', '=', $payment->getTransactionId());
return false === empty($order_payments->getResults());
}
}

View File

@ -0,0 +1,80 @@
<?php
namespace BTCPay\Repository;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Exception;
if (!\defined('_PS_VERSION_')) {
exit;
}
class TableRepository
{
/**
* @var Connection
*/
private $connection;
public function __construct(Connection $connection)
{
$this->connection = $connection;
$this->prefix = \_DB_PREFIX_;
}
/**
* @throws \JsonException
*/
public function createTables(): array
{
$errors = [];
$engine = \_MYSQL_ENGINE_;
$queries = [
"CREATE TABLE IF NOT EXISTS `{$this->prefix}bitcoin_payment`(
`id` int(11) NOT NULL AUTO_INCREMENT,
`cart_id` int(11) NOT NULL,
`order_id` int(11),
`status` varchar(255) NOT NULL,
`invoice_id` varchar(255),
`invoice_reference` varchar(255),
`amount` varchar(255),
`bitcoin_price` varchar(255),
`bitcoin_paid` varchar(255),
`bitcoin_address` varchar(255),
`bitcoin_refund_address` varchar(255),
`redirect` varchar(255),
`rate` varchar(255),
PRIMARY KEY (`id`),
UNIQUE KEY `invoice_id` (`invoice_id`)
) ENGINE=$engine DEFAULT CHARSET=utf8",
];
try {
foreach ($queries as $query) {
$this->connection->executeQuery($query);
}
} catch (Exception $e) {
$errors[] = ['key' => \json_encode($e->getMessage(), \JSON_THROW_ON_ERROR), 'parameters' => [], 'domain' => 'Admin.Modules.Notification'];
}
return $errors;
}
/**
* @throws \JsonException
*/
public function dropTables(): array
{
$errors = [];
$query = "DROP TABLE IF EXISTS `{$this->prefix}bitcoin_payment`";
try {
$this->connection->executeQuery($query);
} catch (Exception $e) {
$errors[] = ['key' => \json_encode($e->getMessage(), \JSON_THROW_ON_ERROR), 'parameters' => [], 'domain' => 'Admin.Modules.Notification'];
}
return $errors;
}
}

View File

@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@ -2,37 +2,141 @@
namespace BTCPay\Server;
use BTCPay\LegacyOrderBitcoinRepository;
use BTCPayServer\Client\Client as BaseClient;
use BTCPayServer\PrivateKey;
use BTCPayServer\TokenInterface;
use BTCPay\Constants;
use BTCPay\Repository\BitcoinPaymentRepository;
use BTCPayServer\Client\AbstractClient;
use BTCPayServer\Client\ApiKey as ApiKeyClient;
use BTCPayServer\Client\Invoice as InvoiceClient;
use BTCPayServer\Client\Server as ServerClient;
use BTCPayServer\Client\Store as StoreClient;
use BTCPayServer\Client\StorePaymentMethod;
use PrestaShop\PrestaShop\Adapter\Configuration;
use PrestaShop\PrestaShop\Core\Domain\Configuration\ShopConfigurationInterface;
class Client extends BaseClient
if (!\defined('_PS_VERSION_')) {
exit;
}
class Client extends AbstractClient
{
/**
* @var Encryption
* @var InvoiceClient
*/
private $encryption;
private $invoice;
/**
* @var LegacyOrderBitcoinRepository
* @var ApiKeyClient
*/
private $repository;
private $apiKey;
public function __construct()
/**
* @var ServerClient
*/
private $server;
/**
* @var StoreClient
*/
private $store;
/**
* @var StorePaymentMethod
*/
private $payment;
/**
* @var Webhook
*/
private $webhook;
/**
* @var Configuration
*/
private $configuration;
public function __construct(string $baseUrl, string $apiKey)
{
$this->encryption = new Encryption();
$this->repository = new LegacyOrderBitcoinRepository();
$httpClient = new CurlAdapter();
// Set our own CURL adapter, always
$this->setAdapter(new CurlAdapter());
parent::__construct($baseUrl, $apiKey, $httpClient);
$this->apiKey = new ApiKeyClient($baseUrl, $apiKey, $httpClient);
$this->invoice = new InvoiceClient($baseUrl, $apiKey, $httpClient);
$this->server = new ServerClient($baseUrl, $apiKey, $httpClient);
$this->store = new StoreClient($baseUrl, $apiKey, $httpClient);
$this->payment = new StorePaymentMethod($baseUrl, $apiKey, $httpClient);
$this->webhook = new Webhook($baseUrl, $apiKey, $httpClient);
$this->configuration = new Configuration();
}
public function getEncryption(): Encryption
public static function createFromConfiguration(ShopConfigurationInterface $configuration): ?self
{
return $this->encryption;
$host = $configuration->get(Constants::CONFIGURATION_BTCPAY_HOST, null);
$apiKey = $configuration->get(Constants::CONFIGURATION_BTCPAY_API_KEY, null);
// Cannot create a client, if we do not have valid configuration
if (empty($host) || empty($apiKey)) {
return null;
}
return new self($host, $apiKey);
}
public function getBaseUrl(): string
{
return parent::getBaseUrl();
}
public function invoice(): InvoiceClient
{
return $this->invoice;
}
public function apiKey(): ApiKeyClient
{
return $this->apiKey;
}
public function server(): ServerClient
{
return $this->server;
}
public function store(): StoreClient
{
return $this->store;
}
public function payment(): StorePaymentMethod
{
return $this->payment;
}
public function webhook(): Webhook
{
return $this->webhook;
}
public function isValid(): bool
{
try {
// Test the server connection
$this->server()->getInfo();
// Test the store connection
$this->store()->getStore($this->configuration->get(Constants::CONFIGURATION_BTCPAY_STORE_ID))->getName();
} catch (\Throwable) {
return false;
}
return true;
}
/**
* @throws \PrestaShopDatabaseException
* @throws \JsonException
*/
public function getBTCPayRedirect(\Cart $cart): ?string
{
// Check if we have a cart ID we can use
@ -40,62 +144,23 @@ class Client extends BaseClient
return null;
}
if (null === ($orderBitcoin = $this->repository->getOneByCartID($cart->id))) {
if (null === ($bitcoinPayment = BitcoinPaymentRepository::getOneByCartID($cart->id))) {
return null;
}
if (empty($redirect = $orderBitcoin->getRedirect())) {
if (empty($redirect = $bitcoinPayment->getRedirect())) {
return null;
}
$errorReporting = error_reporting();
error_reporting(\E_ALL & ~\E_NOTICE & ~\E_STRICT & ~\E_DEPRECATED & ~\E_WARNING);
$invoice = $this->getInvoice($orderBitcoin->getInvoiceId());
error_reporting($errorReporting);
// Get the store ID
$storeID = $this->configuration->get(Constants::CONFIGURATION_BTCPAY_STORE_ID);
$status = $invoice->getStatus();
if ('invalid' === $status || 'expired' === $status) {
// Check the invoice status
$invoice = $this->invoice->getInvoice($storeID, $bitcoinPayment->getInvoiceId());
if ($invoice->isInvalid() || $invoice->isExpired()) {
return null;
}
return $redirect;
}
public static function createFromConfiguration(): self
{
$client = new self();
$client->setUri(self::getURI(\Configuration::get('BTCPAY_URL')));
$privateKey = $client->getEncryption()->decrypt(\Configuration::get('BTCPAY_KEY'));
if (!$privateKey instanceof PrivateKey) {
throw new \RuntimeException('Could not decrypted the stored private key', 3);
}
$token = $client->getEncryption()->decrypt(\Configuration::get('BTCPAY_TOKEN'));
if (!$token instanceof TokenInterface) {
throw new \RuntimeException('Could not decrypted the stored token', 3);
}
$client->setPrivateKey($privateKey);
$client->setPublicKey($privateKey->getPublicKey());
// We need to do some extra work for the token
$client->setToken(Token::createToken($token->getToken()));
return $client;
}
/**
* Inject ports into the URL, because the client somehow demands a port.
*/
public static function getURI(string $url): string
{
// Sanitize URL first
$url = rtrim($url, '/\\');
if ('https' === (parse_url($url, \PHP_URL_SCHEME))) {
return sprintf('%s:443', $url);
}
return sprintf('%s:80', $url);
}
}

View File

@ -2,12 +2,15 @@
namespace BTCPay\Server;
use BTCPayServer\Client\Adapter\CurlAdapter as BaseCurlAdapter;
use BTCPayServer\Client\RequestInterface;
use BTCPayServer\Client\ResponseInterface;
use BTCPayServer\Http\CurlClient;
use BTCPayServer\Http\ResponseInterface;
use STS\Backoff\Backoff;
class CurlAdapter extends BaseCurlAdapter
if (!\defined('_PS_VERSION_')) {
exit;
}
class CurlAdapter extends CurlClient
{
/**
* @var int
@ -19,11 +22,9 @@ class CurlAdapter extends BaseCurlAdapter
*/
private $backoff;
public function __construct(array $curlOptions = [])
public function __construct()
{
parent::__construct($curlOptions);
$this->backoff = new Backoff(self::$defaultMaxAttempts, Backoff::$defaultStrategy, self::$defaultMaxAttempts * 10 * 1000, true);
$this->backoff = new Backoff(self::$defaultMaxAttempts, Backoff::$defaultStrategy, self::$defaultMaxAttempts * 5 * 1000, true);
}
/**
@ -31,16 +32,16 @@ class CurlAdapter extends BaseCurlAdapter
*
* Four things can happen:
* 1. This call succeeds and we return like normal
* 2. The call fails and we retry 3 times using the default strategy, if any retry succeeds, we return it
* 3. The call fails and we retry 3 times using the default strategy, if all retries fail, it will throw the last error
* 4. The maximum waiting time exceeds and we will just throw the last error
* 2. The call fails, and we retry 3 times using the default strategy, if any retry succeeds, we return it
* 3. The call fails, and we retry 3 times using the default strategy, if all retries fail, it will throw the last error
* 4. The maximum waiting time exceeds, and we will just throw the last error
*
* @throws \Exception
*/
public function sendRequest(RequestInterface $request): ResponseInterface
public function request(string $method, string $url, array $headers = [], string $body = ''): ResponseInterface
{
return $this->backoff->run(function () use ($request) {
return parent::sendRequest($request);
return $this->backoff->run(function () use ($method, $url, $headers, $body) {
return parent::request($method, $url, $headers, $body);
});
}
}

View File

@ -0,0 +1,91 @@
<?php
namespace BTCPay\Server\Data;
use BTCPay\Constants;
use Symfony\Component\HttpFoundation\ParameterBag;
use Symfony\Component\Validator\Constraints as Assert;
if (!\defined('_PS_VERSION_')) {
exit;
}
class ValidateApiKey
{
/**
* @Assert\NotBlank()
*
* @var string|null
*/
private $apiKey;
/**
* @Assert\All({@Assert\NotBlank()})
* @Assert\NotBlank()
*
* @var string[]
*/
private $permissions;
public function __construct(ParameterBag $request)
{
$this->apiKey = $request->get('apiKey');
$this->permissions = $request->get('permissions', []);
}
public function getApiKey(): ?string
{
return $this->apiKey;
}
public function getStoreID(): string
{
return \explode(':', $this->permissions[0])[1];
}
/**
* @Assert\IsTrue(message="This plugin expects all passed permissions to be given. Please remove and recreate the API key")
*/
public function hasRequiredPermissions(): bool
{
$permissions = \array_reduce($this->permissions, static function (array $carry, string $permission) {
return \array_merge($carry, [\explode(':', $permission)[0]]);
}, []);
return empty(\array_merge(
\array_diff(Constants::BTCPAY_PERMISSIONS, $permissions),
\array_diff($permissions, Constants::BTCPAY_PERMISSIONS)
));
}
/**
* @Assert\IsTrue(message="This plugin requires one store (and one store only) to be authorized. Please remove and recreate the API key.")
*/
public function hasSingleStore(): bool
{
$storeId = null;
foreach ($this->permissions as $perms) {
if (2 !== \count($exploded = \explode(':', $perms))) {
return false;
}
if (null === ($receivedStoreId = $exploded[1])) {
return false;
}
if ($storeId === $receivedStoreId) {
continue;
}
if (null === $storeId) {
$storeId = $receivedStoreId;
continue;
}
return false;
}
return true;
}
}

View File

@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@ -1,82 +0,0 @@
<?php
namespace BTCPay\Server;
use BTCPayServer\Crypto\OpenSSLExtension;
use BTCPayServer\Key;
use BTCPayServer\PrivateKey;
use BTCPayServer\PublicKey;
use BTCPayServer\SinKey;
use BTCPayServer\Token;
use BTCPayServer\TokenInterface;
class Encryption
{
/**
* @param object|Key|Token $data
*
* @return array|string
*/
public function encrypt(object $data)
{
if (empty($data)) {
return [
'key' => 'The BTCPay payment plugin was called to encrypt data but no data was passed!',
'domain' => 'Admin.Catalog.Notification',
'parameters' => [],
];
}
if (40 !== \strlen($fingerprint = sha1(sha1(__DIR__)))) {
return [
'key' => 'Invalid server fingerprint generated!',
'domain' => 'Admin.Catalog.Notification',
'parameters' => [],
];
}
$openssl = new OpenSSLExtension();
if (empty($encrypted = $openssl->encrypt(base64_encode(serialize($data)), $fingerprint, '1234567890123456'))) {
return [
'key' => 'The BTCPay payment plugin was called to serialize an encrypted object and failed!',
'domain' => 'Admin.Catalog.Notification',
'parameters' => [],
];
}
return $encrypted;
}
/**
* @return PrivateKey|PublicKey|SinKey|TokenInterface|array
*/
public function decrypt(string $data)
{
if (empty($data)) {
return [
'key' => 'The BTCPay payment plugin was called to decrypt data but no data was passed!',
'domain' => 'Admin.Catalog.Notification',
'parameters' => [],
];
}
if (40 !== \strlen($fingerprint = sha1(sha1(__DIR__)))) {
return [
'key' => 'Invalid server fingerprint generated!',
'domain' => 'Admin.Catalog.Notification',
'parameters' => [],
];
}
$openssl = new OpenSSLExtension();
if (false === ($decrypted = base64_decode($openssl->decrypt($data, $fingerprint, '1234567890123456'), true))) {
return [
'key' => 'The BTCPay payment plugin was called to unserialize a decrypted object and failed! The decrypt function was called with "%s"',
'domain' => 'Admin.Catalog.Notification',
'parameters' => [],
];
}
return unserialize($decrypted, [PrivateKey::class, PublicKey::class, SinKey::class, Token::class]);
}
}

View File

@ -2,167 +2,232 @@
namespace BTCPay\Server;
use BTCPay\Constants;
use BTCPay\Exception\BTCPayException;
use BTCPay\LegacyOrderBitcoinRepository;
use BTCPayServer\Buyer;
use BTCPayServer\Currency as BTCPayCurrency;
use BTCPayServer\Invoice;
use BTCPayServer\Item;
use BTCPay\Repository\BitcoinPaymentRepository;
use BTCPayServer\Client\InvoiceCheckoutOptions;
use BTCPayServer\Util\PreciseNumber;
use PrestaShop\PrestaShop\Adapter\Configuration;
if (!\defined('_PS_VERSION_')) {
exit;
}
class Factory
{
/**
* @var LegacyOrderBitcoinRepository
*/
private $repository;
/**
* @var \Link
*/
private $link;
/**
* @var string
* @var Configuration
*/
private $moduleName;
private $configuration;
public function __construct(LegacyOrderBitcoinRepository $repository, \Link $link, string $moduleName)
/**
* @var \Context
*/
private $context;
/**
* @var \BTCPay
*/
private $module;
public function __construct(\BTCPay $module, \Context $context)
{
$this->repository = $repository;
$this->link = $link;
$this->moduleName = $moduleName;
$this->link = new \Link();
$this->configuration = new Configuration();
$this->context = $context;
$this->module = $module;
}
/**
* @throws \PrestaShopDatabaseException
* @throws \JsonException
*/
public function createPaymentRequest(\Customer $customer, \Cart $cart): ?string
{
// Check if we have a cart ID we can use
if (empty($cart->id)) {
\PrestaShopLogger::addLog(
'[Error] The BTCPay payment plugin was called to process a payment but the cart ID was missing.',
3
);
\PrestaShopLogger::addLog('[ERROR] The BTCPay payment plugin was called to process a payment but the cart ID was missing.', \PrestaShopLogger::LOG_SEVERITY_LEVEL_ERROR);
return null;
}
// Build the client from our stored configuration
try {
$client = Client::createFromConfiguration();
} catch (\Exception $e) {
\PrestaShopLogger::addLog('[ERROR] ' . $e->getMessage(), $e->getCode());
throw new BTCPayException($e->getMessage(), $e->getCode(), $e);
$client = Client::createFromConfiguration($this->configuration);
// Ensure the client is ready for use
if (null === $client || false === $client->isValid()) {
\PrestaShopLogger::addLog("[ERROR] The BTCPay payment plugin was called to process a payment but the client doesn't exist.", \PrestaShopLogger::LOG_SEVERITY_LEVEL_ERROR);
return null;
}
// Make sure we have a webhook, before we redirect anyone anywhere
$client->webhook()->ensureWebhook($this->configuration->get(Constants::CONFIGURATION_BTCPAY_STORE_ID));
// If another BTCPay invoice was created before, returns the original one
if (null !== ($redirect = $client->getBTCPayRedirect($cart))) {
\PrestaShopLogger::addLog(
'[WARNING] Existing BTCPay invoice has already been created, redirecting to it...',
2
);
\PrestaShopLogger::addLog('[WARNING] Existing BTCPay invoice has already been created for this cart, redirecting...', \PrestaShopLogger::LOG_SEVERITY_LEVEL_WARNING, null, 'Cart', $cart->id);
return $redirect;
}
// Setup the Invoice
$invoice = new Invoice();
$invoice->setFullNotifications(true);
$invoice->setExtendedNotifications(true);
// Get and set transaction speed
if (empty($transactionSpeed = \Configuration::get('BTCPAY_TXSPEED'))) {
$transactionSpeed = 'default';
}
$invoice->setTransactionSpeed($transactionSpeed);
// Set an order reference instead of ID, since we haven't made one yet
$invoiceReference = \Tools::passwdGen(20);
$invoice->setOrderId($invoiceReference);
// Get shopping currency, currently tested with be EUR
$currency = \Currency::getCurrencyInstance((int) $cart->id_currency);
$btcpayCurrency = new BTCPayCurrency($currency->iso_code);
$invoice->setCurrency($btcpayCurrency);
// Add a basic item to our invoice
$orderTotal = $cart->getOrderTotal(true);
$invoice->setItem(
(new Item())
->setCode('Cart: ' . $cart->id)
->setDescription('Your purchase')
->setPrice($orderTotal)
);
// Set POS data so we can verify later on that the call is legit
$invoice->setPosData($customer->secure_key);
// Create a buyer we can add to the invoice
$buyer = new Buyer();
// Add customer information to buyer
$customer = new \Customer((int) $cart->id_customer);
$buyer->setEmail($customer->email);
$buyer->setFirstName($customer->firstname);
$buyer->setLastName($customer->lastname);
// Add address information to buyer
$address = new \Address($cart->id_address_delivery);
$buyer->setAddress([$address->address1, $address->address2]);
$buyer->setCountry($address->country);
$buyer->setZip($address->postcode);
$buyer->setCity($address->city);
// Add the state if available
if (0 !== ($stateId = $address->id_state)) {
$buyer->setState((new \State($stateId))->name);
}
// Finally, add the build buyer to the invoice
$invoice->setBuyer($buyer);
// Create the redirect URL once payment has been done.
$invoice->setRedirectUrl($this->link->getModuleLink($this->moduleName, 'validation', ['invoice_reference' => $invoiceReference], true));
// This is the callback url for invoice paid.
$invoice->setNotificationUrl($this->link->getModuleLink($this->moduleName, 'ipn', [], true));
// Ask BTCPay to create an invoice with cart information
try {
$errorReporting = error_reporting();
error_reporting(\E_ALL & ~\E_NOTICE & ~\E_STRICT & ~\E_DEPRECATED & ~\E_WARNING);
$invoice = $client->createInvoice($invoice);
error_reporting($errorReporting);
// Setup some stuff
$currency = \Currency::getCurrencyInstance($cart->id_currency);
$address = new \Address($cart->id_address_delivery);
$invoiceReference = \Tools::passwdGen(20);
\PrestaShopLogger::addLog('Invoice ' . $invoice->getId() . ' created, see ' . $invoice->getUrl(), 2);
// Get totals
$taxAmount = (string) $cart->getOrderTotal(true, \Cart::ONLY_PRODUCTS) - $cart->getOrderTotal(false, \Cart::ONLY_PRODUCTS);
$orderTotal = (string) $cart->getOrderTotal(true);
// Setup custom checkout options, defaults get picked from store config.
$checkoutOptions = new InvoiceCheckoutOptions();
$checkoutOptions
->setSpeedPolicy($this->configuration->get(Constants::CONFIGURATION_SPEED_MODE, InvoiceCheckoutOptions::SPEED_MEDIUM))
->setRedirectURL($this->link->getModuleLink($this->module->name, 'validation', ['invoice_reference' => $invoiceReference], true));
// Get the store ID
$storeID = $this->configuration->get(Constants::CONFIGURATION_BTCPAY_STORE_ID);
// Build the metadata
$metadata = $this->createMetadata($customer, $address, $invoiceReference, $taxAmount);
// Ask BTCPay to create an invoice with cart information
$invoice = $client->invoice()->createInvoice(
$storeID,
$currency->iso_code,
PreciseNumber::parseString($orderTotal),
$invoiceReference,
$customer->email,
$metadata,
$checkoutOptions
);
// Process response
$invoiceResponse = $invoice->getData();
$invoiceId = $invoiceResponse['id'];
$invoiceUrl = $invoiceResponse['checkoutLink'];
\PrestaShopLogger::addLog(\sprintf('[INFO] Invoice %s created, see %s', $invoiceId, $invoiceUrl));
$orderStatus = (string) $this->configuration->get(Constants::CONFIGURATION_ORDER_STATE_WAITING);
// Register invoice into bitcoin_payment table, if we didn't have one before.
if (null === ($orderBitcoin = $this->repository->getOneByCartID($cart->id))) {
$orderBitcoin = $this->repository->create($cart->id, (string) \Configuration::get('BTCPAY_OS_WAITING'), $invoice->getId());
if (null === ($bitcoinPayment = BitcoinPaymentRepository::getOneByCartID($cart->id))) {
$bitcoinPayment = BitcoinPaymentRepository::create($cart->id, $orderStatus, $invoiceId);
}
$orderBitcoin->setInvoiceId($invoice->getId());
$orderBitcoin->setInvoiceReference($invoiceReference);
$orderBitcoin->setAmount((string) $orderTotal);
$orderBitcoin->setRedirect($invoice->getUrl());
$bitcoinPayment->setInvoiceId($invoiceId);
$bitcoinPayment->setInvoiceReference($invoiceReference);
$bitcoinPayment->setAmount($orderTotal);
$bitcoinPayment->setRedirect($invoiceUrl);
$response = \json_decode($client->getResponse()->getBody(), false, 512, \JSON_THROW_ON_ERROR);
$orderBitcoin->setRate($response->data->rate);
$orderBitcoin->setBitcoinPrice($response->data->btcPrice);
$orderBitcoin->setBitcoinPaid($response->data->btcPaid);
$orderBitcoin->setBitcoinAddress($response->data->bitcoinAddress);
if (false === $bitcoinPayment->save(true)) {
$error = \sprintf('[ERROR] Could not store bitcoin_payment: %s', \Db::getInstance()->getMsgError());
\PrestaShopLogger::addLog($error, \PrestaShopLogger::LOG_SEVERITY_LEVEL_ERROR, null, 'BitcoinPayment', $bitcoinPayment->getId());
if (false === $orderBitcoin->save(true)) {
\PrestaShopLogger::addLog('[ERROR] Could not store bitcoin_payment', 3);
throw new \RuntimeException('[ERROR] Could not store bitcoin_payment');
throw new \RuntimeException($error);
}
\PrestaShopLogger::addLog('Invoice ' . $invoice->getId() . ' updated', 2);
// If we create the order after payment, do not make the order yet
if (Constants::ORDER_MODE_AFTER === $this->configuration->get(Constants::CONFIGURATION_ORDER_MODE)) {
// Update the object, so we can always validate it afterward
if (false === $bitcoinPayment->update(true)) {
$error = \sprintf('[ERROR] Could not update bitcoin_payment: %s', \Db::getInstance()->getMsgError());
\PrestaShopLogger::addLog($error, \PrestaShopLogger::LOG_SEVERITY_LEVEL_ERROR, null, 'BitcoinPayment', $bitcoinPayment->getId());
return $orderBitcoin->getRedirect();
} catch (\Exception $e) {
\PrestaShopLogger::addLog('[ERROR] ' . $e->getMessage(), 3);
throw new BTCPayException($e->getMessage(), $e->getCode(), $e);
throw new \RuntimeException($error);
}
\PrestaShopLogger::addLog(\sprintf('[INFO] Invoice %s has been updated', $invoiceId), \PrestaShopLogger::LOG_SEVERITY_LEVEL_INFORMATIVE, null, 'BitcoinPayment', $bitcoinPayment->getId());
// Redirect user to payment
return $bitcoinPayment->getRedirect();
}
\PrestaShopLogger::addLog(\sprintf('[INFO] Invoice %s has been updated, creating actual order', $invoiceId), \PrestaShopLogger::LOG_SEVERITY_LEVEL_INFORMATIVE, null, 'BitcoinPayment', $bitcoinPayment->getId());
$this->module->validateOrder(
$bitcoinPayment->getCartId(),
$bitcoinPayment->getStatus(),
$bitcoinPayment->getAmount(),
$this->module->displayName,
null,
[],
null,
false,
$customer->secure_key,
$this->context->shop
);
// Get the new order ID
$orderId = (int) \Order::getIdByCartId($bitcoinPayment->getCartId());
$bitcoinPayment->setOrderId($orderId);
$bitcoinPayment->setStatus($orderStatus);
// Update the object
if (false === $bitcoinPayment->update(true)) {
$error = \sprintf('[ERROR] Could not update bitcoin_payment: %s', \Db::getInstance()->getMsgError());
\PrestaShopLogger::addLog($error, \PrestaShopLogger::LOG_SEVERITY_LEVEL_ERROR, null, 'BitcoinPayment', $bitcoinPayment->getId());
throw new \RuntimeException($error);
}
// Redirect user to payment
return $bitcoinPayment->getRedirect();
} catch (\Throwable $throwable) {
\PrestaShopLogger::addLog(\sprintf('[ERROR] %s', $throwable->getMessage()), \PrestaShopLogger::LOG_SEVERITY_LEVEL_ERROR, $throwable->getCode());
throw new BTCPayException($throwable->getMessage(), $throwable->getCode(), $throwable);
}
}
/**
* @throws \PrestaShopDatabaseException
* @throws \PrestaShopException
*/
private function createMetadata(\Customer $customer, \Address $address, string $invoiceReference, string $taxAmount): array
{
$metadata = [
'posData' => $customer->secure_key,
'itemCode' => \sprintf('invoice-reference-%s', $invoiceReference),
'itemDesc' => \sprintf('Purchase from %s', $this->context->shop->name),
'taxIncluded' => $taxAmount,
];
// Only include personal details if enabled, if not, return here (force to bool, as the default could be not bool)
if (false === (bool) $this->configuration->get(Constants::CONFIGURATION_SHARE_METADATA, false)) {
return $metadata;
}
$metadata = \array_merge($metadata, [
'buyerName' => \sprintf('%s %s', $customer->firstname, $customer->lastname),
'buyerAddress1' => $address->address1,
'buyerAddress2' => $address->address2,
'buyerCity' => $address->city,
'buyerZip' => $address->postcode,
'buyerCountry' => $address->country,
]);
// Set state if available
if (0 !== ($stateId = $address->id_state)) {
$metadata['buyerState'] = (new \State($stateId))->name;
}
// Set phone/mobile phone number if available
if (!empty($address->phone)) {
$metadata['buyerPhone'] = $address->phone;
} elseif (!empty($address->phone_mobile)) {
$metadata['buyerPhone'] = $address->phone_mobile;
}
return $metadata;
}
}

View File

@ -1,386 +0,0 @@
<?php
namespace BTCPay\Server;
use BTCPay\Constants;
use BTCPay\LegacyOrderBitcoinRepository;
use Symfony\Component\HttpFoundation\Request;
class IPN
{
/**
* @var LegacyOrderBitcoinRepository
*/
private $repository;
public function __construct(LegacyOrderBitcoinRepository $repository)
{
$this->repository = $repository;
}
public function process(\BTCPay $btcpay, Request $request): void
{
$json = json_decode($request->getContent(), true);
if (false === $json || null === $json) {
return;
}
// Check if we received an event
if (!\array_key_exists('event', $json)) {
return;
}
// Get event from JSON
$event = $json['event'];
// Check if event code exist and is not empty
if (!\array_key_exists('code', $event) || empty($event['code'])) {
return;
}
// Check if event name exist and is not empty
if (!\array_key_exists('name', $event) || empty($event['name'])) {
return;
}
// Check if event data exist and is not empty
if (!\array_key_exists('data', $json) || empty($json['data'])) {
return;
}
// Get data
$data = $json['data'];
// Check if ID exists and that it's not empty.
if (!\array_key_exists('id', $data) || empty($data['id'])) {
return;
}
// Get order mode
$orderMode = \Configuration::get('BTCPAY_ORDERMODE');
// Invoice created - Before
if ('invoice_created' === $event['name'] && Constants::ORDER_MODE_BEFORE === $orderMode) {
$this->invoiceCreated($data, $btcpay);
return;
}
// Invoice created - After
if ('invoice_created' === $event['name'] && Constants::ORDER_MODE_AFTER === $orderMode) {
\PrestaShopLogger::addLog('[INFO] Received invoice_created event, but not creating order because order mode is ' . Constants::ORDER_MODE_AFTER, 1);
return;
}
// Payment Received - Before
if ('invoice_receivedPayment' === $event['name'] && Constants::ORDER_MODE_BEFORE === $orderMode) {
$this->receivedPaymentBefore($data);
return;
}
// Payment Received - After
if ('invoice_receivedPayment' === $event['name'] && Constants::ORDER_MODE_AFTER === $orderMode) {
$this->receivedPaymentAfter($data, $btcpay);
return;
}
// Pending full payment, not much to do but wait
if ('invoice_paidInFull' === $event['name']) {
return;
}
// Payment failed
if ('invoice_failedToConfirm' === $event['name'] || 'invoice_markedInvalid' === $event['name'] || 'invoice_expired' === $event['name']) {
$this->failedPayment($data);
return;
}
// Payment confirmed
if ('invoice_confirmed' === $event['name'] || 'invoice_markedComplete' === $event['name']) {
$this->paymentConfirmed($data);
return;
}
// Payment completed
if ('invoice_completed' === $event['name']) {
\PrestaShopLogger::addLog('[INFO] BTCPay server has told us that invoice "' . $data['id'] . '" is finished', 1);
return;
}
// Log other IPN's.
\PrestaShopLogger::addLog('[Error] Could not process IPN', 3);
\PrestaShopLogger::addLog('[INFO] Received IPN: ' . $request->getContent(), 1);
}
private function invoiceCreated(array $data, \BTCPay $btcpay): void
{
$invoiceId = (string) $data['id'];
\PrestaShopLogger::addLog('[Info] invoice created for ' . $invoiceId, 1);
if (null === ($orderBitcoin = $this->repository->getOneByInvoiceID($invoiceId))) {
\PrestaShopLogger::addLog('[Error] Could not load order', 3);
throw new \RuntimeException('[Error] Could not load order');
}
// waiting payment
$orderStatus = \Configuration::get('BTCPAY_OS_WAITING');
// on Order, just say payment processor is BTCPay
$displayName = $btcpay->displayName;
// fetch secure key, used to check cart comes from your prestashop
$secure_key = $data['posData'];
if (false === isset($secure_key)) {
\PrestaShopLogger::addLog('[Error] No securekey', 3);
throw new \RuntimeException('[Error] No securekey');
}
// rate in fiat currency
$rate = $data['rate'];
if (false === isset($rate)) {
\PrestaShopLogger::addLog('[Error] No rate', 3);
throw new \RuntimeException('[Error] No rate');
}
// generate an order only if their is not another one with this cart
$orderId = \Order::getIdByCartId($orderBitcoin->getCartId());
if (false === $orderId || 0 === $orderId) {
$btcpay->validateOrder(
$orderBitcoin->getCartId(),
$orderStatus,
$orderBitcoin->getAmount(),
$displayName, //bitcoin btcpay
null, //message should be new Message
[], //extravars for mail
null, //currency special
false, // don't touch amount
$secure_key
);
// Get the new order ID
$orderId = (int) \Order::getIdByCartId($orderBitcoin->getCartId());
$orderBitcoin->setOrderId($orderId);
$orderBitcoin->setBitcoinPaid('0.0');
$orderBitcoin->setStatus((string) $orderStatus);
// Update the object
if (false === $orderBitcoin->update(true)) {
$error = '[Error] Could not update bitcoin_payment: ' . \Db::getInstance()->getMsgError();
\PrestaShopLogger::addLog($error, 3);
throw new \RuntimeException($error);
}
return;
}
// Order already paid
\PrestaShopLogger::addLog('[Error] already created order', 1);
throw new \RuntimeException('[Error] already created order');
}
private function receivedPaymentBefore(array $data): void
{
$invoiceId = (string) $data['id'];
\PrestaShopLogger::addLog('[Info] payment received for ' . $invoiceId, 1);
if (null === ($orderBitcoin = $this->repository->getOneByInvoiceID($invoiceId))) {
\PrestaShopLogger::addLog('[Error] Could not load order', 3);
throw new \RuntimeException('[Error] Could not load order');
}
$orderId = $orderBitcoin->getOrderId();
// waiting confirmation
$orderStatus = \Configuration::get('BTCPAY_OS_CONFIRMING');
$orderBitcoin->setBitcoinPaid($data['btcPaid']);
$orderBitcoin->setStatus((string) $orderStatus);
// Update the object
if (false === $orderBitcoin->update(true)) {
$error = '[Error] Could not update bitcoin_payment: ' . \Db::getInstance()->getMsgError();
\PrestaShopLogger::addLog($error, 3);
throw new \RuntimeException($error);
}
// add Order status change to Order history table
$orderHistory = new \OrderHistory();
$orderHistory->id_order = $orderId;
// bitcoin confirmation ok
$orderHistory->changeIdOrderState($orderStatus, $orderId, true);
//add with email is mandatory to add new order state in order_history
$orderHistory->add(true);
}
private function receivedPaymentAfter(array $data, \BTCPay $btcpay): void
{
$invoiceId = (string) $data['id'];
\PrestaShopLogger::addLog('[Info] payment received for ' . $invoiceId, 1);
if (null === ($orderBitcoin = $this->repository->getOneByInvoiceID($invoiceId))) {
\PrestaShopLogger::addLog('[Error] Could not load order', 3);
throw new \RuntimeException('[Error] Could not load order');
}
// waiting confirmation
$orderStatus = \Configuration::get('BTCPAY_OS_CONFIRMING');
// on Order, just say payment processor is BTCPay
$displayName = $btcpay->displayName;
// fetch secure key, used to check cart comes from your prestashop
$secure_key = $data['posData'];
if (false === isset($secure_key)) {
\PrestaShopLogger::addLog('[Error] No securekey', 3);
throw new \RuntimeException('[Error] No securekey');
}
// rate in fiat currency
$rate = $data['rate'];
if (false === isset($rate)) {
\PrestaShopLogger::addLog('[Error] No rate', 3);
throw new \RuntimeException('[Error] No rate');
}
// generate an order only if their is not another one with this cart
$orderId = \Order::getIdByCartId($orderBitcoin->getCartId());
if (false === $orderId || 0 === $orderId) {
$btcpay->validateOrder(
$orderBitcoin->getCartId(),
$orderStatus,
$orderBitcoin->getAmount(),
$displayName, //bitcoin btcpay
$rate, //message
[], //extravars
null, //currency special
false, // don't touch amount
$secure_key
);
// Get the new order ID
$orderId = (int) \Order::getIdByCartId($orderBitcoin->getCartId());
$orderBitcoin->setOrderId($orderId);
$orderBitcoin->setBitcoinPaid($data['btcPaid']);
$orderBitcoin->setStatus((string) $orderStatus);
// Update the object
if (false === $orderBitcoin->update(true)) {
$error = '[Error] Could not update bitcoin_payment: ' . \Db::getInstance()->getMsgError();
\PrestaShopLogger::addLog($error, 3);
throw new \RuntimeException($error);
}
return;
}
// Order already paid
\PrestaShopLogger::addLog('[Error] already paid order', 1);
throw new \RuntimeException('[Error] already paid order');
}
private function failedPayment(array $data): void
{
$invoiceId = (string) $data['id'];
\PrestaShopLogger::addLog('[Info] payment failed for ' . $invoiceId, 1);
if (null === ($orderBitcoin = $this->repository->getOneByInvoiceID($invoiceId))) {
\PrestaShopLogger::addLog('[Error] Could not load order', 3);
throw new \RuntimeException('[Error] Could not load order');
}
// wait for confirm
$orderStatus = \Configuration::get('BTCPAY_OS_CONFIRMING');
if ('invalid' === $data['status'] || 'expired' === $data['status']) {
// time setup on invoice is expired
$orderStatus = \Configuration::get('BTCPAY_OS_FAILED');
}
$orderBitcoin->setStatus((string) $orderStatus);
// Update the object
if (false === $orderBitcoin->update(true)) {
$error = '[Error] Could not update bitcoin_payment: ' . \Db::getInstance()->getMsgError();
\PrestaShopLogger::addLog($error, 3);
throw new \RuntimeException($error);
}
// add Order status change to Order history table
$orderHistory = new \OrderHistory();
$orderHistory->id_order = $orderBitcoin->getOrderId();
// bitcoin confirmation ok
$orderHistory->changeIdOrderState($orderStatus, $orderBitcoin->getOrderId(), true);
$orderHistory->add(true);
}
private function paymentConfirmed(array $data): void
{
$invoiceId = (string) $data['id'];
\PrestaShopLogger::addLog('[Info] payment confirmed for ' . $invoiceId, 1);
if (null === ($orderBitcoin = $this->repository->getOneByInvoiceID($invoiceId))) {
\PrestaShopLogger::addLog('[Error] Could not load order', 3);
throw new \RuntimeException('[Error] Could not load order');
}
$order = new \Order($orderBitcoin->getOrderId());
// wait for confirm
$orderStatus = \Configuration::get('BTCPAY_OS_CONFIRMING');
if ('invalid' === $data['status'] || 'expired' === $data['status']) {
// time setup on invoice is expired
$orderStatus = \Configuration::get('BTCPAY_OS_FAILED');
}
if ('paid' === $data['status']) {
// TX received but we have to wait some confirmation
$orderStatus = \Configuration::get('BTCPAY_OS_CONFIRMING');
}
if ('confirmed' === $data['status'] || 'complete' === $data['status']) {
//Transaction confirmed
$orderStatus = \Configuration::get('BTCPAY_OS_PAID');
}
$orderBitcoin->setStatus((string) $orderStatus);
// Update the object
if (false === $orderBitcoin->update(true)) {
$error = '[Error] Could not update bitcoin_payment: ' . \Db::getInstance()->getMsgError();
\PrestaShopLogger::addLog($error, 3);
throw new \RuntimeException($error);
}
// add Order status change to Order history table
if ($order->current_state !== $orderStatus) {
$orderHistory = new \OrderHistory();
$orderHistory->id_order = $orderBitcoin->getOrderId();
// bitcoin confirmation ok
$orderHistory->changeIdOrderState($orderStatus, $orderBitcoin->getOrderId(), true);
$orderHistory->add(true);
} else {
\PrestaShopLogger::addLog('[Info] current state is not different than new order status in invoice confirmed', 1);
}
}
}

View File

@ -1,15 +0,0 @@
<?php
namespace BTCPay\Server;
use BTCPayServer\Token as BTCPayToken;
class Token extends BTCPayToken
{
public static function createToken(string $token): self
{
return (new self())
->setToken($token)
->setFacade('merchant');
}
}

View File

@ -0,0 +1,118 @@
<?php
namespace BTCPay\Server;
use BTCPay\Constants;
use BTCPay\Exception\BTCPayException;
use BTCPayServer\Http\ClientInterface;
use PrestaShop\PrestaShop\Adapter\Configuration;
use Symfony\Component\HttpFoundation\Response;
if (!\defined('_PS_VERSION_')) {
exit;
}
class Webhook extends \BTCPayServer\Client\Webhook
{
/**
* @var Configuration
*/
private $configuration;
/**
* @var \Link
*/
private $link;
public function __construct(string $baseUrl, string $apiKey, ClientInterface $client = null)
{
parent::__construct($baseUrl, $apiKey, $client);
$this->configuration = new Configuration();
$this->link = new \Link();
}
/**
* @throws \JsonException
* @throws \Exception
*/
public function ensureWebhook(string $storeId): void
{
// Check if we have an existing webhook, if so, just cancel now (empty check is required).
if (false === empty($this->getCurrent($storeId, $this->configuration->get(Constants::CONFIGURATION_BTCPAY_WEBHOOK_ID)))) {
return;
}
// Generate new webhook secret
$secret = \bin2hex(\random_bytes(24));
// Build the webhook URL
$webhookURL = $this->link->getModuleLink('btcpay', 'webhook', [], true);
// Create the brand-new webhook
$webhook = $this->createWebhook($storeId, $webhookURL, null, $secret);
// Ensure we actually made a proper webhook
if (empty($webhook->getId()) || empty($webhook->getSecret())) {
throw new BTCPayException("Webhook wasn't created correctly.", Response::HTTP_INTERNAL_SERVER_ERROR);
}
// Ensure the webhook was created with the secret we provided
if ($webhook->getSecret() !== $secret) {
throw new BTCPayException("Webhook secret doesn't match our secret.", Response::HTTP_INTERNAL_SERVER_ERROR);
}
// Store the webhook secret we made, so we can check that the webhook is actually made by us
$this->configuration->set(Constants::CONFIGURATION_BTCPAY_WEBHOOK_SECRET, $secret);
// Store the ID, so we can check if we already have a valid webhook
$this->configuration->set(Constants::CONFIGURATION_BTCPAY_WEBHOOK_ID, $webhook->getId());
}
public function getCurrent(string $storeId, ?string $webhookId): ?\BTCPayServer\Result\Webhook
{
try {
// We need to check for empty here as twig passes a null variable as "" instead of null in configure.html.twig.
if (empty($webhookId)) {
return null;
}
if (null === ($webhook = $this->getWebhook($storeId, $webhookId))) {
return null;
}
return !empty($webhook->getData()) ? $webhook : null;
} catch (\Throwable $throwable) {
$warning = \sprintf("[WARNING] expected webhook '%s' for store '%s' to exist, but it didn't. Exception received: %s", $webhookId, $storeId, $throwable->getMessage());
\PrestaShopLogger::addLog($warning, \PrestaShopLogger::LOG_SEVERITY_LEVEL_WARNING, $throwable->getCode());
return null;
}
}
public function removeCurrent(): bool
{
if (empty($storeId = $this->configuration->get(Constants::CONFIGURATION_BTCPAY_STORE_ID))) {
return false;
}
if (empty($webhookId = $this->configuration->get(Constants::CONFIGURATION_BTCPAY_WEBHOOK_ID))) {
return false;
}
try {
if (null === $this->getWebhook($storeId, $webhookId)) {
return false;
}
$this->deleteWebhook($storeId, $webhookId);
return true;
} catch (\Throwable $throwable) {
$message = \sprintf("[WARNING] Could not remove webhook '%s' from the store '%s'. Please double check it is actually gone. Exception received: %s", $webhookId, $storeId, $throwable->getMessage());
\PrestaShopLogger::addLog($message, \PrestaShopLogger::LOG_SEVERITY_LEVEL_WARNING, $throwable->getCode());
return false;
}
}
}

View File

@ -0,0 +1,259 @@
<?php
namespace BTCPay\Server;
use BTCPay\Constants;
use BTCPay\Factory\CustomerMessage;
use BTCPay\Invoice\Processor;
use BTCPay\Repository\BitcoinPaymentRepository;
use PrestaShop\PrestaShop\Adapter\Configuration;
use Symfony\Component\HttpFoundation\Request;
if (!\defined('_PS_VERSION_')) {
exit;
}
class WebhookHandler
{
/**
* @var \Context
*/
private $context;
/**
* @var Configuration
*/
private $configuration;
/**
* @var Processor
*/
private $processor;
public function __construct(\BTCPay $module, \Context $context, Client $client)
{
$this->context = $context;
$this->configuration = new Configuration();
$this->processor = new Processor($module, $context, $this->configuration, $client);
}
/**
* @throws \PrestaShopDatabaseException
* @throws \JsonException
* @throws \PrestaShopException
*/
public function process(Request $request): void
{
$data = \json_decode($request->getContent(), true, 512, \JSON_THROW_ON_ERROR);
if (false === $data || null === $data) {
return;
}
// Check if we received an event
if (!\array_key_exists('type', $data) || !\array_key_exists('invoiceId', $data)) {
return;
}
// If it's a test, just accept it
if (\str_contains($data['invoiceId'], '__test__')) {
\PrestaShopLogger::addLog(\sprintf('[INFO] Received test IPN: %s', \json_encode($data, \JSON_THROW_ON_ERROR)));
return;
}
// Get the data type
$eventType = (string) $data['type'];
// Get order mode
$orderMode = $this->configuration->get(Constants::CONFIGURATION_ORDER_MODE);
// Payment has been received (order already exists)
if (Constants::ORDER_MODE_BEFORE === $orderMode && \in_array($eventType, ['InvoiceProcessing', 'InvoicePaidInFull', 'InvoiceReceivedPayment'], true)) {
$this->paymentReceived($data);
return;
}
// Payment has been received (order needs to be made)
if (Constants::ORDER_MODE_AFTER === $orderMode && \in_array($eventType, ['InvoiceProcessing', 'InvoicePaidInFull', 'InvoiceReceivedPayment'], true)) {
$this->paymentReceivedDelayedOrder($data);
return;
}
// Payment has been confirmed
if ('InvoicePaymentSettled' === $eventType) {
$this->paymentSettled($data);
return;
}
// Invoice has failed or expired
if (\in_array($eventType, ['InvoiceInvalid', 'InvoiceExpired'], true)) {
$this->invoiceFailed($data);
return;
}
// Invoice has been confirmed
if ('InvoiceSettled' === $eventType) {
$this->invoiceSettled($data);
return;
}
// Invoice was crated, but either order already exists or will be created on first payment, skip
if ('InvoiceCreated' === $eventType) {
return;
}
// Log other IPN's.
\PrestaShopLogger::addLog('[INFO] Received IPN that we did not process IPN');
\PrestaShopLogger::addLog(\sprintf('[INFO] Received IPN: %s', \json_encode($data, \JSON_THROW_ON_ERROR)));
}
/**
* @throws \PrestaShopDatabaseException
* @throws \PrestaShopException
* @throws \JsonException
*/
private function paymentReceived(array $data): void
{
$invoiceId = (string) $data['invoiceId'];
\PrestaShopLogger::addLog(\sprintf('[INFO] Payment received for invoice %s', $invoiceId));
if (null === ($bitcoinPayment = BitcoinPaymentRepository::getOneByInvoiceID($invoiceId))) {
$error = \sprintf('[WARNING] Could not load order with invoice ID %s', $invoiceId);
\PrestaShopLogger::addLog(\sprintf('[INFO] Received IPN: %s', \json_encode($data, \JSON_THROW_ON_ERROR)));
\PrestaShopLogger::addLog($error, \PrestaShopLogger::LOG_SEVERITY_LEVEL_WARNING);
// Don't bother retrying
return;
}
$this->processor->paymentReceived($bitcoinPayment);
}
/**
* @throws \PrestaShopDatabaseException
* @throws \PrestaShopException
* @throws \JsonException
*/
private function paymentReceivedDelayedOrder(array $data): void
{
$invoiceId = (string) $data['invoiceId'];
\PrestaShopLogger::addLog(\sprintf('[INFO] Payment received for invoice %s', $invoiceId));
if (null === ($bitcoinPayment = BitcoinPaymentRepository::getOneByInvoiceID($invoiceId))) {
$error = \sprintf('[WARNING] Could not load order with invoice ID %s', $invoiceId);
\PrestaShopLogger::addLog(\sprintf('[INFO] Received IPN: %s', \json_encode($data, \JSON_THROW_ON_ERROR)));
\PrestaShopLogger::addLog($error, \PrestaShopLogger::LOG_SEVERITY_LEVEL_WARNING);
// Don't bother retrying
return;
}
// Deal with the actual invoice now
$this->processor->paymentReceivedCreateAfter($bitcoinPayment);
}
/**
* @throws \PrestaShopDatabaseException
* @throws \PrestaShopException
* @throws \JsonException
*/
private function paymentSettled(array $data): void
{
$invoiceId = (string) $data['invoiceId'];
\PrestaShopLogger::addLog(\sprintf('[INFO] One of the payments has settled for invoice %s', $invoiceId));
if (null === ($bitcoinPayment = BitcoinPaymentRepository::getOneByInvoiceID($invoiceId))) {
$error = \sprintf('[WARNING] Could not load order with invoice ID %s', $invoiceId);
\PrestaShopLogger::addLog(\sprintf('[INFO] Received IPN: %s', \json_encode($data, \JSON_THROW_ON_ERROR)));
\PrestaShopLogger::addLog($error, \PrestaShopLogger::LOG_SEVERITY_LEVEL_WARNING);
// Don't bother retrying
return;
}
// Deal with the actual invoice now
$this->processor->paymentSettled($bitcoinPayment);
}
/**
* @throws \JsonException
* @throws \PrestaShopDatabaseException
* @throws \PrestaShopException
*/
private function invoiceFailed(array $data): void
{
$invoiceId = (string) $data['invoiceId'];
\PrestaShopLogger::addLog(\sprintf("[INFO] Invoice '%s' failed, either because it wasn't paid, it expired or it was marked as invalid", $invoiceId));
if (null === ($bitcoinPayment = BitcoinPaymentRepository::getOneByInvoiceID($invoiceId))) {
$error = \sprintf('[WARNING] Could not load order with invoice ID %s', $invoiceId);
\PrestaShopLogger::addLog(\sprintf('[INFO] Received IPN: %s', \json_encode($data, \JSON_THROW_ON_ERROR)));
\PrestaShopLogger::addLog($error, \PrestaShopLogger::LOG_SEVERITY_LEVEL_WARNING);
// Don't bother retrying
return;
}
// If there is no order, don't bother updating it
if (false === $bitcoinPayment->hasOrder()) {
return;
}
// Check if protection is disabled, if so, just process the failure
if (false === $this->configuration->get(Constants::CONFIGURATION_PROTECT_ORDERS, true)) {
$this->processor->invoiceFailed($bitcoinPayment);
}
// Otherwise, will need to check the order so fetch it
$order = new \Order($bitcoinPayment->getOrderId());
// Check if the order has been paid, if so, add a note and abort
if (\Validate::isLoadedObject($orderState = $order->getCurrentOrderState()) && $orderState->paid) {
// Ensure we log this IPN
\PrestaShopLogger::addLog(\sprintf('[INFO] Received IPN: %s', \json_encode($data, \JSON_THROW_ON_ERROR)));
\PrestaShopLogger::addLog(\sprintf("[WARN] Webhook ('%s') received from BTCPay Server, but the order was already marked as paid.", $data['type']), \PrestaShopLogger::LOG_SEVERITY_LEVEL_WARNING, null, 'Order', $order->id);
// Build a simple note and add it to the order
$note = \sprintf("BTCPay Server: Webhook ('%s') received, but the order was already marked as paid.", $data['type']);
CustomerMessage::addToOrder($this->context->shop, $order, $note);
// Don't bother with the rest
return;
}
// The order has not been set to paid, process the failure
$this->processor->invoiceFailed($bitcoinPayment);
}
/**
* @throws \JsonException
* @throws \PrestaShopException
* @throws \PrestaShopDatabaseException
*/
private function invoiceSettled(array $data): void
{
$invoiceId = (string) $data['invoiceId'];
\PrestaShopLogger::addLog(\sprintf("[INFO] Invoice '%s' has been settled and thus fully paid", $invoiceId));
if (null === ($bitcoinPayment = BitcoinPaymentRepository::getOneByInvoiceID($invoiceId))) {
$error = \sprintf('[WARNING] Could not load order with invoice ID %s', $invoiceId);
\PrestaShopLogger::addLog(\sprintf('[INFO] Received IPN: %s', \json_encode($data, \JSON_THROW_ON_ERROR)));
\PrestaShopLogger::addLog($error, \PrestaShopLogger::LOG_SEVERITY_LEVEL_WARNING);
// Don't bother retrying
return;
}
// If there is no order, don't bother updating it
if (false === $bitcoinPayment->hasOrder()) {
return;
}
$this->processor->invoiceSettled($bitcoinPayment);
}
}

View File

@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@ -1,10 +1,20 @@
<?php
use PrestaShop\PrestaShop\Core\Module\ModuleInterface;
if (!defined('_PS_VERSION_')) {
exit;
}
function upgrade_module_2_0_0(): bool
/**
* @param BTCpay|ModuleInterface|mixed $module
*/
function upgrade_module_2_0_0(mixed $module): bool
{
if (!$module instanceof BTCPay) {
throw new LogicException('Received invalid module');
}
// Add invoice reference
return Db::getInstance()->Execute('ALTER TABLE `' . _DB_PREFIX_ . 'order_bitcoin` ADD invoice_reference varchar(255) AFTER invoice_id');
}

View File

@ -1,5 +1,6 @@
<?php
use BTCPay\Constants;
use PrestaShop\PrestaShop\Core\Module\ModuleInterface;
if (!defined('_PS_VERSION_')) {
@ -7,9 +8,11 @@ if (!defined('_PS_VERSION_')) {
}
/**
* @param BTCpay $module
* @param BTCpay|ModuleInterface|mixed $module
*
* @throws JsonException
*/
function upgrade_module_3_0_0(ModuleInterface $module): bool
function upgrade_module_3_0_0(mixed $module): bool
{
if (!$module instanceof BTCPay) {
throw new LogicException('Received invalid module');
@ -31,7 +34,7 @@ function updateDatabase(): bool
/** @var PDO $connection */
$connection = Db::getInstance()->connect();
// Start a transaction so we don't fuck up the database if shit goes wrong
// Start a transaction, so we don't mess up the database if something goes wrong
$connection->beginTransaction();
$queries = [
@ -49,7 +52,7 @@ function updateDatabase(): bool
];
foreach ($queries as $query) {
// Execute query
// Execute the query
if (false === $connection->query($query)) {
// Cancel the transaction
if (false === $connection->rollBack()) {
@ -99,10 +102,10 @@ function updateConfig(): bool
// Add old order states to the configuration
$order_states = [
'BTCPAY_OS_WAITING' => 39,
'BTCPAY_OS_CONFIRMING' => 40,
'BTCPAY_OS_FAILED' => 41,
'BTCPAY_OS_PAID' => 42,
Constants::CONFIGURATION_ORDER_STATE_WAITING => 39,
Constants::CONFIGURATION_ORDER_STATE_CONFIRMING => 40,
Constants::CONFIGURATION_ORDER_STATE_FAILED => 41,
Constants::CONFIGURATION_ORDER_STATE_PAID => 42,
];
foreach ($order_states as $order_state => $id) {

Some files were not shown because too many files have changed in this diff Show More