Compare commits
405 Commits
feature/ma
...
925faeb6f4
Author | SHA1 | Date | |
---|---|---|---|
925faeb6f4 | |||
f11b7dcd9b | |||
e35053edce | |||
829ab86770 | |||
4b66694166 | |||
d4f8804fbb | |||
5f4d8a4bc2 | |||
1fa152c07f | |||
7f8bd607e3 | |||
1bbee1121b | |||
352e33179c | |||
f34d7338f1 | |||
4dd83ae63d | |||
e265854958 | |||
174b29efff | |||
1c0f4a5ae9 | |||
ccee5f9f56 | |||
9677f11aef | |||
c21de2848d | |||
348bb18654 | |||
a2a9f4bbb4 | |||
ab7328b40b | |||
7f97862324 | |||
9edf0d9120 | |||
ca1ed3f870 | |||
360537c638 | |||
a6e6b8acc0 | |||
a4e2b4fc7a | |||
479047cd6a | |||
29d9ea8e4a | |||
a7cd661938 | |||
7bdcc7168a | |||
d2dff57531 | |||
39198bbe7c | |||
200510d60a | |||
ecc67a43c8 | |||
64791d1fc5 | |||
4053854410 | |||
a687743762 | |||
38fb6f3bcc | |||
1e6bac61b5 | |||
a611ae247d | |||
c02c6eb15c | |||
b7e0217cf3 | |||
2fd1a44984 | |||
fe912db62b | |||
da90160a2a | |||
64047ef577 | |||
feef90afd6 | |||
32e1e49a97 | |||
11c64cb10f | |||
823f97ce5f | |||
4ae72199fc | |||
d841b1aeed | |||
666cac1958 | |||
71c189e236 | |||
5b6a1c42e3 | |||
81bce6fe7f | |||
e1072ea252 | |||
21473fe52c | |||
7d589e0e87 | |||
c48a0d2381 | |||
abb1ce7299 | |||
f1ed9668fc | |||
f9ae809fc4 | |||
06e5292af1 | |||
47ba664142 | |||
d10ee33215 | |||
5134630525 | |||
13b246b998 | |||
d601d7d719 | |||
dc0ae2746b | |||
eb402b1b71 | |||
c5188a1feb | |||
1c3052219c | |||
9e8a388653 | |||
cbee830f7a | |||
d5b8c7f877 | |||
b668844fea | |||
f2169c9536 | |||
48bcb33bad | |||
92ae0b4ac2 | |||
44540d0dc3 | |||
d9a2f63691 | |||
b10accf602 | |||
981858f251 | |||
8c0bd450ef | |||
8996765cb4 | |||
ec2451cb69 | |||
37d30d2aec | |||
afb6e2526f | |||
a9b6f2a87b | |||
9aeb6906f6 | |||
879d365baf | |||
1d03b262ae | |||
2c175c8171 | |||
a750bdbfaa | |||
7f6d0232c0 | |||
37cff67a1c | |||
bc3d739af9 | |||
46efbb57c1 | |||
d71333b334 | |||
688b500f1e | |||
d4b1a66a9e | |||
e796d91d95 | |||
2a442417ce | |||
3c161ed4e9 | |||
3c8822e531 | |||
b3b91d3f8f | |||
6e34a76a3f | |||
ed29dfb984 | |||
7f37dc76e3 | |||
a62293e509 | |||
fbfc2cb8ae | |||
02665ac6bd | |||
300d966f3f | |||
27031035ed | |||
18fc9a76fd | |||
cb6fa73a21 | |||
8796762cfe | |||
99c9952c93 | |||
9895fd6a70 | |||
c1149d89be | |||
7d8e2249de | |||
a54586e870 | |||
734f258382 | |||
f728ed0b55 | |||
6144accb8e | |||
f399eb8d47 | |||
b4159d1417 | |||
2a792a947d | |||
25710d616a | |||
3197802264 | |||
6c53127c2f | |||
b7391a77d3 | |||
5b499aee75 | |||
4505531c5f | |||
3f8adc753c | |||
ace205798f | |||
6e0e1fc75e | |||
026474c63c | |||
f32204df97 | |||
2852816eae | |||
892cdf324f | |||
a9a10e012d | |||
b7089f7a1c | |||
aed26cfcd8 | |||
896dded6eb | |||
3b03c4b64b | |||
f34ed03b84 | |||
ce75ec1548 | |||
312baa34f6 | |||
b7c5e4ebc3 | |||
105179b4ed | |||
16cd29635d | |||
2bdb2a0ed0 | |||
8ce7d2570d | |||
8ba54fd3ad | |||
f47f86dd2b | |||
8ca68bf7e8 | |||
8965354528 | |||
8d32aecd09 | |||
c8f79e076e | |||
9e0d604d79 | |||
331d004040 | |||
03317b3aa5 | |||
e33edc4d7b | |||
bb459a2ff5 | |||
5e2d2e861f | |||
e9b2fe9963 | |||
2f481ef8a9 | |||
386fe452af | |||
91ad1e39f8 | |||
a3a5b58cfb | |||
1d77d65af2 | |||
0f0c81e283 | |||
ac278ca690 | |||
97d34f9ad6 | |||
134588c96d | |||
8b6516241d | |||
d6e60efcaf | |||
3e937ab748 | |||
fa6881d0a9 | |||
f07c1f1cbd | |||
148d08089d | |||
45b6ee710e | |||
c84277fdc4 | |||
c0024a4a63 | |||
308a84a448 | |||
91c74bf113 | |||
024a6eae54 | |||
d536342425 | |||
e7f3b33850 | |||
c47d94d475 | |||
ee74fc7588 | |||
5ac324de6a | |||
dfb0ff7aea | |||
6d1a1c914a | |||
b45d03aa7e | |||
4e0b611bcf | |||
20ea5d021d | |||
32dc24a783 | |||
95a6aa96e9 | |||
f14cdd2730 | |||
3006adb0f7 | |||
d22480dcb8 | |||
425b85e40d | |||
2c21e48562 | |||
8d3ce99be7 | |||
35386724b3 | |||
1597657f0e | |||
c6bbaf3404 | |||
9e2d7277b0 | |||
abe37227ce | |||
32130f0bc2 | |||
d78bdaa7f5 | |||
1266c3859d | |||
c5466b2c4d | |||
6d8e8a9068 | |||
4d5b657b92 | |||
4ca1616dfc | |||
fb7177fd65 | |||
1486d6cf38 | |||
8b2de31e02 | |||
61324f159b | |||
c95e74d574 | |||
59ecb6cc79 | |||
db84187461 | |||
c2f98c8b0d | |||
8d73987ac3 | |||
400b2754bf | |||
418becaeda | |||
679b401101 | |||
26b6862955 | |||
e239669839 | |||
adc0e52c1e | |||
d1905194bd | |||
a5c1d60819 | |||
5ad4fc4038 | |||
ca5354a3ee | |||
c1ebac6c0c | |||
f742c7ddd0 | |||
5d5f9866bb | |||
0866292d84 | |||
e02ed4684f | |||
8be5f94b7c | |||
878b02ee52 | |||
f3e15b34a8 | |||
3903551176 | |||
43eb8ec758 | |||
a405b15410 | |||
a2f2d94e64 | |||
0587b64d65 | |||
a6b81f1bff | |||
4239bafc26 | |||
6591e9f80e | |||
b57f32c86b | |||
0e903f99c4 | |||
186cd0f5b8 | |||
167d8e1ab7 | |||
46802507a7 | |||
aaf2ed7612 | |||
3ced9e40b1 | |||
594cb68b09 | |||
af68c4b8ec | |||
ea8f483dd5 | |||
5f53c77a1f | |||
b9adb9108b | |||
8be085222a | |||
d1e4314b35 | |||
7d04b406ab | |||
972e57b6f1 | |||
5f63bdbf4a | |||
a8325c3310 | |||
7e54b72587 | |||
ebe31a3d3d | |||
db6445bcf3 | |||
4e1901b7c8 | |||
c3316029c9 | |||
cbfc796685 | |||
da56192f97 | |||
b5d08620f9 | |||
c92b07ee6f | |||
ee6956d417 | |||
21d5e2d03b | |||
73a742c01e | |||
dd42c12d49 | |||
41ea5f5c15 | |||
eeb6f5bcd1 | |||
2680f51167 | |||
019d57a0b0 | |||
1a400d9a5c | |||
6276f87274 | |||
28c93a42bc | |||
4ff5d28522 | |||
a93642c55d | |||
87c0d8c8d9 | |||
dd1741a930 | |||
ad0fd82a9e | |||
bae5c1740d | |||
f5f1482b7a | |||
4bd5fe16df | |||
61845fbd05 | |||
f8ac0f14f0 | |||
acb7a1336d | |||
8af56137a8 | |||
c3247838b3 | |||
dd82ac6bb7 | |||
2acf0362fa | |||
e6892ee085 | |||
86b8d6b3c7 | |||
53115b085f | |||
c3b7427f60 | |||
5d939f970b | |||
4845801b27 | |||
d5bf9a7660 | |||
795dda868b | |||
53a3633dc7 | |||
0143fd11ac | |||
55745a8d0a | |||
2a1930c5f7 | |||
31f49dddb6 | |||
b4ca59fb6d | |||
d910f3eb69 | |||
555cdb7138 | |||
65088da2f5 | |||
966b341b65 | |||
90b05ca25c | |||
bb3a2fffa1 | |||
8a5e41a722 | |||
5736a346e7 | |||
4f4e69f0c3 | |||
00deebeaa8 | |||
aee0754b5a | |||
eabdab23c3 | |||
5147450ed6 | |||
ed96f25475 | |||
d5a3512852 | |||
d6730cd020 | |||
c7dddc818c | |||
33b4182bd3 | |||
fc776e6cec | |||
5d79ea83c3 | |||
c34048a53a | |||
f7af93b815 | |||
993e4ff3b8 | |||
bc49ba7629 | |||
3c2b486083 | |||
76f69f3bda | |||
8ba3c456b6 | |||
98b18fab3e | |||
12a4831887 | |||
da46914de4 | |||
596bc71cf8 | |||
7f8e4ea943 | |||
5456485f71 | |||
836503a71b | |||
4df0cca675 | |||
00a0adb4ac | |||
037fcd60f3 | |||
7a97fc9dfe | |||
7b2df74e4d | |||
b5d6d0acb9 | |||
8a1e6a7761 | |||
ced673e452 | |||
8a7a1d4e64 | |||
9be20ab1cd | |||
1c40f18624 | |||
db36549699 | |||
4ce83fb270 | |||
b191a01313 | |||
d3b0026ca4 | |||
2b3f476df7 | |||
39c148b7b3 | |||
bae0f1f555 | |||
2e49e2c947 | |||
68aebdb4fe | |||
346001db8e | |||
8b04eb262f | |||
7c7c8315e2 | |||
510e05e5ca | |||
5055d2703c | |||
2bc30ab9e8 | |||
c7ee440e03 | |||
18dd8c4ec0 | |||
8ea4995f6b | |||
aeeca65d94 | |||
5f69069aa0 | |||
095a65a643 | |||
928d2e57be | |||
2a0335f834 | |||
9ccf53fa4e | |||
ef54c36edc | |||
4aa88d5164 | |||
8ea13c3efd | |||
12e3d7ed3b | |||
a7fc89ac29 | |||
a71df4e70d | |||
f17b7a758a | |||
7fb28cd44c | |||
a44bd610ad | |||
28bba8a438 | |||
0ec6ebdafe | |||
3ebe256a66 | |||
9d135e2c26 |
@ -3,8 +3,7 @@ FROM php:8.4-cli
|
|||||||
ENV TZ "${TZ}"
|
ENV TZ "${TZ}"
|
||||||
ENV APP_NAME "${APP_NAME}"
|
ENV APP_NAME "${APP_NAME}"
|
||||||
|
|
||||||
RUN apt-get update && apt-get install -y --no-install-recommends cron rsyslog nano beanstalkd \
|
RUN apt-get update && apt-get install -y --no-install-recommends cron rsyslog nano && rm -r /var/lib/apt/lists/*
|
||||||
&& rm -r /var/lib/apt/lists/*
|
|
||||||
|
|
||||||
RUN pecl install xdebug-3.4.2 \
|
RUN pecl install xdebug-3.4.2 \
|
||||||
&& docker-php-ext-enable xdebug \
|
&& docker-php-ext-enable xdebug \
|
||||||
|
@ -3,7 +3,7 @@ FROM php:8.4-fpm
|
|||||||
ENV TZ=America/Santiago
|
ENV TZ=America/Santiago
|
||||||
|
|
||||||
RUN apt-get update && apt-get install -y --no-install-recommends libzip-dev libicu-dev git \
|
RUN apt-get update && apt-get install -y --no-install-recommends libzip-dev libicu-dev git \
|
||||||
libpng-dev unzip tzdata libxml2-dev beanstalkd \
|
libpng-dev unzip tzdata libxml2-dev \
|
||||||
&& rm -r /var/lib/apt/lists/* \
|
&& rm -r /var/lib/apt/lists/* \
|
||||||
&& docker-php-ext-install pdo pdo_mysql zip intl gd bcmath dom \
|
&& docker-php-ext-install pdo pdo_mysql zip intl gd bcmath dom \
|
||||||
&& pecl install xdebug-3.4.2 \
|
&& pecl install xdebug-3.4.2 \
|
||||||
|
0
app/bin/console
Executable file → Normal file
0
app/bin/console
Executable file → Normal file
0
app/bin/integration_tests
Executable file → Normal file
0
app/bin/integration_tests
Executable file → Normal file
0
app/bin/performance_tests
Executable file → Normal file
0
app/bin/performance_tests
Executable file → Normal file
0
app/bin/unit_tests
Executable file → Normal file
0
app/bin/unit_tests
Executable file → Normal file
@ -1,10 +0,0 @@
|
|||||||
<?php
|
|
||||||
namespace Incoviba\Common\Ideal\Service;
|
|
||||||
|
|
||||||
use Incoviba\Common\Define;
|
|
||||||
use Incoviba\Common\Ideal;
|
|
||||||
|
|
||||||
abstract class Repository extends Ideal\Service
|
|
||||||
{
|
|
||||||
abstract public function getRepository(): Define\Repository;
|
|
||||||
}
|
|
@ -64,10 +64,10 @@ class Select extends Ideal\Query implements Define\Query\Select
|
|||||||
public function having(array|string $conditions): Select
|
public function having(array|string $conditions): Select
|
||||||
{
|
{
|
||||||
if (is_string($conditions)) {
|
if (is_string($conditions)) {
|
||||||
return $this->addHaving($conditions);
|
return $this->addCondition($conditions);
|
||||||
}
|
}
|
||||||
foreach ($conditions as $condition) {
|
foreach ($conditions as $condition) {
|
||||||
$this->addHaving($condition);
|
$this->addCondition($condition);
|
||||||
}
|
}
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
@ -8,13 +8,11 @@
|
|||||||
"ext-gd": "*",
|
"ext-gd": "*",
|
||||||
"ext-openssl": "*",
|
"ext-openssl": "*",
|
||||||
"ext-pdo": "*",
|
"ext-pdo": "*",
|
||||||
"ext-sockets": "*",
|
|
||||||
"berrnd/slim-blade-view": "^1",
|
"berrnd/slim-blade-view": "^1",
|
||||||
"guzzlehttp/guzzle": "^7",
|
"guzzlehttp/guzzle": "^7",
|
||||||
"monolog/monolog": "^3",
|
"monolog/monolog": "^3",
|
||||||
"nyholm/psr7": "^1",
|
"nyholm/psr7": "^1",
|
||||||
"nyholm/psr7-server": "^1",
|
"nyholm/psr7-server": "^1",
|
||||||
"pda/pheanstalk": "^7.0",
|
|
||||||
"php-di/php-di": "^7",
|
"php-di/php-di": "^7",
|
||||||
"php-di/slim-bridge": "^3",
|
"php-di/slim-bridge": "^3",
|
||||||
"phpoffice/phpspreadsheet": "^3",
|
"phpoffice/phpspreadsheet": "^3",
|
||||||
|
@ -125,7 +125,7 @@ pm = ondemand
|
|||||||
; forget to tweak pm.* to fit your needs.
|
; forget to tweak pm.* to fit your needs.
|
||||||
; Note: Used when pm is set to 'static', 'dynamic' or 'ondemand'
|
; Note: Used when pm is set to 'static', 'dynamic' or 'ondemand'
|
||||||
; Note: This value is mandatory.
|
; Note: This value is mandatory.
|
||||||
pm.max_children = 2
|
pm.max_children = 5
|
||||||
|
|
||||||
; The number of child processes created on startup.
|
; The number of child processes created on startup.
|
||||||
; Note: Used only when pm is set to 'dynamic'
|
; Note: Used only when pm is set to 'dynamic'
|
||||||
@ -152,7 +152,6 @@ pm.max_children = 2
|
|||||||
; Note: Used only when pm is set to 'ondemand'
|
; Note: Used only when pm is set to 'ondemand'
|
||||||
; Default Value: 10s
|
; Default Value: 10s
|
||||||
;pm.process_idle_timeout = 10s;
|
;pm.process_idle_timeout = 10s;
|
||||||
pm.process_idle_timeout = 10s
|
|
||||||
|
|
||||||
; The number of requests each child process should execute before respawning.
|
; The number of requests each child process should execute before respawning.
|
||||||
; This can be useful to work around memory leaks in 3rd party libraries. For
|
; This can be useful to work around memory leaks in 3rd party libraries. For
|
||||||
|
@ -19,18 +19,14 @@ final class CreateTokuAccounts extends AbstractMigration
|
|||||||
*/
|
*/
|
||||||
public function change(): void
|
public function change(): void
|
||||||
{
|
{
|
||||||
$this->execute('SET unique_checks=0; SET foreign_key_checks=0;');
|
|
||||||
|
|
||||||
$this->table('toku_accounts')
|
$this->table('toku_accounts')
|
||||||
->addColumn('sociedad_rut', 'integer', ['limit' => 8, 'signed' => false, 'null' => false])
|
->addColumn('toku_id', 'integer')
|
||||||
->addColumn('toku_id', 'string', ['length' => 255, 'null' => false])
|
->addColumn('sociedad_rut', 'integer', ['limit' => 8])
|
||||||
->addColumn('account_key', 'string', ['length' => 255, 'null' => false])
|
->addColumn('account_key', 'string', ['length' => 255])
|
||||||
->addColumn('enabled', 'boolean', ['default' => true])
|
|
||||||
->addTimestamps()
|
|
||||||
#->addForeignKey('sociedad_rut', 'inmobiliaria', 'rut', ['delete' => 'CASCADE', 'update' => 'CASCADE'])
|
|
||||||
->addIndex(['toku_id'], ['unique' => true])
|
->addIndex(['toku_id'], ['unique' => true])
|
||||||
|
->addIndex(['account_id'], ['unique' => true])
|
||||||
|
->addForeignKey('sociedad_rut', 'sociedades', 'rut', ['delete' => 'CASCADE', 'update' => 'CASCADE'])
|
||||||
|
->addTimestamps()
|
||||||
->create();
|
->create();
|
||||||
|
|
||||||
$this->execute('SET unique_checks=1; SET foreign_key_checks=1;');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,26 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
use Phinx\Migration\AbstractMigration;
|
|
||||||
|
|
||||||
final class ChangeTelefonoSizeInPropietario extends AbstractMigration
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Change Method.
|
|
||||||
*
|
|
||||||
* Write your reversible migrations using this method.
|
|
||||||
*
|
|
||||||
* More information on writing migrations is available here:
|
|
||||||
* https://book.cakephp.org/phinx/0/en/migrations.html#the-change-method
|
|
||||||
*
|
|
||||||
* Remember to call "create()" or "update()" and NOT "save()" when working
|
|
||||||
* with the Table class.
|
|
||||||
*/
|
|
||||||
public function change(): void
|
|
||||||
{
|
|
||||||
$this->table('propietario')
|
|
||||||
->changeColumn('telefono', 'biginteger', ['null' => true, 'signed' => false, 'default' => null])
|
|
||||||
->update();
|
|
||||||
}
|
|
||||||
}
|
|
1
app/resources/routes/api/external/toku.php
vendored
1
app/resources/routes/api/external/toku.php
vendored
@ -7,5 +7,4 @@ $app->group('/toku', function($app) {
|
|||||||
$app->get('/test[/]', [Toku::class, 'test']);
|
$app->get('/test[/]', [Toku::class, 'test']);
|
||||||
$app->delete('/reset[/]', [Toku::class, 'reset']);
|
$app->delete('/reset[/]', [Toku::class, 'reset']);
|
||||||
$app->post('/enqueue[/]', [Toku::class, 'enqueue']);
|
$app->post('/enqueue[/]', [Toku::class, 'enqueue']);
|
||||||
$app->post('/update[/{type}[/]]', [Toku::class, 'update']);
|
|
||||||
});
|
});
|
||||||
|
@ -2,9 +2,9 @@
|
|||||||
use Incoviba\Controller\API\Queues;
|
use Incoviba\Controller\API\Queues;
|
||||||
|
|
||||||
$app->group('/queue', function($app) {
|
$app->group('/queue', function($app) {
|
||||||
#$app->get('/jobs[/]', [Queues::class, 'jobs']);
|
$app->get('/jobs[/]', [Queues::class, 'jobs']);
|
||||||
$app->group('/run', function($app) {
|
$app->group('/run', function($app) {
|
||||||
#$app->get('/{job_id:[0-9]+}[/]', [Queues::class, 'run']);
|
$app->get('/{job_id:[0-9]+}[/]', [Queues::class, 'run']);
|
||||||
$app->get('[/]', Queues::class);
|
$app->get('[/]', Queues::class);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -156,7 +156,7 @@
|
|||||||
<script>
|
<script>
|
||||||
const regiones = [
|
const regiones = [
|
||||||
@foreach ($regiones as $region)
|
@foreach ($regiones as $region)
|
||||||
'<div class="item" data-value="{{$region->id}}">{{$region->numeral}} - {{$region->descripcion}}</div>',
|
'<div class="item" data-value="{{$region->id}}">{{$region->descripcion}}</div>',
|
||||||
@endforeach
|
@endforeach
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -54,23 +54,22 @@
|
|||||||
}
|
}
|
||||||
$(document).ready(() => {
|
$(document).ready(() => {
|
||||||
const url = '{{$urls->api}}/ventas/pago/{{$venta->resciliacion()->id}}'
|
const url = '{{$urls->api}}/ventas/pago/{{$venta->resciliacion()->id}}'
|
||||||
let old = new Date(Date.parse('{{$venta->resciliacion()?->fecha->format('Y-m-d') ?? $venta->currentEstado()->fecha->format('Y-m-d') ?? $venta->fecha->format('Y-m-d')}}') + 24 * 60 * 60 * 1000)
|
let old = new Date({{$venta->resciliacion()?->fecha->format('Y') ?? date('Y')}},
|
||||||
|
{{$venta->resciliacion()?->fecha->format('n') ?? date('n')}}-1, {{$venta->resciliacion()?->fecha->format('j') ?? date('j')}})
|
||||||
calendar_date_options['initialDate'] = old
|
calendar_date_options['initialDate'] = old
|
||||||
calendar_date_options['onChange'] = function(date, text, mode) {
|
calendar_date_options['onChange'] = function(date, text, mode) {
|
||||||
if (date.getTime() === old.getTime()) {
|
if (date.getTime() === old.getTime()) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const body = new FormData()
|
const body = new FormData()
|
||||||
const fecha = new Date(date.getTime())
|
body.set('fecha', date.toISOString())
|
||||||
fecha.setDate(fecha.getDate() - 1)
|
|
||||||
body.set('fecha', fecha.toISOString())
|
|
||||||
$('#loading-spinner-fecha').show()
|
$('#loading-spinner-fecha').show()
|
||||||
APIClient.fetch(url, {method: 'post', body}).then(response => {
|
APIClient.fetch(url, {method: 'post', body}).then(response => {
|
||||||
$('#loading-spinner-fecha').hide()
|
$('#loading-spinner-fecha').hide()
|
||||||
if (!response) {
|
if (!response) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
old = new Date(date.getTime())
|
old = date
|
||||||
alertResponse('Fecha cambiada correctamente.')
|
alertResponse('Fecha cambiada correctamente.')
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -6,26 +6,15 @@
|
|||||||
|
|
||||||
@section('venta_content')
|
@section('venta_content')
|
||||||
<div class="ui list">
|
<div class="ui list">
|
||||||
@if (isset($venta->formaPago()->pie))
|
<div class="item">
|
||||||
<div class="item">
|
<div class="header">Valor Pagado</div>
|
||||||
<div class="header">Valor Pagado</div>
|
<div class="content">
|
||||||
<div class="content">
|
{{$format->pesos($venta->formaPago()->pie->pagado('pesos'))}}
|
||||||
{{$format->pesos($venta->formaPago()->pie->pagado('pesos'))}}
|
<div class="ui left pointing small label">
|
||||||
<div class="ui left pointing small label">
|
{{$format->number($venta->formaPago()->pie->pagado() / $venta->valor * 100)}}% de la venta
|
||||||
{{$format->number($venta->formaPago()->pie->pagado() / $venta->valor * 100)}}% de la venta
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@else
|
</div>
|
||||||
<div class="item">
|
|
||||||
<div class="ui compact warning message">
|
|
||||||
<div class="content">
|
|
||||||
<i class="exclamation triangle icon"></i>
|
|
||||||
No tiene valor pagado
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@endif
|
|
||||||
<div class="item">
|
<div class="item">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
Multa Estandar
|
Multa Estandar
|
||||||
|
@ -116,18 +116,7 @@ return [
|
|||||||
->registerSub($container->get(Incoviba\Service\Contabilidad\Cartola\BCI\Mes::class));
|
->registerSub($container->get(Incoviba\Service\Contabilidad\Cartola\BCI\Mes::class));
|
||||||
},
|
},
|
||||||
'TokuClient' => function(ContainerInterface $container) {
|
'TokuClient' => function(ContainerInterface $container) {
|
||||||
$logger = $container->get('externalLogger');
|
|
||||||
$stack = GuzzleHttp\HandlerStack::create();
|
|
||||||
$stack->push(GuzzleHttp\Middleware::mapRequest(function(Psr\Http\Message\RequestInterface $request) use ($logger) {
|
|
||||||
$logger->info('Toku Request', [
|
|
||||||
'method' => $request->getMethod(),
|
|
||||||
'uri' => (string) $request->getUri(),
|
|
||||||
'headers' => $request->getHeaders(),
|
|
||||||
'body' => $request->getBody()->getContents(),
|
|
||||||
]);
|
|
||||||
}));
|
|
||||||
return new GuzzleHttp\Client([
|
return new GuzzleHttp\Client([
|
||||||
'handler' => $stack,
|
|
||||||
'base_uri' => $container->get('TOKU_URL'),
|
'base_uri' => $container->get('TOKU_URL'),
|
||||||
'headers' => [
|
'headers' => [
|
||||||
'x-api-key' => $container->get('TOKU_TOKEN'),
|
'x-api-key' => $container->get('TOKU_TOKEN'),
|
||||||
@ -173,16 +162,6 @@ return [
|
|||||||
->register('subscription', $container->get(Incoviba\Service\Venta\MediosPago\Toku\Subscription::class))
|
->register('subscription', $container->get(Incoviba\Service\Venta\MediosPago\Toku\Subscription::class))
|
||||||
->register('invoice', $container->get(Incoviba\Service\Venta\MediosPago\Toku\Invoice::class));
|
->register('invoice', $container->get(Incoviba\Service\Venta\MediosPago\Toku\Invoice::class));
|
||||||
},
|
},
|
||||||
Pheanstalk\Pheanstalk::class => function(ContainerInterface $container) {
|
|
||||||
return Pheanstalk\Pheanstalk::create(
|
|
||||||
$container->get('BEANSTALKD_HOST'),
|
|
||||||
$container->has('BEANSTALKD_PORT') ? $container->get('BEANSTALKD_PORT') : 11300
|
|
||||||
);
|
|
||||||
},
|
|
||||||
Incoviba\Service\MQTT::class => function(ContainerInterface $container) {
|
|
||||||
return new Incoviba\Service\MQTT()
|
|
||||||
->register('default', $container->get(Incoviba\Service\MQTT\Pheanstalk::class));
|
|
||||||
},
|
|
||||||
Incoviba\Service\Queue::class => function(ContainerInterface $container) {
|
Incoviba\Service\Queue::class => function(ContainerInterface $container) {
|
||||||
return new Incoviba\Service\Queue(
|
return new Incoviba\Service\Queue(
|
||||||
$container->get(Psr\Log\LoggerInterface::class),
|
$container->get(Psr\Log\LoggerInterface::class),
|
||||||
|
@ -22,4 +22,20 @@ class Queues extends Ideal\Controller
|
|||||||
}
|
}
|
||||||
return $this->withJson($response, $output);
|
return $this->withJson($response, $output);
|
||||||
}
|
}
|
||||||
|
public function jobs(ServerRequestInterface $request, ResponseInterface $response,
|
||||||
|
Service\Queue $queueService): ResponseInterface
|
||||||
|
{
|
||||||
|
$output = [
|
||||||
|
'jobs' => array_column($queueService->getPendingJobs(), 'id')
|
||||||
|
];
|
||||||
|
return $this->withJson($response, $output);
|
||||||
|
}
|
||||||
|
public function run(ServerRequestInterface $request, ResponseInterface $response, Service\Queue $queueService,
|
||||||
|
int $job_id): ResponseInterface
|
||||||
|
{
|
||||||
|
if ($queueService->runJob($job_id, $request)) {
|
||||||
|
return $response->withStatus(200);
|
||||||
|
}
|
||||||
|
return $response->withStatus(422);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -146,25 +146,4 @@ class Toku extends Controller
|
|||||||
}
|
}
|
||||||
return $this->withJson($response, $output);
|
return $this->withJson($response, $output);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function update(ServerRequestInterface $request, ResponseInterface $response,
|
|
||||||
Service\Venta\MediosPago\Toku $tokuService, ?string $type = null): ResponseInterface
|
|
||||||
{
|
|
||||||
$body = $request->getBody()->getContents();
|
|
||||||
$input = json_decode($body, true);
|
|
||||||
$output = [
|
|
||||||
'type' => $type,
|
|
||||||
'input' => $input,
|
|
||||||
'output' => [],
|
|
||||||
'success' => false
|
|
||||||
];
|
|
||||||
try {
|
|
||||||
$output['output'] = $tokuService->update($input, $type);
|
|
||||||
$output['success'] = true;
|
|
||||||
} catch (Exception $exception) {
|
|
||||||
$this->logger->error($exception);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->withJson($response, $output);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -4,9 +4,6 @@ namespace Incoviba\Controller;
|
|||||||
use Incoviba\Common\Alias\View;
|
use Incoviba\Common\Alias\View;
|
||||||
use Incoviba\Common\Implement\Exception\EmptyRedis;
|
use Incoviba\Common\Implement\Exception\EmptyRedis;
|
||||||
use Incoviba\Common\Implement\Exception\EmptyResult;
|
use Incoviba\Common\Implement\Exception\EmptyResult;
|
||||||
use Incoviba\Exception\ServiceAction\Create;
|
|
||||||
use Incoviba\Exception\ServiceAction\Read;
|
|
||||||
use Incoviba\Exception\ServiceAction\Update;
|
|
||||||
use Incoviba\Model;
|
use Incoviba\Model;
|
||||||
use Incoviba\Repository;
|
use Incoviba\Repository;
|
||||||
use Incoviba\Service;
|
use Incoviba\Service;
|
||||||
@ -145,24 +142,9 @@ class Ventas
|
|||||||
return $view->render($response, 'ventas.desistir', compact('venta'));
|
return $view->render($response, 'ventas.desistir', compact('venta'));
|
||||||
}
|
}
|
||||||
public function desistida(ServerRequestInterface $request, ResponseInterface $response, Service\Venta $ventaService,
|
public function desistida(ServerRequestInterface $request, ResponseInterface $response, Service\Venta $ventaService,
|
||||||
Service\Venta\Pago $pagoService,
|
|
||||||
View $view, int $venta_id): ResponseInterface
|
View $view, int $venta_id): ResponseInterface
|
||||||
{
|
{
|
||||||
try {
|
$venta = $ventaService->getById($venta_id);
|
||||||
$venta = $ventaService->getById($venta_id);
|
|
||||||
} catch (Read) {
|
|
||||||
return $view->render($response->withStatus(404), 'not_found');
|
|
||||||
}
|
|
||||||
if ($venta->resciliacion() === null) {
|
|
||||||
$pagoData = [
|
|
||||||
'fecha' => $venta->currentEstado()->fecha->format('Y-m-d'),
|
|
||||||
'valor' => 0
|
|
||||||
];
|
|
||||||
try {
|
|
||||||
$pago = $pagoService->add($pagoData);
|
|
||||||
$venta = $ventaService->edit($venta, ['resciliacion' => $pago->id]);
|
|
||||||
} catch (Create | Update) {}
|
|
||||||
}
|
|
||||||
return $view->render($response, 'ventas.desistida', compact('venta'));
|
return $view->render($response, 'ventas.desistida', compact('venta'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,18 +0,0 @@
|
|||||||
<?php
|
|
||||||
namespace Incoviba\Exception;
|
|
||||||
|
|
||||||
use Throwable;
|
|
||||||
use Exception;
|
|
||||||
|
|
||||||
abstract class MQTT extends Exception
|
|
||||||
{
|
|
||||||
public function __construct($message = "", $code = 0, ?Throwable $previous = null)
|
|
||||||
{
|
|
||||||
$baseCode = 700;
|
|
||||||
$code = $baseCode + $code;
|
|
||||||
if ($message == "") {
|
|
||||||
$message = "MQTT Exception";
|
|
||||||
}
|
|
||||||
parent::__construct($message, $code, $previous);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,18 +0,0 @@
|
|||||||
<?php
|
|
||||||
namespace Incoviba\Exception\MQTT;
|
|
||||||
|
|
||||||
use Throwable;
|
|
||||||
use Incoviba\Exception\MQTT;
|
|
||||||
|
|
||||||
class MissingClient extends MQTT
|
|
||||||
{
|
|
||||||
public function __construct(string $host = '', ?Throwable $previous = null)
|
|
||||||
{
|
|
||||||
$message = 'Missing MQTT client';
|
|
||||||
if ($host !== '') {
|
|
||||||
$message = "{$message} for host {$host}";
|
|
||||||
}
|
|
||||||
$code = 1;
|
|
||||||
parent::__construct($message, $code, $previous);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,15 +0,0 @@
|
|||||||
<?php
|
|
||||||
namespace Incoviba\Exception\MQTT;
|
|
||||||
|
|
||||||
use Throwable;
|
|
||||||
use Incoviba\Exception\MQTT;
|
|
||||||
|
|
||||||
class MissingJob extends MQTT
|
|
||||||
{
|
|
||||||
public function __construct(?Throwable $previous = null)
|
|
||||||
{
|
|
||||||
$message = 'Missing MQTT job';
|
|
||||||
$code = 10;
|
|
||||||
parent::__construct($message, $code, $previous);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,15 +0,0 @@
|
|||||||
<?php
|
|
||||||
namespace Incoviba\Exception\MQTT;
|
|
||||||
|
|
||||||
use Throwable;
|
|
||||||
use Incoviba\Exception\MQTT;
|
|
||||||
|
|
||||||
class RemoveJob extends MQTT
|
|
||||||
{
|
|
||||||
public function __construct(int $jobId, ?Throwable $previous = null)
|
|
||||||
{
|
|
||||||
$message = "Could not remove job {$jobId}";
|
|
||||||
$code = 13;
|
|
||||||
parent::__construct($message, $code, $previous);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,15 +0,0 @@
|
|||||||
<?php
|
|
||||||
namespace Incoviba\Exception\MQTT;
|
|
||||||
|
|
||||||
use Throwable;
|
|
||||||
use Incoviba\Exception\MQTT;
|
|
||||||
|
|
||||||
class SetJob extends MQTT
|
|
||||||
{
|
|
||||||
public function __construct(string $payload, ?Throwable $previous = null)
|
|
||||||
{
|
|
||||||
$message = "Could not set job with {$payload}";
|
|
||||||
$code = 11;
|
|
||||||
parent::__construct($message, $code, $previous);
|
|
||||||
}
|
|
||||||
}
|
|
@ -5,43 +5,60 @@ use DateInvalidTimeZoneException;
|
|||||||
use DateMalformedStringException;
|
use DateMalformedStringException;
|
||||||
use DateTimeImmutable;
|
use DateTimeImmutable;
|
||||||
use DateTimeZone;
|
use DateTimeZone;
|
||||||
|
use InvalidArgumentException;
|
||||||
|
use OutOfRangeException;
|
||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
|
use Predis\Connection\ConnectionException;
|
||||||
use Incoviba\Common\Ideal;
|
use Incoviba\Common\Ideal;
|
||||||
use Incoviba\Exception\MQTT as MQTTException;
|
use Incoviba\Common\Implement\Exception\EmptyRedis;
|
||||||
|
use Incoviba\Common\Implement\Exception\EmptyResult;
|
||||||
use Incoviba\Exception\ServiceAction\{Create, Delete, Read, Update};
|
use Incoviba\Exception\ServiceAction\{Create, Delete, Read, Update};
|
||||||
use Incoviba\Model;
|
|
||||||
use Incoviba\Repository;
|
use Incoviba\Repository;
|
||||||
|
use Incoviba\Model;
|
||||||
|
|
||||||
class Job extends Ideal\Service
|
class Job extends Ideal\Service
|
||||||
{
|
{
|
||||||
public function __construct(LoggerInterface $logger, protected MQTT $mqttService,
|
public function __construct(LoggerInterface $logger, protected Redis $redisService,
|
||||||
protected Repository\Job $jobRepository)
|
protected Repository\Job $jobRepository)
|
||||||
{
|
{
|
||||||
parent::__construct($logger);
|
parent::__construct($logger);
|
||||||
}
|
}
|
||||||
|
protected string $redisKey = 'jobs';
|
||||||
|
|
||||||
public function isPending(): bool
|
public function getPending(null|string|array $orderBy = null): array
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
return $this->mqttService->exists();
|
$jobs = $this->redisService->get($this->redisKey);
|
||||||
} catch (MQTTException $exception) {
|
if ($jobs === null) {
|
||||||
$this->logger->error($exception->getMessage(), ['exception' => $exception]);
|
return [];
|
||||||
return false;
|
}
|
||||||
|
$jobs = json_decode($jobs, true);
|
||||||
|
if ($orderBy !== null) {
|
||||||
|
uksort($jobs, function($a, $b) use ($orderBy) {
|
||||||
|
return $a[$orderBy] <=> $b[$orderBy];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return array_map([$this, 'load'], $jobs);
|
||||||
|
} catch (ConnectionException | EmptyRedis) {
|
||||||
|
return [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @param int $id
|
||||||
* @return Model\Job
|
* @return Model\Job
|
||||||
* @throws Read
|
* @throws Read
|
||||||
*/
|
*/
|
||||||
public function get(): Model\Job
|
public function getPendingById(int $id): Model\Job
|
||||||
{
|
{
|
||||||
|
$jobs = $this->getJobs();
|
||||||
try {
|
try {
|
||||||
return $this->load(json_decode($this->mqttService->get(), true));
|
$idx = $this->findJob($jobs, $id);
|
||||||
} catch (MQTTException $exception) {
|
} catch (EmptyResult $exception) {
|
||||||
$this->logger->error($exception->getMessage(), ['exception' => $exception]);
|
$exception = new OutOfRangeException('Job not found', count($jobs), $exception);
|
||||||
throw new Read(__CLASS__, $exception);
|
throw new Read(__CLASS__, $exception);
|
||||||
}
|
}
|
||||||
|
return $this->load($jobs[$idx]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -54,7 +71,6 @@ class Job extends Ideal\Service
|
|||||||
try {
|
try {
|
||||||
$now = (new DateTimeImmutable('now', new DateTimeZone($_ENV['TZ'] ?? 'America/Santiago')));
|
$now = (new DateTimeImmutable('now', new DateTimeZone($_ENV['TZ'] ?? 'America/Santiago')));
|
||||||
} catch (DateMalformedStringException | DateInvalidTimeZoneException $exception) {
|
} catch (DateMalformedStringException | DateInvalidTimeZoneException $exception) {
|
||||||
$this->logger->warning($exception->getMessage(), ['exception' => $exception]);
|
|
||||||
$now = new DateTimeImmutable();
|
$now = new DateTimeImmutable();
|
||||||
}
|
}
|
||||||
$data = [
|
$data = [
|
||||||
@ -65,9 +81,17 @@ class Job extends Ideal\Service
|
|||||||
'updated_at' => null,
|
'updated_at' => null,
|
||||||
'retries' => 0
|
'retries' => 0
|
||||||
];
|
];
|
||||||
|
$jobs = [];
|
||||||
try {
|
try {
|
||||||
$this->mqttService->set(json_encode($data));
|
$jobs = $this->redisService->get($this->redisKey);
|
||||||
} catch (MQTTException $exception) {
|
if ($jobs !== null) {
|
||||||
|
$jobs = json_decode($jobs, true);
|
||||||
|
}
|
||||||
|
} catch (EmptyRedis) {}
|
||||||
|
$jobs []= $data;
|
||||||
|
try {
|
||||||
|
$this->redisService->set($this->redisKey, json_encode($jobs), -1);
|
||||||
|
} catch (ConnectionException $exception) {
|
||||||
throw new Create(__CLASS__, $exception);
|
throw new Create(__CLASS__, $exception);
|
||||||
}
|
}
|
||||||
return $this->load($data);
|
return $this->load($data);
|
||||||
@ -75,35 +99,50 @@ class Job extends Ideal\Service
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Model\Job $job
|
* @param Model\Job $job
|
||||||
* @return void
|
* @return Model\Job
|
||||||
* @throws Update
|
* @throws Update
|
||||||
|
* @throws Read
|
||||||
*/
|
*/
|
||||||
public function update(Model\Job $job): void
|
public function update(Model\Job $job): Model\Job
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$now = (new DateTimeImmutable('now', new DateTimeZone($_ENV['TZ'] ?? 'America/Santiago')));
|
$now = (new DateTimeImmutable('now', new DateTimeZone($_ENV['TZ'] ?? 'America/Santiago')));
|
||||||
} catch (DateMalformedStringException | DateInvalidTimeZoneException) {
|
} catch (DateMalformedStringException | DateInvalidTimeZoneException) {
|
||||||
$now = new DateTimeImmutable();
|
$now = new DateTimeImmutable();
|
||||||
}
|
}
|
||||||
$data = json_decode(json_encode($job), true);
|
$jobs = $this->getJobs();
|
||||||
$data['updated_at'] = $now->format('Y-m-d H:i:s');
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$this->mqttService->update(json_encode($data));
|
$idx = $this->findJob($jobs, $job->id);
|
||||||
} catch (MQTTException $exception) {
|
} catch (EmptyResult $exception) {
|
||||||
|
throw new Read(__CLASS__, $exception);
|
||||||
|
}
|
||||||
|
$jobs[$idx]['updated_at'] = $now->format('Y-m-d H:i:s');
|
||||||
|
$jobs[$idx]['retries'] = $job->retries;
|
||||||
|
try {
|
||||||
|
$this->redisService->set($this->redisKey, json_encode($jobs), -1);
|
||||||
|
} catch (ConnectionException $exception) {
|
||||||
throw new Update(__CLASS__, $exception);
|
throw new Update(__CLASS__, $exception);
|
||||||
}
|
}
|
||||||
|
return $this->load($jobs[$idx]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Model\Job $job
|
* @param Model\Job $job
|
||||||
|
* @throws Read
|
||||||
* @throws Delete
|
* @throws Delete
|
||||||
*/
|
*/
|
||||||
public function remove(Model\Job $job): void
|
public function remove(Model\Job $job): void
|
||||||
{
|
{
|
||||||
|
$jobs = $this->getJobs();
|
||||||
try {
|
try {
|
||||||
$this->mqttService->remove();
|
$idx = $this->findJob($jobs, $job->id);
|
||||||
} catch (MQTTException $exception) {
|
} catch (EmptyResult $exception) {
|
||||||
|
throw new Read(__CLASS__, $exception);
|
||||||
|
}
|
||||||
|
unset($jobs[$idx]);
|
||||||
|
try {
|
||||||
|
$this->redisService->set($this->redisKey, json_encode(array_values($jobs)), -1);
|
||||||
|
} catch (ConnectionException $exception) {
|
||||||
throw new Delete(__CLASS__, $exception);
|
throw new Delete(__CLASS__, $exception);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -111,18 +150,59 @@ class Job extends Ideal\Service
|
|||||||
/**
|
/**
|
||||||
* @param Model\Job $job
|
* @param Model\Job $job
|
||||||
* @return bool
|
* @return bool
|
||||||
|
* @throws Read | Create
|
||||||
*/
|
*/
|
||||||
public function execute(Model\Job $job): bool
|
public function execute(Model\Job $job): bool
|
||||||
{
|
{
|
||||||
|
$jobs = $this->getJobs();
|
||||||
try {
|
try {
|
||||||
$this->mqttService->remove();
|
$idx = $this->findJob($jobs, $job->id);
|
||||||
return true;
|
} catch (EmptyResult $exception) {
|
||||||
} catch (MQTTException $exception) {
|
$exception = new OutOfRangeException('Job not found', count($jobs), $exception);
|
||||||
$this->logger->error($exception->getMessage(), ['exception' => $exception]);
|
throw new Read(__CLASS__, $exception);
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
unset($jobs[$idx]);
|
||||||
|
try {
|
||||||
|
$this->redisService->set($this->redisKey, json_encode(array_values($jobs)), -1);
|
||||||
|
} catch (ConnectionException $exception) {
|
||||||
|
throw new Create(__CLASS__, $exception);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
* @throws Read
|
||||||
|
*/
|
||||||
|
protected function getJobs(): array
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$jobs = $this->redisService->get($this->redisKey);
|
||||||
|
} catch (EmptyRedis $exception) {
|
||||||
|
throw new Read(__CLASS__, $exception);
|
||||||
|
}
|
||||||
|
if ($jobs === null) {
|
||||||
|
$exception = new InvalidArgumentException("Redis Key {$this->redisKey} not found");
|
||||||
|
throw new Read(__CLASS__, $exception);
|
||||||
|
}
|
||||||
|
return json_decode($jobs, true);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @param array $jobs
|
||||||
|
* @param int $id
|
||||||
|
* @return int
|
||||||
|
* @throws EmptyResult
|
||||||
|
*/
|
||||||
|
protected function findJob(array $jobs, int $id): int
|
||||||
|
{
|
||||||
|
$idx = array_find_key($jobs, function($job) use ($id) {
|
||||||
|
return (int) $job['id'] === $id;
|
||||||
|
});
|
||||||
|
if ($idx === null) {
|
||||||
|
throw new EmptyResult("SELECT * FROM jobs WHERE id = ?");
|
||||||
|
}
|
||||||
|
return $idx;
|
||||||
|
}
|
||||||
protected function load(array $data, ?int $id = null): Model\Job
|
protected function load(array $data, ?int $id = null): Model\Job
|
||||||
{
|
{
|
||||||
$job = new Model\Job();
|
$job = new Model\Job();
|
||||||
|
@ -1,102 +0,0 @@
|
|||||||
<?php
|
|
||||||
namespace Incoviba\Service;
|
|
||||||
|
|
||||||
use Incoviba\Exception\MQTT as MQTTException;
|
|
||||||
use Incoviba\Service\MQTT\MQTTInterface;
|
|
||||||
|
|
||||||
class MQTT implements MQTTInterface
|
|
||||||
{
|
|
||||||
protected array $clients = [];
|
|
||||||
public function register(string $name, MQTTInterface $client): self
|
|
||||||
{
|
|
||||||
$this->clients[$name] = $client;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
public function clientExists(string $name): bool
|
|
||||||
{
|
|
||||||
return isset($this->clients[$name]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string|null $name
|
|
||||||
* @return MQTTInterface
|
|
||||||
* @throws MQTTException/MissingClient
|
|
||||||
*/
|
|
||||||
public function getClient(?string $name = null): MQTTInterface
|
|
||||||
{
|
|
||||||
if ($name === null) {
|
|
||||||
$name = array_keys($this->clients)[0];
|
|
||||||
}
|
|
||||||
if (!$this->clientExists($name)) {
|
|
||||||
throw new MQTTException\MissingClient($name);
|
|
||||||
}
|
|
||||||
return $this->clients[$name];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string|null $host
|
|
||||||
* @return bool
|
|
||||||
* @throws MQTTException/MissingClient
|
|
||||||
* @throws MQTTException/MissingJob
|
|
||||||
*/
|
|
||||||
public function exists(?string $host = null): bool
|
|
||||||
{
|
|
||||||
$client = $this->getClient($host);
|
|
||||||
return $client->exists();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string|null $host
|
|
||||||
* @return string
|
|
||||||
* @throws MQTTException/MissingClient
|
|
||||||
* @throws MQTTException/MissingJob
|
|
||||||
*/
|
|
||||||
public function get(?string $host = null): string
|
|
||||||
{
|
|
||||||
$client = $this->getClient($host);
|
|
||||||
return $client->get();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string $value
|
|
||||||
* @param int $delay
|
|
||||||
* @param string|null $host
|
|
||||||
* @return $this
|
|
||||||
* @throws MQTTException/MissingClient
|
|
||||||
* @throws MQTTException/SetJob
|
|
||||||
*/
|
|
||||||
public function set(string $value, int $delay = 0, ?string $host = null): self
|
|
||||||
{
|
|
||||||
$client = $this->getClient($host);
|
|
||||||
$client->set($value, $delay);
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param int|null $jobId
|
|
||||||
* @param string|null $host
|
|
||||||
* @return $this
|
|
||||||
* @throws MQTTException/MissingJob
|
|
||||||
* @throws MQTTException/RemoveJob
|
|
||||||
*/
|
|
||||||
public function remove(?int $jobId = null, ?string $host = null): self
|
|
||||||
{
|
|
||||||
$this->getClient($host)->remove($jobId);
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string $newPayload
|
|
||||||
* @param int|null $jobId
|
|
||||||
* @param string|null $host
|
|
||||||
* @return $this
|
|
||||||
* @throws MQTTException/MissingJob
|
|
||||||
* @throws MQTTException/RemoveJob
|
|
||||||
* @throws MQTTException/SetJob
|
|
||||||
*/
|
|
||||||
public function update(string $newPayload, ?int $jobId = null, ?string $host = null): self
|
|
||||||
{
|
|
||||||
$this->getClient($host)->update($newPayload, $jobId);
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,111 +0,0 @@
|
|||||||
<?php
|
|
||||||
namespace Incoviba\Service\MQTT;
|
|
||||||
|
|
||||||
use Exception;
|
|
||||||
use Incoviba\Exception\MQTT\MissingJob;
|
|
||||||
use Incoviba\Exception\MQTT\RemoveJob;
|
|
||||||
use Incoviba\Exception\MQTT\SetJob;
|
|
||||||
use Psr\Log\LoggerInterface;
|
|
||||||
use xobotyi\beansclient;
|
|
||||||
use xobotyi\beansclient\Exception\ClientException;
|
|
||||||
use xobotyi\beansclient\Exception\CommandException;
|
|
||||||
use xobotyi\beansclient\Exception\JobException;
|
|
||||||
|
|
||||||
class Beanstalkd implements MQTTInterface
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @throws JobException
|
|
||||||
* @throws ClientException
|
|
||||||
* @throws CommandException
|
|
||||||
*/
|
|
||||||
public function __construct(protected LoggerInterface $logger, protected beansclient\BeansClient $client,
|
|
||||||
protected string $tube = 'default', protected int $ttr = beansclient\BeansClient::DEFAULT_TTR,
|
|
||||||
protected int $priority = 1)
|
|
||||||
{
|
|
||||||
$this->client->watchTube($this->tube);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function exists(): bool
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$stats = $this->client->statsTube($this->tube);
|
|
||||||
return $stats['current-jobs-ready'] > 0;
|
|
||||||
} catch (Exception $exception) {
|
|
||||||
$this->logger->error($exception->getMessage(), ['exception' => $exception]);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected ?beansclient\Job $currentJob = null;
|
|
||||||
public function get(): string
|
|
||||||
{
|
|
||||||
if (!$this->exists()) {
|
|
||||||
throw new MissingJob();
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
$job = $this->client->watchTube($this->tube)->reserve();
|
|
||||||
$this->currentJob = $job;
|
|
||||||
return $job->payload;
|
|
||||||
} catch (Exception $exception) {
|
|
||||||
$this->logger->error($exception->getMessage(), ['exception' => $exception]);
|
|
||||||
throw new MissingJob($exception);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string $value
|
|
||||||
* @param int $delay
|
|
||||||
* @return $this
|
|
||||||
* @throws SetJob
|
|
||||||
*/
|
|
||||||
public function set(string $value, int $delay = 0): self
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$this->client->useTube($this->tube)->put($value, $this->priority, $delay, $this->ttr ?? 0);
|
|
||||||
} catch (Exception $exception) {
|
|
||||||
$this->logger->error($exception->getMessage(), ['payload' => $value, 'delay' => $delay, 'exception' => $exception]);
|
|
||||||
throw new SetJob($value, $exception);
|
|
||||||
}
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string $newPayload
|
|
||||||
* @param int|null $jobId
|
|
||||||
* @return self
|
|
||||||
* @throws RemoveJob
|
|
||||||
* @throws SetJob
|
|
||||||
*/
|
|
||||||
public function update(string $newPayload, ?int $jobId = null): self
|
|
||||||
{
|
|
||||||
if ($jobId === null) {
|
|
||||||
$jobId = $this->currentJob->id;
|
|
||||||
}
|
|
||||||
return $this->remove($jobId)
|
|
||||||
->set($newPayload);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param int|null $jobId
|
|
||||||
* @return $this
|
|
||||||
* @throws RemoveJob
|
|
||||||
*/
|
|
||||||
public function remove(?int $jobId = null): self
|
|
||||||
{
|
|
||||||
if ($jobId === null) {
|
|
||||||
$jobId = $this->currentJob->id;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
if (!$this->client->useTube($this->tube)->delete($jobId)) {
|
|
||||||
throw new JobException("Failed to delete job {$jobId}");
|
|
||||||
}
|
|
||||||
if ($this->currentJob !== null && $this->currentJob->id === $jobId) {
|
|
||||||
$this->currentJob = null;
|
|
||||||
}
|
|
||||||
} catch (Exception $exception) {
|
|
||||||
$this->logger->error($exception->getMessage(), ['jobId' => $jobId, 'exception' => $exception]);
|
|
||||||
throw new RemoveJob($jobId, $exception);
|
|
||||||
}
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,25 +0,0 @@
|
|||||||
<?php
|
|
||||||
namespace Incoviba\Service\MQTT;
|
|
||||||
|
|
||||||
use Incoviba\Exception\MQTT\MissingJob;
|
|
||||||
|
|
||||||
interface MQTTInterface {
|
|
||||||
/**
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function exists(): bool;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return string
|
|
||||||
* @throws MissingJob
|
|
||||||
*/
|
|
||||||
public function get(): string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string $value
|
|
||||||
* @param int $delay
|
|
||||||
* @return self
|
|
||||||
*/
|
|
||||||
public function set(string $value, int $delay = 0): self;
|
|
||||||
public function remove(?int $jobId = null): self;
|
|
||||||
}
|
|
@ -1,59 +0,0 @@
|
|||||||
<?php
|
|
||||||
namespace Incoviba\Service\MQTT;
|
|
||||||
|
|
||||||
use Incoviba\Common\Ideal\Service;
|
|
||||||
use Psr\Log\LoggerInterface;
|
|
||||||
use Pheanstalk as PBA;
|
|
||||||
|
|
||||||
class Pheanstalk extends Service implements MQTTInterface
|
|
||||||
{
|
|
||||||
const string DEFAULT_TUBE = 'default';
|
|
||||||
const int DEFAULT_TTR = 60;
|
|
||||||
const int DEFAULT_PRIORITY = 1_024;
|
|
||||||
|
|
||||||
public function __construct(LoggerInterface $logger, protected PBA\Pheanstalk $client, string $tubeName = self::DEFAULT_TUBE)
|
|
||||||
{
|
|
||||||
parent::__construct($logger);
|
|
||||||
$this->tube = new PBA\Values\TubeName($tubeName);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected PBA\Values\TubeName $tube;
|
|
||||||
|
|
||||||
public function set(string $value, int $delay = 0): self
|
|
||||||
{
|
|
||||||
$this->client->useTube($this->tube);
|
|
||||||
$this->client->put($value, self::DEFAULT_PRIORITY, $delay, self::DEFAULT_TTR);
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
public function exists(): bool
|
|
||||||
{
|
|
||||||
$stats = $this->client->statsTube($this->tube);
|
|
||||||
return $stats->currentJobsReady > 0;
|
|
||||||
}
|
|
||||||
protected int $currentJobId;
|
|
||||||
public function get(): string
|
|
||||||
{
|
|
||||||
$this->client->useTube($this->tube);
|
|
||||||
$job = $this->client->reserve();
|
|
||||||
$this->currentJobId = $job->getId();
|
|
||||||
return $job->getData();
|
|
||||||
}
|
|
||||||
public function update(string $newPayload, ?int $jobId = null): self
|
|
||||||
{
|
|
||||||
if ($jobId === null) {
|
|
||||||
$jobId = $this->currentJobId;
|
|
||||||
}
|
|
||||||
$this->remove($jobId);
|
|
||||||
$this->set($newPayload);
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
public function remove(?int $jobId = null): self
|
|
||||||
{
|
|
||||||
if ($jobId === null) {
|
|
||||||
$jobId = $this->currentJobId;
|
|
||||||
}
|
|
||||||
$this->client->useTube($this->tube);
|
|
||||||
$this->client->delete(new PBA\Values\JobId($jobId));
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
}
|
|
@ -7,7 +7,6 @@ use Psr\Log\LoggerInterface;
|
|||||||
use Incoviba\Common\Ideal;
|
use Incoviba\Common\Ideal;
|
||||||
use Incoviba\Exception\ServiceAction\{Create, Delete, Read, Update};
|
use Incoviba\Exception\ServiceAction\{Create, Delete, Read, Update};
|
||||||
use Incoviba\Service;
|
use Incoviba\Service;
|
||||||
use Incoviba\Model;
|
|
||||||
|
|
||||||
class Queue extends Ideal\Service
|
class Queue extends Ideal\Service
|
||||||
{
|
{
|
||||||
@ -30,7 +29,7 @@ class Queue extends Ideal\Service
|
|||||||
try {
|
try {
|
||||||
$this->jobService->add($configuration);
|
$this->jobService->add($configuration);
|
||||||
return true;
|
return true;
|
||||||
} catch (Create $exception) {
|
} catch (Read $exception) {
|
||||||
$final = new Exception("Could not enqueue job", 0, $exception);
|
$final = new Exception("Could not enqueue job", 0, $exception);
|
||||||
$this->logger->warning($final);
|
$this->logger->warning($final);
|
||||||
return false;
|
return false;
|
||||||
@ -41,8 +40,22 @@ class Queue extends Ideal\Service
|
|||||||
return $this->enqueue($configuration);
|
return $this->enqueue($configuration);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function runJob(Model\Job $job, ?RequestInterface $request = null): bool
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getPendingJobs(): array
|
||||||
{
|
{
|
||||||
|
return $this->jobService->getPending();
|
||||||
|
}
|
||||||
|
public function runJob(int $job_id, ?RequestInterface $request = null): bool
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$job = $this->jobService->getPendingById($job_id);
|
||||||
|
} catch (Read $exception) {
|
||||||
|
$this->logger->debug($exception);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
$type = 'default';
|
$type = 'default';
|
||||||
if (isset($job->configuration['type'])) {
|
if (isset($job->configuration['type'])) {
|
||||||
$type = strtolower($job->configuration['type']);
|
$type = strtolower($job->configuration['type']);
|
||||||
@ -58,57 +71,50 @@ class Queue extends Ideal\Service
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
if (!$worker->execute($job)) {
|
if (!$worker->execute($job)) {
|
||||||
$this->logger->debug("Could not execute job {$job->id}");
|
$this->logger->debug("Could not execute job {$job_id}");
|
||||||
$job->retries++;
|
|
||||||
$this->jobService->update($job);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!$this->jobService->execute($job)) {
|
if (!$this->jobService->execute($job)) {
|
||||||
$this->logger->debug("Could not remove job {$job->id}");
|
$this->logger->debug("Could not remove job {$job_id}");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} catch (Exception $exception) {
|
} catch (Exception $exception) {
|
||||||
$this->logger->warning("Could not run job {$job->id}", ['exception' => $exception]);
|
$final = new Exception("Could not run job", 0, $exception);
|
||||||
$job->retries++;
|
$this->logger->warning($final);
|
||||||
try {
|
|
||||||
$this->jobService->update($job);
|
|
||||||
} catch (Update $exception) {
|
|
||||||
$this->logger->error($exception->getMessage(), ['job' => $job, 'exception' => $exception]);
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
public function run(?RequestInterface $request = null): bool
|
public function run(?RequestInterface $request = null): bool
|
||||||
{
|
{
|
||||||
if (!$this->jobService->isPending()) {
|
$jobs = $this->jobService->getPending();
|
||||||
|
if (count($jobs) === 0) {
|
||||||
|
$this->logger->debug("No pending jobs");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
try {
|
|
||||||
$job = $this->jobService->get();
|
$errors = [];
|
||||||
} catch (Read $exception) {
|
foreach ($jobs as $job) {
|
||||||
$this->logger->error($exception->getMessage(), ['exception' => $exception]);
|
if ($job->retries >= $this->maxRetries) {
|
||||||
return false;
|
try {
|
||||||
}
|
$this->jobService->remove($job);
|
||||||
if ($job->retries >= $this->maxRetries) {
|
} catch (Read | Delete $exception) {
|
||||||
try {
|
$this->logger->error($exception->getMessage(), ['exception' => $exception]);
|
||||||
$this->jobService->remove($job);
|
}
|
||||||
} catch (Delete $exception) {
|
continue;
|
||||||
$this->logger->error($exception->getMessage(), ['job' => $job, 'exception' => $exception]);
|
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
$this->runJob($job, $request);
|
|
||||||
} catch (Exception) {
|
|
||||||
$job->retries ++;
|
|
||||||
try {
|
try {
|
||||||
$this->jobService->update($job);
|
$this->runJob($job->id, $request);
|
||||||
} catch (Update $exception) {
|
} catch (Exception) {
|
||||||
$this->logger->error($exception->getMessage(), ['job' => $job, 'exception' => $exception]);
|
$job->retries ++;
|
||||||
|
try {
|
||||||
|
$this->jobService->update($job);
|
||||||
|
} catch (Read | Update $exception) {
|
||||||
|
$this->logger->error($exception->getMessage(), ['exception' => $exception]);
|
||||||
|
}
|
||||||
|
$errors []= $job->id;
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
return true;
|
return count($errors) === 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ namespace Incoviba\Service;
|
|||||||
use DateTimeInterface;
|
use DateTimeInterface;
|
||||||
use DateTimeImmutable;
|
use DateTimeImmutable;
|
||||||
use DateMalformedStringException;
|
use DateMalformedStringException;
|
||||||
use Incoviba\Service\Valor\Phone;
|
use function PHPUnit\Framework\countOf;
|
||||||
|
|
||||||
class Valor
|
class Valor
|
||||||
{
|
{
|
||||||
@ -40,14 +40,6 @@ class Valor
|
|||||||
}
|
}
|
||||||
return $value / $this->ufService->get($date);
|
return $value / $this->ufService->get($date);
|
||||||
}
|
}
|
||||||
public function phone(): Phone
|
|
||||||
{
|
|
||||||
return new Phone();
|
|
||||||
}
|
|
||||||
public function telefono(): Phone
|
|
||||||
{
|
|
||||||
return $this->phone();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function getDateTime(null|string|DateTimeInterface $date): DateTimeInterface
|
protected function getDateTime(null|string|DateTimeInterface $date): DateTimeInterface
|
||||||
{
|
{
|
||||||
|
@ -1,28 +0,0 @@
|
|||||||
<?php
|
|
||||||
namespace Incoviba\Service\Valor;
|
|
||||||
|
|
||||||
class Phone
|
|
||||||
{
|
|
||||||
public function toDatabase(?string $phone): ?int
|
|
||||||
{
|
|
||||||
if ($phone === null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return (int) str_replace([' ', '+'], '', $phone) ?? null;
|
|
||||||
}
|
|
||||||
public function toDisplay(?int $phone): ?string
|
|
||||||
{
|
|
||||||
if ($phone === null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
$parts = preg_split('/(?=<country>\d{2})?(?=<area>\d)(?=<first>\d{4})(?=<last>\d{4})/', $phone);
|
|
||||||
$output = [];
|
|
||||||
if (array_key_exists('country', $parts)) {
|
|
||||||
$output [] = "+{$parts[0]}";
|
|
||||||
}
|
|
||||||
$output [] = $parts[1] ?? '';
|
|
||||||
$output [] = $parts[2] ?? '';
|
|
||||||
$output [] = $parts[3] ?? '';
|
|
||||||
return implode(' ', $output);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,10 +1,10 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace Incoviba\Service;
|
namespace Incoviba\Service;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
use DateTimeImmutable;
|
use DateTimeImmutable;
|
||||||
use DateMalformedStringException;
|
use DateMalformedStringException;
|
||||||
use Incoviba\Exception\ServiceAction\{Create, Read, Update};
|
use Incoviba\Exception\ServiceAction\{Create, Read, Update};
|
||||||
use Incoviba\Common\Define;
|
|
||||||
use PDOException;
|
use PDOException;
|
||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
use Incoviba\Common\Ideal\Service;
|
use Incoviba\Common\Ideal\Service;
|
||||||
@ -12,7 +12,7 @@ use Incoviba\Common\Implement;
|
|||||||
use Incoviba\Repository;
|
use Incoviba\Repository;
|
||||||
use Incoviba\Model;
|
use Incoviba\Model;
|
||||||
|
|
||||||
class Venta extends Service\Repository
|
class Venta extends Service
|
||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
LoggerInterface $logger,
|
LoggerInterface $logger,
|
||||||
@ -189,11 +189,6 @@ class Venta extends Service\Repository
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getRepository(): Define\Repository
|
|
||||||
{
|
|
||||||
return $this->ventaRepository;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function process(Model\Venta $venta): Model\Venta
|
protected function process(Model\Venta $venta): Model\Venta
|
||||||
{
|
{
|
||||||
if ($venta->uf === 0.0) {
|
if ($venta->uf === 0.0) {
|
||||||
|
@ -76,24 +76,15 @@ abstract class AbstractEndPoint extends LoggerEnabled implements EndPoint
|
|||||||
* @param array $data
|
* @param array $data
|
||||||
* @param array $validStatus
|
* @param array $validStatus
|
||||||
* @param array $invalidStatus
|
* @param array $invalidStatus
|
||||||
* @param string|null $accountKey
|
|
||||||
* @return bool
|
* @return bool
|
||||||
* @throws EmptyResponse
|
* @throws EmptyResponse
|
||||||
*/
|
*/
|
||||||
protected function sendAdd(string $request_uri, array $data, array $validStatus, array $invalidStatus, ?string $accountKey = null): bool
|
protected function sendAdd(string $request_uri, array $data, array $validStatus, array $invalidStatus): bool
|
||||||
{
|
{
|
||||||
$params = $this->mapParams($data);
|
$params = $this->mapParams($data);
|
||||||
$this->logger->info('Send Add', ['uri' => $request_uri, 'params' => $params]);
|
$this->logger->info('Send Add', ['uri' => $request_uri, 'params' => $params]);
|
||||||
try {
|
try {
|
||||||
$options = [
|
$response = $this->client->post($request_uri, ['json' => $params]);
|
||||||
'json' => $params
|
|
||||||
];
|
|
||||||
if ($accountKey !== null) {
|
|
||||||
$options['headers'] = [
|
|
||||||
'X-Account-Key' => $accountKey
|
|
||||||
];
|
|
||||||
}
|
|
||||||
$response = $this->client->post($request_uri, $options);
|
|
||||||
} catch (ClientExceptionInterface $exception) {
|
} catch (ClientExceptionInterface $exception) {
|
||||||
throw new EmptyResponse($request_uri, $exception);
|
throw new EmptyResponse($request_uri, $exception);
|
||||||
}
|
}
|
||||||
@ -120,23 +111,14 @@ abstract class AbstractEndPoint extends LoggerEnabled implements EndPoint
|
|||||||
* @param array $data
|
* @param array $data
|
||||||
* @param array $validStatus
|
* @param array $validStatus
|
||||||
* @param array $invalidStatus
|
* @param array $invalidStatus
|
||||||
* @param string|null $accountKey
|
|
||||||
* @return bool
|
* @return bool
|
||||||
* @throws EmptyResponse
|
* @throws EmptyResponse
|
||||||
*/
|
*/
|
||||||
protected function sendEdit(string $request_uri, array $data, array $validStatus, array $invalidStatus, ?string $accountKey = null): bool
|
protected function sendEdit(string $request_uri, array $data, array $validStatus, array $invalidStatus): bool
|
||||||
{
|
{
|
||||||
$params = $this->mapParams($data);
|
$params = $this->mapParams($data);
|
||||||
try {
|
try {
|
||||||
$options = [
|
$response = $this->client->put($request_uri, ['json' => $params]);
|
||||||
'json' => $params
|
|
||||||
];
|
|
||||||
if ($accountKey !== null) {
|
|
||||||
$options['headers'] = [
|
|
||||||
'X-Account-Key' => $accountKey
|
|
||||||
];
|
|
||||||
}
|
|
||||||
$response = $this->client->put($request_uri, $options);
|
|
||||||
} catch (ClientExceptionInterface $exception) {
|
} catch (ClientExceptionInterface $exception) {
|
||||||
throw new EmptyResponse($request_uri, $exception);
|
throw new EmptyResponse($request_uri, $exception);
|
||||||
}
|
}
|
||||||
|
@ -28,20 +28,18 @@ interface EndPoint
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param array $data
|
* @param array $data
|
||||||
* @param string|null $accountKey
|
|
||||||
* @return bool
|
* @return bool
|
||||||
* @throws EmptyResponse
|
* @throws EmptyResponse
|
||||||
*/
|
*/
|
||||||
public function add(array $data, ?string $accountKey = null): bool;
|
public function add(array $data): bool;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $id
|
* @param string $id
|
||||||
* @param array $data
|
* @param array $data
|
||||||
* @param string|null $accountKey
|
|
||||||
* @return bool
|
* @return bool
|
||||||
* @throws EmptyResponse
|
* @throws EmptyResponse
|
||||||
*/
|
*/
|
||||||
public function edit(string $id, array $data, ?string $accountKey = null): bool;
|
public function edit(string $id, array $data): bool;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $id
|
* @param string $id
|
||||||
|
@ -1,10 +1,8 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace Incoviba\Service\Venta\MediosPago;
|
namespace Incoviba\Service\Venta\MediosPago;
|
||||||
|
|
||||||
use Incoviba\Common\Implement\Exception\EmptyResult;
|
|
||||||
use InvalidArgumentException;
|
use InvalidArgumentException;
|
||||||
use PDO;
|
use PDO;
|
||||||
use PDOException;
|
|
||||||
use Psr\Http\Message\ServerRequestInterface;
|
use Psr\Http\Message\ServerRequestInterface;
|
||||||
use Incoviba\Common\Define\Connection;
|
use Incoviba\Common\Define\Connection;
|
||||||
use Incoviba\Common\Ideal;
|
use Incoviba\Common\Ideal;
|
||||||
@ -82,18 +80,13 @@ class Toku extends Ideal\Service
|
|||||||
try {
|
try {
|
||||||
return $this->subscription->getById($venta->id);
|
return $this->subscription->getById($venta->id);
|
||||||
} catch (InvalidResult $exception) {
|
} catch (InvalidResult $exception) {
|
||||||
$inmobiliaria = $venta->proyecto()->inmobiliaria();
|
|
||||||
$accountKey = null;
|
|
||||||
try {
|
|
||||||
$accountKey = $this->getAccountKey($inmobiliaria->rut);
|
|
||||||
} catch (EmptyResult) {}
|
|
||||||
$subscriptionData = [
|
$subscriptionData = [
|
||||||
'customer' => $customer['toku_id'],
|
'customer' => $customer['toku_id'],
|
||||||
'product_id' => $venta->id,
|
'product_id' => $venta->id,
|
||||||
'venta' => $venta
|
'venta' => $venta
|
||||||
];
|
];
|
||||||
try {
|
try {
|
||||||
if (!$this->subscription->add($subscriptionData, $accountKey)) {
|
if (!$this->subscription->add($subscriptionData)) {
|
||||||
throw new InvalidResult("Could not save Subscription for Venta {$venta->id}", 409, $exception);
|
throw new InvalidResult("Could not save Subscription for Venta {$venta->id}", 409, $exception);
|
||||||
}
|
}
|
||||||
} catch (EmptyResponse $exception) {
|
} catch (EmptyResponse $exception) {
|
||||||
@ -102,6 +95,7 @@ class Toku extends Ideal\Service
|
|||||||
return $this->subscription->getById($venta->id);
|
return $this->subscription->getById($venta->id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Model\Venta $venta
|
* @param Model\Venta $venta
|
||||||
* @param array $cuotas_ids
|
* @param array $cuotas_ids
|
||||||
@ -121,12 +115,6 @@ class Toku extends Ideal\Service
|
|||||||
});
|
});
|
||||||
} catch (EmptyResponse) {}
|
} catch (EmptyResponse) {}
|
||||||
|
|
||||||
$inmobiliaria = $venta->proyecto()->inmobiliaria();
|
|
||||||
$accountKey = null;
|
|
||||||
try {
|
|
||||||
$accountKey = $this->getAccountKey($inmobiliaria->rut);
|
|
||||||
} catch (EmptyResult) {}
|
|
||||||
|
|
||||||
$invoices = [];
|
$invoices = [];
|
||||||
$errors = [];
|
$errors = [];
|
||||||
foreach ($venta->formaPago()->pie->cuotas() as $cuota) {
|
foreach ($venta->formaPago()->pie->cuotas() as $cuota) {
|
||||||
@ -154,7 +142,7 @@ class Toku extends Ideal\Service
|
|||||||
'cuota' => $cuota,
|
'cuota' => $cuota,
|
||||||
'venta' => $venta
|
'venta' => $venta
|
||||||
];
|
];
|
||||||
if (!$this->invoice->add($invoiceData, $accountKey)) {
|
if (!$this->invoice->add($invoiceData)) {
|
||||||
throw new EmptyResponse("Could not add Invoice for Cuota {$cuota->id}", $exception);
|
throw new EmptyResponse("Could not add Invoice for Cuota {$cuota->id}", $exception);
|
||||||
}
|
}
|
||||||
$invoices []= $this->invoice->getById($cuota->id);
|
$invoices []= $this->invoice->getById($cuota->id);
|
||||||
@ -302,95 +290,6 @@ class Toku extends Ideal\Service
|
|||||||
return $queues;
|
return $queues;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function update(array $ids, ?string $type = null): array
|
|
||||||
{
|
|
||||||
if ($type === null) {
|
|
||||||
$types = [
|
|
||||||
'customers',
|
|
||||||
'subscriptions',
|
|
||||||
'invoices'
|
|
||||||
];
|
|
||||||
$results = [];
|
|
||||||
foreach ($types as $type) {
|
|
||||||
$results[$type] = $this->update($ids[$type], $type);
|
|
||||||
}
|
|
||||||
return $results;
|
|
||||||
}
|
|
||||||
$results = [];
|
|
||||||
switch ($type) {
|
|
||||||
case 'subscriptions':
|
|
||||||
try {
|
|
||||||
$results['subscription'] = $this->subscription->update($ids);
|
|
||||||
} catch (EmptyResult | EmptyResponse $exception) {
|
|
||||||
$this->logger->error($exception);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'invoices':
|
|
||||||
try {
|
|
||||||
$results['invoice'] = $this->invoice->updateAll($ids);
|
|
||||||
} catch (EmptyResult $exception) {
|
|
||||||
$this->logger->error($exception);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return $results;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param ServerRequestInterface $request
|
|
||||||
* @param array $tokenConfig
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function validateToken(ServerRequestInterface $request, array $tokenConfig): bool
|
|
||||||
{
|
|
||||||
if (!$request->hasHeader('User-Agent') or !str_starts_with($request->getHeaderLine('User-Agent'), 'Toku-Webhooks')) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!$request->hasHeader('X-Datadog-Tags') or !$request->hasHeader('Tracestate')) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!$request->hasHeader('Toku-Signature')) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$tokuSignature = $request->getHeaderLine('Toku-Signature');
|
|
||||||
try {
|
|
||||||
list($timestamp, $signature) = array_map(function($elem) {
|
|
||||||
return explode('=', $elem)[1];
|
|
||||||
}, explode(',', $tokuSignature));
|
|
||||||
$body = $request->getBody()->getContents();
|
|
||||||
$json = json_decode($body, true);
|
|
||||||
if (!is_array($json)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!array_key_exists('id', $json)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
$eventId = $json['id'];
|
|
||||||
$eventType = $json['event_type'];
|
|
||||||
|
|
||||||
$query = $this->connection->getQueryBuilder()
|
|
||||||
->select('secret')
|
|
||||||
->from('toku_webhooks')
|
|
||||||
->where('enabled = ? AND JSON_SEARCH(events, "one", ?) IS NOT NULL');
|
|
||||||
$params = [true, $eventType];
|
|
||||||
$statement = $this->connection->prepare($query);
|
|
||||||
$statement->execute($params);
|
|
||||||
$results = $statement->fetchAll(PDO::FETCH_COLUMN);
|
|
||||||
if (count($results) === 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (array_any($results, fn($secret) => $this->hmac->validate($timestamp, $signature, $eventId, $secret))) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (Throwable $throwable) {
|
|
||||||
$this->logger->error($throwable);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param array $request
|
* @param array $request
|
||||||
* @return bool
|
* @return bool
|
||||||
@ -507,20 +406,54 @@ class Toku extends Ideal\Service
|
|||||||
$data['date'] = $data['transaction_date'];
|
$data['date'] = $data['transaction_date'];
|
||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
protected function getAccountKey(int $sociedad_rut): string
|
|
||||||
|
public function validateToken(ServerRequestInterface $request, array $tokenConfig): bool
|
||||||
{
|
{
|
||||||
$query = $this->connection->getQueryBuilder()
|
if (!$request->hasHeader('User-Agent') or !str_starts_with($request->getHeaderLine('User-Agent'), 'Toku-Webhooks')) {
|
||||||
->select('account_key')
|
return false;
|
||||||
->from('toku_accounts')
|
}
|
||||||
->where('enabled = ? AND sociedad_rut = ?');
|
if (!$request->hasHeader('X-Datadog-Tags') or !$request->hasHeader('Tracestate')) {
|
||||||
$params = [true, $sociedad_rut];
|
return false;
|
||||||
|
}
|
||||||
|
if (!$request->hasHeader('Toku-Signature')) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$tokuSignature = $request->getHeaderLine('Toku-Signature');
|
||||||
try {
|
try {
|
||||||
|
list($timestamp, $signature) = array_map(function($elem) {
|
||||||
|
return explode('=', $elem)[1];
|
||||||
|
}, explode(',', $tokuSignature));
|
||||||
|
$body = $request->getBody()->getContents();
|
||||||
|
$json = json_decode($body, true);
|
||||||
|
if (!is_array($json)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!array_key_exists('id', $json)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$eventId = $json['id'];
|
||||||
|
$eventType = $json['event_type'];
|
||||||
|
|
||||||
|
$query = $this->connection->getQueryBuilder()
|
||||||
|
->select('secret')
|
||||||
|
->from('toku_webhooks')
|
||||||
|
->where('enabled = ? AND JSON_SEARCH(events, "one", ?) IS NOT NULL');
|
||||||
|
$params = [true, $eventType];
|
||||||
$statement = $this->connection->prepare($query);
|
$statement = $this->connection->prepare($query);
|
||||||
$statement->execute($params);
|
$statement->execute($params);
|
||||||
return $statement->fetchColumn();
|
$results = $statement->fetchAll(PDO::FETCH_COLUMN);
|
||||||
} catch (PDOException $exception) {
|
if (count($results) === 0) {
|
||||||
$this->logger->error($exception);
|
return false;
|
||||||
throw new EmptyResult($query, $exception);
|
}
|
||||||
|
|
||||||
|
if (array_any($results, fn($secret) => $this->hmac->validate($timestamp, $signature, $eventId, $secret))) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Throwable $throwable) {
|
||||||
|
$this->logger->error($throwable);
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,15 +29,15 @@ class Customer extends AbstractEndPoint
|
|||||||
$request_uri = "/customers/{$id}";
|
$request_uri = "/customers/{$id}";
|
||||||
return $this->sendGet($request_uri, [200], [404, 422]);
|
return $this->sendGet($request_uri, [200], [404, 422]);
|
||||||
}
|
}
|
||||||
public function add(array $data, ?string $accountKey = null): bool
|
public function add(array $data): bool
|
||||||
{
|
{
|
||||||
$request_uri = "/customers";
|
$request_uri = "/customers";
|
||||||
return $this->sendAdd($request_uri, $data, [200, 201], [400, 422], $accountKey);
|
return $this->sendAdd($request_uri, $data, [200, 201], [400, 422]);
|
||||||
}
|
}
|
||||||
public function edit(string $id, array $data, ?string $accountKey = null): bool
|
public function edit(string $id, array $data): bool
|
||||||
{
|
{
|
||||||
$request_uri = "customers/{$id}";
|
$request_uri = "customers/{$id}";
|
||||||
return $this->sendEdit($request_uri, $data, [200], [400, 404, 422], $accountKey);
|
return $this->sendEdit($request_uri, $data, [200], [400, 404, 422]);
|
||||||
}
|
}
|
||||||
public function delete(string $id): void
|
public function delete(string $id): void
|
||||||
{
|
{
|
||||||
|
@ -4,7 +4,6 @@ namespace Incoviba\Service\Venta\MediosPago\Toku;
|
|||||||
use DateMalformedStringException;
|
use DateMalformedStringException;
|
||||||
use DateTimeImmutable;
|
use DateTimeImmutable;
|
||||||
use DateTimeZone;
|
use DateTimeZone;
|
||||||
use PDO;
|
|
||||||
use PDOException;
|
use PDOException;
|
||||||
use Psr\Http\Client\ClientInterface;
|
use Psr\Http\Client\ClientInterface;
|
||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
@ -40,15 +39,15 @@ class Invoice extends AbstractEndPoint
|
|||||||
$request_uri = "/invoices/{$id}";
|
$request_uri = "/invoices/{$id}";
|
||||||
return $this->sendGet($request_uri, [200], [404]);
|
return $this->sendGet($request_uri, [200], [404]);
|
||||||
}
|
}
|
||||||
public function add(array $data, ?string $accountKey = null): bool
|
public function add(array $data): bool
|
||||||
{
|
{
|
||||||
$request_uri = "/invoices";
|
$request_uri = "/invoices";
|
||||||
return $this->sendAdd($request_uri, $data, [200, 201], [400, 409, 422], $accountKey);
|
return $this->sendAdd($request_uri, $data, [200, 201], [400, 409, 422]);
|
||||||
}
|
}
|
||||||
public function edit(string $id, array $data, ?string $accountKey = null): bool
|
public function edit(string $id, array $data): bool
|
||||||
{
|
{
|
||||||
$request_uri = "/invoices/{$id}";
|
$request_uri = "/invoices/{$id}";
|
||||||
return $this->sendEdit($request_uri, $data, [200], [400, 404, 409, 422], $accountKey);
|
return $this->sendEdit($request_uri, $data, [200], [400, 404, 409, 422]);
|
||||||
}
|
}
|
||||||
public function delete(string $id): void
|
public function delete(string $id): void
|
||||||
{
|
{
|
||||||
@ -200,41 +199,6 @@ class Invoice extends AbstractEndPoint
|
|||||||
return $this->pagoService->depositar($invoice->cuota->pago, $date);
|
return $this->pagoService->depositar($invoice->cuota->pago, $date);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param array $idsData
|
|
||||||
* @return array
|
|
||||||
* @throws EmptyResult
|
|
||||||
*/
|
|
||||||
public function updateAll(array $idsData): array
|
|
||||||
{
|
|
||||||
$tokuIds = array_column($idsData, 'toku_id');
|
|
||||||
$oldIds = array_column($idsData, 'product_id');
|
|
||||||
|
|
||||||
$placeholders = array_map(fn($id) => "id{$id}", array_keys($oldIds));
|
|
||||||
$placeholdersString = implode(', ', array_map(fn($id) => ":{$id}", $placeholders));
|
|
||||||
$query = $this->pagoService->getRepository()->getConnection()->getQueryBuilder()
|
|
||||||
->select('pago.id, CONCAT_WS("-", unidad.descripcion, CONCAT_WS("-", propietario.rut, propietario.dv)) AS old_pid')
|
|
||||||
->from('pago')
|
|
||||||
->joined('JOIN cuota ON cuota.pago = pago.id')
|
|
||||||
->joined('JOIN venta ON venta.pie = cuota.pie')
|
|
||||||
->joined('JOIN propietario ON propietario.rut = venta.propietario')
|
|
||||||
->joined('JOIN propiedad_unidad pu ON pu.propiedad = venta.propiedad')
|
|
||||||
->joined('JOIN unidad ON pu.unidad = unidad.id')
|
|
||||||
->having("old_pid IN ({$placeholdersString})");
|
|
||||||
$values = array_combine($placeholders, $oldIds);
|
|
||||||
try {
|
|
||||||
$statement = $this->pagoService->getRepository()->getConnection()->execute($query, $values);
|
|
||||||
$results = $statement->fetchAll(PDO::FETCH_ASSOC);
|
|
||||||
} catch (PDOException $exception) {
|
|
||||||
$this->logger->error($exception);
|
|
||||||
throw new EmptyResult($query, $exception);
|
|
||||||
}
|
|
||||||
|
|
||||||
$ids = array_column($results, 'pago.id');
|
|
||||||
$newIds = array_combine($ids, $tokuIds);
|
|
||||||
return array_map(fn($id) => ['product_id' => $id, 'toku_id' => $newIds[$id]], $ids);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function save(array $data): bool
|
public function save(array $data): bool
|
||||||
{
|
{
|
||||||
return $this->doSave($this->invoiceRepository, $data);
|
return $this->doSave($this->invoiceRepository, $data);
|
||||||
@ -251,7 +215,7 @@ class Invoice extends AbstractEndPoint
|
|||||||
{
|
{
|
||||||
$paramsMap = [
|
$paramsMap = [
|
||||||
'customer' => 'customer',
|
'customer' => 'customer',
|
||||||
'product_id' => 'cuota_id',
|
'product_id' => 'product_id',
|
||||||
'due_date' => 'fecha',
|
'due_date' => 'fecha',
|
||||||
'subscription' => 'subscription',
|
'subscription' => 'subscription',
|
||||||
'amount' => 'valor',
|
'amount' => 'valor',
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace Incoviba\Service\Venta\MediosPago\Toku;
|
namespace Incoviba\Service\Venta\MediosPago\Toku;
|
||||||
|
|
||||||
use PDO;
|
|
||||||
use PDOException;
|
use PDOException;
|
||||||
use Psr\Http\Client\ClientInterface;
|
use Psr\Http\Client\ClientInterface;
|
||||||
use Incoviba\Common\Implement\Exception\EmptyResponse;
|
use Incoviba\Common\Implement\Exception\EmptyResponse;
|
||||||
@ -35,15 +34,15 @@ class Subscription extends AbstractEndPoint
|
|||||||
$request_uri = "/subscriptions/{$id}";
|
$request_uri = "/subscriptions/{$id}";
|
||||||
return $this->sendGet($request_uri, [200], [401, 404, 422]);
|
return $this->sendGet($request_uri, [200], [401, 404, 422]);
|
||||||
}
|
}
|
||||||
public function add(array $data, ?string $accountKey = null): bool
|
public function add(array $data): bool
|
||||||
{
|
{
|
||||||
$request_uri = '/subscriptions';
|
$request_uri = '/subscriptions';
|
||||||
return $this->sendAdd($request_uri, $data, [200, 201], [401, 404, 409, 422], $accountKey);
|
return $this->sendAdd($request_uri, $data, [200, 201], [401, 404, 409, 422]);
|
||||||
}
|
}
|
||||||
public function edit(string $id, array $data, ?string $accountKey = null): bool
|
public function edit(string $id, array $data): bool
|
||||||
{
|
{
|
||||||
$request_uri = "/subscriptions/{$id}";
|
$request_uri = "/subscriptions/{$id}";
|
||||||
return $this->sendEdit($request_uri, $data, [200], [401, 404, 409, 422], $accountKey);
|
return $this->sendEdit($request_uri, $data, [200], [401, 404, 409, 422]);
|
||||||
}
|
}
|
||||||
public function delete(string $id): void
|
public function delete(string $id): void
|
||||||
{
|
{
|
||||||
@ -112,101 +111,6 @@ class Subscription extends AbstractEndPoint
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param array $idsData
|
|
||||||
* @return array
|
|
||||||
* @throws EmptyResult
|
|
||||||
* @throws EmptyResponse
|
|
||||||
*/
|
|
||||||
public function update(array $idsData): array
|
|
||||||
{
|
|
||||||
$tokuIds = array_column($idsData, 'toku_id');
|
|
||||||
$oldPids = array_column($idsData, 'product_id');
|
|
||||||
|
|
||||||
$placeholders = array_map(fn($id) => "id{$id}", array_keys($oldPids));
|
|
||||||
$placeholdersString = implode(', ', array_map(fn($id) => ":{$id}", $placeholders));
|
|
||||||
$query = $this->ventaService->getRepository()->getConnection()->getQueryBuilder()
|
|
||||||
->select('venta.id, CONCAT_WS("-", unidad.descripcion, CONCAT_WS("-", propietario.rut, propietario.dv)) AS old_pid')
|
|
||||||
->from('venta')
|
|
||||||
->joined('JOIN propietario ON propietario.rut = venta.propietario')
|
|
||||||
->joined('JOIN propiedad_unidad pu ON pu.propiedad = venta.propiedad')
|
|
||||||
->joined('JOIN unidad ON pu.unidad = unidad.id')
|
|
||||||
->having("old_pid IN ({$placeholdersString})");
|
|
||||||
$values = array_combine($placeholders, $oldPids);
|
|
||||||
try {
|
|
||||||
$statement = $this->ventaService->getRepository()->getConnection()->execute($query, $values);
|
|
||||||
$results = $statement->fetchAll(PDO::FETCH_ASSOC);
|
|
||||||
} catch (PDOException $exception) {
|
|
||||||
$this->logger->error($exception->getMessage(), [
|
|
||||||
'query' => $query,
|
|
||||||
'values' => $values,
|
|
||||||
'ids' => $idsData,
|
|
||||||
'exception' => $exception]);
|
|
||||||
throw new EmptyResult($query, $exception);
|
|
||||||
}
|
|
||||||
|
|
||||||
$accountKeys = $this->getAccountKey(array_column($results, 'id'));
|
|
||||||
|
|
||||||
$newPids = [];
|
|
||||||
$keys = [];
|
|
||||||
foreach ($results as $result) {
|
|
||||||
$idx = array_search($result['old_pid'], $oldPids);
|
|
||||||
$newPids[$idx] = $result['id'];
|
|
||||||
if (array_key_exists($result['id'], $accountKeys)) {
|
|
||||||
$keys[$idx] = $accountKeys[$result['id']];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$output = [];
|
|
||||||
foreach ($tokuIds as $idx => $tokuId) {
|
|
||||||
if (!isset($newPids[$idx])) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
$data = [
|
|
||||||
'product_id' => $newPids[$idx],
|
|
||||||
];
|
|
||||||
try {
|
|
||||||
if (!$this->edit($tokuId, $data, array_key_exists($idx, $keys) ? $keys[$idx] : null)) {
|
|
||||||
$this->logger->error('Error while updating Toku', [
|
|
||||||
'toku_id' => $tokuId,
|
|
||||||
'old_pid' => $oldPids[$idx],
|
|
||||||
'product_id' => $newPids[$idx],
|
|
||||||
'account_key' => array_key_exists($idx, $keys) ? $keys[$idx] : null]);
|
|
||||||
$output[] = [
|
|
||||||
'toku_id' => $tokuId,
|
|
||||||
'old_pid' => $oldPids[$idx],
|
|
||||||
'product_id' => $newPids[$idx],
|
|
||||||
'account_key' => array_key_exists($idx, $keys) ? $keys[$idx] : null,
|
|
||||||
'error' => 'Error while updating Toku'
|
|
||||||
];
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
} catch (EmptyResponse $exception) {
|
|
||||||
$this->logger->error($exception->getMessage(), [
|
|
||||||
'toku_id' => $tokuId,
|
|
||||||
'old_pid' => $oldPids[$idx],
|
|
||||||
'product_id' => $newPids[$idx],
|
|
||||||
'account_key' => array_key_exists($idx, $keys) ? $keys[$idx] : null,
|
|
||||||
'exception' => $exception]);
|
|
||||||
$output[] = [
|
|
||||||
'toku_id' => $tokuId,
|
|
||||||
'old_pid' => $oldPids[$idx],
|
|
||||||
'product_id' => $newPids[$idx],
|
|
||||||
'account_key' => array_key_exists($idx, $keys) ? $keys[$idx] : null,
|
|
||||||
'error' => $exception->getMessage()
|
|
||||||
];
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
$output[] = [
|
|
||||||
'toku_id' => $tokuId,
|
|
||||||
'old_pid' => $oldPids[$idx],
|
|
||||||
'product_id' => $newPids[$idx],
|
|
||||||
'account_key' => array_key_exists($idx, $keys) ? $keys[$idx] : null
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
return $output;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function save(array $data): bool
|
public function save(array $data): bool
|
||||||
{
|
{
|
||||||
return $this->doSave($this->subscriptionRepsitory, $data);
|
return $this->doSave($this->subscriptionRepsitory, $data);
|
||||||
@ -229,11 +133,11 @@ class Subscription extends AbstractEndPoint
|
|||||||
if ($ref === null) {
|
if ($ref === null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if ($ref === 'pieValor' and array_key_exists('venta', $data)) {
|
if ($ref === 'pieValor') {
|
||||||
$params[$key] = $data['venta']?->formaPago()?->pie?->valor ?? 0;
|
$params[$key] = $data['venta']->formaPago()?->pie?->valor ?? 0;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if ($ref === 'datosVenta' and array_key_exists('venta', $data)) {
|
if ($ref === 'datosVenta') {
|
||||||
$params[$key] = $this->datosVenta($data['venta']);
|
$params[$key] = $this->datosVenta($data['venta']);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -265,38 +169,4 @@ class Subscription extends AbstractEndPoint
|
|||||||
'Unidades' => $venta->propiedad()->summary()
|
'Unidades' => $venta->propiedad()->summary()
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param array $ventaIds
|
|
||||||
* @return array
|
|
||||||
* @throws EmptyResult
|
|
||||||
*/
|
|
||||||
protected function getAccountKey(array $ventaIds): array
|
|
||||||
{
|
|
||||||
$placeholders = array_map(fn($id) => "id{$id}", array_keys($ventaIds));
|
|
||||||
$placeholdersString = implode(', ', array_map(fn($id) => ":{$id}", $placeholders));
|
|
||||||
$query = $this->ventaService->getRepository()->getConnection()->getQueryBuilder()
|
|
||||||
->select('account_key, venta.id AS venta_id')
|
|
||||||
->from('toku_accounts')
|
|
||||||
->joined('JOIN proyecto ON proyecto.inmobiliaria = toku_accounts.sociedad_rut')
|
|
||||||
->joined('JOIN proyecto_tipo_unidad ptu ON ptu.proyecto = proyecto.id')
|
|
||||||
->joined('JOIN unidad ON unidad.pt = ptu.id')
|
|
||||||
->joined('JOIN propiedad_unidad pu ON pu.unidad = unidad.id')
|
|
||||||
->joined('JOIN venta ON venta.propiedad = pu.propiedad')
|
|
||||||
->where("venta.id IN ({$placeholdersString}) AND toku_accounts.enabled = 1");
|
|
||||||
$values = array_combine($placeholders, $ventaIds);
|
|
||||||
try {
|
|
||||||
$statement = $this->ventaService->getRepository()->getConnection()->execute($query, $values);
|
|
||||||
$results = $statement->fetchAll(PDO::FETCH_ASSOC);
|
|
||||||
} catch (PDOException $exception) {
|
|
||||||
$this->logger->error($exception->getMessage(), [
|
|
||||||
'query' => $query,
|
|
||||||
'values' => $values,
|
|
||||||
'exception' => $exception]);
|
|
||||||
throw new EmptyResult($query, $exception);
|
|
||||||
}
|
|
||||||
$keys = array_column($results, 'account_key');
|
|
||||||
$ids = array_column($results, 'venta_id');
|
|
||||||
return array_combine($ids, $keys);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -4,37 +4,25 @@ namespace Incoviba\Service\Venta;
|
|||||||
use DateTimeInterface;
|
use DateTimeInterface;
|
||||||
use DateTimeImmutable;
|
use DateTimeImmutable;
|
||||||
use DateMalformedStringException;
|
use DateMalformedStringException;
|
||||||
use Incoviba\Common\Define;
|
|
||||||
use Incoviba\Exception\ServiceAction\Create;
|
use Incoviba\Exception\ServiceAction\Create;
|
||||||
use Incoviba\Exception\ServiceAction\Read;
|
use Incoviba\Exception\ServiceAction\Read;
|
||||||
use Incoviba\Exception\ServiceAction\Update;
|
use Incoviba\Exception\ServiceAction\Update;
|
||||||
use PDOException;
|
use PDOException;
|
||||||
use Incoviba\Common\Ideal;
|
|
||||||
use Incoviba\Common\Implement\Exception\EmptyResult;
|
use Incoviba\Common\Implement\Exception\EmptyResult;
|
||||||
use Incoviba\Repository;
|
use Incoviba\Repository;
|
||||||
use Incoviba\Model;
|
use Incoviba\Model;
|
||||||
use Incoviba\Service;
|
use Incoviba\Service;
|
||||||
use Psr\Log\LoggerInterface;
|
|
||||||
|
|
||||||
class Pago extends Ideal\Service\Repository
|
class Pago
|
||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
LoggerInterface $logger,
|
|
||||||
protected Repository\Venta\Pago $pagoRepository,
|
protected Repository\Venta\Pago $pagoRepository,
|
||||||
protected Repository\Venta\EstadoPago $estadoPagoRepository,
|
protected Repository\Venta\EstadoPago $estadoPagoRepository,
|
||||||
protected Repository\Venta\TipoEstadoPago $tipoEstadoPagoRepository,
|
protected Repository\Venta\TipoEstadoPago $tipoEstadoPagoRepository,
|
||||||
protected Service\UF $ufService,
|
protected Service\UF $ufService,
|
||||||
protected Service\Valor $valorService,
|
protected Service\Valor $valorService,
|
||||||
protected Service\Queue $queueService
|
protected Service\Queue $queueService
|
||||||
)
|
) {}
|
||||||
{
|
|
||||||
parent::__construct($logger);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getRepository(): Define\Repository
|
|
||||||
{
|
|
||||||
return $this->pagoRepository;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function depositar(Model\Venta\Pago $pago, DateTimeInterface $fecha): bool
|
public function depositar(Model\Venta\Pago $pago, DateTimeInterface $fecha): bool
|
||||||
{
|
{
|
||||||
|
@ -1,24 +1,22 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace Incoviba\Service\Venta;
|
namespace Incoviba\Service\Venta;
|
||||||
|
|
||||||
use PDOException;
|
|
||||||
use Psr\Log\LoggerInterface;
|
|
||||||
use Incoviba\Common\Ideal\Service;
|
use Incoviba\Common\Ideal\Service;
|
||||||
use Incoviba\Common\Implement\Exception\EmptyResult;
|
use Incoviba\Common\Implement\Exception\EmptyResult;
|
||||||
use Incoviba\Exception\ServiceAction\Create;
|
use Incoviba\Exception\ServiceAction\Create;
|
||||||
use Incoviba\Exception\ServiceAction\Read;
|
use Incoviba\Exception\ServiceAction\Read;
|
||||||
use Incoviba\Exception\ServiceAction\Update;
|
use Incoviba\Exception\ServiceAction\Update;
|
||||||
use Incoviba\Model;
|
|
||||||
use Incoviba\Repository;
|
use Incoviba\Repository;
|
||||||
use Incoviba\Service\Valor;
|
use Incoviba\Model;
|
||||||
|
use PDOException;
|
||||||
|
use Psr\Log\LoggerInterface;
|
||||||
|
|
||||||
class Propietario extends Service
|
class Propietario extends Service
|
||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
LoggerInterface $logger,
|
LoggerInterface $logger,
|
||||||
protected Repository\Venta\Propietario $propietarioRepository,
|
protected Repository\Venta\Propietario $propietarioRepository,
|
||||||
protected Repository\Direccion $direccionRepository,
|
protected Repository\Direccion $direccionRepository
|
||||||
protected Valor $valorService
|
|
||||||
) {
|
) {
|
||||||
parent::__construct($logger);
|
parent::__construct($logger);
|
||||||
}
|
}
|
||||||
@ -51,9 +49,6 @@ class Propietario extends Service
|
|||||||
$data['direccion'] = $direccion->id;
|
$data['direccion'] = $direccion->id;
|
||||||
}
|
}
|
||||||
$filteredData = $this->propietarioRepository->filterData($data);
|
$filteredData = $this->propietarioRepository->filterData($data);
|
||||||
if (array_key_exists('telefono', $filteredData)) {
|
|
||||||
$filteredData['telefono'] = $this->valorService->telefono()->toDatabase($filteredData['telefono']);
|
|
||||||
}
|
|
||||||
try {
|
try {
|
||||||
return $this->propietarioRepository->edit($propietario, $filteredData);
|
return $this->propietarioRepository->edit($propietario, $filteredData);
|
||||||
} catch (PDOException | EmptyResult $exception) {
|
} catch (PDOException | EmptyResult $exception) {
|
||||||
@ -90,10 +85,6 @@ class Propietario extends Service
|
|||||||
]);
|
]);
|
||||||
$filtered_data = array_intersect_key($data, $fields);
|
$filtered_data = array_intersect_key($data, $fields);
|
||||||
|
|
||||||
if (array_key_exists('telefono', $filtered_data)) {
|
|
||||||
$filtered_data['telefono'] = $this->valorService->telefono()->toDatabase($filtered_data['telefono']);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$propietario = $this->propietarioRepository->fetchById($data['rut']);
|
$propietario = $this->propietarioRepository->fetchById($data['rut']);
|
||||||
$edits = [];
|
$edits = [];
|
||||||
@ -104,7 +95,6 @@ class Propietario extends Service
|
|||||||
} catch (EmptyResult) {
|
} catch (EmptyResult) {
|
||||||
try {
|
try {
|
||||||
$propietario = $this->propietarioRepository->create($filtered_data);
|
$propietario = $this->propietarioRepository->create($filtered_data);
|
||||||
$this->logger->info('Propietario', ['propietario' => $propietario]);
|
|
||||||
$propietario = $this->propietarioRepository->save($propietario);
|
$propietario = $this->propietarioRepository->save($propietario);
|
||||||
} catch (PDOException $exception) {
|
} catch (PDOException $exception) {
|
||||||
throw new Create(__CLASS__, $exception);
|
throw new Create(__CLASS__, $exception);
|
||||||
|
@ -1,101 +0,0 @@
|
|||||||
<?php
|
|
||||||
namespace Incoviba\Test\Service\MQTT;
|
|
||||||
|
|
||||||
use Psr\Log\LoggerInterface;
|
|
||||||
use PHPUnit\Framework\TestCase;
|
|
||||||
use xobotyi\beansclient\BeansClient;
|
|
||||||
use xobotyi\beansclient\Connection;
|
|
||||||
use xobotyi\beansclient\Exception\JobException;
|
|
||||||
use xobotyi\beansclient\Job;
|
|
||||||
use Incoviba\Exception\MQTT\MissingJob;
|
|
||||||
use Incoviba\Service\MQTT\Beanstalkd;
|
|
||||||
|
|
||||||
class BeanstalkdTest extends TestCase
|
|
||||||
{
|
|
||||||
protected LoggerInterface $logger;
|
|
||||||
protected BeansClient $client;
|
|
||||||
protected function setUp(): void
|
|
||||||
{
|
|
||||||
$this->logger = $this->getMockBuilder(LoggerInterface::class)->getMock();
|
|
||||||
$this->client = $this->getMockBuilder(BeansClient::class)->disableOriginalConstructor()->getMock();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testExists(): void
|
|
||||||
{
|
|
||||||
$stats = ['current-jobs-ready' => 1];
|
|
||||||
$this->client->method('watchTube')->willReturn($this->client);
|
|
||||||
$this->client->method('statsTube')->willReturn($stats);
|
|
||||||
$service = new Beanstalkd($this->logger, $this->client);
|
|
||||||
$this->assertTrue($service->exists());
|
|
||||||
}
|
|
||||||
public function testNotExists(): void
|
|
||||||
{
|
|
||||||
$stats = ['current-jobs-ready' => 0];
|
|
||||||
$this->client->method('watchTube')->willReturn($this->client);
|
|
||||||
$this->client->method('statsTube')->willReturn($stats);
|
|
||||||
$service = new Beanstalkd($this->logger, $this->client);
|
|
||||||
$this->assertFalse($service->exists());
|
|
||||||
}
|
|
||||||
public function testGet(): void
|
|
||||||
{
|
|
||||||
$jobData = [
|
|
||||||
'id' => 1,
|
|
||||||
'configuration' => [
|
|
||||||
'type' => 'service',
|
|
||||||
],
|
|
||||||
'created_at' => '2020-01-01 00:00:00',
|
|
||||||
];
|
|
||||||
$connection = $this->getMockBuilder(Connection::class)->disableOriginalConstructor()->getMock();
|
|
||||||
$connection->method('isActive')->willReturn(true);
|
|
||||||
$this->client->method('getConnection')->willReturn($connection);
|
|
||||||
$this->client->method('watchTube')->willReturn($this->client);
|
|
||||||
$this->client->method('statsTube')->willReturn(['current-jobs-ready' => 1]);
|
|
||||||
$job = new Job($this->client, 1, 'ready', json_encode($jobData));
|
|
||||||
$this->client->method('reserve')->willReturn($job);
|
|
||||||
$service = new Beanstalkd($this->logger, $this->client);
|
|
||||||
$this->assertEquals(json_encode($jobData), $service->get());
|
|
||||||
}
|
|
||||||
public function testGetException(): void
|
|
||||||
{
|
|
||||||
$this->client->method('watchTube')->willReturn($this->client);
|
|
||||||
$this->client->method('statsTube')->willReturn(['current-jobs-ready' => 0]);
|
|
||||||
$service = new Beanstalkd($this->logger, $this->client);
|
|
||||||
$this->expectException(MissingJob::class);
|
|
||||||
$service->get();
|
|
||||||
|
|
||||||
$this->client->method('statsTube')->willReturn(['current-jobs-ready' => 1]);
|
|
||||||
$exception = new JobException();
|
|
||||||
$this->client->method('reserve')->willThrowException($exception);
|
|
||||||
$this->expectException(MissingJob::class);
|
|
||||||
$service->get();
|
|
||||||
}
|
|
||||||
public function testSet(): void
|
|
||||||
{
|
|
||||||
$this->client->method('useTube')->willReturn($this->client);
|
|
||||||
$this->client->method('put');
|
|
||||||
$service = new Beanstalkd($this->logger, $this->client);
|
|
||||||
$service->set('test');
|
|
||||||
$this->assertTrue(true);
|
|
||||||
}
|
|
||||||
public function testSetException(): void
|
|
||||||
{
|
|
||||||
$this->client->method('useTube')->willReturn($this->client);
|
|
||||||
$exception = new JobException();
|
|
||||||
$this->client->method('put')->willThrowException($exception);
|
|
||||||
$service = new Beanstalkd($this->logger, $this->client);
|
|
||||||
$service->set('test');
|
|
||||||
$this->assertTrue(true);
|
|
||||||
}
|
|
||||||
public function testRemove(): void
|
|
||||||
{
|
|
||||||
$this->client->method('useTube')->willReturn($this->client);
|
|
||||||
$this->client->method('delete')->willReturn(true);
|
|
||||||
$service = new Beanstalkd($this->logger, $this->client);
|
|
||||||
$service->remove(1);
|
|
||||||
$this->assertTrue(true);
|
|
||||||
|
|
||||||
$this->client->method('delete')->willReturn(false);
|
|
||||||
$service->remove(1);
|
|
||||||
$this->assertTrue(true);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,69 +0,0 @@
|
|||||||
<?php
|
|
||||||
namespace Incoviba\Test\Service;
|
|
||||||
|
|
||||||
use Psr\Log\LoggerInterface;
|
|
||||||
use PHPUnit\Framework\TestCase;
|
|
||||||
use xobotyi\beansclient\BeansClient;
|
|
||||||
use Incoviba\Exception\MQTT\MissingClient;
|
|
||||||
use Incoviba\Service\MQTT;
|
|
||||||
use Incoviba\Service\MQTT\Beanstalkd;
|
|
||||||
|
|
||||||
class MQTTTest extends TestCase
|
|
||||||
{
|
|
||||||
public function testRegisterAndClientExistsAndGet(): void
|
|
||||||
{
|
|
||||||
$mqtt = new MQTT();
|
|
||||||
$beanstalkd = $this->getMockBuilder(Beanstalkd::class)->disableOriginalConstructor()->getMock();
|
|
||||||
$mqtt->register('beanstalkd', $beanstalkd);
|
|
||||||
$this->assertTrue($mqtt->clientExists('beanstalkd'));
|
|
||||||
}
|
|
||||||
public function testGetClient(): void
|
|
||||||
{
|
|
||||||
$mqtt = new MQTT();
|
|
||||||
$logger = $this->getMockBuilder(LoggerInterface::class)->disableOriginalConstructor()->getMock();
|
|
||||||
$client = $this->getMockBuilder(BeansClient::class)->disableOriginalConstructor()->getMock();
|
|
||||||
$beanstalkd = new Beanstalkd($logger, $client);
|
|
||||||
$mqtt->register('beanstalkd', $beanstalkd);
|
|
||||||
$this->assertEquals($beanstalkd, $mqtt->getClient('beanstalkd'));
|
|
||||||
}
|
|
||||||
public function testGetClientException(): void
|
|
||||||
{
|
|
||||||
$mqtt = new MQTT();
|
|
||||||
$this->expectException(MissingClient::class);
|
|
||||||
$mqtt->getClient('test');
|
|
||||||
}
|
|
||||||
public function testExists(): void
|
|
||||||
{
|
|
||||||
$mqtt = new MQTT();
|
|
||||||
$beanstalkd = $this->getMockBuilder(Beanstalkd::class)->disableOriginalConstructor()->getMock();
|
|
||||||
$beanstalkd->method('exists')->willReturn(true);
|
|
||||||
$mqtt->register('beanstalkd', $beanstalkd);
|
|
||||||
$this->assertTrue($mqtt->exists('beanstalkd'));
|
|
||||||
}
|
|
||||||
public function testGet(): void
|
|
||||||
{
|
|
||||||
$mqtt = new MQTT();
|
|
||||||
$beanstalkd = $this->getMockBuilder(Beanstalkd::class)->disableOriginalConstructor()->getMock();
|
|
||||||
$beanstalkd->method('get')->willReturn('test');
|
|
||||||
$mqtt->register('beanstalkd', $beanstalkd);
|
|
||||||
$this->assertEquals('test', $mqtt->get('beanstalkd'));
|
|
||||||
}
|
|
||||||
public function testSet(): void
|
|
||||||
{
|
|
||||||
$mqtt = new MQTT();
|
|
||||||
$beanstalkd = $this->getMockBuilder(Beanstalkd::class)->disableOriginalConstructor()->getMock();
|
|
||||||
$beanstalkd->method('set');
|
|
||||||
$mqtt->register('beanstalkd', $beanstalkd);
|
|
||||||
$mqtt->set('test', 0, 'beanstalkd');
|
|
||||||
$this->assertTrue(true);
|
|
||||||
}
|
|
||||||
public function testRemove(): void
|
|
||||||
{
|
|
||||||
$mqtt = new MQTT();
|
|
||||||
$beanstalkd = $this->getMockBuilder(Beanstalkd::class)->disableOriginalConstructor()->getMock();
|
|
||||||
$beanstalkd->method('remove');
|
|
||||||
$mqtt->register('beanstalkd', $beanstalkd);
|
|
||||||
$mqtt->remove(0, 'beanstalkd');
|
|
||||||
$this->assertTrue(true);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,66 +0,0 @@
|
|||||||
<?php
|
|
||||||
namespace Incoviba\Test\Service;
|
|
||||||
|
|
||||||
use Psr\Log\LoggerInterface;
|
|
||||||
use PHPUnit\Framework\TestCase;
|
|
||||||
use Incoviba\Service\Job;
|
|
||||||
use Incoviba\Service\Queue;
|
|
||||||
use Incoviba\Service\Worker;
|
|
||||||
use Incoviba\Model;
|
|
||||||
|
|
||||||
class QueueTest extends TestCase
|
|
||||||
{
|
|
||||||
protected LoggerInterface $logger;
|
|
||||||
protected Job $jobService;
|
|
||||||
protected Worker $defaultWorker;
|
|
||||||
protected function setUp(): void
|
|
||||||
{
|
|
||||||
$this->logger = $this->getMockBuilder(LoggerInterface::class)
|
|
||||||
->disableOriginalConstructor()
|
|
||||||
->getMock();
|
|
||||||
$this->jobService = $this->getMockBuilder(Job::class)
|
|
||||||
->disableOriginalConstructor()
|
|
||||||
->getMock();
|
|
||||||
$this->defaultWorker = $this->getMockBuilder(Worker::class)
|
|
||||||
->disableOriginalConstructor()
|
|
||||||
->getMock();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testRegister(): void
|
|
||||||
{
|
|
||||||
$queue = new Queue($this->logger, $this->jobService, $this->defaultWorker);
|
|
||||||
$worker = $this->getMockBuilder(Worker::class)
|
|
||||||
->disableOriginalConstructor()
|
|
||||||
->getMock();
|
|
||||||
$queue->register('test', $worker);
|
|
||||||
$this->assertTrue(true);
|
|
||||||
}
|
|
||||||
public function testEnqueue(): void
|
|
||||||
{
|
|
||||||
$queue = new Queue($this->logger, $this->jobService, $this->defaultWorker);
|
|
||||||
$jobData = ['test' => 'test'];
|
|
||||||
$result = $queue->enqueue($jobData);
|
|
||||||
$this->assertTrue($result);
|
|
||||||
|
|
||||||
$result = $queue->push($jobData);
|
|
||||||
$this->assertTrue($result);
|
|
||||||
}
|
|
||||||
public function testRun(): void
|
|
||||||
{
|
|
||||||
$queue = new Queue($this->logger, $this->jobService, $this->defaultWorker);
|
|
||||||
$result = $queue->run();
|
|
||||||
$this->assertTrue($result);
|
|
||||||
|
|
||||||
|
|
||||||
$jobData = [
|
|
||||||
'type' => 'test',
|
|
||||||
];
|
|
||||||
$job = new Model\Job();
|
|
||||||
$job->id = 1;
|
|
||||||
$job->configuration = $jobData;
|
|
||||||
$this->jobService->method('isPending')->willReturn(true);
|
|
||||||
$this->jobService->method('get')->willReturn($job);
|
|
||||||
$result = $queue->run();
|
|
||||||
$this->assertTrue($result);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,2 +1,2 @@
|
|||||||
[www]
|
[www]
|
||||||
pm.max_children = 8
|
pm.max_children = 15
|
||||||
|
@ -2,12 +2,10 @@
|
|||||||
"name": "incoviba/cli",
|
"name": "incoviba/cli",
|
||||||
"type": "project",
|
"type": "project",
|
||||||
"require": {
|
"require": {
|
||||||
"ext-sockets": "*",
|
|
||||||
"dragonmantank/cron-expression": "^3.4",
|
"dragonmantank/cron-expression": "^3.4",
|
||||||
"guzzlehttp/guzzle": "^7.8",
|
"guzzlehttp/guzzle": "^7.8",
|
||||||
"hollodotme/fast-cgi-client": "^3.1",
|
"hollodotme/fast-cgi-client": "^3.1",
|
||||||
"monolog/monolog": "^3.5",
|
"monolog/monolog": "^3.5",
|
||||||
"pda/pheanstalk": "^7.0",
|
|
||||||
"php-di/php-di": "^7.0",
|
"php-di/php-di": "^7.0",
|
||||||
"predis/predis": "^3.0",
|
"predis/predis": "^3.0",
|
||||||
"symfony/console": "^6.3"
|
"symfony/console": "^6.3"
|
||||||
|
@ -7,5 +7,5 @@
|
|||||||
0 2 * * * /code/bin/incoviba money:uf >> /logs/commands 2>&1
|
0 2 * * * /code/bin/incoviba money:uf >> /logs/commands 2>&1
|
||||||
0 2 * * * /code/bin/incoviba money:uf:update >> /logs/commands 2>&1
|
0 2 * * * /code/bin/incoviba money:uf:update >> /logs/commands 2>&1
|
||||||
0 2 1 * * /code/bin/incoviba money:ipc >> /logs/commands 2>&1
|
0 2 1 * * /code/bin/incoviba money:ipc >> /logs/commands 2>&1
|
||||||
*/1 * * * * /code/bin/incoviba queue >> /logs/commands 2>&1
|
*/2 * * * * /code/bin/incoviba queue >> /logs/commands 2>&1
|
||||||
0 3 * * * /code/bin/incoviba external:services >> /logs/commands 2>&1
|
#0 3 * * * /code/bin/incoviba external:services >> /logs/commands 2>&1
|
||||||
|
9
cli/entrypoint
Executable file → Normal file
9
cli/entrypoint
Executable file → Normal file
@ -6,13 +6,8 @@ then
|
|||||||
then
|
then
|
||||||
CMD=$1
|
CMD=$1
|
||||||
shift
|
shift
|
||||||
if [[ $# -gt 0 ]]
|
$CMD -c "$@"
|
||||||
then
|
exit
|
||||||
$CMD -c "$@"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
$CMD
|
|
||||||
exit 0
|
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -16,15 +16,4 @@ return [
|
|||||||
}
|
}
|
||||||
return new Predis\Client($options);
|
return new Predis\Client($options);
|
||||||
},
|
},
|
||||||
Pheanstalk\Pheanstalk::class => function(ContainerInterface $container) {
|
|
||||||
return Pheanstalk\Pheanstalk::create(
|
|
||||||
$container->get('BEANSTALKD_HOST'),
|
|
||||||
$container->has('BEANSTALKD_PORT') ? $container->get('BEANSTALKD_PORT') : 11300
|
|
||||||
);
|
|
||||||
},
|
|
||||||
Incoviba\Service\MQTT\MQTTInterface::class => function(ContainerInterface $container) {
|
|
||||||
$service = new Incoviba\Service\MQTT($container->get(Psr\Log\LoggerInterface::class));
|
|
||||||
$service->register('default', $container->get(Incoviba\Service\MQTT\Pheanstalk::class));
|
|
||||||
return $service;
|
|
||||||
}
|
|
||||||
];
|
];
|
||||||
|
@ -37,8 +37,6 @@ class BaseLoop extends Console\Command\Command
|
|||||||
foreach ($commands as $command) {
|
foreach ($commands as $command) {
|
||||||
$this->runCommand($input, $output, $command);
|
$this->runCommand($input, $output, $command);
|
||||||
}
|
}
|
||||||
unset($commands);
|
|
||||||
memory_reset_peak_usage();
|
|
||||||
$this->waitNextTimeout($output, $start);
|
$this->waitNextTimeout($output, $start);
|
||||||
}
|
}
|
||||||
return self::SUCCESS;
|
return self::SUCCESS;
|
||||||
|
48
cli/src/Command/Job/Pending.php
Normal file
48
cli/src/Command/Job/Pending.php
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
<?php
|
||||||
|
namespace Incoviba\Command\Job;
|
||||||
|
|
||||||
|
use Symfony\Component\Console;
|
||||||
|
use Incoviba\Service;
|
||||||
|
|
||||||
|
#[Console\Attribute\AsCommand(name: 'jobs:pending', description: 'List pending jobs')]
|
||||||
|
class Pending extends Console\Command\Command
|
||||||
|
{
|
||||||
|
public function __construct(protected Service\Job $jobService, ?string $name = null)
|
||||||
|
{
|
||||||
|
parent::__construct($name);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function configure(): void
|
||||||
|
{
|
||||||
|
$this->addOption('full', 'f', Console\Input\InputOption::VALUE_NONE, 'Full output');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function execute(Console\Input\InputInterface $input, Console\Output\OutputInterface $output): int
|
||||||
|
{
|
||||||
|
$jobs = $this->jobService->getPending();
|
||||||
|
$jobCount = count($jobs);
|
||||||
|
$output->writeln("Found {$jobCount} pending jobs");
|
||||||
|
|
||||||
|
if ($input->getOption('full') and $jobCount > 0) {
|
||||||
|
$io = new Console\Style\SymfonyStyle($input, $output);
|
||||||
|
|
||||||
|
$rows = [];
|
||||||
|
foreach ($jobs as $job) {
|
||||||
|
$retries = $job['retries'] ?? 0;
|
||||||
|
$updated = $job['updated_at'] ?? '';
|
||||||
|
|
||||||
|
$rows[] = [
|
||||||
|
$job['id'],
|
||||||
|
$job['created_at'],
|
||||||
|
$job['configuration']['type'],
|
||||||
|
$retries,
|
||||||
|
$updated
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
$io->table(['ID', 'Created', 'Type', 'Retries', 'Updated'], $rows);
|
||||||
|
}
|
||||||
|
|
||||||
|
return self::SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
@ -9,16 +9,22 @@ use Incoviba\Service;
|
|||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
use Symfony\Component\Console;
|
use Symfony\Component\Console;
|
||||||
|
|
||||||
#[Console\Attribute\AsCommand(name: 'jobs:run', description: 'Run job')]
|
#[Console\Attribute\AsCommand(name: 'jobs:run', description: 'Run jobs')]
|
||||||
class Run extends Console\Command\Command
|
class Run extends Console\Command\Command
|
||||||
{
|
{
|
||||||
public function __construct(protected Service\FastCGI $fastcgi, protected LoggerInterface $logger,
|
public function __construct(protected Service\FastCGI $fastcgi, protected LoggerInterface $logger,
|
||||||
protected Service\Job $jobService,
|
|
||||||
protected DateTimeZone $timeZone, ?string $name = null)
|
protected DateTimeZone $timeZone, ?string $name = null)
|
||||||
{
|
{
|
||||||
parent::__construct($name);
|
parent::__construct($name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function configure(): void
|
||||||
|
{
|
||||||
|
$this->addArgument('job_ids',
|
||||||
|
Console\Input\InputArgument::IS_ARRAY | Console\Input\InputArgument::REQUIRED, 'Job IDs');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected array $output = [];
|
||||||
public function execute(Console\Input\InputInterface $input, Console\Output\OutputInterface $output): int
|
public function execute(Console\Input\InputInterface $input, Console\Output\OutputInterface $output): int
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
@ -27,18 +33,44 @@ class Run extends Console\Command\Command
|
|||||||
$now = new DateTimeImmutable();
|
$now = new DateTimeImmutable();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->jobService->getPending() === 0) {
|
$jobIds = $input->getArgument('job_ids');
|
||||||
$output->writeln("[{$now->format('Y-m-d H:i:s e')}] No pending jobs to run.");
|
$jobCount = count($jobIds);
|
||||||
return self::SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
$output->writeln("[{$now->format('Y-m-d H:i:s e')}] Running Ready Job...");
|
$this->pushOutput('top', ['message' => "[{$now->format('Y-m-d H:i:s e')}] Running {$jobCount} jobs..."]);
|
||||||
$this->runJob();
|
$this->pushOutput('bottom', ['table' => [
|
||||||
return $this->getResponses();
|
['Job IDs'],
|
||||||
|
array_map(function($row) {return [$row];},$jobIds)
|
||||||
|
]]);
|
||||||
|
$this->pushOutput('top', ['progress' => $jobCount]);
|
||||||
|
$result = $this->runJobs($jobIds);
|
||||||
|
$this->pushOutput('top', ['progress' => 'finish']);
|
||||||
|
|
||||||
|
$this->writeOutput($input, $output);
|
||||||
|
|
||||||
|
return $result;
|
||||||
}
|
}
|
||||||
protected function runJob(): bool
|
|
||||||
|
protected function runJobs(array $jobIds): int
|
||||||
{
|
{
|
||||||
$uri = "/api/queue/run";
|
$pendingJobs = [];
|
||||||
|
foreach ($jobIds as $jobId) {
|
||||||
|
if (!$this->runJob($jobId)) {
|
||||||
|
$pendingJobs []= $jobId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$result = $this->getResponses();
|
||||||
|
|
||||||
|
if (count($pendingJobs) > 0) {
|
||||||
|
if ($this->runJobs($pendingJobs) === self::FAILURE) {
|
||||||
|
$result = self::FAILURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
protected function runJob(int $jobId): bool
|
||||||
|
{
|
||||||
|
$uri = "/api/queue/run/{$jobId}";
|
||||||
|
$this->pushOutput('bottom', ['message' => "GET {$uri}"]);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$this->fastcgi->get($uri);
|
$this->fastcgi->get($uri);
|
||||||
@ -53,6 +85,7 @@ class Run extends Console\Command\Command
|
|||||||
$result = self::SUCCESS;
|
$result = self::SUCCESS;
|
||||||
$responses = $this->fastcgi->awaitResponses();
|
$responses = $this->fastcgi->awaitResponses();
|
||||||
foreach ($responses as $response) {
|
foreach ($responses as $response) {
|
||||||
|
$this->pushOutput('top', ['progress' => 'advance']);
|
||||||
if ($response->getError() !== '') {
|
if ($response->getError() !== '') {
|
||||||
$this->logger->error("Error running job", [
|
$this->logger->error("Error running job", [
|
||||||
'error' => $response->getError(),
|
'error' => $response->getError(),
|
||||||
@ -60,8 +93,100 @@ class Run extends Console\Command\Command
|
|||||||
'headers' => $response->getHeaders(),
|
'headers' => $response->getHeaders(),
|
||||||
]);
|
]);
|
||||||
$result = self::FAILURE;
|
$result = self::FAILURE;
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
$this->pushOutput('bottom', ['message' => $response->getBody()]);
|
||||||
}
|
}
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function pushOutput(string $section, array $configuration): void
|
||||||
|
{
|
||||||
|
if (!isset($this->output[$section])) {
|
||||||
|
$this->output[$section] = [];
|
||||||
|
}
|
||||||
|
foreach ($configuration as $key => $value) {
|
||||||
|
if (!isset($this->output[$section][$key])) {
|
||||||
|
$this->output[$section][$key] = [];
|
||||||
|
}
|
||||||
|
$this->output[$section][$key] []= $value;
|
||||||
|
}
|
||||||
|
if (isset($this->output[$section]['progress'])) {
|
||||||
|
usort($this->output[$section]['progress'], function($a, $b) {
|
||||||
|
if ($a === $b) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (is_int($a)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (is_int($b)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if ($a === 'finish') {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if ($b === 'finish') {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
protected function writeOutput(Console\Input\InputInterface $input, Console\Output\OutputInterface $output): void
|
||||||
|
{
|
||||||
|
$sectionNames = array_keys($this->output);
|
||||||
|
$ios = [];
|
||||||
|
foreach ($sectionNames as $sectionName) {
|
||||||
|
$section = $output->section();
|
||||||
|
$ios[$sectionName] = new Console\Style\SymfonyStyle($input, $section);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($this->output as $sectionName => $configurations) {
|
||||||
|
$io = $ios[$sectionName];
|
||||||
|
$this->writeSection($io, $configurations);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
protected function writeSection(Console\Style\SymfonyStyle $io, array $configurations): void
|
||||||
|
{
|
||||||
|
if (array_key_exists('table', $configurations)) {
|
||||||
|
$this->writeTables($io, $configurations['table']);
|
||||||
|
}
|
||||||
|
if (array_key_exists('progress', $configurations)) {
|
||||||
|
$this->writeProgress($io, $configurations['progress']);
|
||||||
|
}
|
||||||
|
if (array_key_exists('message', $configurations)) {
|
||||||
|
$this->writeMessages($io, $configurations['message']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
protected function writeTables(Console\Style\SymfonyStyle $io, array $tableConfigurations): void
|
||||||
|
{
|
||||||
|
foreach ($tableConfigurations as $tableData) {
|
||||||
|
$io->table(...$tableData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
protected function writeMessages(Console\Style\SymfonyStyle $io, array $messages): void
|
||||||
|
{
|
||||||
|
foreach ($messages as $message) {
|
||||||
|
$io->writeln($message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
protected function writeProgress(Console\Style\SymfonyStyle $io, array $progresses): void
|
||||||
|
{
|
||||||
|
$progressBar = null;
|
||||||
|
foreach ($progresses as $progress) {
|
||||||
|
if ($progress === 'advance' and $progressBar !== null) {
|
||||||
|
$progressBar->advance();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ($progress === 'finish' and $progressBar !== null) {
|
||||||
|
$progressBar->finish();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (in_array($progress, ['finish', 'advance'])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$progressBar = $io->createProgressBar($progress);
|
||||||
|
}
|
||||||
|
$io->newLine();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -35,29 +35,61 @@ class Queue extends Command
|
|||||||
];
|
];
|
||||||
$io = new Console\Style\SymfonyStyle($input, $this->sections['top']);
|
$io = new Console\Style\SymfonyStyle($input, $this->sections['top']);
|
||||||
$now = new DateTimeImmutable('now', $this->timezone);
|
$now = new DateTimeImmutable('now', $this->timezone);
|
||||||
|
|
||||||
if ($this->jobService->getPending() === 0) {
|
|
||||||
$io->success("[{$now->format('Y-m-d H:i:s e')}] Queue is empty");
|
|
||||||
return self::SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
$io->title("[{$now->format('Y-m-d H:i:s e')}] Running Queue...");
|
$io->title("[{$now->format('Y-m-d H:i:s e')}] Running Queue...");
|
||||||
$results = [];
|
|
||||||
for ($i = 0; $i < $this->batchSize; $i++) {
|
$jobs = $this->getJobs();
|
||||||
if ($this->jobService->getPending() === 0) {
|
$jobCount = count($jobs);
|
||||||
break;
|
if ($jobCount === 0) {
|
||||||
}
|
return Console\Command\Command::SUCCESS;
|
||||||
$results []= $this->runJob();
|
|
||||||
}
|
}
|
||||||
return count(array_filter($results, fn ($result) => $result === self::FAILURE)) === 0 ? self::SUCCESS : self::FAILURE;
|
|
||||||
|
$io->writeln("Found {$jobCount} jobs to run");
|
||||||
|
$result = $this->runJobs($io, $jobs);
|
||||||
|
foreach ($this->outputs as $output) {
|
||||||
|
$this->sections['bottom']->writeln($output);
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected array $sections;
|
protected array $sections;
|
||||||
|
|
||||||
|
protected function getJobs(): array
|
||||||
|
{
|
||||||
|
$this->logger->debug("Getting jobs");
|
||||||
|
$jobs = $this->jobService->getPending();
|
||||||
|
$jobCount = count($jobs);
|
||||||
|
if ($jobCount === 0) {
|
||||||
|
$this->logger->debug("No jobs to run");
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
$this->logger->debug("Found {$jobCount} jobs");
|
||||||
|
return array_column($jobs, 'id');
|
||||||
|
}
|
||||||
|
protected function runJobs(Console\Style\SymfonyStyle $io, array $jobs): int
|
||||||
|
{
|
||||||
|
$chunks = array_chunk($jobs, $this->batchSize);
|
||||||
|
$chunkCount = count($chunks);
|
||||||
|
$result = self::SUCCESS;
|
||||||
|
$progress1 = $io->createProgressBar($chunkCount);
|
||||||
|
$progress1->start();
|
||||||
|
foreach ($chunks as $chunk) {
|
||||||
|
if ($this->runJobBatch($chunk) === self::FAILURE) {
|
||||||
|
$result = self::FAILURE;
|
||||||
|
}
|
||||||
|
$progress1->advance();
|
||||||
|
}
|
||||||
|
$progress1->finish();
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
protected array $outputs = [];
|
protected array $outputs = [];
|
||||||
protected function runJob(): int
|
protected function runJobBatch(array $jobIds): int
|
||||||
{
|
{
|
||||||
$baseCommand = "{$this->baseCommand} jobs:run";
|
$baseCommand = "{$this->baseCommand} jobs:run";
|
||||||
$command = "{$baseCommand}";
|
|
||||||
|
$jobsLine = implode(' ', $jobIds);
|
||||||
|
$command = "{$baseCommand} {$jobsLine}";
|
||||||
|
|
||||||
try {
|
try {
|
||||||
exec($command, $output, $resultCode);
|
exec($command, $output, $resultCode);
|
||||||
$this->outputs []= $output;
|
$this->outputs []= $output;
|
||||||
@ -74,8 +106,7 @@ class Queue extends Command
|
|||||||
'result_code' => $resultCode
|
'result_code' => $resultCode
|
||||||
]);
|
]);
|
||||||
return self::FAILURE;
|
return self::FAILURE;
|
||||||
} else {
|
|
||||||
return self::SUCCESS;
|
|
||||||
}
|
}
|
||||||
|
return self::SUCCESS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,22 +0,0 @@
|
|||||||
<?php
|
|
||||||
namespace Incoviba\Command\Queue;
|
|
||||||
|
|
||||||
use Incoviba\Service;
|
|
||||||
use Symfony\Component\Console;
|
|
||||||
|
|
||||||
#[Console\Attribute\AsCommand(name: 'queue:pending', description: 'List pending jobs in queue')]
|
|
||||||
class Pending extends Console\Command\Command
|
|
||||||
{
|
|
||||||
public function __construct(protected Service\Job $jobService, ?string $name = null)
|
|
||||||
{
|
|
||||||
parent::__construct($name);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function execute(Console\Input\InputInterface $input, Console\Output\OutputInterface $output): int
|
|
||||||
{
|
|
||||||
$jobCount = $this->jobService->getPending();
|
|
||||||
$output->writeln("Found {$jobCount} pending jobs");
|
|
||||||
|
|
||||||
return self::SUCCESS;
|
|
||||||
}
|
|
||||||
}
|
|
@ -2,22 +2,20 @@
|
|||||||
namespace Incoviba\Command\Queue;
|
namespace Incoviba\Command\Queue;
|
||||||
|
|
||||||
use Throwable;
|
use Throwable;
|
||||||
use Psr\Log\LoggerInterface;
|
|
||||||
use Symfony\Component\Console;
|
use Symfony\Component\Console;
|
||||||
use Incoviba\Service;
|
use Incoviba\Service;
|
||||||
|
|
||||||
#[Console\Attribute\AsCommand(name: 'queue:push', description: 'Push a job to the queue')]
|
#[Console\Attribute\AsCommand(name: 'queue:push', description: 'Push a job to the queue')]
|
||||||
class Push extends Console\Command\Command
|
class Push extends Console\Command\Command
|
||||||
{
|
{
|
||||||
public function __construct(protected LoggerInterface $logger, protected Service\Job $jobService, ?string $name = null)
|
public function __construct(protected Service\Job $jobService, ?string $name = null)
|
||||||
{
|
{
|
||||||
parent::__construct($name);
|
parent::__construct($name);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function configure(): void
|
protected function configure(): void
|
||||||
{
|
{
|
||||||
$this->addOption('configurations', 'c', Console\Input\InputOption::VALUE_REQUIRED | Console\Input\InputOption::VALUE_IS_ARRAY, 'Job configuration options array, each job configuration must be in valid JSON format');
|
$this->addOption('configurations', 'c', Console\Input\InputOption::VALUE_REQUIRED | Console\Input\InputOption::VALUE_IS_ARRAY, 'Job configuration, must be in valid JSON format');
|
||||||
$this->addOption('files', 'f', Console\Input\InputOption::VALUE_REQUIRED | Console\Input\InputOption::VALUE_IS_ARRAY, 'Paths to jobs configurations files with JSON array content');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function execute(Console\Input\InputInterface $input, Console\Output\OutputInterface $output): int
|
protected function execute(Console\Input\InputInterface $input, Console\Output\OutputInterface $output): int
|
||||||
@ -25,8 +23,8 @@ class Push extends Console\Command\Command
|
|||||||
$io = new Console\Style\SymfonyStyle($input, $output);
|
$io = new Console\Style\SymfonyStyle($input, $output);
|
||||||
$io->title("Pushing job");
|
$io->title("Pushing job");
|
||||||
|
|
||||||
$configurations = $this->getConfigurations($input);
|
$configurations = $input->getOption('configurations');
|
||||||
if (count($configurations) === 0) {
|
if ($configurations === null) {
|
||||||
$io->error('Missing configurations');
|
$io->error('Missing configurations');
|
||||||
return self::FAILURE;
|
return self::FAILURE;
|
||||||
}
|
}
|
||||||
@ -48,74 +46,4 @@ class Push extends Console\Command\Command
|
|||||||
}
|
}
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function getConfigurations(Console\Input\InputInterface $input): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
...$this->getFilesConfigurations($input),
|
|
||||||
...$this->getOptionConfigurations($input),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
protected function getFilesConfigurations(Console\Input\InputInterface $input): array
|
|
||||||
{
|
|
||||||
$configurations = [];
|
|
||||||
$files = $input->getOption('files');
|
|
||||||
if ($files === null) {
|
|
||||||
return $configurations;
|
|
||||||
}
|
|
||||||
foreach ($files as $filePath) {
|
|
||||||
if (!file_exists($filePath)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
$configurations = array_merge($configurations, $this->getFileConfigurations($filePath));
|
|
||||||
}
|
|
||||||
return $configurations;
|
|
||||||
}
|
|
||||||
protected function getFileConfigurations(string $filePath): array
|
|
||||||
{
|
|
||||||
$configurations = [];
|
|
||||||
if (!file_exists($filePath)) {
|
|
||||||
return $configurations;
|
|
||||||
}
|
|
||||||
$json = file_get_contents($filePath);
|
|
||||||
if (!json_validate($json)) {
|
|
||||||
return $configurations;
|
|
||||||
}
|
|
||||||
$tmp = json_decode($json, true);
|
|
||||||
foreach ($tmp as $config) {
|
|
||||||
try {
|
|
||||||
$configurations []= $this->processConfiguration(json_encode($config));
|
|
||||||
} catch (Throwable $exception) {
|
|
||||||
$this->logger->warning($exception->getMessage(), ['exception' => $exception, 'config' => $config]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return $configurations;
|
|
||||||
}
|
|
||||||
protected function getOptionConfigurations(Console\Input\InputInterface $input): array
|
|
||||||
{
|
|
||||||
$configurations = [];
|
|
||||||
$configOptions = $input->getOption('configurations');
|
|
||||||
if ($configOptions === null) {
|
|
||||||
return $configurations;
|
|
||||||
}
|
|
||||||
foreach ($configOptions as $config) {
|
|
||||||
try {
|
|
||||||
$configurations []= $this->processConfiguration($config);
|
|
||||||
} catch (Throwable $exception) {
|
|
||||||
$this->logger->warning($exception->getMessage(), ['exception' => $exception, 'config' => $config]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return $configurations;
|
|
||||||
}
|
|
||||||
protected function processConfiguration(string $configuration): string
|
|
||||||
{
|
|
||||||
$json = json_decode($configuration, true);
|
|
||||||
if (!array_key_exists('type', $json) and !array_key_exists('configuration', $json)) {
|
|
||||||
throw new Console\Exception\InvalidArgumentException('Missing type or configuration key in JSON');
|
|
||||||
}
|
|
||||||
if (array_key_exists('type', $json)) {
|
|
||||||
return json_encode($json);
|
|
||||||
}
|
|
||||||
return json_encode($json['configuration']);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,18 +0,0 @@
|
|||||||
<?php
|
|
||||||
namespace Incoviba\Exception;
|
|
||||||
|
|
||||||
use Throwable;
|
|
||||||
use Exception;
|
|
||||||
|
|
||||||
abstract class MQTT extends Exception
|
|
||||||
{
|
|
||||||
public function __construct(string $message = "", int $code = 0, ?Throwable $previous = null)
|
|
||||||
{
|
|
||||||
$baseCode = 700;
|
|
||||||
$code = $baseCode + $code;
|
|
||||||
if ($message == "") {
|
|
||||||
$message = "MQTT Exception";
|
|
||||||
}
|
|
||||||
parent::__construct($message, $code, $previous);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,15 +0,0 @@
|
|||||||
<?php
|
|
||||||
namespace Incoviba\Exception\MQTT;
|
|
||||||
|
|
||||||
use Throwable;
|
|
||||||
use Incoviba\Exception\MQTT;
|
|
||||||
|
|
||||||
class Create extends MQTT
|
|
||||||
{
|
|
||||||
public function __construct(string $tube = '', string $payload = '', ?Throwable $previous = null)
|
|
||||||
{
|
|
||||||
$message = "Unable to create MQTT message: {$payload} in tube {$tube}";
|
|
||||||
$code = 11;
|
|
||||||
parent::__construct($message, $code, $previous);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,15 +0,0 @@
|
|||||||
<?php
|
|
||||||
namespace Incoviba\Exception\MQTT;
|
|
||||||
|
|
||||||
use Throwable;
|
|
||||||
use Incoviba\Exception\MQTT;
|
|
||||||
|
|
||||||
class Delete extends MQTT
|
|
||||||
{
|
|
||||||
public function __construct(string $tube, int $jobId, ?Throwable $previous = null)
|
|
||||||
{
|
|
||||||
$message = "Could not delete job {$jobId} in tube {$tube}";
|
|
||||||
$code = 13;
|
|
||||||
parent::__construct($message, $code, $previous);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,15 +0,0 @@
|
|||||||
<?php
|
|
||||||
namespace Incoviba\Exception\MQTT;
|
|
||||||
|
|
||||||
use Throwable;
|
|
||||||
use Incoviba\Exception\MQTT;
|
|
||||||
|
|
||||||
class Read extends MQTT
|
|
||||||
{
|
|
||||||
public function __construct(string $tube, ?Throwable $previous = null)
|
|
||||||
{
|
|
||||||
$message = "Error reading from tube {$tube}";
|
|
||||||
$code = 10;
|
|
||||||
parent::__construct($message, $code, $previous);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,14 +0,0 @@
|
|||||||
<?php
|
|
||||||
namespace Incoviba\Exception\MQTT;
|
|
||||||
|
|
||||||
use Incoviba\Exception\MQTT;
|
|
||||||
use Throwable;
|
|
||||||
|
|
||||||
class UnknownTransport extends MQTT
|
|
||||||
{
|
|
||||||
public function __construct(string $transportName, ?Throwable $previous = null)
|
|
||||||
{
|
|
||||||
$message = "Unknown transport {$transportName}";
|
|
||||||
parent::__construct($message, 1, $previous);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,16 +0,0 @@
|
|||||||
<?php
|
|
||||||
namespace Incoviba\Exception\MQTT;
|
|
||||||
|
|
||||||
use Throwable;
|
|
||||||
use Incoviba\Exception\MQTT;
|
|
||||||
|
|
||||||
class Update extends MQTT
|
|
||||||
{
|
|
||||||
public function __construct(string $tube, string $payload, ?int $jobId = null, ?Throwable $previous = null)
|
|
||||||
{
|
|
||||||
$jobString = $jobId !== null ? " with jobId {$jobId}" : '';
|
|
||||||
$message = "Could not update job{$jobString} with {$payload} in tube {$tube}";
|
|
||||||
$code = 12;
|
|
||||||
parent::__construct($message, $code, $previous);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,9 +0,0 @@
|
|||||||
<?php
|
|
||||||
namespace Incoviba;
|
|
||||||
|
|
||||||
use Psr\Log\LoggerInterface;
|
|
||||||
|
|
||||||
abstract class Service
|
|
||||||
{
|
|
||||||
public function __construct(protected LoggerInterface $logger) {}
|
|
||||||
}
|
|
@ -5,22 +5,27 @@ use DateInvalidTimeZoneException;
|
|||||||
use DateMalformedStringException;
|
use DateMalformedStringException;
|
||||||
use DateTimeImmutable;
|
use DateTimeImmutable;
|
||||||
use DateTimeZone;
|
use DateTimeZone;
|
||||||
|
use Exception;
|
||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
use Incoviba\Exception\MQTT as MQTTException;
|
use Predis\Connection\ConnectionException;
|
||||||
use Incoviba\Service\MQTT\MQTTInterface;
|
|
||||||
|
|
||||||
class Job
|
class Job
|
||||||
{
|
{
|
||||||
public function __construct(protected LoggerInterface $logger, protected MQTTInterface $mqttService) {}
|
public function __construct(protected LoggerInterface $logger, protected Redis $redisService)
|
||||||
|
{
|
||||||
|
$this->redisKey = 'jobs';
|
||||||
|
}
|
||||||
protected string $redisKey;
|
protected string $redisKey;
|
||||||
|
|
||||||
public function getPending(): int
|
public function getPending(): array
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
return $this->mqttService->pending();
|
$jobs = $this->redisService->get($this->redisKey);
|
||||||
} catch (MQTTException $exception) {
|
return json_decode($jobs, true);
|
||||||
|
} catch (ConnectionException|Exception $exception) {
|
||||||
|
$exception = new Exception("Could not read {$this->redisKey} from Redis", $exception->getCode(), $exception);
|
||||||
$this->logger->warning($exception->getMessage(), ['exception' => $exception]);
|
$this->logger->warning($exception->getMessage(), ['exception' => $exception]);
|
||||||
return 0;
|
return [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -39,11 +44,9 @@ class Job
|
|||||||
'updated_at' => null,
|
'updated_at' => null,
|
||||||
'retries' => 0
|
'retries' => 0
|
||||||
];
|
];
|
||||||
try {
|
$jobs = $this->getPending();
|
||||||
$this->mqttService->set(json_encode($data));
|
$jobs []= $data;
|
||||||
} catch (MQTTException $exception) {
|
$this->redisService->set($this->redisKey, json_encode($jobs), -1);
|
||||||
$this->logger->warning($exception->getMessage(), ['exception' => $exception]);
|
|
||||||
}
|
|
||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,124 +0,0 @@
|
|||||||
<?php
|
|
||||||
namespace Incoviba\Service;
|
|
||||||
|
|
||||||
use Incoviba\Exception\MQTT as MQTTException;
|
|
||||||
use Incoviba\Service;
|
|
||||||
use Incoviba\Service\MQTT\MQTTInterface;
|
|
||||||
|
|
||||||
class MQTT extends Service implements MQTTInterface
|
|
||||||
{
|
|
||||||
protected array $transports = [];
|
|
||||||
public function register(string $name, MQTTInterface $transport): self
|
|
||||||
{
|
|
||||||
$this->transports[$name] = $transport;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string $payload
|
|
||||||
* @param int $delay
|
|
||||||
* @param string|null $transportName
|
|
||||||
* @return $this
|
|
||||||
* @throws MQTTException\UnknownTransport
|
|
||||||
* @throws MQTTException\Create
|
|
||||||
*/
|
|
||||||
public function set(string $payload, int $delay = 0, ?string $transportName = null): self
|
|
||||||
{
|
|
||||||
$transport = $this->getTransport($transportName);
|
|
||||||
$transport->set($payload, $delay);
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string|null $transportName
|
|
||||||
* @return int
|
|
||||||
* @throws MQTTException\UnknownTransport
|
|
||||||
* @throws MQTTException\Read
|
|
||||||
*/
|
|
||||||
public function pending(?string $transportName = null): int
|
|
||||||
{
|
|
||||||
$transport = $this->getTransport($transportName);
|
|
||||||
return $transport->pending();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param int|null $jobId
|
|
||||||
* @param string|null $transportName
|
|
||||||
* @return bool
|
|
||||||
* @throws MQTTException\UnknownTransport
|
|
||||||
* @throws MQTTException\Read
|
|
||||||
*/
|
|
||||||
public function exists(?int $jobId = null, ?string $transportName = null): bool
|
|
||||||
{
|
|
||||||
$transport = $this->getTransport($transportName);
|
|
||||||
return $transport->exists($jobId);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param int|null $jobId
|
|
||||||
* @param string|null $transportName
|
|
||||||
* @return string
|
|
||||||
* @throws MQTTException\UnknownTransport
|
|
||||||
* @throws MQTTException\Read
|
|
||||||
*/
|
|
||||||
public function get(?int $jobId = null, ?string $transportName = null): string
|
|
||||||
{
|
|
||||||
$transport = $this->getTransport($transportName);
|
|
||||||
return $transport->get($jobId);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string $newPayload
|
|
||||||
* @param int|null $jobId
|
|
||||||
* @param string|null $transportName
|
|
||||||
* @return $this
|
|
||||||
* @throws MQTTException\UnknownTransport
|
|
||||||
* @throws MQTTException\Update
|
|
||||||
*/
|
|
||||||
public function update(string $newPayload, ?int $jobId = null, ?string $transportName = null): self
|
|
||||||
{
|
|
||||||
$transport = $this->getTransport($transportName);
|
|
||||||
$transport->update($newPayload, $jobId);
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param int|null $jobId
|
|
||||||
* @param string|null $transportName
|
|
||||||
* @return $this
|
|
||||||
* @throws MQTTException\UnknownTransport
|
|
||||||
* @throws MQTTException\Delete
|
|
||||||
*/
|
|
||||||
public function remove(?int $jobId = null, ?string $transportName = null): self
|
|
||||||
{
|
|
||||||
$transport = $this->getTransport($transportName);
|
|
||||||
$transport->remove($jobId);
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string|null $transportName
|
|
||||||
* @return mixed
|
|
||||||
* @throws MQTTException\UnknownTransport
|
|
||||||
*/
|
|
||||||
protected function getTransport(?string $transportName): mixed
|
|
||||||
{
|
|
||||||
if (count($this->transports) === 0) {
|
|
||||||
throw new MQTTException\UnknownTransport('');
|
|
||||||
}
|
|
||||||
if ($transportName === null) {
|
|
||||||
if (array_key_exists('default', $this->transports)) {
|
|
||||||
$transportName = 'default';
|
|
||||||
} else {
|
|
||||||
$transportName = array_keys($this->transports)[0];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!array_key_exists($transportName, $this->transports)) {
|
|
||||||
if ($transportName === null) {
|
|
||||||
$transportName = '';
|
|
||||||
}
|
|
||||||
throw new MQTTException\UnknownTransport($transportName);
|
|
||||||
}
|
|
||||||
return $this->transports[$transportName];
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,127 +0,0 @@
|
|||||||
<?php
|
|
||||||
namespace Incoviba\Service\MQTT;
|
|
||||||
|
|
||||||
use Exception;
|
|
||||||
use Psr\Log\LoggerInterface;
|
|
||||||
use xobotyi\beansclient;
|
|
||||||
use Incoviba\Service;
|
|
||||||
use Incoviba\Exception\MQTT;
|
|
||||||
|
|
||||||
class Beanstalkd extends Service implements MQTTInterface
|
|
||||||
{
|
|
||||||
const string DEFAULT_TUBE = 'default';
|
|
||||||
const int DEFAULT_TTR = 30;
|
|
||||||
const int DEFAULT_PRIORITY = 1_024;
|
|
||||||
|
|
||||||
public function __construct(LoggerInterface $logger, protected beansclient\Client $client,
|
|
||||||
protected string $tube = self::DEFAULT_TUBE,
|
|
||||||
protected int $ttr = self::DEFAULT_TTR,
|
|
||||||
protected int $priority = self::DEFAULT_PRIORITY)
|
|
||||||
{
|
|
||||||
parent::__construct($logger);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string $payload
|
|
||||||
* @param int $delay
|
|
||||||
* @return self
|
|
||||||
* @throws MQTT\Create
|
|
||||||
*/
|
|
||||||
public function set(string $payload, int $delay = 60): self
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$this->client->put($payload, $this->ttr, $this->priority, $delay);
|
|
||||||
} catch (Exception $exception) {
|
|
||||||
throw new MQTT\Create($this->tube, $payload, $exception);
|
|
||||||
}
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return int
|
|
||||||
* @throws MQTT\Read
|
|
||||||
*/
|
|
||||||
public function pending(): int
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$stats = $this->client
|
|
||||||
->statsTube($this->tube);
|
|
||||||
} catch (Exception $exception) {
|
|
||||||
throw new MQTT\Read($this->tube, $exception);
|
|
||||||
}
|
|
||||||
if (!array_key_exists('current-jobs-ready', $stats)) {
|
|
||||||
throw new MQTT\Read($this->tube);
|
|
||||||
}
|
|
||||||
return $stats['current-jobs-ready'];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param int|null $jobId
|
|
||||||
* @return bool
|
|
||||||
* @throws MQTT\Read
|
|
||||||
*/
|
|
||||||
public function exists(?int $jobId = null): bool
|
|
||||||
{
|
|
||||||
return $this->pending() > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected int $currentJobId;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param int|null $jobId
|
|
||||||
* @return string
|
|
||||||
* @throws MQTT\Read
|
|
||||||
*/
|
|
||||||
public function get(?int $jobId = null): string
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
if ($jobId !== null) {
|
|
||||||
$job = (object) $this->client
|
|
||||||
->reserveJob($jobId);
|
|
||||||
} else {
|
|
||||||
$job = (object) $this->client
|
|
||||||
->reserve();
|
|
||||||
}
|
|
||||||
} catch (Exception $exception) {
|
|
||||||
throw new MQTT\Read($this->tube, $exception);
|
|
||||||
}
|
|
||||||
$this->currentJobId = $job->id;
|
|
||||||
return $job->payload;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string $newPayload
|
|
||||||
* @param int|null $jobId
|
|
||||||
* @return self
|
|
||||||
* @throws MQTT\Update
|
|
||||||
*/
|
|
||||||
public function update(string $newPayload, ?int $jobId = null): self
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$this->remove($jobId);
|
|
||||||
$this->set($newPayload);
|
|
||||||
} catch (MQTT\Delete | MQTT\Create $exception) {
|
|
||||||
throw new MQTT\Update($this->tube, $newPayload, $jobId, $exception);
|
|
||||||
}
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param int|null $jobId
|
|
||||||
* @return self
|
|
||||||
* @throws MQTT\Delete
|
|
||||||
*/
|
|
||||||
public function remove(?int $jobId = null): self
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
if ($jobId === null) {
|
|
||||||
$jobId = $this->currentJobId;
|
|
||||||
}
|
|
||||||
$this->client
|
|
||||||
->delete($jobId);
|
|
||||||
} catch (Exception $exception) {
|
|
||||||
throw new MQTT\Delete($this->tube, $jobId, $exception);
|
|
||||||
}
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,12 +0,0 @@
|
|||||||
<?php
|
|
||||||
namespace Incoviba\Service\MQTT;
|
|
||||||
|
|
||||||
interface MQTTInterface
|
|
||||||
{
|
|
||||||
public function set(string $payload, int $delay = 0): self;
|
|
||||||
public function pending(): int;
|
|
||||||
public function exists(?int $jobId = null): bool;
|
|
||||||
public function get(?int $jobId = null): string;
|
|
||||||
public function update(string $newPayload, ?int $jobId = null): self;
|
|
||||||
public function remove(?int $jobId = null): self;
|
|
||||||
}
|
|
@ -1,65 +0,0 @@
|
|||||||
<?php
|
|
||||||
namespace Incoviba\Service\MQTT;
|
|
||||||
|
|
||||||
use Psr\Log\LoggerInterface;
|
|
||||||
use Pheanstalk as PBA;
|
|
||||||
use Incoviba\Service;
|
|
||||||
|
|
||||||
class Pheanstalk extends Service implements MQTTInterface
|
|
||||||
{
|
|
||||||
public function __construct(LoggerInterface $logger, protected PBA\Pheanstalk $client, string $tubeName = 'default')
|
|
||||||
{
|
|
||||||
parent::__construct($logger);
|
|
||||||
$this->tube = new PBA\Values\TubeName($tubeName);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected PBA\Values\TubeName $tube;
|
|
||||||
|
|
||||||
public function set(string $payload, int $delay = 0): self
|
|
||||||
{
|
|
||||||
$this->client->useTube($this->tube);
|
|
||||||
$this->client->put($payload, $delay);
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function pending(): int
|
|
||||||
{
|
|
||||||
$stats = $this->client->statsTube($this->tube);
|
|
||||||
return $stats->currentJobsReady;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function exists(?int $jobId = null): bool
|
|
||||||
{
|
|
||||||
return $this->pending() > 0;
|
|
||||||
}
|
|
||||||
protected int $currentJobId;
|
|
||||||
public function get(?int $jobId = null): string
|
|
||||||
{
|
|
||||||
$this->client->watch($this->tube);
|
|
||||||
if ($jobId !== null) {
|
|
||||||
$jobId = new PBA\Values\JobId($jobId);
|
|
||||||
$job = $this->client->reserveJob($jobId);
|
|
||||||
} else {
|
|
||||||
$job = $this->client->reserve();
|
|
||||||
}
|
|
||||||
$this->currentJobId = $job->getId();
|
|
||||||
return $job->getData();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function update(string $newPayload, ?int $jobId = null): self
|
|
||||||
{
|
|
||||||
$this->remove($jobId);
|
|
||||||
$this->set($newPayload);
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function remove(?int $jobId = null): self
|
|
||||||
{
|
|
||||||
if ($jobId === null) {
|
|
||||||
$jobId = $this->currentJobId;
|
|
||||||
}
|
|
||||||
$this->client->watch($this->tube);
|
|
||||||
$this->client->delete(new PBA\Values\JobId($jobId));
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,85 +0,0 @@
|
|||||||
<?php
|
|
||||||
namespace Incoviba\Service;
|
|
||||||
|
|
||||||
class SystemInfo
|
|
||||||
{
|
|
||||||
public function getAllInfo(): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'memory' => [
|
|
||||||
'usage' => $this->getMemoryUsage(),
|
|
||||||
'peak' => $this->getPeakMemoryUsage()
|
|
||||||
],
|
|
||||||
'cpu' => [
|
|
||||||
'usage' => $this->getCpuUsage(),
|
|
||||||
'last_15minutes' => $this->getCpuUsageLast15minutes(),
|
|
||||||
'cores' => $this->getCpuCores()
|
|
||||||
]
|
|
||||||
];
|
|
||||||
}
|
|
||||||
public function get(string $name): int|null|float
|
|
||||||
{
|
|
||||||
return match ($name) {
|
|
||||||
'memory' => $this->getMemoryUsage(),
|
|
||||||
'peak_memory' => $this->getPeakMemoryUsage(),
|
|
||||||
'cpu' => $this->getCpuUsage(),
|
|
||||||
'cpu_last_15minutes' => $this->getCpuUsageLast15minutes(),
|
|
||||||
'cpu_cores' => $this->getCpuCores(),
|
|
||||||
default => null
|
|
||||||
};
|
|
||||||
}
|
|
||||||
public function getMemoryUsage(): float
|
|
||||||
{
|
|
||||||
return memory_get_usage(true);
|
|
||||||
}
|
|
||||||
public function getPeakMemoryUsage(): float
|
|
||||||
{
|
|
||||||
return memory_get_peak_usage(true);
|
|
||||||
}
|
|
||||||
public function getCpuUsage(): float
|
|
||||||
{
|
|
||||||
return $this->getCpuLoad()[0];
|
|
||||||
}
|
|
||||||
public function getCpuUsageLast15minutes(): float
|
|
||||||
{
|
|
||||||
return $this->getCpuLoad()[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
protected array $cpuLoad;
|
|
||||||
protected function getCpuLoad(): array
|
|
||||||
{
|
|
||||||
if (isset($this->cpuLoad)) {
|
|
||||||
$load = sys_getloadavg();
|
|
||||||
$cores = $this->getCpuCores();
|
|
||||||
array_walk($load, function (&$value) use ($cores) {
|
|
||||||
$value = $value / $cores;
|
|
||||||
});
|
|
||||||
$this->cpuLoad = $load;
|
|
||||||
unset($load);
|
|
||||||
}
|
|
||||||
return $this->cpuLoad;
|
|
||||||
}
|
|
||||||
protected function getCpuCores(): int
|
|
||||||
{
|
|
||||||
$cpu_cores = 1;
|
|
||||||
if (is_file('/proc/cpuinfo')) {
|
|
||||||
$cpuinfo = file('/proc/cpuinfo');
|
|
||||||
preg_match_all('/^processor/m', $cpuinfo, $matches);
|
|
||||||
$cpu_cores = count($matches[0]);
|
|
||||||
}
|
|
||||||
return $cpu_cores;
|
|
||||||
}
|
|
||||||
public function formatMemoryUsage(float $usage, string $unit = 'MB'): string
|
|
||||||
{
|
|
||||||
$sizeFactor = match ($unit) {
|
|
||||||
'MB' => 1024 * 1024,
|
|
||||||
'GB' => 1024 * 1024 * 1024,
|
|
||||||
default => 1
|
|
||||||
};
|
|
||||||
return number_format($usage / $sizeFactor, 2) . " {$unit}";
|
|
||||||
}
|
|
||||||
public function formatCpuLoad(float $load): string
|
|
||||||
{
|
|
||||||
return number_format($load * 100, 2) . '%';
|
|
||||||
}
|
|
||||||
}
|
|
0
cli/start_command
Executable file → Normal file
0
cli/start_command
Executable file → Normal file
@ -1,21 +0,0 @@
|
|||||||
services:
|
|
||||||
mqtt:
|
|
||||||
profiles:
|
|
||||||
- mqtt
|
|
||||||
container_name: incoviba_mqtt
|
|
||||||
image: maateen/docker-beanstalkd
|
|
||||||
restart: unless-stopped
|
|
||||||
volumes:
|
|
||||||
- incoviba_mqtt:/var/lib/beanstalkd
|
|
||||||
|
|
||||||
mqtt-admin:
|
|
||||||
profiles:
|
|
||||||
- mqtt
|
|
||||||
container_name: incoviba_mqtt_admin
|
|
||||||
image: mitulislam/beanstalkd-aurora:latest
|
|
||||||
restart: unless-stopped
|
|
||||||
ports:
|
|
||||||
- "8093:3000"
|
|
||||||
|
|
||||||
volumes:
|
|
||||||
incoviba_mqtt: {}
|
|
@ -18,8 +18,6 @@ services:
|
|||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
test-redis:
|
test-redis:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
test-mqtt:
|
|
||||||
condition: service_started
|
|
||||||
|
|
||||||
test-db:
|
test-db:
|
||||||
profiles:
|
profiles:
|
||||||
@ -50,19 +48,6 @@ services:
|
|||||||
networks:
|
networks:
|
||||||
- testing
|
- testing
|
||||||
|
|
||||||
test-mqtt:
|
|
||||||
profiles:
|
|
||||||
- testing
|
|
||||||
image: maateen/docker-beanstalkd
|
|
||||||
container_name: incoviba_test_mqtt
|
|
||||||
healthcheck:
|
|
||||||
test: [ "CMD", "nc", "-z", "localhost", "11300" ]
|
|
||||||
interval: 5s
|
|
||||||
timeout: 5s
|
|
||||||
retries: 5
|
|
||||||
networks:
|
|
||||||
- testing
|
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
test-db: {}
|
test-db: {}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user