Skip to content

Commit 2f97949

Browse files
authored
Add User.com API calls after order state changes (#4)
* [UC-4] Extend customer model * [UC-4] Remove unnecessarily extended customer * [UC-4] Add User.com API front config * [UC-4] Add updaters logic * Add event subscriber and manager to init update & add missing events entry * Add user type extension * [UC-4] Fix code style * [UC-4] Add changes requested on CR * [UC-4] Format script * [UC-4] Fix send event argument * [UC-4] Fix send event payload * [UC-4] Replace assert with if statement * [UC-5] Add user com api calls on order state changes * [UC-5] Skip if channel does not have api data provided * [UC-5] Add phpstan fixes
1 parent edf63ff commit 2f97949

23 files changed

Lines changed: 527 additions & 20 deletions

config/config.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
imports:
2+
- { resource: "state_machine/*" }

config/services/api.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
<service id="bit_bag.sylius_user_com_plugin.api.deal_api" class="BitBag\SyliusUserComPlugin\Api\DealApi">
1212
<argument type="service" id="http_client"/>
1313
<argument type="service" id="monolog.logger"/>
14+
<argument type="service" id="bit_bag.sylius_user_com_plugin.api.user_api"/>
1415
</service>
1516

1617
<service id="bit_bag.sylius_user_com_plugin.api.product_api" class="BitBag\SyliusUserComPlugin\Api\ProductApi">

config/services/builder.xml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,20 @@
66
<service
77
id="bit_bag.sylius_user_com_plugin.builder.payload.customer_payload_builder"
88
class="BitBag\SyliusUserComPlugin\Builder\Payload\CustomerPayloadBuilder"
9+
/>
10+
<service
11+
id="bit_bag.sylius_user_com_plugin.builder.payload.order_payload_builder"
12+
class="BitBag\SyliusUserComPlugin\Builder\Payload\OrderPayloadBuilder"
913
>
14+
<argument type="service" id="bit_bag.sylius_user_com_plugin.builder.payload.order_item_payload_builder"/>
1015
</service>
16+
<service
17+
id="bit_bag.sylius_user_com_plugin.builder.payload.order_item_payload_builder"
18+
class="BitBag\SyliusUserComPlugin\Builder\Payload\OrderItemPayloadBuilder"
19+
/>
20+
<service
21+
id="bit_bag.sylius_user_com_plugin.builder.payload.product_event_payload_builder"
22+
class="BitBag\SyliusUserComPlugin\Builder\Payload\ProductEventPayloadBuilder"
23+
/>
1124
</services>
1225
</container>

config/services/handler.xml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?xml version="1.0" encoding="UTF-8" ?>
2+
3+
<container xmlns="http://symfony.com/schema/dic/services" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
4+
<services>
5+
<defaults autowire="false" autoconfigure="false"/>
6+
<service
7+
id="bit_bag.sylius_user_com_plugin.handler.order_state_update_handler"
8+
class="BitBag\SyliusUserComPlugin\Handler\OrderStateUpdateHandler"
9+
public="true"
10+
>
11+
<argument type="service" id="bit_bag.sylius_user_com_plugin.builder.payload.order_payload_builder"/>
12+
<argument type="service" id="bit_bag.sylius_user_com_plugin.builder.payload.product_event_payload_builder"/>
13+
<argument type="service" id="bit_bag.sylius_user_com_plugin.api.deal_api"/>
14+
<argument type="service" id="bit_bag.sylius_user_com_plugin.api.product_api"/>
15+
<argument type="service" id="monolog.logger"/>
16+
</service>
17+
</services>
18+
</container>

config/state_machine/order.yaml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
winzou_state_machine:
2+
sylius_order:
3+
class: "%sylius.model.order.class%"
4+
property_path: state
5+
graph: sylius_order
6+
state_machine_class: "%sylius.state_machine.class%"
7+
callbacks:
8+
after:
9+
order_user_com_update:
10+
on: ['create', 'cancel', 'fulfill']
11+
do: ['@bit_bag.sylius_user_com_plugin.handler.order_state_update_handler', 'handle']
12+
args: ['object']

src/Api/AbstractClient.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919

2020
abstract class AbstractClient
2121
{
22+
public const ERROR = 'error';
23+
2224
private const API_ENDPOINT_PREFIX = '/api/public/';
2325

2426
public function __construct(
@@ -31,6 +33,7 @@ protected function request(
3133
string $path,
3234
string $method,
3335
array $options,
36+
bool $retrial = false,
3437
): ?array {
3538
try {
3639
/** @var ResponseInterface $response */
@@ -41,6 +44,12 @@ protected function request(
4144
);
4245

4346
$status = $response->getStatusCode();
47+
if ($status === Response::HTTP_TOO_MANY_REQUESTS && !$retrial) {
48+
sleep(1);
49+
50+
return $this->request($path, $method, $options, true);
51+
}
52+
4453
if ($status >= Response::HTTP_OK && $status < Response::HTTP_MULTIPLE_CHOICES) {
4554
return $response->toArray();
4655
}
@@ -62,6 +71,12 @@ protected function request(
6271
'options' => $options,
6372
]);
6473

74+
if (isset($response) &&
75+
$response->getStatusCode() === Response::HTTP_NOT_FOUND
76+
) {
77+
return [self::ERROR => $response->getStatusCode()];
78+
}
79+
6580
return null;
6681
}
6782
}

src/Api/DealApi.php

Lines changed: 62 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,20 @@
1212
namespace BitBag\SyliusUserComPlugin\Api;
1313

1414
use BitBag\SyliusUserComPlugin\Trait\UserComApiAwareInterface;
15+
use Psr\Log\LoggerInterface;
1516
use Symfony\Component\HttpFoundation\Request;
17+
use Symfony\Contracts\HttpClient\HttpClientInterface;
1618

1719
final class DealApi extends AbstractClient implements DealApiInterface
1820
{
21+
public function __construct(
22+
HttpClientInterface $client,
23+
LoggerInterface $logger,
24+
private readonly UserApiInterface $userApi,
25+
) {
26+
parent::__construct($client, $logger);
27+
}
28+
1929
public function updateDealByCustomId(UserComApiAwareInterface $resource, string $customId, array $data): ?array
2030
{
2131
$url = $this->getApiEndpointUrl($resource, sprintf(self::UPDATE_DEAL_ENDPOINT, $customId));
@@ -27,8 +37,32 @@ public function updateDealByCustomId(UserComApiAwareInterface $resource, string
2737
);
2838
}
2939

30-
public function createDeal(UserComApiAwareInterface $resource, array $data): ?array
31-
{
40+
public function createDeal(
41+
UserComApiAwareInterface $resource,
42+
array $data,
43+
string $email,
44+
): ?array {
45+
$response = $this->request(
46+
$this->getApiEndpointUrl($resource, self::CREATE_DEAL_ENDPOINT),
47+
Request::METHOD_POST,
48+
$this->buildOptions($resource, [
49+
'json' => $data,
50+
'headers' => [
51+
'Content-Type' => 'application/json',
52+
],
53+
]),
54+
);
55+
56+
if ($response === null) {
57+
return null;
58+
}
59+
60+
if (!array_key_exists(self::ERROR, $response)) {
61+
return $response;
62+
}
63+
64+
$this->userApi->createUser($resource, ['email' => $email, 'custom_id' => $email]);
65+
3266
return $this->request(
3367
$this->getApiEndpointUrl($resource, self::CREATE_DEAL_ENDPOINT),
3468
Request::METHOD_POST,
@@ -41,8 +75,32 @@ public function createDeal(UserComApiAwareInterface $resource, array $data): ?ar
4175
);
4276
}
4377

44-
public function updateOrCreateDeal(UserComApiAwareInterface $resource, array $data): ?array
45-
{
78+
public function updateOrCreateDeal(
79+
UserComApiAwareInterface $resource,
80+
array $data,
81+
string $email,
82+
): ?array {
83+
$response = $this->request(
84+
$this->getApiEndpointUrl($resource, self::CREATE_OR_UPDATE_DEAL_ENDPOINT),
85+
Request::METHOD_POST,
86+
$this->buildOptions($resource, [
87+
'json' => $data,
88+
'headers' => [
89+
'Content-Type' => 'application/json',
90+
],
91+
]),
92+
);
93+
94+
if ($response === null) {
95+
return null;
96+
}
97+
98+
if (!array_key_exists(self::ERROR, $response)) {
99+
return $response;
100+
}
101+
102+
$this->userApi->createUser($resource, ['email' => $email, 'custom_id' => $email]);
103+
46104
return $this->request(
47105
$this->getApiEndpointUrl($resource, self::CREATE_OR_UPDATE_DEAL_ENDPOINT),
48106
Request::METHOD_POST,

src/Api/DealApiInterface.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ interface DealApiInterface
2323

2424
public function updateDealByCustomId(UserComApiAwareInterface $resource, string $customId, array $data): ?array;
2525

26-
public function createDeal(UserComApiAwareInterface $resource, array $data): ?array;
26+
public function createDeal(UserComApiAwareInterface $resource, array $data, string $email): ?array;
2727

28-
public function updateOrCreateDeal(UserComApiAwareInterface $resource, array $data): ?array;
28+
public function updateOrCreateDeal(UserComApiAwareInterface $resource, array $data, string $email): ?array;
2929
}

src/Api/ProductApi.php

Lines changed: 47 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,61 @@
1212
namespace BitBag\SyliusUserComPlugin\Api;
1313

1414
use BitBag\SyliusUserComPlugin\Trait\UserComApiAwareInterface;
15+
use Psr\Log\LoggerInterface;
1516
use Symfony\Component\HttpFoundation\Request;
17+
use Symfony\Contracts\HttpClient\HttpClientInterface;
1618

1719
final class ProductApi extends AbstractClient implements ProductApiInterface
1820
{
19-
public function getProductByCustomId(UserComApiAwareInterface $resource, int $productId): ?array
21+
public function __construct(
22+
HttpClientInterface $client,
23+
LoggerInterface $logger,
24+
) {
25+
parent::__construct($client, $logger);
26+
}
27+
28+
public function createProductEventByCustomId(
29+
UserComApiAwareInterface $resource,
30+
int $productId,
31+
array $payload,
32+
string $productName,
33+
): ?array {
34+
$url = $this->getApiEndpointUrl($resource, sprintf(self::CREATE_PRODUCT_EVENT_BY_CUSTOM_ID_ENDPOINT, $productId));
35+
36+
$response = $this->request(
37+
$url,
38+
Request::METHOD_POST,
39+
$this->buildOptions($resource, ['json' => $payload]),
40+
);
41+
42+
if ($response === null) {
43+
return null;
44+
}
45+
46+
if (!array_key_exists(self::ERROR, $response)) {
47+
return $response;
48+
}
49+
50+
$this->createProduct($resource, [
51+
'custom_id' => $productId,
52+
'name' => $productName,
53+
]);
54+
55+
return $this->request(
56+
$url,
57+
Request::METHOD_POST,
58+
$this->buildOptions($resource, ['json' => $payload]),
59+
);
60+
}
61+
62+
public function createProduct(UserComApiAwareInterface $resource, array $payload): array|null
2063
{
21-
$url = $this->getApiEndpointUrl($resource, sprintf(self::GET_PRODUCT_BY_CUSTOM_ID_ENDPOINT, $productId));
64+
$url = $this->getApiEndpointUrl($resource, self::CREATE_PRODUCT_ENDPOINT);
2265

2366
return $this->request(
2467
$url,
25-
Request::METHOD_GET,
26-
$this->buildOptions($resource),
68+
Request::METHOD_POST,
69+
$this->buildOptions($resource, ['json' => $payload]),
2770
);
2871
}
2972
}

src/Api/ProductApiInterface.php

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,14 @@
1515

1616
interface ProductApiInterface
1717
{
18-
public const GET_PRODUCT_BY_CUSTOM_ID_ENDPOINT = '/products-by-id/%s/product_event/';
18+
public const CREATE_PRODUCT_EVENT_BY_CUSTOM_ID_ENDPOINT = '/products-by-id/%s/product_event/';
1919

20-
public function getProductByCustomId(UserComApiAwareInterface $resource, int $productId): ?array;
20+
public const CREATE_PRODUCT_ENDPOINT = '/products/';
21+
22+
public function createProductEventByCustomId(
23+
UserComApiAwareInterface $resource,
24+
int $productId,
25+
array $payload,
26+
string $productName,
27+
): ?array;
2128
}

0 commit comments

Comments
 (0)