-
Notifications
You must be signed in to change notification settings - Fork 41
feature: paypal commerce agent #322
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft
Lennart Tinkloh (lernhart)
wants to merge
47
commits into
trunk
Choose a base branch
from
feature/paypal-commerce-agent
base: trunk
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from 28 commits
Commits
Show all changes
47 commits
Select commit
Hold shift + click to select a range
d0eee21
feat: paypal-commerce-ai-route-scopes (#299)
lernhart e696f7b
feat: paypal commerce agent sales channel (#305)
lernhart b29f964
feat: paypal resolver (#324)
En0Ma1259 7ad9a74
feat: PayPal data transformer (#325)
En0Ma1259 284a9da
feat: route response (#316)
En0Ma1259 5c2c3ba
Merge remote-tracking branch 'origin/trunk' into feature/paypal-comme…
En0Ma1259 5f2225f
feat: delete old billing address (#341)
En0Ma1259 9ffd988
feat: added price validation (#347)
En0Ma1259 ca5c54c
feat: convert cart errors (#349)
En0Ma1259 0206052
fix: JWT token handling according to PayPal (#359)
lernhart 5dbd94b
Merge branch 'trunk' into feature/paypal-commerce-agent
En0Ma1259 290a8de
Merge branch 'trunk' into feature/paypal-commerce-agent
En0Ma1259 6331ad1
feat: webhook for Agentic Commerce (#362)
En0Ma1259 d9ea76c
feat: added tests+ (#368)
En0Ma1259 36b3822
Merge branch 'trunk' into feature/paypal-commerce-agent
En0Ma1259 bc937b1
Unit tests (#378)
En0Ma1259 d1e17f8
feat: save paypal webhook status (#367)
En0Ma1259 5f04631
Merge branch 'trunk' into feature/paypal-commerce-agent
En0Ma1259 c24649a
feat: load favicon (#386)
En0Ma1259 8d93d18
fix: change signed with (#389)
En0Ma1259 7866697
feat: paypal commerce agent checkout (#333)
lernhart 3f84dec
Merge branch 'trunk' into feature/paypal-commerce-agent
En0Ma1259 e4b7124
Merge branch 'trunk' into feature/paypal-commerce-agent
En0Ma1259 94da79d
feat: change shipping method (#398)
En0Ma1259 73218eb
feat: create coupons (#413)
En0Ma1259 1d84c21
feat: route tests (#417)
En0Ma1259 f1eb416
feat: subscriber tests (#422)
En0Ma1259 8e33a2b
Merge remote-tracking branch 'origin/trunk' into feature/paypal-comme…
En0Ma1259 615f232
wrong method name
En0Ma1259 76a0b91
change namespace
En0Ma1259 724de3b
small changes
En0Ma1259 dea3423
Merge remote-tracking branch 'origin/trunk' into feature/paypal-comme…
En0Ma1259 95c94ba
Merge branch 'trunk' into feature/paypal-commerce-agent
En0Ma1259 d140c6b
Merge branch 'trunk' into feature/paypal-commerce-agent
En0Ma1259 7f0d155
Merge branch 'trunk' into feature/paypal-commerce-agent
En0Ma1259 0cde9b9
feat: Added country state (#518)
En0Ma1259 6e59d06
fix: external id validation
lernhart f4c0196
Merge branch 'trunk' into feature/paypal-commerce-agent
En0Ma1259 8e0a064
fix phpstan errors
En0Ma1259 ef206a1
fix: public key mismatch
lernhart d4fa672
Merge remote-tracking branch 'origin/feature/paypal-commerce-agent' i…
lernhart 97fe950
fix: bearer auth header + update cart route scope
lernhart c9499e2
fix: remove available shipping methods which do not have calculated p…
lernhart 42105a9
fix: route scope + shipping address response format
lernhart 0b2afca
Merge branch 'trunk' into feature/paypal-commerce-agent
En0Ma1259 1f820a0
feat: external id contraint (#528)
En0Ma1259 39c1bdc
Merge branch 'trunk' into feature/paypal-commerce-agent
En0Ma1259 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or 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 hidden or 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 hidden or 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 hidden or 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 hidden or 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,172 @@ | ||
| <?php declare(strict_types=1); | ||
| /* | ||
| * (c) shopware AG <info@shopware.com> | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
|
|
||
| namespace Swag\PayPal\AgentCommerce\Exception; | ||
|
|
||
| use Shopware\Core\Framework\Log\Package; | ||
| use Shopware\PayPalSDK\Struct\AgenticCommerce\V1\AgentErrorDetail; | ||
| use Shopware\PayPalSDK\Struct\AgenticCommerce\V1\AgentErrorDetailCollection; | ||
| use Symfony\Component\HttpFoundation\Response; | ||
|
|
||
| #[Package('checkout')] | ||
| class AgentException extends AgentHttpException | ||
| { | ||
| public const INVALID_REQUEST = 'INVALID_REQUEST'; | ||
| public const INVALID_CART_ID = 'INVALID_CART_ID'; | ||
| public const CART_NOT_FOUND = 'CART_NOT_FOUND'; | ||
| public const INTERNAL_SERVER_ERROR = 'INTERNAL_SERVER_ERROR'; | ||
| public const SERVICE_UNAVAILABLE = 'SERVICE_UNAVAILABLE'; | ||
| public const PAYMENT_PROCESSOR_UNAVAILABLE = 'PAYMENT_PROCESSOR_UNAVAILABLE'; | ||
| public const PAYMENT_CAPTURE_FAILED = 'PAYMENT_CAPTURE_FAILED'; | ||
| public const INVENTORY_SYSTEM_ERROR = 'INVENTORY_SYSTEM_ERROR'; | ||
| public const ORDER_SYSTEM_ERROR = 'ORDER_SYSTEM_ERROR'; | ||
|
|
||
| public static function requiredFieldsMissing(string ...$fields): self | ||
| { | ||
| $message = 'Required field \'{{ fields }}\' is missing'; | ||
| $parameters = ['fields' => implode(', ', $fields)]; | ||
| $details = new AgentErrorDetailCollection(); | ||
|
|
||
| foreach ($fields as $field) { | ||
| $detail = (new AgentErrorDetail()); | ||
| $detail->setField($field); | ||
| $detail->setIssue('MISSING_REQUIRED_FIELD'); | ||
| $detail->setDescription(\sprintf('The field \'%s\' is required and cannot be empty', $field)); | ||
|
|
||
| $details->add($detail); | ||
| } | ||
|
|
||
| return new self( | ||
| Response::HTTP_BAD_REQUEST, | ||
| self::INVALID_REQUEST, | ||
| $message, | ||
| $parameters, | ||
| $details | ||
| ); | ||
| } | ||
|
|
||
| public static function requiredFieldInvalid(string $field, string $reason): self | ||
| { | ||
| $message = 'Required field \'{{ field }}\' is invalid: \'{{ reason }}\''; | ||
| $parameters = ['field' => $field, 'reason' => $reason]; | ||
|
|
||
| $detail = new AgentErrorDetail(); | ||
| $detail->setField($field); | ||
| $detail->setIssue('MISSING_REQUIRED_FIELD'); | ||
| $detail->setDescription(\sprintf('The field \'%s\' is invalid: %s', $field, $reason)); | ||
|
|
||
| return new self( | ||
| Response::HTTP_BAD_REQUEST, | ||
| self::INVALID_REQUEST, | ||
| $message, | ||
| $parameters, | ||
| new AgentErrorDetailCollection([$detail]) | ||
| ); | ||
| } | ||
|
|
||
| public static function invalidJSONFormat(): self | ||
| { | ||
| return new self( | ||
| Response::HTTP_BAD_REQUEST, | ||
| self::INVALID_REQUEST, | ||
| 'Request body contains invalid JSON' | ||
| ); | ||
| } | ||
|
|
||
| public static function unauthorized(string $message, ?\Throwable $previous = null): self | ||
| { | ||
| return new self( | ||
| Response::HTTP_UNAUTHORIZED, | ||
| self::INVALID_REQUEST, | ||
| $message, | ||
| previous: $previous, | ||
| ); | ||
| } | ||
|
|
||
| public static function invalidCartId(): self | ||
| { | ||
| return new self( | ||
| Response::HTTP_BAD_REQUEST, | ||
| self::INVALID_CART_ID, | ||
| 'Cart ID format is invalid. Expected format: CART-[a-zA-Z0-9]{32}' | ||
| ); | ||
| } | ||
|
|
||
| public static function cartNotFound(string $token): self | ||
| { | ||
| return new self( | ||
| Response::HTTP_NOT_FOUND, | ||
| self::CART_NOT_FOUND, | ||
| 'Cart with ID \'{{ token }}\' does not exist', | ||
| ['token' => $token] | ||
| ); | ||
| } | ||
|
|
||
| public static function databaseConnectionFailure(): self | ||
| { | ||
| return new self( | ||
| Response::HTTP_INTERNAL_SERVER_ERROR, | ||
| self::INTERNAL_SERVER_ERROR, | ||
| 'A temporary system error occurred. Please try again later.' | ||
| ); | ||
| } | ||
|
|
||
| public static function externalServiceFailure(): self | ||
| { | ||
| return new self( | ||
| Response::HTTP_INTERNAL_SERVER_ERROR, | ||
| self::SERVICE_UNAVAILABLE, | ||
| 'The payment processor is currently unavailable. Please try again later.' | ||
| ); | ||
| } | ||
|
|
||
| public static function paymentProcessorUnavailable(): self | ||
| { | ||
| return new self( | ||
| Response::HTTP_INTERNAL_SERVER_ERROR, | ||
| self::PAYMENT_PROCESSOR_UNAVAILABLE, | ||
| 'Payment processing is temporarily unavailable' | ||
| ); | ||
| } | ||
|
|
||
| public static function paymentCaptureFailed(string $message): self | ||
| { | ||
| $detail = (new AgentErrorDetail()); | ||
| $detail->setField('payment_method'); | ||
| $detail->setIssue('CAPTURE_FAILED'); | ||
| $detail->setDescription($message); | ||
|
|
||
| $details = new AgentErrorDetailCollection([$detail]); | ||
|
|
||
| return new self( | ||
| Response::HTTP_INTERNAL_SERVER_ERROR, | ||
| self::PAYMENT_CAPTURE_FAILED, | ||
| 'Unable to capture payment at this time', | ||
| [], | ||
| $details | ||
| ); | ||
| } | ||
|
|
||
| public static function inventorySystemError(): self | ||
| { | ||
| return new self( | ||
| Response::HTTP_INTERNAL_SERVER_ERROR, | ||
| self::INVENTORY_SYSTEM_ERROR, | ||
| 'Unable to reserve inventory for checkout' | ||
| ); | ||
| } | ||
|
|
||
| public static function orderSystemError(?\Throwable $previous = null): self | ||
| { | ||
| return new self( | ||
| Response::HTTP_INTERNAL_SERVER_ERROR, | ||
| self::ORDER_SYSTEM_ERROR, | ||
| 'Order could not be created due to system error', | ||
| previous: $previous, | ||
| ); | ||
| } | ||
| } |
This file contains hidden or 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,32 @@ | ||
| <?php declare(strict_types=1); | ||
| /* | ||
| * (c) shopware AG <info@shopware.com> | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
|
|
||
| namespace Swag\PayPal\AgentCommerce\Exception; | ||
|
|
||
| use Shopware\Core\Framework\HttpException; | ||
| use Shopware\Core\Framework\Log\Package; | ||
| use Shopware\PayPalSDK\Struct\AgenticCommerce\V1\AgentErrorDetailCollection; | ||
|
|
||
| #[Package('checkout')] | ||
| abstract class AgentHttpException extends HttpException | ||
| { | ||
| public function __construct( | ||
| int $statusCode, | ||
| string $errorCode, | ||
| string $message, | ||
| array $parameters = [], | ||
| protected AgentErrorDetailCollection $details = new AgentErrorDetailCollection(), | ||
| ?\Throwable $previous = null | ||
| ) { | ||
| parent::__construct($statusCode, $errorCode, $message, $parameters, $previous); | ||
| } | ||
|
|
||
| public function getDetails(): AgentErrorDetailCollection | ||
| { | ||
| return $this->details; | ||
| } | ||
| } |
This file contains hidden or 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,82 @@ | ||
| <?php declare(strict_types=1); | ||
| /* | ||
| * (c) shopware AG <info@shopware.com> | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
|
|
||
| namespace Swag\PayPal\AgentCommerce\Exception; | ||
|
|
||
| use Shopware\Core\Framework\HttpException; | ||
| use Shopware\Core\Framework\Log\Package; | ||
| use Swag\PayPal\AgentCommerce\HoneyWebhookResult; | ||
| use Symfony\Component\HttpFoundation\Response; | ||
|
|
||
| /** | ||
| * @internal | ||
| */ | ||
| #[Package('checkout')] | ||
| class HoneyWebhookException extends HttpException | ||
| { | ||
| public const API_ERROR = 'API_ERROR'; | ||
| public const NOT_REGISTERED = 'NOT_REGISTERED'; | ||
| public const SALES_CHANNEL_NOT_FOUND = 'SALES_CHANNEL_NOT_FOUND'; | ||
| public const PRODUCT_EXPORT_NOT_FOUND = 'PRODUCT_EXPORT_NOT_FOUND'; | ||
| public const STOREFRONT_SALES_CHANNEL_NOT_FOUND = 'STOREFRONT_SALES_CHANNEL_NOT_FOUND'; | ||
| public const INVALID_PRODUCT_EXPORT_ROUTE = 'INVALID_PRODUCT_EXPORT_ROUTE'; | ||
|
|
||
| public static function salesChannelNotRegistered(): self | ||
| { | ||
| return new self( | ||
| Response::HTTP_BAD_REQUEST, | ||
| self::NOT_REGISTERED, | ||
| 'Sales channel is not registered and can\'t be deregistered' | ||
| ); | ||
| } | ||
|
|
||
| public static function invalidSalesChannel(): self | ||
| { | ||
| return new self( | ||
| Response::HTTP_BAD_REQUEST, | ||
| self::SALES_CHANNEL_NOT_FOUND, | ||
| 'Agent commerce sales channel not found' | ||
| ); | ||
| } | ||
|
|
||
| public static function productExportNotFound(): self | ||
| { | ||
| return new self( | ||
| Response::HTTP_BAD_REQUEST, | ||
| self::PRODUCT_EXPORT_NOT_FOUND, | ||
| 'Product export sales channel not found' | ||
| ); | ||
| } | ||
|
|
||
| public static function storefrontSalesChannelNotFound(): self | ||
| { | ||
| return new self( | ||
| Response::HTTP_BAD_REQUEST, | ||
| self::STOREFRONT_SALES_CHANNEL_NOT_FOUND, | ||
| 'Storefront sales channel not found' | ||
| ); | ||
| } | ||
|
|
||
| public static function invalidProductExportRoute(): self | ||
| { | ||
| return new self( | ||
| Response::HTTP_BAD_REQUEST, | ||
| self::INVALID_PRODUCT_EXPORT_ROUTE, | ||
| 'Invalid product export route' | ||
| ); | ||
| } | ||
|
|
||
| public static function invalidRequest(HoneyWebhookResult $result): self | ||
| { | ||
| return new self( | ||
| Response::HTTP_BAD_REQUEST, | ||
| self::API_ERROR . '_' . $result->error, | ||
| $result->message, | ||
| previous: $result->exception, | ||
| ); | ||
| } | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Need to be changed