Wie kann ich die Stripe Live Tax API in Shopware 6 integrieren?

Für E-Commerce-Websites ist eine Live-Berechnung des Steuersatzes erforderlich. Um die Einhaltung dynamischer Steuersätze sicherzustellen, das Kundenerlebnis durch genaue Kostentransparenz zu verbessern und Prozesse für effiziente globale Abläufe zu automatisieren.

Diese Funktion garantiert fehlerfreie Steuerberechnungen in Echtzeit und ermöglicht nahtlose Transaktionen und präzise Finanzberichte.

Schritte zur Live-Steuerberechnung mit der Stripe Lve Tax API

  • Sammeln Sie den API-Schlüssel vom Stripe-Entwicklerkonto.
    • Melden Sie sich beim Stripe-Dashboard an
    • Wählen Sie in der Kopfzeile das Menü „Entwickler“.
    • Wählen Sie die Registerkarte „API-Schlüssel“ und erstellen Sie einen Schlüssel

https://tinyurl.com/yr377vh5

  • Erstellen Sie einen neuen Abonnenten mit dem Ereignis CartChangedEventSubscriber

Registrieren Sie den Abonnenten in der Dienstdatei

/custom/plugins/HatslogicLiveTax/src/Resources/config/services.xml

 <service id="HatslogicLiveTax\Subscriber\CartChangedEventSubscriber">
           <argument type="service" id="request_stack"/>
           <argument type="service" id="HatslogicLiveTax\Service\CustomTax"/>
           <tag name="kernel.event_subscriber"/>
 </service>

Das Gleiche müssen wir auch für die folgenden Abonnenten tun

  • CustomerAddressWrittenSubscriber
  • CustomerSetDefaultShippingAddressEventSubscriber
  • CustomerLoginEventSubscriber
<service id="HatslogicLiveTax\Subscriber\CustomerAddressWrittenSubscriber">
            <argument type="service" id="customer_address.repository"/>
            <argument type="service" id="request_stack"/>
            <argument type="service" id="Doctrine\DBAL\Connection"/>
            <tag name="kernel.event_subscriber"/>
        </service>
        <service id="HatslogicLiveTax\Subscriber\CustomerSetDefaultShippingAddressEventSubscriber">
            <argument type="service" id="request_stack"/>
            <argument type="service" id="HatslogicLiveTax\Service\CustomTax"/>
            <argument type="service" id="Shopware\Core\Checkout\Cart\SalesChannel\CartService"/>
            <argument type="service" id="customer_address.repository"/>
            <tag name="kernel.event_subscriber"/>
        </service>
        <service id="HatslogicLiveTax\Subscriber\CustomerLoginEventSubscriber">
            <argument type="service" id="request_stack"/>
            <argument type="service" id="HatslogicLiveTax\Service\CustomTax"/>
            <argument type="service" id="Shopware\Core\Checkout\Cart\SalesChannel\CartService"/>
            <tag name="kernel.event_subscriber"/>
        </service>

Erstellen Sie die Teilnehmerdatei in

/custom/plugins/HatslogicLiveTax/src/Subscriber/CartChangedEventSubscriber.php

  • <?php declare(strict_types=1);
    namespace Hatslogic\Subscriber;
    use Hatslogic\Service\CustomTax;
    use Symfony\Component\EventDispatcher\EventSubscriberInterface;
    use Shopware\Core\Checkout\Cart\Event\CartChangedEvent;
    use Symfony\Component\HttpFoundation\RequestStack;
    class CartChangedEventSubscriber implements EventSubscriberInterface
    {
        private $requestStack;
        private $customTax;
        public function __construct(
            RequestStack $requestStack,
            CustomTax $customTax
        )
        {
            $this->requestStack = $requestStack;
            $this->customTax = $customTax;
        }
        public static function getSubscribedEvents()
        {
           return [
               CartChangedEvent::class => 'onEvent'
           ];
        }
        public function onEvent(CartChangedEvent $event)
        { 
            $salesChannelContext    =  $event->getContext();
            $context                = $salesChannelContext->getContext();
            $cart                   = $event->getCart();
            $customer               = $salesChannelContext->getCustomer();
            $shippingLocation       = $salesChannelContext->getShippingLocation(); 
            if($customer and $cart->getLineItems()->count()){ 
                $products = $cart->getLineItems();
                $taxData = $this->customTax->getLineitemTax( $products, $shippingLocation->getAddress(), $context ); 
                $this->requestStack->getSession()->set('HatslogicTaxData', $taxData);
            }
        }
    }

    Erstellen Sie eine Dienstklasse namens CustomTax unter folgendem Pfad /custom/plugins/HatslogicLiveTax/src/Service/CustomTax.php

<service id="HatslogicLiveTax\Service\CustomTax">
            <argument type="service" id="Shopware\Core\System\SystemConfig\SystemConfigService"/>
            <argument type="service" id="Shopware\Core\System\SalesChannel\Context\SalesChannelContextService"/>
            <argument type="service" id="order.repository"/>
            <argument type="service" id="product.repository"/>
            <argument type="service" id="request_stack"/>
</service>

Hier können wir den Code für den API-Aufruf schreiben und auch zusätzliche Logik hinzufügen, wenn wir sie haben.

<?php
namespace HatslogicLiveTax\Service;
use GuzzleHttp\Client as HttpClient;
use Shopware\Core\Checkout\Cart\Cart;
use Shopware\Core\Framework\Context;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Sorting\FieldSorting;
use Shopware\Core\System\SalesChannel\SalesChannelContext;
use Shopware\Core\System\SystemConfig\SystemConfigService;
use Shopware\Core\System\SalesChannel\Context\SalesChannelContextServiceInterface;
use Symfony\Component\HttpFoundation\RequestStack;
class CustomTax
{
    private $httpClient;
    private $orderRepository;
    private $productRepository;
    private $systemConfigService;
    private $contextService;
    private $requestStack;
    public function __construct(
        SystemConfigService $systemConfigService,
        SalesChannelContextServiceInterface $contextService,
        $orderRepository,
        $productRepository,
        RequestStack $requestStack
    ) {
        $this->httpClient = new HttpClient();
        $this->systemConfigService = $systemConfigService;
        $this->contextService = $contextService;
        $this->orderRepository = $orderRepository;
        $this->productRepository = $productRepository;
        $this->requestStack = $requestStack;
    }
    private function getLastOrder()
    {
        $criteria   = new Criteria();
        $criteria->setLimit(1);
        $criteria->addSorting(new FieldSorting('createdAt', FieldSorting::DESCENDING));
        $order = $this->orderRepository->search($criteria, Context::createDefaultContext())->first();
        return $order;
    }
    public function getLineItemTax($lineItems, $shippingLocation, $context)
    {
        $zipCodeExplode     = explode('-', $shippingLocation->getZipcode());
        $zipCode = $zipCodeExplode[0] ?? ''; 
        $stripeSecretKey = $this->systemConfigService->get('HatslogicLiveTax.config.hatsStripeSecretKey');
        $url = 'https://api.stripe.com/v1/tax/calculations'; 
 
        $shipToState = $shippingLocation->getCountryState();
         
        $body = [
            'customer_details'=> [
                    'address' => [
                        'line1' => (string) $shippingLocation->getStreet(),
                        'city' => (string) $shippingLocation->getCity(),
                        'state' => (string) $shipToState,
                        'postal_code' => (string) $zipCode,
                        'country' => 'US',
                    ]
                ],
                "address_source" => 'shipping'
        ];
        
 
        $i = 1;
        foreach ($lineItems as $lineItem) {
            if ($lineItem->getType() == 'HatslogicLiveTax_tax') {
                continue;
            } 
            $product    = $this->getProductById($lineItem->getId(), $context);
            if(!$product)

Wir haben den geheimen Schlüssel von Stripe in der Plugin-Konfiguration konfiguriert.
Wir holen diesen Wert wie folgt ab

$stripeSecretKey = $this->systemConfigService->get(‘HatslogicLiveTax.config.hatsStripeSecretKey’);

Durch den Aufruf der Funktion getLineitemTax() erhalten wir den aktuellen Steuerbetrag im Warenkorb.
Nun müssen wir die Steuerberechnungen anhand dieses Wertes ändern.

Dazu müssen wir den Warenkorbprozessor verwenden und die bestehenden Steuerberechnungen des Warenkorbs außer Kraft setzen

Registrieren Sie den Warenkorbprozessor in der Servicedatei

/custom/plugins/HatslogicLiveTax/src/Resources/config/services.xml

<service id="HatslogicLiveTax\Core\Checkout\CustomCartProcessor">
            <argument type="service" id="HatslogicLiveTax\Core\Checkout\Cart\Price\AbsolutePriceCalculator"/>
            <argument type="service" id="request_stack"/>
            <argument type="service" id="HatslogicLiveTax\Service\CustomTax"/>
            <argument type="service" id="logger"/>
            <tag name="shopware.cart.processor" priority="5000"/>
</service>

Erstellen Sie die Datei CustomCartProcessor in folgendem Pfad

/custom/plugins/HatslogicLiveTax/src/Core/Checkout/CustomCartProcessor.php

<?php declare(strict_types=1);
namespace HatslogicLiveTax\Core\Checkout;
use HatslogicLiveTax\Service\CustomTax;
use Shopware\Core\Checkout\Cart\Cart;
use Shopware\Core\Checkout\Cart\CartBehavior;
use Shopware\Core\Checkout\Cart\CartProcessorInterface;
use Shopware\Core\Checkout\Cart\LineItem\CartDataCollection;
use Shopware\Core\Checkout\Cart\LineItem\LineItem;
use Shopware\Core\Checkout\Cart\LineItem\LineItemCollection;
use HatslogicLiveTax\Core\Checkout\Cart\Price\AbsolutePriceCalculator;
use Shopware\Core\Checkout\Cart\Price\Struct\AbsolutePriceDefinition;
use Shopware\Core\Checkout\Cart\Rule\LineItemRule;
use Shopware\Core\Framework\Struct\ArrayStruct;
use Shopware\Core\Framework\Uuid\Uuid;
use Shopware\Core\System\SalesChannel\SalesChannelContext;
use Symfony\Component\HttpFoundation\RequestStack;
use Psr\Log\LoggerInterface;
use Shopware\Core\Checkout\Cart\Tax\Struct\CalculatedTaxCollection;
use Shopware\Core\Checkout\Cart\Tax\Struct\CalculatedTax;
class CustomCartProcessor implements CartProcessorInterface
{
    private $calculator;
    private $requestStack;
    private $customTax;
    private LoggerInterface $logger;
    public function __construct(AbsolutePriceCalculator $calculator,
        $requestStack,
        $customTax,
        $logger
    )
    {
        $this->calculator = $calculator;
        $this->requestStack = $requestStack;
        $this->customTax = $customTax;
        $this->logger = $logger;
    }
    public function process(CartDataCollection $data, Cart $original, Cart $toCalculate, SalesChannelContext $context, CartBehavior $behavior): void
    {
        $customer           = $context->getCustomer();
        if(!$customer) {
            $this->requestStack->getSession()->remove('HatslogicTaxData');
            return;
        }
        $products = $toCalculate->getLineItems();
        if ($products->count() === 0) {
            return;
        }
        $taxData = $this->requestStack->getSession()->get('HatslogicTaxData');
        if(!$taxData) {
            return;
        }  
        if( isset( $taxData['error comments'] ) ) {
            $this->logger->info($taxData['error comments']);
            $this->requestStack->getSession()->set('Hatslogic_has_error', true);
            return;
        } else {
            $this->requestStack->getSession()->remove('Hatslogic_has_error');
        }
        $taxTotal = 0;
        
        $taxesDetails = [];
        $taxesLineTotal = [];
        foreach ($taxData['line_items']['data'] as $taxDatum){
            foreach( $taxDatum['tax_breakdown'] as $taxBreakDowns) {
                if($taxBreakDowns['amount'] > 0) { 
                    $slug = strtolower(str_replace(' ','_',$taxBreakDowns['tax_rate_details']['display_name']));
                    if(isset($taxesLineTotal["total_".$slug])) {
                        $taxesLineTotal["total_".$slug] += $taxBreakDowns['amount'];
                    } else {
                        $taxesLineTotal["total_".$slug] = $taxBreakDowns['amount'];
                    }
                    $taxTotal +=$taxBreakDowns['tax_rate_details']['percentage_decimal'];
                    $taxesDetails["tax_".$slug] =  array(
                        'rate'=>$taxBreakDowns['tax_rate_details']['percentage_decimal'], 
                        'amount'=>$taxesLineTotal["total_".$slug], 
                        'label'=>$taxBreakDowns['tax_rate_details']['display_name']
                    );
                }
            }
        }
        $body['data'] = $taxData;
        $body['HatslogicTax'] = $taxesDetails;  
         
        if($taxTotal) {
            $uuid = Uuid::randomHex();
            $taxLineItem = $this->createLineItem($uuid);
            $definition = new AbsolutePriceDefinition(
                $taxTotal,
                new LineItemRule(LineItemRule::OPERATOR_EQ, $products->getKeys())
            );
            $taxLineItem->setPriceDefinition($definition);
            $taxLineItem->setPrice(
                $this->calculator->calculate($definition->getPrice(), $products->getPrices(), $context)
            );  
            $taxLineItem->setPayload($body);
            $toCalculate->add($taxLineItem); 
        }
    }
    private function createLineItem(string $id): LineItem
    {
        $taxLineItem = new LineItem($id, 'Hatslogic_tax', null, 1);
        $taxLineItem->setLabel('Hatslogic Tax');
        $taxLineItem->setGood(false);
        $taxLineItem->setStackable(false);
        $taxLineItem->setRemovable(false);
        return $taxLineItem;
    }
}

Hier aktualisieren wir die Steuerberechnungen. Wenn der Einkaufswagen zusätzliche Steuern enthält, werden diese auch als separate Steuerposition hinzugefügt.

Wir müssen Änderungen an der Rechnungsdatei und den Zusammenfassungsseiten der Bestellung vornehmen.
Für die Änderungen am Schaufenster müssen wir die folgenden Twig-Vorlagen aktualisieren.

/custom/plugins/HatslogicLiveTax/src/Resources/views/storefront/page/checkout/checkout-item.html.twig

{% sw_extends '@Storefront/storefront/page/checkout/checkout-item.html.twig' %}
{% block page_checkout_item_container %}
    {% if lineItem.type !== 'Hatslogic_tax' %}
        {{ parent() }}
    {% endif %}
{% endblock %}




/custom/plugins/HatslogicLiveTax/src/Resources/views/storefront/page/checkout/summary/summary-position.html.twig


{% sw_extends '@Storefront/storefront/page/checkout/summary/summary-position.html.twig' %}
{% block page_checkout_summary_position_value %}
    {% set lineItem = page.order.lineItems.filterByType('Hatslogic_tax')%}
    {% set cartData = true %}
    {% if lineItem %}
        {% set cartData = false %}
    {% else %}
        {% set lineItem = page.cart.lineItems.filterFlatByType('Hatslogic_tax') %}
    {% endif %}
    {% if lineItem %}
            {% if cartData %}
                {% set lineItem =  lineItem[0] %}
            {% else %}
                {% set lineItem =  lineItem.first() %}
            {% endif %}
            {% set hatslogicLiveTax = lineItem.getPayload() %}
            {% set taxTotal =  0 %}
            {% for tax in hatslogicLiveTax.HatslogicTax %}
                {% if (tax.rate > 0) %}
                    {% set taxTotal = (taxTotal + tax.amount)  %}
                {% endif %}
            {% endfor %}
 
            <dd class="col-5 checkout-aside-summary-value">
                {{ (summary.price.positionPrice - taxTotal)|currency }}{{ "general.star"|trans|sw_sanitize }}
            </dd>
        {% else %}
            {{ parent() }}
        {% endif %}
{% endblock %}

Dies sind die einfachen Schritte, die erforderlich sind, um eine Stripe-Live-Steuerberechnung mit der Shopware 6-Kasse einzurichten.

Comments are closed.