-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* EXS-126 - Added In-App purchase modal * EXS-126 - Fixed PHPStan errors and linter issues * EXS-126 - Added tests for checkout-button, checkout-state, overview and price-box; * NEXT - 37408 - IAP badge * EXS-127 - Added listing modal for IAPs * EXS-127 - Listing modal completed * EXS-127 - Logic to get the list * EXS-127 - Design and phpstan changes * EXS-127 - Updated code to use id not string * EXS-127 - Added check for IAP's before calling list * EXS-127 - Styling updates * EXS-127 - Update URL's * EXS-128 - Update endpoints and data types * NEXT-36303 - Small changes to get code in line with SBP and fix some issues * EXS-127 - Moved translations * NEXT-38473 - Refresh IAP's after purchase * NEXT-36303 - Fixed an issue where the return type wasn't valid * NEXT-36303 - Fixed admin install * NEXT-37409 - Add licensed IAP flag and badge * NEXT-36303 - Code review improvements * NEXT-38822 - Add filter gateway to list and checkout calls * NEXT-37049 - Add licensed iap flag * NEXT-39485 - Fixed gateway * NEXT-39467 - Replaced syncer with updater * NEXT-39461 - Changed handling of updated response * NEXT-36303 - Github workflow changes * NEXT-36303 - Git workflow updates by pweyck * NEXT-36303 - Code review changes * NEXT-36303 - Linter changes * NEXT-36303 - Test changes and fixes --------- Co-authored-by: Michel Bade <[email protected]> Co-authored-by: Albert Scherman <[email protected]> Co-authored-by: Patrick Weyck <[email protected]> Co-authored-by: Albert Scherman <[email protected]> Co-authored-by: Philip Reinken <[email protected]> Co-authored-by: Max Stegmeyer <[email protected]>
- Loading branch information
1 parent
1294c2c
commit 362dd7b
Showing
64 changed files
with
4,293 additions
and
846 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace SwagExtensionStore\Controller; | ||
|
||
use Shopware\Core\Framework\App\AppCollection; | ||
use Shopware\Core\Framework\App\AppEntity; | ||
use Shopware\Core\Framework\App\InAppPurchases\Gateway\InAppPurchasesGateway; | ||
use Shopware\Core\Framework\App\InAppPurchases\Payload\InAppPurchasesPayload; | ||
use Shopware\Core\Framework\Context; | ||
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository; | ||
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria; | ||
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter; | ||
use Shopware\Core\Framework\Log\Package; | ||
use Shopware\Core\Framework\Store\InAppPurchase\Services\InAppPurchaseUpdater; | ||
use Shopware\Core\Framework\Store\Services\AbstractExtensionDataProvider; | ||
use Shopware\Core\Framework\Validation\DataBag\RequestDataBag; | ||
use SwagExtensionStore\Exception\ExtensionStoreException; | ||
use SwagExtensionStore\Services\InAppPurchasesService; | ||
use SwagExtensionStore\Struct\InAppPurchaseCartPositionCollection; | ||
use Symfony\Component\HttpFoundation\JsonResponse; | ||
use Symfony\Component\HttpFoundation\Response; | ||
use Symfony\Component\Routing\Attribute\Route; | ||
|
||
/** | ||
* @internal | ||
*/ | ||
#[Package('checkout')] | ||
#[Route(defaults: ['_routeScope' => ['api']])] | ||
class InAppPurchasesController | ||
{ | ||
/** | ||
* @param EntityRepository<AppCollection> $appRepository | ||
*/ | ||
public function __construct( | ||
private readonly InAppPurchasesService $inAppPurchasesService, | ||
private readonly InAppPurchaseUpdater $inAppPurchaseUpdater, | ||
private readonly AbstractExtensionDataProvider $extensionDataProvider, | ||
private readonly InAppPurchasesGateway $appPurchasesGateway, | ||
private readonly EntityRepository $appRepository, | ||
) {} | ||
|
||
#[Route('/api/_action/in-app-purchases/{technicalName}/details', name: 'api.in-app-purchases.detail', methods: ['GET'])] | ||
public function getInAppFeature(string $technicalName, Context $context): Response | ||
{ | ||
$criteria = new Criteria(); | ||
$criteria->addFilter(new EqualsFilter('name', $technicalName)); | ||
|
||
$extension = $this->extensionDataProvider | ||
->getInstalledExtensions($context, false, $criteria) | ||
->first(); | ||
|
||
return new JsonResponse($extension); | ||
} | ||
|
||
#[Route('/api/_action/in-app-purchases/cart/new', name: 'api.in-app-purchases.cart.new', methods: ['POST'])] | ||
public function createCart(RequestDataBag $data, Context $context): Response | ||
{ | ||
$name = $data->getString('name'); | ||
$feature = $data->getString('feature'); | ||
|
||
$cart = $this->inAppPurchasesService->createCart($name, $feature, $context); | ||
|
||
return new JsonResponse($cart); | ||
} | ||
|
||
#[Route('/api/_action/in-app-purchases/cart/order', name: 'api.in-app-purchases.cart.order', methods: ['POST'])] | ||
public function orderCart(RequestDataBag $data, Context $context): Response | ||
{ | ||
$taxRate = \floatval($data->getString('taxRate')); | ||
$positions = $data->get('positions'); | ||
$extensionName = $data->get('name'); | ||
|
||
$positionCollection = InAppPurchaseCartPositionCollection::fromArray($positions->all()); | ||
|
||
$app = $this->getAppByName($extensionName, $context); | ||
if (!$app) { | ||
// if no app is found, it's a plugin, and no filtering will happen | ||
return $this->inAppPurchasesService->orderCart($taxRate, $positionCollection->toCart(), $context); | ||
} | ||
|
||
$payload = new InAppPurchasesPayload($positionCollection->getIdentifiers()); | ||
$iapGatewayResponse = $this->appPurchasesGateway->process($payload, $context, $app); | ||
if (!$iapGatewayResponse) { | ||
// if $iapGatewayResponse is null, the app does not have a gateway url, and no filtering will happen | ||
return $this->inAppPurchasesService->orderCart($taxRate, $positionCollection->toCart(), $context); | ||
} | ||
|
||
$positionCollection = $positionCollection->filterValidInAppPurchases($positionCollection, $iapGatewayResponse->purchases); | ||
if ($positionCollection->count() === 0) { | ||
throw ExtensionStoreException::invalidInAppPurchase(); | ||
} | ||
|
||
return $this->inAppPurchasesService->orderCart($taxRate, $positionCollection->toCart(), $context); | ||
} | ||
|
||
#[Route('/api/_action/in-app-purchases/{extensionName}/list', name: 'api.in-app-purchase.list', methods: ['GET'])] | ||
public function listPurchases(string $extensionName, Context $context): Response | ||
{ | ||
$purchases = $this->inAppPurchasesService->listPurchases($extensionName, $context); | ||
|
||
$app = $this->getAppByName($extensionName, $context); | ||
if (!$app) { | ||
return new JsonResponse($purchases); | ||
} | ||
|
||
$payload = new InAppPurchasesPayload($purchases->getIdentifiers()); | ||
$validCartItems = $this->appPurchasesGateway->process($payload, $context, $app); | ||
if (!$validCartItems) { | ||
return new JsonResponse($purchases); | ||
} | ||
|
||
$purchases = $purchases->filterValidInAppPurchases($purchases, $validCartItems->purchases); | ||
if ($purchases->count() === 0) { | ||
throw ExtensionStoreException::invalidInAppPurchase(); | ||
} | ||
|
||
return new JsonResponse($purchases); | ||
} | ||
|
||
#[Route('/api/_action/in-app-purchases/refresh', name: 'api.in-app-purchase.refresh', methods: ['GET'])] | ||
public function refreshInAppPurchases(Context $context): Response | ||
{ | ||
$context->scope(Context::SYSTEM_SCOPE, function (Context $context) { | ||
$this->inAppPurchaseUpdater->update($context); | ||
}); | ||
|
||
return new JsonResponse(status: Response::HTTP_NO_CONTENT); | ||
} | ||
|
||
private function getAppByName(string $appName, Context $context): ?AppEntity | ||
{ | ||
$criteria = new Criteria(); | ||
$criteria->setLimit(1); | ||
$criteria->addFilter(new EqualsFilter('name', $appName)); | ||
|
||
return $this->appRepository->search($criteria, $context)->getEntities()->first(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.