piwheels-rpi-crypto
dgtlmoon 7 months ago
parent 32579d7800
commit 575bdcfbe8

@ -519,13 +519,17 @@ class processor_text_json_diff_form(commonSettingsForm):
result = False
return result
class processor_restock_diff_form(processor_text_json_diff_form):
in_stock_only = BooleanField('Only trigger when product goes BACK to in-stock', default=True)
price_change_min = FloatField('Minimum amount to trigger notification', [validators.Optional()], render_kw={"placeholder": "No limit", "size": "10"})
price_change_max = FloatField('Maximum amount to trigger notification', [validators.Optional()], render_kw={"placeholder": "No limit", "size": "10"})
price_change_threshold_percent = FloatField('Threshold in % for price changes', validators=[
validators.Optional(),
validators.NumberRange(min=0, max=100, message="Should be between 0 and 100"),
], render_kw={"placeholder": "0%", "size": "5"})
#@todo - add "Any increase" and "Any decrease" options
in_stock_only = BooleanField('Only trigger when product goes BACK to in-stock', default=True)
price_change_min = FloatField('Minimum amount to trigger notification',[validators.Optional()], render_kw={"placeholder": "No limit"} )
price_change_max = FloatField('Maximum amount to trigger notification',[validators.Optional()], render_kw={"placeholder": "No limit"} )
follow_price_changes = BooleanField('Follow price changes', default=False)
def extra_tab_content(self):
@ -560,6 +564,11 @@ class processor_restock_diff_form(processor_text_json_diff_form):
{{ render_field(form.price_change_max) }}
<span class="pure-form-message-inline">Maximum amount, only trigger a change when the price is more than this amount.</span>
</fieldset>
<fieldset class="pure-group price-change-minmax">
{{ render_field(form.price_change_threshold_percent) }}
<span class="pure-form-message-inline">Price must change more than this % to trigger a change.</span><br>
<span class="pure-form-message-inline">For example, If the product is $1,000 USD, <strong>2%</strong> would mean it has to change more than $20 since the last check.</span><br>
</fieldset>
</div>
</fieldset>"""

@ -58,6 +58,7 @@ class watch_base(dict):
'previous_md5': False,
'previous_md5_before_filters': False, # Used for skipping changedetection entirely
'processor': 'text_json_diff', # could be restock_diff or others from .processors
'price_change_threshold_percent': None,
'proxy': None, # Preferred proxy connection
'remote_server_reply': None, # From 'server' reply header
'sort_text_alphabetically': False,

@ -87,6 +87,22 @@ def get_itemprop_availability(html_content) -> Restock:
return Restock(value)
def is_between(number, lower=None, upper=None):
"""
Check if a number is between two values.
Parameters:
number (float): The number to check.
lower (float or None): The lower bound (inclusive). If None, no lower bound.
upper (float or None): The upper bound (inclusive). If None, no upper bound.
Returns:
bool: True if the number is between the lower and upper bounds, False otherwise.
"""
return (lower is None or lower <= number) and (upper is None or number <= upper)
class perform_site_check(difference_detection_processor):
screenshot = None
xpath_data = None
@ -161,7 +177,7 @@ class perform_site_check(difference_detection_processor):
# All cases
changed_detected = True
if watch.get('follow_price_changes') and watch.get('restock') and update_obj['restock'].get('price'):
if watch.get('follow_price_changes') and watch.get('restock') and update_obj.get('restock') and update_obj['restock'].get('price'):
price = float(update_obj['restock'].get('price'))
previous_price = float(watch['restock'].get('price'))
@ -170,18 +186,21 @@ class perform_site_check(difference_detection_processor):
changed_detected = True
# Minimum/maximum price limit
if update_obj.get('restock') and update_obj['restock'].get('price') and watch.get('price_change_min'):
if update_obj.get('restock') and update_obj['restock'].get('price'):
logger.debug(
f"{uuid} - Change was detected, 'price_change_max' is '{watch.get('price_change_max', '')}' 'price_change_min' is '{watch.get('price_change_min', '')}', price from website is '{update_obj['restock'].get('price', '')}'.")
if update_obj['restock'].get('price'):
min_limit = float(watch.get('price_change_min', 0))
max_limit = float(watch.get('price_change_max', float('inf'))) # Set to infinity if not provided
min_limit = float(watch.get('price_change_min')) if watch.get('price_change_min') else None
max_limit = float(watch.get('price_change_max')) if watch.get('price_change_max') else None
price = float(update_obj['restock'].get('price'))
logger.debug(f"{uuid} after float conversion - Min limit: '{min_limit}' Max limit: '{max_limit}' Price: '{price}'")
if changed_detected:
if price < max_limit and price > min_limit:
changed_detected = False
if min_limit or max_limit:
if is_between(number=price, lower=min_limit, upper=max_limit):
if changed_detected:
logger.debug(
f"{uuid} Override change-detected to FALSE because price was inside threshold")
changed_detected = False
# Always record the new checksum
update_obj["previous_md5"] = fetched_md5

@ -80,7 +80,7 @@ def test_restock_itemprop_basic(client, live_server):
assert b'Deleted' in res.data
def test_itemprop_price_change(client, live_server):
# live_server_setup(live_server)
#live_server_setup(live_server)
test_url = url_for('test_endpoint', _external=True)
@ -123,10 +123,12 @@ def test_itemprop_price_change(client, live_server):
res = client.get(url_for("form_delete", uuid="all"), follow_redirects=True)
assert b'Deleted' in res.data
def test_itemprop_price_minmax_limit(client, live_server):
#live_server_setup(live_server)
res = client.get(url_for("form_delete", uuid="all"), follow_redirects=True)
assert b'Deleted' in res.data
test_url = url_for('test_endpoint', _external=True)
set_original_response(props_markup=instock_props[0], price="950.95")
@ -184,3 +186,6 @@ def test_itemprop_price_minmax_limit(client, live_server):
res = client.get(url_for("index"))
assert b'1890.45' in res.data
assert b'unviewed' in res.data
res = client.get(url_for("form_delete", uuid="all"), follow_redirects=True)
assert b'Deleted' in res.data

@ -0,0 +1,21 @@
#!/usr/bin/python3
# run from dir above changedetectionio/ dir
# python3 -m unittest changedetectionio.tests.unit.test_restock_logic
import unittest
import os
from changedetectionio.processors import restock_diff
# mostly
class TestDiffBuilder(unittest.TestCase):
def test_logic(self):
assert restock_diff.is_between(number=10, lower=9, upper=11) == True, "Between 9 and 11"
assert restock_diff.is_between(number=10, lower=0, upper=11) == True, "Between 9 and 11"
assert restock_diff.is_between(number=10, lower=None, upper=11) == True, "Between None and 11"
assert not restock_diff.is_between(number=12, lower=None, upper=11) == True, "12 is not between None and 11"
if __name__ == '__main__':
unittest.main()
Loading…
Cancel
Save