fix: order creation

This commit is contained in:
2025-12-08 00:24:19 +03:00
committed by Nikita Kiselev
parent 4a3dcc11d1
commit 82ab8134e1
13 changed files with 164 additions and 96 deletions

View File

@@ -64,6 +64,11 @@ export const useCheckoutStore = defineStore('checkout', {
const pulse = usePulseStore();
await nextTick(() => {
pulse.ingest(TC_PULSE_EVENTS.ORDER_CREATED, {
order_id: this.order.id,
revenue: this.order?.final_total_numeric,
currency: this.order?.currency,
});
yaMetrika.reachGoal(YA_METRIKA_GOAL.ORDER_CREATED_SUCCESS, {
price: this.order?.final_total_numeric,
currency: this.order?.currency,
@@ -88,11 +93,6 @@ export const useCheckoutStore = defineStore('checkout', {
}
}
});
pulse.ingest(TC_PULSE_EVENTS.ORDER_CREATED, {
order_id: this.order.id,
revenue: this.order?.final_total_numeric,
currency: this.order?.currency,
});
});
await window.Telegram.WebApp.HapticFeedback.notificationOccurred('success');

View File

@@ -2,6 +2,7 @@
<?php
use Console\ApplicationFactory;
use Console\Commands\PulseSendEventsCommand;
use Console\Commands\ScheduleListCommand;
use Console\Commands\ScheduleRunCommand;
use Console\Commands\VersionCommand;
@@ -92,4 +93,5 @@ $console = new Application('TeleCart', module_version());
$console->add($app->get(VersionCommand::class));
$console->add($app->get(ScheduleRunCommand::class));
$console->add($app->get(ScheduleListCommand::class));
$console->add($app->get(PulseSendEventsCommand::class));
$console->run();

View File

@@ -1,3 +1,3 @@
APP_DEBUG=true
PULSE_API_HOST=http://host.docker.internal:8086/api/
PULSE_API_HOST=https://pulse.telecart.pro/api/
PULSE_HEARTBEAT_SECRET=c5261f5d-529e-45ad-a69c-9778b755b7cb

View File

@@ -6,7 +6,6 @@ use GuzzleHttp\Exception\GuzzleException;
use Openguru\OpenCartFramework\Cache\CacheInterface;
use Openguru\OpenCartFramework\Config\Settings;
use Openguru\OpenCartFramework\Scheduler\TaskInterface;
use Openguru\OpenCartFramework\Settings\UserSettingsInterface;
use Openguru\OpenCartFramework\TeleCartPulse\TeleCartEvent;
use Openguru\OpenCartFramework\TeleCartPulse\TeleCartPulseEventsSender;
use Psr\Log\LoggerInterface;

View File

@@ -0,0 +1,29 @@
<?php
namespace Console\Commands;
use Bastion\ScheduledTasks\TeleCartPulseSendEventsTask;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class PulseSendEventsCommand extends TeleCartCommand
{
protected static $defaultName = 'pulse:send';
protected static $defaultDescription = 'Manually send pulse events ignoring schedule.';
private TeleCartPulseSendEventsTask $teleCartPulseSendEventsTask;
public function __construct(TeleCartPulseSendEventsTask $teleCartPulseSendEventsTask)
{
parent::__construct();
$this->teleCartPulseSendEventsTask = $teleCartPulseSendEventsTask;
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
$output->writeln('<info>Sending Pulse events.</info>');
$this->teleCartPulseSendEventsTask->execute();
return self::SUCCESS;
}
}

View File

@@ -4,7 +4,7 @@ namespace Console\Commands;
use Symfony\Component\Console\Command\Command;
class TeleCartCommand extends Command
abstract class TeleCartCommand extends Command
{
public function __construct()
{

View File

@@ -8,6 +8,7 @@ use Symfony\Component\HttpFoundation\Request as SymfonyRequest;
final class Request extends SymfonyRequest
{
public function json(string $key = null, $default = null)
{
$content = $this->getContent();

View File

@@ -4,7 +4,7 @@ declare(strict_types=1);
namespace App\Handlers;
use App\Services\TelegramCustomerService;
use App\Services\TelecartCustomerService;
use Symfony\Component\HttpFoundation\JsonResponse;
use Openguru\OpenCartFramework\Http\Request;
use Symfony\Component\HttpFoundation\Response;
@@ -19,12 +19,12 @@ use Throwable;
class TelegramCustomerHandler
{
private TelegramCustomerService $telegramCustomerService;
private TelecartCustomerService $telegramCustomerService;
private LoggerInterface $logger;
private TelegramInitDataDecoder $initDataDecoder;
public function __construct(
TelegramCustomerService $telegramCustomerService,
TelecartCustomerService $telegramCustomerService,
LoggerInterface $logger,
TelegramInitDataDecoder $initDataDecoder
) {

View File

@@ -4,7 +4,7 @@ namespace App\Services;
use Openguru\OpenCartFramework\QueryBuilder\Builder;
use Openguru\OpenCartFramework\QueryBuilder\Connections\ConnectionInterface;
use Openguru\OpenCartFramework\Support\Arr;
use Openguru\OpenCartFramework\QueryBuilder\JoinClause;
class OcCustomerService
{
@@ -17,25 +17,8 @@ class OcCustomerService
$this->database = $database;
}
public function findOrCreate(array $orderData): ?int
public function create(array $orderData, ?int $telecartCustomerId): ?int
{
$email = Arr::get($orderData, 'email');
$phone = Arr::get($orderData, 'telephone');
if (! $email && ! $phone) {
return null;
}
$customer = $this->builder->newQuery()
->from(db_table('customer'))
->where('email', '=', $email)
->where('telephone', '=', $phone)
->firstOrNull();
if ($customer) {
return (int) $customer['customer_id'];
}
$customerData = [
'customer_group_id' => $orderData['customer_group_id'],
'store_id' => $orderData['store_id'],
@@ -56,7 +39,50 @@ class OcCustomerService
];
$this->database->insert(db_table('customer'), $customerData);
$lastInsertId = $this->database->lastInsertId();
return $this->database->lastInsertId();
if ($telecartCustomerId) {
$this->builder
->where('id', '=', $telecartCustomerId)
->update('telecart_customers', [
'oc_customer_id' => $lastInsertId,
]);
}
return $lastInsertId;
}
public function findByTelecartCustomerId(int $telegramCustomerId): ?array
{
return $this->builder->newQuery()
->select(['oc_customers.*'])
->from(db_table('customer'), 'oc_customers')
->join('telecart_customers', function (JoinClause $join) {
$join->on('telecart_customers.oc_customer_id', '=', 'oc_customers.customer_id');
})
->where('telecart_customers.id', '=', $telegramCustomerId)
->firstOrNull();
}
public function findById(int $ocCustomerId): ?array
{
return $this->builder->newQuery()
->select(['oc_customers.*'])
->from(db_table('customer'), 'oc_customers')
->where('oc_customers.customer_id', '=', $ocCustomerId)
->firstOrNull();
}
public function findOrCreateByTelecartCustomerId(int $telecartCustomerId, array $orderData): ?array
{
$ocCustomer = $this->findByTelecartCustomerId($telecartCustomerId);
if (! $ocCustomer) {
$ocCustomerId = $this->create($orderData, $telecartCustomerId);
return $this->findById($ocCustomerId);
}
return $ocCustomer;
}
}

View File

@@ -23,7 +23,7 @@ class OrderCreateService
private SettingsService $settings;
private TelegramService $telegramService;
private LoggerInterface $logger;
private TelegramCustomerService $telegramCustomerService;
private TelecartCustomerService $telecartCustomerService;
private OcCustomerService $ocCustomerService;
private OrderMetaService $orderMetaService;
@@ -34,7 +34,7 @@ class OrderCreateService
SettingsService $settings,
TelegramService $telegramService,
LoggerInterface $logger,
TelegramCustomerService $telegramCustomerService,
TelecartCustomerService $telegramCustomerService,
OcCustomerService $ocCustomerService,
OrderMetaService $orderMetaService
) {
@@ -44,7 +44,7 @@ class OrderCreateService
$this->settings = $settings;
$this->telegramService = $telegramService;
$this->logger = $logger;
$this->telegramCustomerService = $telegramCustomerService;
$this->telecartCustomerService = $telegramCustomerService;
$this->ocCustomerService = $ocCustomerService;
$this->orderMetaService = $orderMetaService;
}
@@ -72,6 +72,7 @@ class OrderCreateService
// Получаем telegram_user_id из tgData
$telegramUserId = Arr::get($data['tgData'] ?? [], 'user.id');
$telegramUserdata = Arr::get($data['tgData'] ?? [], 'user');
if (! $telegramUserId) {
throw new RuntimeException('Telegram user id is required.');
@@ -109,16 +110,12 @@ class OrderCreateService
try {
$this->database->beginTransaction();
$ocCustomerId = $this->ocCustomerService->findOrCreate($orderData);
$telecartCustomerId = null;
if ($ocCustomerId) {
$telecartCustomerId = $this->telegramCustomerService->assignOcCustomer(
$telegramUserId,
$ocCustomerId
);
}
$telecartCustomer = $this->telecartCustomerService->saveOrUpdate($telegramUserdata);
$telecartCustomerId = (int) $telecartCustomer['id'];
$ocCustomer = $this->ocCustomerService->findOrCreateByTelecartCustomerId($telecartCustomerId, $orderData);
$ocCustomerId = (int) $ocCustomer['customer_id'];
$orderData['customer_id'] = $ocCustomerId ?? 0;
$orderData['customer_id'] = $ocCustomerId;
$this->database->insert(db_table('order'), $orderData);
$orderId = $this->database->lastInsertId();
@@ -137,6 +134,8 @@ class OrderCreateService
$this->orderMetaService->insert($orderId, $storeId, $customOrderFields, $telecartCustomerId);
}
$this->telecartCustomerService->increaseOrdersCount($telecartCustomerId);
$this->database->commitTransaction();
} catch (Throwable $exception) {
$this->database->rollBackTransaction();
@@ -151,10 +150,6 @@ class OrderCreateService
$this->sendNotifications($orderData, $data['tgData']);
if ($telecartCustomerId) {
$this->telegramCustomerService->increaseOrdersCount($telecartCustomerId);
}
$dateTimeFormatted = '';
try {
$dateTimeFormatted = $now->format('d.m.Y H:i');
@@ -196,8 +191,12 @@ class OrderCreateService
$this->telegramService->sendMessage($chatId, $message);
} catch (Throwable $exception) {
$this->logger->error(
"Telegram sendMessage to owner error. ChatID: $chatId, Message: $message",
['exception' => $exception],
'Telegram sendMessage to owner error.',
[
'exception' => $exception,
'chat_id' => $chatId,
'message' => $message,
],
);
}
}
@@ -212,8 +211,12 @@ class OrderCreateService
$this->telegramService->sendMessage($customerChatId, $message);
} catch (Throwable $exception) {
$this->logger->error(
"Telegram sendMessage to customer error. ChatID: $chatId, Message: $message",
['exception' => $exception]
"Telegram sendMessage to customer error.",
[
'exception' => $exception,
'chat_id' => $chatId,
'message' => $message,
],
);
}
}

View File

@@ -10,7 +10,7 @@ use Openguru\OpenCartFramework\Support\Arr;
use Openguru\OpenCartFramework\Support\Utils;
use RuntimeException;
class TelegramCustomerService
class TelecartCustomerService
{
private TelegramCustomer $telegramCustomer;

View File

@@ -88,6 +88,12 @@ class TestCase extends BaseTestCase
'oc_customer_group_id' => 99,
],
'pulse' => [
'api_key' => '',
'batch_size' => 50,
'max_attempts' => 3,
],
'mainpage_blocks' => [
[
'type' => 'products_feed',

View File

@@ -7,7 +7,7 @@ use App\Services\OcCustomerService;
use App\Services\OrderCreateService;
use App\Services\OrderMetaService;
use App\Services\SettingsService;
use App\Services\TelegramCustomerService;
use App\Services\TelecartCustomerService;
use Carbon\Carbon;
use Mockery as m;
use Openguru\OpenCartFramework\OpenCart\Decorators\OcRegistryDecorator;
@@ -83,39 +83,39 @@ class OrderCreateServiceTest extends TestCase
$connection = m::mock(ConnectionInterface::class);
$connection->shouldReceive('beginTransaction')->once()->andReturnTrue();
$connection->shouldReceive('commitTransaction')->once()->andReturnTrue();
// $connection->shouldReceive('rollBackTransaction')->once()->andReturnTrue();
$connection->shouldReceive('rollBackTransaction')->andReturnTrue();
$connection->shouldReceive('lastInsertId')->once()->andReturn($orderId)->ordered();
$connection->shouldReceive('lastInsertId')->once()->andReturn($orderProductId)->ordered();
$connection->shouldReceive('insert')->once()->with(
db_table('order'),
[
'store_id' => $storeId,
'store_name' => $this->app->getConfigValue('app.app_name'),
'firstname' => $data['firstname'],
'lastname' => $data['lastname'],
'email' => $data['email'],
'telephone' => $data['telephone'],
'payment_method' => $data['payment_method'],
'comment' => $data['comment'],
'shipping_address_1' => $data['shipping_address_1'],
'shipping_city' => $data['shipping_city'],
'shipping_zone' => $data['shipping_zone'],
'shipping_postcode' => $data['shipping_postcode'],
'total' => $totalNumeric,
'order_status_id' => $this->app->getConfigValue('orders.order_default_status_id'),
'ip' => $meta['ip'],
'forwarded_ip' => $meta['ip'],
'user_agent' => $meta['user_agent'],
'date_added' => $dateAdded,
'date_modified' => $dateAdded,
'language_id' => $this->app->getConfigValue('app.language_id'),
'currency_id' => $currencyId,
'currency_code' => $currencyCode,
'currency_value' => $currencyValue,
'customer_group_id' => $this->app->getConfigValue('orders.oc_customer_group_id'),
'customer_id' => $ocCustomerId,
],
m::on(function ($orderData) use ($storeId, $data, $totalNumeric, $meta, $currencyId, $currencyCode, $currencyValue, $ocCustomerId) {
return $orderData['store_id'] === $storeId
&& $orderData['store_name'] === $this->app->getConfigValue('app.app_name')
&& $orderData['firstname'] === $data['firstname']
&& $orderData['lastname'] === $data['lastname']
&& $orderData['email'] === $data['email']
&& $orderData['telephone'] === $data['telephone']
&& $orderData['payment_method'] === $data['payment_method']
&& $orderData['comment'] === $data['comment']
&& $orderData['shipping_address_1'] === $data['shipping_address_1']
&& $orderData['shipping_city'] === $data['shipping_city']
&& $orderData['shipping_zone'] === $data['shipping_zone']
&& $orderData['shipping_postcode'] === $data['shipping_postcode']
&& $orderData['total'] === $totalNumeric
&& $orderData['order_status_id'] === $this->app->getConfigValue('orders.order_default_status_id')
&& $orderData['ip'] === $meta['ip']
&& $orderData['forwarded_ip'] === $meta['ip']
&& $orderData['user_agent'] === $meta['user_agent']
&& $orderData['date_added'] instanceof Carbon
&& $orderData['date_modified'] instanceof Carbon
&& $orderData['language_id'] === $this->app->getConfigValue('app.language_id')
&& $orderData['currency_id'] === $currencyId
&& $orderData['currency_code'] === $currencyCode
&& $orderData['currency_value'] === $currencyValue
&& $orderData['customer_group_id'] === $this->app->getConfigValue('orders.oc_customer_group_id')
&& $orderData['customer_id'] === $ocCustomerId;
}),
)
->andReturn(true);
@@ -135,16 +135,16 @@ class OrderCreateServiceTest extends TestCase
$connection->shouldReceive('insert')->once()->with(
db_table('order_history'),
[
'order_id' => $orderId,
'order_status_id' => $this->app->getConfigValue('orders.order_default_status_id'),
'notify' => 0,
'comment' => 'Заказ оформлен через Telegram Mini App.'
m::on(function ($historyData) use ($orderId) {
return $historyData['order_id'] === $orderId
&& $historyData['order_status_id'] === $this->app->getConfigValue('orders.order_default_status_id')
&& $historyData['notify'] === 0
&& $historyData['comment'] === 'Заказ оформлен через Telegram Mini App.'
. "\n\nДополнительная информация по заказу:"
. "\nfield_1: кирилица"
. "\nfield_2: hello\n",
'date_added' => $dateAdded,
],
. "\nfield_2: hello\n"
&& $historyData['date_added'] instanceof Carbon;
}),
)->andReturnTrue();
$cartService = m::mock(CartService::class);
@@ -176,17 +176,19 @@ class OrderCreateServiceTest extends TestCase
$telegramServiceMock = m::mock(TelegramService::class);
$loggerMock = m::mock(LoggerInterface::class);
$telegramCustomerService = m::mock(TelegramCustomerService::class);
$telegramCustomerService->shouldReceive('assignOcCustomer')->once()
->with($telegramUserId, $ocCustomerId)
->andReturn($telecartCustomerId);
$telegramCustomerService = m::mock(TelecartCustomerService::class);
$telegramCustomerService->shouldReceive('saveOrUpdate')->once()
->with($tgData['user'])
->andReturn(['id' => $telecartCustomerId]);
$telegramCustomerService->shouldReceive('increaseOrdersCount')->once()
->with($telecartCustomerId)
->andReturnNull();
$ocCustomerService = m::mock(OcCustomerService::class);
$ocCustomerService->shouldReceive('findOrCreate')->once()->andReturn($ocCustomerId);
$ocCustomerService->shouldReceive('findOrCreateByTelecartCustomerId')->once()
->with($telecartCustomerId, m::type('array'))
->andReturn(['customer_id' => $ocCustomerId]);
$orderMetaService = m::mock(OrderMetaService::class);
$orderMetaService->shouldReceive('insert')