• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

stripe / stripe-mirakl-connector / 4405154266

pending completion
4405154266

push

github

GitHub
Merge pull request #116 from tejpal-mirakl/tax-split-changes

91 of 91 new or added lines in 6 files covered. (100.0%)

1740 of 1806 relevant lines covered (96.35%)

7.58 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

90.91
/src/Command/PaymentValidationCommand.php
1
<?php
2

3
namespace App\Command;
4

5
use App\Message\CancelPendingPaymentMessage;
6
use App\Message\CapturePendingPaymentMessage;
7
use App\Message\ValidateMiraklOrderMessage;
8
use App\Repository\PaymentMappingRepository;
9
use App\Service\MiraklClient;
10
use Psr\Log\LoggerAwareInterface;
11
use Psr\Log\LoggerAwareTrait;
12
use Symfony\Component\Console\Command\Command;
13
use Symfony\Component\Console\Input\InputInterface;
14
use Symfony\Component\Console\Output\OutputInterface;
15
use Symfony\Component\Messenger\MessageBusInterface;
16

17
class PaymentValidationCommand extends Command implements LoggerAwareInterface
18
{
19
    use LoggerAwareTrait;
20

21
    protected const ORDER_STATUS_VALIDATED = ['SHIPPING', 'SHIPPED', 'TO_COLLECT', 'RECEIVED', 'CLOSED', 'REFUSED', 'CANCELED'];
22
    protected const ORDER_STATUS_TO_CAPTURE = ['SHIPPING', 'SHIPPED', 'TO_COLLECT', 'RECEIVED', 'CLOSED'];
23
    protected static $defaultName = 'connector:validate:pending-debit';
24
    /**
25
     * @var MessageBusInterface
26
     */
27
    private $bus;
28

29
    /**
30
     * @var MiraklClient
31
     */
32
    private $miraklClient;
33

34
    /**
35
     * @var PaymentMappingRepository
36
     */
37
    private $paymentMappingRepository;
38

39
    public function __construct(
40
        MessageBusInterface $bus,
41
        MiraklClient $miraklClient,
42
        PaymentMappingRepository $paymentMappingRepository
43
    ) {
44
        $this->bus = $bus;
8✔
45
        $this->miraklClient = $miraklClient;
8✔
46
        $this->paymentMappingRepository = $paymentMappingRepository;
8✔
47

48
        parent::__construct();
8✔
49
    }
50

51
    protected function configure()
52
    {
53
        $this
8✔
54
            ->setDescription('Validate pending order whose payment can be captured')
8✔
55
            ->setHelp('This command will fetch pending Mirakl orders, check if we have payment intent or charge and confirm it on mirakl');
8✔
56
    }
57

58
    protected function execute(InputInterface $input, OutputInterface $output): ?int
59
    {
60
        $this->logger->info('starting');
8✔
61
        // validate payment to mirakl when we have a charge/paymentIntent
62
        $ordersByCommercialId = $this->miraklClient->listProductPendingDebits();
8✔
63
        if (!empty($ordersByCommercialId)) {
8✔
64
            $this->validateOrders($ordersByCommercialId);
8✔
65
        } else {
66
            $this->logger->info('No mirakl orders pending debit');
×
67
        }
68

69
        // capture payment when mirakl order is totally validated
70
        $paymentMappings = $this->paymentMappingRepository->findToCapturePayments();
8✔
71
        if (!empty($paymentMappings)) {
8✔
72
            $this->capturePayments($paymentMappings);
7✔
73
        } else {
74
            $this->logger->info('No payment to capture');
1✔
75
        }
76

77
        $this->logger->info('job succeeded');
8✔
78
        return 0;
8✔
79
    }
80

81
    /**
82
     * @param array $ordersByCommercialId
83
     */
84
    protected function validateOrders(array $ordersByCommercialId): void
85
    {
86
        // get stripe known payment intent or charge for pending order
87
        $paymentMappings = $this->paymentMappingRepository->findPaymentsByCommercialOrderIds(
8✔
88
            array_keys($ordersByCommercialId)
8✔
89
        );
8✔
90

91
        // Keep orders with a payment mapping and vice versa
92
        $readyForValidation = array_intersect_key($ordersByCommercialId, $paymentMappings);
8✔
93
        $paymentMappings = array_intersect_key($paymentMappings, $readyForValidation);
8✔
94

95
        if (empty($readyForValidation)) {
8✔
96
            $this->logger->info('No mirakl order to validate');
7✔
97
            return;
7✔
98
        }
99

100
        $this->bus->dispatch(new ValidateMiraklOrderMessage(
1✔
101
            $readyForValidation,
1✔
102
            $paymentMappings
1✔
103
        ));
1✔
104
    }
105

106
    /**
107
     * @param array $paymentMappings
108
     */
109
    protected function capturePayments(array $paymentMappings): void
110
    {
111
        // List all orders using the provided commercial IDs
112
        $ordersByCommercialId = $this->miraklClient->listProductOrdersByCommercialId(
7✔
113
            array_keys($paymentMappings)
7✔
114
        );
7✔
115

116
        // Calculate the right amount to be captured for each commercial order
117
        foreach ($paymentMappings as $commercialId => $paymentMapping) {
7✔
118
            if (!isset($ordersByCommercialId[$commercialId])) {
7✔
119
                $this->logger->info(
1✔
120
                    'Skipping payment capture for non-existing commercial order.',
1✔
121
                    ['commercial_id' => $commercialId]
1✔
122
                );
1✔
123
                continue;
1✔
124
            }
125

126
            // Amount is initially set to the authorized amount and we deduct refused/canceled orders
127
            $captureAmount = $paymentMapping->getStripeAmount();
6✔
128
            foreach ($ordersByCommercialId[$commercialId] as $orderId => $order) {
6✔
129
                // Order must be validated (accepted/refused)
130
                if (!$order->isValidated()) {
6✔
131
                    $this->logger->info(
1✔
132
                        'Skipping payment capture for non-accepted logistical order.',
1✔
133
                        ['commercial_id' => $commercialId, 'order_id' => $orderId]
1✔
134
                    );
1✔
135
                    continue 2;
1✔
136
                }
137

138
                // Payment must be validated (via PA01) if the order wasn't aborted
139
                if (!$order->isAborted() && !$order->isPaid()) {
5✔
140
                    $this->logger->info(
×
141
                        'Skipping payment capture for non-validated logistical order payment.',
×
142
                        ['commercial_id' => $commercialId, 'order_id' => $orderId]
×
143
                    );
×
144
                    continue 2;
×
145
                }
146

147
                // Deduct refused or canceled orders
148
                $abortedAmount = $order->getAbortedAmount();
5✔
149
                if ($abortedAmount > 0) {
5✔
150
                    $this->logger->info(
3✔
151
                        "Deducting order aborted amount {$abortedAmount} from capture amount.",
3✔
152
                        ['commercial_id' => $commercialId, 'order_id' => $orderId]
3✔
153
                    );
3✔
154
                    $captureAmount -= gmp_intval((string) ($abortedAmount * 100));
3✔
155
                }
156
            }
157

158
            // Capture or cancel payment
159
            $mappingId = $paymentMapping->getId();
5✔
160
            if ($captureAmount > 0) {
5✔
161
                $message = new CapturePendingPaymentMessage($mappingId, $captureAmount);
4✔
162
            } else {
163
                $message = new CancelPendingPaymentMessage($mappingId);
1✔
164
            }
165

166
            $this->bus->dispatch($message);
5✔
167
        }
168
    }
169
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc