Compare commits
2 Commits
feature/ha
...
feature/gi
| Author | SHA1 | Date | |
|---|---|---|---|
| 484a288da1 | |||
| 7e1560c11f |
@@ -1,5 +1,7 @@
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
workflow_dispatch:
|
||||
jobs:
|
||||
deploy-job:
|
||||
|
||||
@@ -118,66 +118,6 @@ class Migrate extends Command
|
||||
]
|
||||
);
|
||||
}
|
||||
if (Capsule::schema()->hasTable('countries') && !Country::where('countryName', 'Netherlands')->exists()) {
|
||||
Capsule::table('countries')->insert([
|
||||
'countryName' => 'Netherlands',
|
||||
'productsUrl' => 'https://nl.ryobitools.eu/api/product-listing/get-products',
|
||||
'cultureCode' => 'nl-NL',
|
||||
'currency' => 'EUR',
|
||||
'locale' => 'nl',
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
]
|
||||
);
|
||||
}
|
||||
if (Capsule::schema()->hasTable('countries') && !Country::where('countryName', 'France')->exists()) {
|
||||
Capsule::table('countries')->insert([
|
||||
'countryName' => 'France',
|
||||
'productsUrl' => 'https://fr.ryobitools.eu/api/product-listing/get-products',
|
||||
'cultureCode' => 'fr-FR',
|
||||
'currency' => 'EUR',
|
||||
'locale' => 'fr',
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
]
|
||||
);
|
||||
}
|
||||
if (Capsule::schema()->hasTable('countries') && !Country::where('countryName', 'Spain')->exists()) {
|
||||
Capsule::table('countries')->insert([
|
||||
'countryName' => 'Spain',
|
||||
'productsUrl' => 'https://es.ryobitools.eu/api/product-listing/get-products',
|
||||
'cultureCode' => 'es-ES',
|
||||
'currency' => 'EUR',
|
||||
'locale' => 'es',
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
]
|
||||
);
|
||||
}
|
||||
if (Capsule::schema()->hasTable('countries') && !Country::where('countryName', 'Poland')->exists()) {
|
||||
$id = Capsule::table('countries')->insertGetId(
|
||||
[
|
||||
'countryName' => 'Poland',
|
||||
'productsUrl' => 'https://pl.ryobitools.eu/api/product-listing/get-products',
|
||||
'cultureCode' => 'pl-PL',
|
||||
'currency' => 'PLN',
|
||||
'locale' => 'pl',
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
]);
|
||||
}
|
||||
if (Capsule::schema()->hasTable('countries') && !Country::where('countryName', 'UK')->exists()) {
|
||||
Capsule::table('countries')->insert([
|
||||
'countryName' => 'UK',
|
||||
'productsUrl' => 'https://uk.ryobitools.eu/api/product-listing/get-products',
|
||||
'cultureCode' => 'en-GB',
|
||||
'currency' => 'GBP',
|
||||
'locale' => 'uk',
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
if (!Capsule::schema()->hasColumn('products', 'country_id')) {
|
||||
Capsule::schema()->table('products', function (Blueprint $table) use ($id) {
|
||||
@@ -246,16 +186,6 @@ class Migrate extends Command
|
||||
$table->json('promotions')->nullable();
|
||||
});
|
||||
}
|
||||
if (!Capsule::schema()->hasColumn('prices', 'conversionRate')) {
|
||||
Capsule::schema()->table('prices', function (Blueprint $table) {
|
||||
$table->float('conversionRate')->nullable();
|
||||
});
|
||||
}
|
||||
if (!Capsule::schema()->hasColumn('products', 'conversionRate')) {
|
||||
Capsule::schema()->table('products', function (Blueprint $table) {
|
||||
$table->float('conversionRate')->nullable();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public function index(): void
|
||||
|
||||
@@ -23,17 +23,15 @@ class ScrapeWebsite extends Command
|
||||
{
|
||||
const COUNTRY_ID = 'country';
|
||||
private Client $client;
|
||||
private array $rates;
|
||||
|
||||
public function __construct(protected Capsule $database)
|
||||
{
|
||||
parent::__construct();
|
||||
$this->client = new Client();
|
||||
$this->rates = $this->getCurrencyExchange();
|
||||
}
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this->client = new Client();
|
||||
$this->addOption(self::COUNTRY_ID, 'c', InputOption::VALUE_OPTIONAL, 'Country id');
|
||||
}
|
||||
|
||||
@@ -70,7 +68,6 @@ class ScrapeWebsite extends Command
|
||||
$product->priceLowest = $product->lowestPrice->price;
|
||||
$product->lastSeen = $newestPrice->created_at->format('Y-m-d');
|
||||
$product->stock = $currentStock->stock;
|
||||
$product->conversionRate = $newestPrice->conversionRate;
|
||||
$product->save(['timestamps' => false]);
|
||||
$progress->advance();
|
||||
}
|
||||
@@ -101,7 +98,7 @@ class ScrapeWebsite extends Command
|
||||
$products = array_merge($products, $responseObject->products);
|
||||
$page++;
|
||||
$canLoadMore = $responseObject->canLoadMore;
|
||||
} catch (GuzzleException) {
|
||||
} catch (GuzzleException $e) {
|
||||
return $products;
|
||||
}
|
||||
} while ($canLoadMore);
|
||||
@@ -135,7 +132,6 @@ class ScrapeWebsite extends Command
|
||||
$price->price = $product->productPrice;
|
||||
$price->productStandardPrice = $product->productStandardPrice;
|
||||
$price->lowestProductPrice30Days = $product->lowestProductPrice30Days;
|
||||
$price->conversionRate = $this->getConversionRate($country->currency);
|
||||
$productModel->price()->save($price);
|
||||
}
|
||||
$stockExist = $productModel->stock()->whereRaw("strftime('%Y-%m-%d', created_at) = ?", [date('Y-m-d')])->exists();
|
||||
@@ -151,22 +147,4 @@ class ScrapeWebsite extends Command
|
||||
$productModel->stock()->save($stock);
|
||||
}
|
||||
}
|
||||
|
||||
public function getCurrencyExchange(): array
|
||||
{
|
||||
$result = $this->client->request('GET', 'https://api.nbp.pl/api/exchangerates/tables/A/?format=json');
|
||||
$rates = ['PLN' => 1.0];
|
||||
foreach(json_decode($result->getBody()->getContents(),true)[0]['rates'] as $rate){
|
||||
$rates[$rate['code']] = $rate['mid'];
|
||||
}
|
||||
|
||||
return $rates;
|
||||
}
|
||||
|
||||
private function getConversionRate(string $currency): float
|
||||
{
|
||||
$currency = strtoupper($currency);
|
||||
|
||||
return $this->rates[$currency];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,11 +20,8 @@ final class PromosController extends BaseController
|
||||
|
||||
|
||||
$promos = Product::select($this->database->getConnection()->raw("distinct json_extract(promotions, '$.slug') as slug, json_extract(promotions, '$.tag') as tag"))
|
||||
->addSelect('countries.locale')
|
||||
->whereRaw("json_extract(promotions, '$.tag') is not null")
|
||||
->join('countries', 'products.country_id', '=', 'countries.id')
|
||||
->get()
|
||||
->groupBy('locale');
|
||||
->get();
|
||||
|
||||
return $this->render('productList.html.twig', ['products' => $products, 'listType' => 'promos' . $promo, 'promos' => $promos->toArray()]);
|
||||
}
|
||||
|
||||
@@ -7,13 +7,9 @@ use Krzysiej\RyobiCrawler\Twig\AppExtension;
|
||||
use Symfony\Bundle\FrameworkBundle\FrameworkBundle;
|
||||
use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait;
|
||||
use Symfony\Bundle\TwigBundle\TwigBundle;
|
||||
use Symfony\Component\Cache\Adapter\FilesystemAdapter;
|
||||
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\HttpKernel\Kernel as BaseKernel;
|
||||
use Symfony\Component\Routing\Loader\Configurator\RoutingConfigurator;
|
||||
use Twig\Extra\Cache\CacheExtension;
|
||||
use Twig\Extra\Cache\CacheRuntime;
|
||||
use Twig\Extra\TwigExtraBundle\TwigExtraBundle;
|
||||
|
||||
class Kernel extends BaseKernel
|
||||
|
||||
@@ -9,7 +9,6 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
* @property float $price
|
||||
* @property float $productStandardPrice
|
||||
* @property float $lowestProductPrice30Days
|
||||
* @property float $conversionRate
|
||||
*/
|
||||
class Price extends Model
|
||||
{
|
||||
|
||||
@@ -27,7 +27,6 @@ use function Symfony\Component\Clock\now;
|
||||
* @property float $priceLowest
|
||||
* @property float $productStandardPrice
|
||||
* @property float $lowestProductPrice30Days
|
||||
* @property float $conversionRate
|
||||
* @property Date $lastSeen
|
||||
* @property integer $stock
|
||||
* @property Object $promotions
|
||||
@@ -104,11 +103,6 @@ class Product extends Model
|
||||
);
|
||||
}
|
||||
|
||||
public function conversionRate(): ?float
|
||||
{
|
||||
return $this->conversionRate;
|
||||
}
|
||||
|
||||
public function isDiscontinued(): bool
|
||||
{
|
||||
return $this->lastSeen < now()->format('Y-m-d');
|
||||
|
||||
@@ -6,17 +6,9 @@
|
||||
{% endif %}
|
||||
|
||||
{% if listType starts with 'promos' %}
|
||||
<ul class="list-group list-group-flush">
|
||||
{% for locale, promoByLocale in promos %}
|
||||
<li class="list-group-item">
|
||||
<h5 class="d-inline-block"><span class="badge bg-info">{{ locale | upper }}</span></h5>
|
||||
{% for promo in promoByLocale %}
|
||||
<a href="{{ path('app_promos', {'promo': promo.slug}) }}"><span
|
||||
class="badge bg-info">PROMO: {{ promo.tag }} [{{ promo.locale | upper }}]</span></a>
|
||||
{% for promo in promos %}
|
||||
<a href="{{ path('app_promos', {'promo': promo.slug}) }}"><span class="badge bg-info">PROMO: {{ promo.tag }}</span></a>
|
||||
{% endfor %}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
|
||||
|
||||
@@ -46,24 +38,22 @@
|
||||
<td class="align-middle">
|
||||
<a href='{{ path('app_product', {'productId': product.id}) }}'
|
||||
class="text-decoration-none">{{ product.name }}</a>
|
||||
<br>
|
||||
{% if product.stock > 0 %}
|
||||
<span class="badge text-bg-light">stock: {{ product.stock }}</span>
|
||||
{% else %}
|
||||
<span class="badge text-bg-warning">out of stock</span>
|
||||
{% endif %}
|
||||
{% if product.isDiscontinued() %}
|
||||
<a href="{{ path('app_discontinued') }}"><span class="badge text-bg-secondary" data-bs-toggle="tooltip"
|
||||
data-bs-title="Last update: {{ product.lastSeen }}">is discontinued</span></a>
|
||||
<span class="badge text-bg-secondary" data-bs-toggle="tooltip"
|
||||
data-bs-title="Last update: {{ product.lastSeen }}">is discontinued</span>
|
||||
{% endif %}
|
||||
{% if product.isNew() %}
|
||||
<a href="{{ path('app_new') }}"><span class="badge text-bg-success">is new</span></a>
|
||||
<span class="badge text-bg-success">is new</span>
|
||||
{% endif %}
|
||||
<span class="badge text-bg-light"><a
|
||||
href="{{ path('app_search', {'search': product.subTitle}) }}"
|
||||
class="link-underline link-underline-opacity-0 link-dark">{{ product.subTitle }}</a></span>
|
||||
{% if product.promotions is not null and product.promotions.hasPromotion %}<a href="{{ path('app_promos', {'promo': product.promotions.slug}) }}"><span class="badge bg-info">PROMO: {{ product.promotions.tag }}</span></a>{% endif %}
|
||||
<span class="badge text-bg-light">{{ product.country.countryName }}</span>
|
||||
</td>
|
||||
<td class="align-middle">
|
||||
<nav aria-label="breadcrumb" style="--bs-breadcrumb-divider: '>';">
|
||||
@@ -80,30 +70,19 @@
|
||||
<td class="align-middle"><a href='https://{{ product.country.locale }}.ryobitools.eu{{ product.url }}'>link</a></td>
|
||||
<td class="align-middle text-end">
|
||||
{% if product.isDiscontinued() or product.priceCurrent == product.productStandardPrice %}
|
||||
{{ product.priceLowest | format_currency(product.country.currency, {}, product.country.locale) }}<br>
|
||||
{% if product.conversionRate is not empty and product.conversionRate != 1 %}
|
||||
{{ (product.priceLowest * product.conversionRate) | format_currency('PLN', {}, 'pl') }}
|
||||
{% endif %}
|
||||
{{ product.priceLowest | format_currency(product.country.currency, {}, product.country.locale) }}
|
||||
{% else %}
|
||||
{% if product.priceLowest != product.priceCurrent %}{{ product.priceLowest | format_currency(product.country.currency, {}, product.country.locale) }}{% else %}
|
||||
<span class="badge text-bg-info">now lowest</span>
|
||||
{% endif %}</td>
|
||||
<span class="badge text-bg-info">now lowest</span>{% endif %}</td>
|
||||
{% endif %}
|
||||
|
||||
<td class="align-middle text-end">
|
||||
{{ product.priceCurrent | format_currency(product.country.currency, {}, product.country.locale) }}<br>
|
||||
{% if product.conversionRate is not empty and product.conversionRate != 1 %}
|
||||
{{ (product.priceCurrent * product.conversionRate) | format_currency('PLN', {}, 'pl') }}
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="align-middle text-end">{{ product.priceCurrent | format_currency(product.country.currency, {}, product.country.locale) }}</td>
|
||||
<td class="align-middle">
|
||||
<div class="d-flex flex-row">
|
||||
{% if product.priceCurrent != product.productStandardPrice %}
|
||||
<span class="badge text-bg-warning text-decoration-line-through flex-fill">{{ product.productStandardPrice | format_currency(product.country.currency, {}, product.country.locale) }}</span>
|
||||
{% if product.conversionRate is not empty and product.conversionRate != 1 %}
|
||||
<span class="badge text-bg-warning text-decoration-line-through flex-fill">{{ (product.productStandardPrice * product.conversionRate) | format_currency('PLN', {}, 'pl') }}</span>
|
||||
{% endif %}
|
||||
<span class="badge text-bg-success flex-fill">{{ ((1 - product.priceCurrent / product.productStandardPrice)*100)|number_format(0) }}%</span>
|
||||
{% if product.priceCurrent != product.productStandardPrice %}<span
|
||||
class="badge text-bg-warning text-decoration-line-through flex-fill">{{ product.productStandardPrice | format_currency(product.country.currency, {}, product.country.locale) }}</span>
|
||||
<span
|
||||
class="badge text-bg-success flex-fill">{{ ((1 - product.priceCurrent / product.productStandardPrice)*100)|number_format(0) }}%</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
</td>
|
||||
|
||||
Reference in New Issue
Block a user