fix
This commit is contained in:
+25
-16
@@ -15,6 +15,7 @@ from ..extensions import db
|
||||
from ..models import AppSetting, CompanySettings, FuelCard, FuelCardPolicy, FuelCardStationRule, FuelEntry, FuelStationCompany, FuelStationPoint, OrlenPrice, User, Vehicle
|
||||
from ..services import POLISH_REGIONS, aggregate_ure_companies, calculate_costs, fetch_orlen_price, fetch_orlen_range, fetch_ure_stations, invoice_period
|
||||
from ..station_catalog import sync_station_catalog
|
||||
from ..orlen_sync import sync_orlen_prices
|
||||
|
||||
FUEL_TYPES = ("PB95", "PB98", "DIESEL", "LPG")
|
||||
|
||||
@@ -28,23 +29,31 @@ def orlen_prices():
|
||||
@api.post('/orlen/sync')
|
||||
@role_required('boss','admin')
|
||||
def orlen_sync():
|
||||
d=payload(); fuels=d.get('fuels',[]); fuels=[fuels] if isinstance(fuels,str) else fuels; fuels=[f.upper() for f in fuels if f.upper() in FUEL_TYPES]; year=int(d.get('year',date.today().year))
|
||||
regions=d.get('regions',[]); regions=[regions] if isinstance(regions,str) else regions; regions=[str(r).strip().lower() for r in regions if str(r).strip().lower() in POLISH_REGIONS]
|
||||
if not fuels:return fail('Wybierz co najmniej jedno paliwo')
|
||||
settings=CompanySettings.query.first(); result={}; total=0
|
||||
d = payload()
|
||||
fuels = d.get('fuels', [])
|
||||
fuels = [fuels] if isinstance(fuels, str) else fuels
|
||||
fuels = [fuel.upper() for fuel in fuels if fuel.upper() in FUEL_TYPES]
|
||||
regions = d.get('regions', [])
|
||||
regions = [regions] if isinstance(regions, str) else regions
|
||||
regions = [str(region).strip().lower() for region in regions if str(region).strip().lower() in POLISH_REGIONS]
|
||||
if not fuels:
|
||||
return fail('Wybierz co najmniej jedno paliwo')
|
||||
|
||||
try:
|
||||
for fuel in fuels:
|
||||
added=updated=0
|
||||
for row in fetch_orlen_range(fuel,date(year,1,1),min(date(year,12,31),date.today()),'all' if fuel=='LPG' else settings.region):
|
||||
if fuel=='LPG' and regions and row.get('region') not in regions: continue
|
||||
x=OrlenPrice.query.filter_by(fuel_type=row['fuel_type'],effective_date=row['effective_date'],region=row['region']).first()
|
||||
if x:
|
||||
for k,v in row.items():setattr(x,k,v)
|
||||
x.fetched_at=datetime.utcnow();updated+=1
|
||||
else:db.session.add(OrlenPrice(**row));added+=1
|
||||
result[fuel]={'added':added,'updated':updated};total+=added+updated
|
||||
db.session.commit();return response(result,f'Przetworzono {total} rekordów')
|
||||
except Exception as exc:db.session.rollback();return fail(str(exc),502)
|
||||
year = int(d.get('year', date.today().year))
|
||||
settings = CompanySettings.query.first()
|
||||
result, total = sync_orlen_prices(
|
||||
fuels=fuels,
|
||||
year=year,
|
||||
regions=regions,
|
||||
default_region=settings.region,
|
||||
full_refresh=boolv(d, 'full_refresh'),
|
||||
)
|
||||
db.session.commit()
|
||||
return response(result, f'Przetworzono {total} rekordów')
|
||||
except Exception as exc:
|
||||
db.session.rollback()
|
||||
return fail(str(exc), 502)
|
||||
|
||||
@api.get('/orlen/preview')
|
||||
@login_required
|
||||
|
||||
+25
-18
@@ -13,6 +13,7 @@ from .station_catalog import sync_station_catalog
|
||||
from . import THEMES
|
||||
from .vat import entry_vat_rate, freeze_vat_action, global_vat_override, save_global_vat_override
|
||||
from .settlement import calculate as calculate_snapshot_settlement, freeze as freeze_settlement
|
||||
from .orlen_sync import sync_orlen_prices
|
||||
|
||||
main = Blueprint("main", __name__)
|
||||
FUEL_TYPES = ("PB95", "PB98", "DIESEL", "LPG")
|
||||
@@ -499,28 +500,34 @@ def orlen_data():
|
||||
@login_required
|
||||
@roles("boss", "admin")
|
||||
def orlen_sync():
|
||||
payload = request.get_json(silent=True) or request.form
|
||||
fuels = payload.get("fuels", [])
|
||||
if isinstance(fuels, str): fuels = [fuels]
|
||||
fuels = [f.upper() for f in fuels if f.upper() in FUEL_TYPES]
|
||||
year = int(payload.get("year", date.today().year))
|
||||
if not fuels: return jsonify({"ok": False, "error": "Wybierz co najmniej jedno paliwo."}), 400
|
||||
settings = CompanySettings.query.first(); start = date(year,1,1); end = min(date(year,12,31), date.today())
|
||||
result = {}; total = 0
|
||||
data = request.get_json(silent=True) or request.form
|
||||
fuels = data.get("fuels", [])
|
||||
if isinstance(fuels, str):
|
||||
fuels = [fuels]
|
||||
fuels = [fuel.upper() for fuel in fuels if fuel.upper() in FUEL_TYPES]
|
||||
if not fuels:
|
||||
return jsonify({"ok": False, "error": "Wybierz co najmniej jedno paliwo."}), 400
|
||||
|
||||
regions = data.get("regions", [])
|
||||
if isinstance(regions, str):
|
||||
regions = [regions]
|
||||
regions = [str(region).strip().lower() for region in regions if str(region).strip().lower() in POLISH_REGIONS]
|
||||
full_refresh = data.get("full_refresh") in (True, 1, "1", "true", "on", "yes")
|
||||
|
||||
try:
|
||||
for fuel in fuels:
|
||||
imported = 0; updated = 0
|
||||
for row in fetch_orlen_range(fuel, start, end, "all" if fuel == "LPG" else settings.region):
|
||||
existing = OrlenPrice.query.filter_by(fuel_type=row["fuel_type"], effective_date=row["effective_date"], region=row["region"]).first()
|
||||
if existing:
|
||||
existing.price_per_liter=row["price_per_liter"]; existing.raw_value=row["raw_value"]; existing.product_name=row["product_name"]; existing.source=row["source"]; existing.fetched_at=datetime.utcnow(); updated += 1
|
||||
else:
|
||||
db.session.add(OrlenPrice(**row)); imported += 1
|
||||
result[fuel] = {"added": imported, "updated": updated}; total += imported + updated
|
||||
settings = CompanySettings.query.first()
|
||||
result, total = sync_orlen_prices(
|
||||
fuels=fuels,
|
||||
year=int(data.get("year", date.today().year)),
|
||||
regions=regions,
|
||||
default_region=settings.region,
|
||||
full_refresh=full_refresh,
|
||||
)
|
||||
db.session.commit()
|
||||
return jsonify({"ok": True, "message": f"Przetworzono {total} rekordów.", "result": result})
|
||||
except Exception as exc:
|
||||
db.session.rollback(); return jsonify({"ok": False, "error": str(exc)}), 502
|
||||
db.session.rollback()
|
||||
return jsonify({"ok": False, "error": str(exc)}), 502
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
from datetime import date, datetime
|
||||
|
||||
from sqlalchemy import func
|
||||
|
||||
from .extensions import db
|
||||
from .models import OrlenPrice
|
||||
from .services import fetch_orlen_range
|
||||
|
||||
|
||||
def _year_bounds(year, today=None):
|
||||
today = today or date.today()
|
||||
start = date(year, 1, 1)
|
||||
end = min(date(year, 12, 31), today)
|
||||
if end < start:
|
||||
raise ValueError("Nie można synchronizować danych dla przyszłego roku")
|
||||
return start, end
|
||||
|
||||
|
||||
def _latest_date(fuel, start, end, region=""):
|
||||
query = db.session.query(func.max(OrlenPrice.effective_date)).filter(
|
||||
OrlenPrice.fuel_type == fuel,
|
||||
OrlenPrice.effective_date.between(start, end),
|
||||
)
|
||||
if fuel == "LPG":
|
||||
query = query.filter(OrlenPrice.region == region)
|
||||
else:
|
||||
query = query.filter(OrlenPrice.region == "")
|
||||
return query.scalar()
|
||||
|
||||
|
||||
def _sync_start(fuel, start, end, regions, full_refresh):
|
||||
if full_refresh:
|
||||
return start
|
||||
|
||||
if fuel != "LPG":
|
||||
return _latest_date(fuel, start, end) or start
|
||||
|
||||
latest_dates = [_latest_date("LPG", start, end, region) for region in regions]
|
||||
return min((value or start) for value in latest_dates)
|
||||
|
||||
|
||||
def sync_orlen_prices(fuels, year, regions, default_region, full_refresh=False, today=None):
|
||||
start, end = _year_bounds(year, today=today)
|
||||
target_regions = [str(region).strip().lower() for region in regions if str(region).strip()]
|
||||
if not target_regions:
|
||||
target_regions = [str(default_region).strip().lower()]
|
||||
|
||||
result = {}
|
||||
total = 0
|
||||
|
||||
for fuel in fuels:
|
||||
fuel_regions = target_regions if fuel == "LPG" else []
|
||||
date_from = _sync_start(fuel, start, end, fuel_regions, full_refresh)
|
||||
added = 0
|
||||
updated = 0
|
||||
|
||||
rows = fetch_orlen_range(
|
||||
fuel,
|
||||
date_from,
|
||||
end,
|
||||
"all" if fuel == "LPG" else default_region,
|
||||
)
|
||||
for row in rows:
|
||||
if fuel == "LPG" and row.get("region") not in fuel_regions:
|
||||
continue
|
||||
|
||||
existing = OrlenPrice.query.filter_by(
|
||||
fuel_type=row["fuel_type"],
|
||||
effective_date=row["effective_date"],
|
||||
region=row["region"],
|
||||
).first()
|
||||
if existing:
|
||||
for key, value in row.items():
|
||||
setattr(existing, key, value)
|
||||
existing.fetched_at = datetime.utcnow()
|
||||
updated += 1
|
||||
else:
|
||||
db.session.add(OrlenPrice(**row))
|
||||
added += 1
|
||||
|
||||
processed = added + updated
|
||||
result[fuel] = {
|
||||
"added": added,
|
||||
"updated": updated,
|
||||
"from": date_from.isoformat(),
|
||||
"to": end.isoformat(),
|
||||
"full_refresh": bool(full_refresh),
|
||||
}
|
||||
total += processed
|
||||
|
||||
return result, total
|
||||
@@ -1,2 +1,2 @@
|
||||
(()=>{const F=FuelTrack;F.bindLpgRegionPicker=()=>{const select=F.qs('#lpg-region-select');if(!select||select.dataset.choicesBound)return;select.dataset.choicesBound='1';const choices=new Choices(select,{removeItemButton:true,searchEnabled:true,shouldSort:false,position:'bottom',placeholder:true,placeholderValue:'Wybierz województwa',noResultsText:'Brak województwa',noChoicesText:'Brak opcji',itemSelectText:'Wybierz'});const modal=F.qs('#lpgRegionsModal');modal?.addEventListener('hidden.bs.modal',()=>{const count=F.qsa('option:checked',select).length;const badge=F.qs('#lpg-region-count');if(badge)badge.textContent=count?`${count} wybrano`:'Domyślne województwo'})};F.bindOrlenSync=()=>{const btn=F.qs('#orlen-sync-btn');if(!btn||btn.dataset.bound)return;btn.dataset.bound='1';btn.addEventListener('click',async()=>{const form=F.qs('#orlen-filter-form'),fuels=F.qsa('[name=fuel]:checked',form).map(x=>x.value),year=F.qs('[name=year]',form).value,status=F.qs('#orlen-sync-status');if(!fuels.length){status.textContent='Wybierz co najmniej jedno paliwo.';return}btn.disabled=true;const old=btn.innerHTML;btn.innerHTML='Pobieranie…';try{const regions=F.qsa('[name=region] option:checked',form).map(x=>x.value);const r=await fetch('/api/orlen/sync',{method:'POST',headers:{'Content-Type':'application/json','X-Requested-With':'XMLHttpRequest'},body:JSON.stringify({fuels,year,regions})}),d=await r.json();if(!r.ok)throw new Error(d.error||'Błąd pobierania');status.textContent=d.message;await F.replaceMain(`/orlen?${new URLSearchParams(new FormData(form))}`,{push:true});F.notify(d.message)}catch(e){status.textContent=`Błąd: ${e.message}`;F.notify(e.message,'danger')}finally{btn.disabled=false;btn.innerHTML=old}})}})();
|
||||
(()=>{const F=FuelTrack;F.bindLpgRegionPicker=()=>{const select=F.qs('#lpg-region-select');if(!select||select.dataset.choicesBound)return;select.dataset.choicesBound='1';new Choices(select,{removeItemButton:true,searchEnabled:true,shouldSort:false,position:'bottom',placeholder:true,placeholderValue:'Wybierz województwa',noResultsText:'Brak województwa',noChoicesText:'Brak opcji',itemSelectText:'Wybierz'});const modal=F.qs('#lpgRegionsModal');modal?.addEventListener('hidden.bs.modal',()=>{const count=F.qsa('option:checked',select).length;const badge=F.qs('#lpg-region-count');if(badge)badge.textContent=count?`${count} wybrano`:'Domyślne województwo'})};F.bindOrlenSync=()=>{const incrementalBtn=F.qs('#orlen-sync-btn'),fullBtn=F.qs('#orlen-full-sync-btn');if(!incrementalBtn||incrementalBtn.dataset.bound)return;incrementalBtn.dataset.bound='1';if(fullBtn)fullBtn.dataset.bound='1';const sync=async fullRefresh=>{const form=F.qs('#orlen-filter-form'),fuels=F.qsa('[name=fuel]:checked',form).map(x=>x.value),year=F.qs('[name=year]',form).value,status=F.qs('#orlen-sync-status');if(!fuels.length){status.textContent='Wybierz co najmniej jedno paliwo.';return}if(fullRefresh&&!confirm(`Pobrać ponownie wszystkie dane dla ${year} roku? Operacja może potrwać dłużej.`))return;const regions=F.qsa('[name=region] option:checked',form).map(x=>x.value),old=incrementalBtn.innerHTML;incrementalBtn.disabled=true;if(fullBtn)fullBtn.disabled=true;incrementalBtn.innerHTML=fullRefresh?'Pełne pobieranie…':'Pobieranie…';try{const r=await fetch('/api/orlen/sync',{method:'POST',headers:{'Content-Type':'application/json','X-Requested-With':'XMLHttpRequest'},body:JSON.stringify({fuels,year,regions,full_refresh:fullRefresh})}),d=await r.json();if(!r.ok||!d.ok)throw new Error(d.error||d.message||'Błąd pobierania');status.textContent=d.message;await F.replaceMain(`/orlen?${new URLSearchParams(new FormData(form))}`,{push:true});F.notify(d.message)}catch(e){status.textContent=`Błąd: ${e.message}`;F.notify(e.message,'danger')}finally{incrementalBtn.disabled=false;if(fullBtn)fullBtn.disabled=false;incrementalBtn.innerHTML=old}};incrementalBtn.addEventListener('click',()=>sync(false));fullBtn?.addEventListener('click',()=>sync(true))}})();
|
||||
;(()=>{const F=FuelTrack;F.bindOrlenComparison=()=>{const type=F.qs('#comparison-type'),fuel=F.qs('#compare-fuel');if(type&&!type.dataset.compareBound){type.dataset.compareBound='1';const update=()=>{F.qs('#year-comparison-fields')?.classList.toggle('d-none',type.value!=='years');F.qs('#period-comparison-fields')?.classList.toggle('d-none',type.value!=='periods')};type.addEventListener('change',update);update()}if(fuel&&!fuel.dataset.compareBound){fuel.dataset.compareBound='1';const update=()=>F.qs('#compare-region-wrap')?.classList.toggle('d-none',fuel.value!=='LPG');fuel.addEventListener('change',update);update()}}})();
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
{% else %}<tr><td colspan="8" class="text-center text-body-secondary py-4">Brak tankowań spełniających kryteria.</td></tr>{% endfor %}</tbody></table></div>
|
||||
{% if entries_page.pages > 1 %}<nav><ul class="pagination mb-0">{% for p in entries_page.iter_pages() %}{% if p %}<li class="page-item {% if p==entries_page.page %}active{% endif %}"><a class="page-link ajax-nav-link" href="{{url_for('main.admin_fuel_entries',page=p,q=q,month=month,company_id=company_id)}}">{{p}}</a></li>{% else %}<li class="page-item disabled"><span class="page-link">…</span></li>{% endif %}{% endfor %}</ul></nav>{% endif %}
|
||||
</div></div>
|
||||
<div class="modal fade" id="fuelEntryEditModal" tabindex="-1"><div class="modal-dialog modal-lg modal-dialog-scrollable"><div class="modal-content"><form id="fuel-entry-edit-form" class="ajax-form" data-method="PUT"><div class="modal-header"><h2 class="modal-title fs-5">Edytuj tankowanie</h2><button type="button" class="btn-close" data-bs-dismiss="modal"></button></div><div class="modal-body"><div class="row g-3">
|
||||
<div class="modal fade" id="fuelEntryEditModal" tabindex="-1"><div class="modal-dialog modal-lg modal-dialog-scrollable"><form id="fuel-entry-edit-form" class="modal-content ajax-form" data-method="PUT"><div class="modal-header"><h2 class="modal-title fs-5">Edytuj tankowanie</h2><button type="button" class="btn-close" data-bs-dismiss="modal"></button></div><div class="modal-body"><div class="row g-3">
|
||||
<div class="col-md-6"><label class="form-label">Pojazd</label><select class="form-select" name="vehicle_id" required>{% for v in vehicles %}<option value="{{v.id}}">{{v.name}} · {{v.registration}}</option>{% endfor %}</select></div>
|
||||
<div class="col-md-6"><label class="form-label">Data i godzina</label><input class="form-control" type="datetime-local" name="fueled_at" required></div>
|
||||
<div class="col-md-4"><label class="form-label">Paliwo</label><select class="form-select" name="fuel_type">{% for f in ['PB95','PB98','DIESEL','LPG'] %}<option>{{f}}</option>{% endfor %}</select></div>
|
||||
@@ -36,5 +36,5 @@
|
||||
<div class="col-md-3"><label class="form-label">Dopłata netto / l</label><input class="form-control" type="number" step="0.0001" name="snapshot_surcharge_per_liter" required></div>
|
||||
<div class="col-md-6"><div class="form-check mt-4"><input class="form-check-input" type="checkbox" name="snapshot_uses_last_price" id="edit-snapshot-last-price"><label class="form-check-label" for="edit-snapshot-last-price">Użyj zapisanej ceny hurtowej jako Last Price</label></div></div>
|
||||
<div class="col-md-6"><label class="form-label">Źródło / opis reguły</label><input class="form-control" name="snapshot_rule_source" maxlength="160"></div>
|
||||
</div></div><div class="modal-footer"><button type="button" class="btn btn-danger me-auto" id="fuel-entry-delete-btn">Usuń tankowanie</button><button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Anuluj</button><button class="btn btn-primary">Zapisz zmiany</button></div></form></div></div></div>
|
||||
</div></div><div class="modal-footer"><button type="button" class="btn btn-danger me-auto" id="fuel-entry-delete-btn">Usuń tankowanie</button><button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Anuluj</button><button class="btn btn-primary">Zapisz zmiany</button></div></form></div></div>
|
||||
{% endblock %}
|
||||
|
||||
@@ -20,7 +20,18 @@
|
||||
<div class="col-md-3"><div class="form-check mb-2"><input class="form-check-input" type="checkbox" name="gross" value="1" id="gross-price" {% if include_vat %}checked{% endif %}><label class="form-check-label" for="gross-price">Dolicz VAT</label></div></div>
|
||||
<div class="col-md-3"><button class="btn btn-secondary w-100">Pokaż dane</button></div>
|
||||
</form>
|
||||
{% if current_user.role in ['boss','admin'] %}<div class="d-flex align-items-center gap-3 mt-3"><button type="button" id="orlen-sync-btn" class="btn btn-primary">Pobierz z API</button><span id="orlen-sync-status" class="small text-body-secondary" aria-live="polite"></span></div>{% endif %}
|
||||
{% if current_user.role in ['boss','admin'] %}
|
||||
<div class="d-flex flex-wrap align-items-center gap-3 mt-3">
|
||||
<div class="btn-group">
|
||||
<button type="button" id="orlen-sync-btn" class="btn btn-primary">Pobierz nowe dane</button>
|
||||
<button type="button" class="btn btn-primary dropdown-toggle dropdown-toggle-split" data-bs-toggle="dropdown" aria-expanded="false"><span class="visually-hidden">Opcje pobierania</span></button>
|
||||
<ul class="dropdown-menu">
|
||||
<li><button type="button" id="orlen-full-sync-btn" class="dropdown-item">Pobierz cały wybrany rok ponownie</button></li>
|
||||
</ul>
|
||||
</div>
|
||||
<span id="orlen-sync-status" class="small text-body-secondary" aria-live="polite"></span>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div></div>
|
||||
|
||||
<div class="modal fade lpg-region-modal" id="lpgRegionsModal" tabindex="-1" aria-hidden="true"><div class="modal-dialog modal-lg modal-dialog-centered"><div class="modal-content"><div class="modal-header"><h2 class="modal-title fs-5">Województwa LPG</h2><button type="button" class="btn-close" data-bs-dismiss="modal"></button></div><div class="modal-body"><label class="form-label" for="lpg-region-select">Wybierz jedno lub wiele województw</label><select class="form-select" name="region" id="lpg-region-select" form="orlen-filter-form" multiple>{% for r in regions %}<option value="{{r}}" {% if r in selected_regions %}selected{% endif %}>{{r}}</option>{% endfor %}</select></div><div class="modal-footer"><button type="button" class="btn btn-primary" data-bs-dismiss="modal">Gotowe</button></div></div></div></div>
|
||||
|
||||
@@ -362,3 +362,146 @@ def test_last_price_zero_and_full_vat_deduction():
|
||||
from app.domain.costs import calculate_net_price_costs
|
||||
assert round(float(calculate_net_price_costs(10, 23, 0)["effective_cost"]), 2) == 12.30
|
||||
assert round(float(calculate_net_price_costs(10, 23, 100)["effective_cost"]), 2) == 10.00
|
||||
|
||||
|
||||
def test_fuel_entry_edit_modal_uses_scrollable_bootstrap_structure(tmp_path):
|
||||
app = make_app(tmp_path, "fuel-entry-modal.db")
|
||||
client = app.test_client()
|
||||
client.post('/login', data={'email': 'admin@example.com', 'password': 'admin123!'})
|
||||
|
||||
html = client.get('/admin/fuel-entries').get_data(as_text=True)
|
||||
|
||||
assert (
|
||||
'modal-dialog modal-lg modal-dialog-scrollable">'
|
||||
'<form id="fuel-entry-edit-form" class="modal-content ajax-form"'
|
||||
in html
|
||||
)
|
||||
assert '<div class="modal-content"><form id="fuel-entry-edit-form"' not in html
|
||||
|
||||
|
||||
def test_orlen_incremental_sync_starts_at_latest_saved_record(tmp_path, monkeypatch):
|
||||
from datetime import date
|
||||
from decimal import Decimal
|
||||
from app.extensions import db
|
||||
from app.models import OrlenPrice
|
||||
from app.orlen_sync import sync_orlen_prices
|
||||
import app.orlen_sync as orlen_sync_module
|
||||
|
||||
app = make_app(tmp_path, "orlen-incremental.db")
|
||||
calls = []
|
||||
|
||||
def fake_fetch(fuel, date_from, date_to, region):
|
||||
calls.append((fuel, date_from, date_to, region))
|
||||
return []
|
||||
|
||||
monkeypatch.setattr(orlen_sync_module, 'fetch_orlen_range', fake_fetch)
|
||||
with app.app_context():
|
||||
db.session.add_all([
|
||||
OrlenPrice(fuel_type='PB95', effective_date=date(2026, 1, 2), price_per_liter=Decimal('4.1000'), raw_value=Decimal('4100'), region='', product_name='PB95', source='test'),
|
||||
OrlenPrice(fuel_type='PB95', effective_date=date(2026, 7, 15), price_per_liter=Decimal('4.5000'), raw_value=Decimal('4500'), region='', product_name='PB95', source='test'),
|
||||
])
|
||||
db.session.commit()
|
||||
|
||||
result, total = sync_orlen_prices(
|
||||
fuels=['PB95'],
|
||||
year=2026,
|
||||
regions=[],
|
||||
default_region='mazowieckie',
|
||||
full_refresh=False,
|
||||
today=date(2026, 8, 2),
|
||||
)
|
||||
|
||||
assert calls == [('PB95', date(2026, 7, 15), date(2026, 8, 2), 'mazowieckie')]
|
||||
assert result['PB95']['from'] == '2026-07-15'
|
||||
assert result['PB95']['full_refresh'] is False
|
||||
assert total == 0
|
||||
|
||||
|
||||
def test_orlen_full_refresh_starts_at_beginning_of_selected_year(tmp_path, monkeypatch):
|
||||
from datetime import date
|
||||
from decimal import Decimal
|
||||
from app.extensions import db
|
||||
from app.models import OrlenPrice
|
||||
from app.orlen_sync import sync_orlen_prices
|
||||
import app.orlen_sync as orlen_sync_module
|
||||
|
||||
app = make_app(tmp_path, "orlen-full-refresh.db")
|
||||
calls = []
|
||||
|
||||
def fake_fetch(fuel, date_from, date_to, region):
|
||||
calls.append((fuel, date_from, date_to, region))
|
||||
return []
|
||||
|
||||
monkeypatch.setattr(orlen_sync_module, 'fetch_orlen_range', fake_fetch)
|
||||
with app.app_context():
|
||||
db.session.add(OrlenPrice(fuel_type='DIESEL', effective_date=date(2026, 7, 20), price_per_liter=Decimal('4.9000'), raw_value=Decimal('4900'), region='', product_name='DIESEL', source='test'))
|
||||
db.session.commit()
|
||||
|
||||
result, _ = sync_orlen_prices(
|
||||
fuels=['DIESEL'],
|
||||
year=2026,
|
||||
regions=[],
|
||||
default_region='mazowieckie',
|
||||
full_refresh=True,
|
||||
today=date(2026, 8, 2),
|
||||
)
|
||||
|
||||
assert calls == [('DIESEL', date(2026, 1, 1), date(2026, 8, 2), 'mazowieckie')]
|
||||
assert result['DIESEL']['from'] == '2026-01-01'
|
||||
assert result['DIESEL']['full_refresh'] is True
|
||||
|
||||
|
||||
def test_orlen_lpg_incremental_sync_uses_oldest_latest_region_date(tmp_path, monkeypatch):
|
||||
from datetime import date
|
||||
from decimal import Decimal
|
||||
from app.extensions import db
|
||||
from app.models import OrlenPrice
|
||||
from app.orlen_sync import sync_orlen_prices
|
||||
import app.orlen_sync as orlen_sync_module
|
||||
|
||||
app = make_app(tmp_path, "orlen-lpg-incremental.db")
|
||||
calls = []
|
||||
|
||||
def fake_fetch(fuel, date_from, date_to, region):
|
||||
calls.append((fuel, date_from, date_to, region))
|
||||
return [
|
||||
{'fuel_type': 'LPG', 'effective_date': date(2026, 8, 1), 'price_per_liter': Decimal('2.1000'), 'raw_value': Decimal('2.1000'), 'region': 'mazowieckie', 'product_name': 'LPG', 'source': 'test'},
|
||||
{'fuel_type': 'LPG', 'effective_date': date(2026, 8, 1), 'price_per_liter': Decimal('2.2000'), 'raw_value': Decimal('2.2000'), 'region': 'pomorskie', 'product_name': 'LPG', 'source': 'test'},
|
||||
]
|
||||
|
||||
monkeypatch.setattr(orlen_sync_module, 'fetch_orlen_range', fake_fetch)
|
||||
with app.app_context():
|
||||
db.session.add_all([
|
||||
OrlenPrice(fuel_type='LPG', effective_date=date(2026, 7, 20), price_per_liter=Decimal('2.0000'), raw_value=Decimal('2.0000'), region='mazowieckie', product_name='LPG', source='test'),
|
||||
OrlenPrice(fuel_type='LPG', effective_date=date(2026, 7, 25), price_per_liter=Decimal('2.0000'), raw_value=Decimal('2.0000'), region='śląskie', product_name='LPG', source='test'),
|
||||
])
|
||||
db.session.commit()
|
||||
|
||||
result, total = sync_orlen_prices(
|
||||
fuels=['LPG'],
|
||||
year=2026,
|
||||
regions=['mazowieckie', 'śląskie'],
|
||||
default_region='mazowieckie',
|
||||
full_refresh=False,
|
||||
today=date(2026, 8, 2),
|
||||
)
|
||||
db.session.commit()
|
||||
|
||||
assert OrlenPrice.query.filter_by(fuel_type='LPG', region='pomorskie').count() == 0
|
||||
|
||||
assert calls == [('LPG', date(2026, 7, 20), date(2026, 8, 2), 'all')]
|
||||
assert result['LPG']['from'] == '2026-07-20'
|
||||
assert total == 1
|
||||
|
||||
|
||||
def test_orlen_page_has_incremental_and_full_refresh_controls(tmp_path):
|
||||
app = make_app(tmp_path, "orlen-sync-ui.db")
|
||||
client = app.test_client()
|
||||
client.post('/login', data={'email': 'admin@example.com', 'password': 'admin123!'})
|
||||
|
||||
html = client.get('/orlen?mode=history').get_data(as_text=True)
|
||||
|
||||
assert 'id="orlen-sync-btn"' in html
|
||||
assert 'Pobierz nowe dane' in html
|
||||
assert 'id="orlen-full-sync-btn"' in html
|
||||
assert 'Pobierz cały wybrany rok ponownie' in html
|
||||
|
||||
Reference in New Issue
Block a user