Skip to content

Commit

Permalink
Improve sell command and move two_column_view
Browse files Browse the repository at this point in the history
- Never prompt for price beforehand
- Always show price suggestions and stats
- Fetching all price suggestions takes too much time, provide a
  "relevant-only-fetcher"
- Move rich two_column_view helper from Textual app to ViewCommon and
  use with sell command.
- sell command logic not moved to ctrl.collection method yet...
- Leave some unused imports in discogs.py...
  • Loading branch information
JOJ0 committed Nov 21, 2024
1 parent bab36ac commit fe3737f
Show file tree
Hide file tree
Showing 5 changed files with 103 additions and 72 deletions.
26 changes: 17 additions & 9 deletions discodos/cmd23/sell.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import logging
import click
from rich import print

from discodos.ctrl import CollectionControlCommandline
from discodos.view import ViewCommonCommandline

log = logging.getLogger('discodos')

Expand Down Expand Up @@ -32,7 +34,6 @@
@click.option(
"-p", "--price",
type=float,
prompt="Price (enter 0 to fetch Discogs suggested price)",
default=None,
help="Listing price for the record. Leave blank for suggested price."
)
Expand Down Expand Up @@ -87,6 +88,7 @@ def update_user_interaction_helper(user):
False, user, user.conf.discogs_token, user.conf.discogs_appid,
user.conf.discobase, user.conf.musicbrainz_user,
user.conf.musicbrainz_password)
view = ViewCommonCommandline()

if not coll_ctrl.ONLINE:
log.warning("Online mode is required to list a record for sale.")
Expand All @@ -97,22 +99,28 @@ def update_user_interaction_helper(user):
# search_release exits program, not required to handle here.
release_id = found_release["id"]

suggested_p = coll_ctrl.collection.fetch_relevant_price_suggestions(release_id)
print("Suggested prices:")
print(view.two_column_view(suggested_p, as_is=True))

stats = coll_ctrl.collection.fetch_marketplace_stats(release_id)
print("Marketplace stats:")
print(view.two_column_view(stats))

if not price:
suggested_price = coll_ctrl.collection.fetch_price_suggestion(
release_id, condition
)
if suggested_price:
click.echo(
recommended_price = suggested_p.get(condition)
if recommended_price:
print(
f"Suggested price for condition '{condition}': "
f"{suggested_price.currency} {suggested_price.value}"
f"EUR {recommended_price}"
)
price = click.prompt(
"Accept?",
type=float,
default=round(suggested_price.value, 2),
default=recommended_price,
)
else:
click.echo("No suggested price available; please enter a price manually.")
print("No suggested price available; please enter a price manually.")
price = click.prompt("Price", type=float)

log.info(f"Attempting to list record {release_id} for sale.")
Expand Down
6 changes: 6 additions & 0 deletions discodos/ctrl/collection.py
Original file line number Diff line number Diff line change
Expand Up @@ -976,3 +976,9 @@ def tui_ls_releases(self, search_terms):
)
app.run(inline=False)
return

def list_record_for_sale(
self, query, release_id, condition, sleeve_condition, price, status, location,
allow_offers, comments, private_comments,
):
pass
54 changes: 2 additions & 52 deletions discodos/ctrl/tui.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import logging
from sqlite3 import Row
from datetime import datetime
from rich.table import Table as rich_table
from rich.markdown import Markdown
from textual.app import App
from textual.containers import Horizontal, Vertical, VerticalScroll
from textual.widgets import DataTable, Digits, Footer, Label, Static, RichLog
Expand Down Expand Up @@ -157,7 +155,7 @@ def on_data_table_row_highlighted(self, event):
listing_id = self.table.get_cell(row_key, "forsale")
listing = self.collection.get_sales_listing_details(listing_id)
self.left_column_content.update(
self._two_column_view(listing, translate_keys=self.key_translation)
self.cli.two_column_view(listing, translate_keys=self.key_translation)
)
self._sales_digits_update(listing)
# Stats
Expand All @@ -178,7 +176,7 @@ def on_data_table_row_selected(self, event):
# Stats - we fetch always
release_id = self.table.get_cell(row_key, "release_id")
stats = self.fetch_marketplace_stats(release_id)
self.middle_column_content.update(self._two_column_view(stats))
self.middle_column_content.update(self.cli.two_column_view(stats))
rlog.write(
f"Updated price, marketplace stats and details of listing {listing_id} "
"with Discogs data."
Expand All @@ -195,54 +193,6 @@ def _load_rows_into_table(self):
for row_id, row in enumerate(self.rows):
table_widget.add_row(*row.values(), key=row_id)

def _two_column_view(self, details_dict, translate_keys=None):
"""A Rich-formatted view of keys and values.
- by default simply capitalizes key names
- optionally alters key names via a passed translaton table
We use it for Marketplace stats and Marketplace listing details.
"""
# Create a rich Table with two columns.
table = rich_table(box=None)
table.add_column("Field", style="cyan", justify="right")
table.add_column("Value", style="white")
# Display an empty table instead of nothing.
if not details_dict:
return table

# Highlight/fix/replace some values first
values_replaced = {}
for key, value in details_dict.items():
if key in ["d_sales_release_url", "d_sales_url"]:
value = Markdown(f"[View in browser]({value})")
if key == "d_sales_allow_offers":
value = "Yes" if value in [1, True] else "No"
elif key == "status" and value == "Sold":
value = f"[magenta]{value}[/magenta]"
elif key == "d_sales_posted" and isinstance(value, datetime):
value = datetime.strftime(value, "%Y-%m-%d")
values_replaced[key] = value

# Prettify column captions
if translate_keys:
final_details = {
translate_keys.get(k, k): v for k, v in values_replaced.items()
}
else: # Without a tranlation table, fall back to simply capitalizing
final_details = {
k.capitalize(): v for k, v in values_replaced.items()
}

# The final creation of the Rich table
for key, value in final_details.items():
if isinstance(value, Markdown):
table.add_row(f"[bold]{key}[/bold]", value)
continue
# Format key bold and value normal font (or as we manipulated it above)
table.add_row(f"[bold]{key}[/bold]", str(value))
return table

def _sales_digits_update(self, listing):
"""A Rich-formatted big digits view of the sales price.
"""
Expand Down
36 changes: 25 additions & 11 deletions discodos/model/discogs.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import time
import logging
from socket import gaierror
from rich.progress import Progress
import discogs_client
import discogs_client.exceptions
from discogs_client import Condition, Status
from discogs_client import Condition, Status, Release
from discogs_client.models import PriceSuggestions
import requests.exceptions
import urllib3.exceptions

Expand Down Expand Up @@ -201,17 +203,29 @@ def fetch_marketplace_stats(self, release_id):
return r if r else None

def fetch_price_suggestion(self, release_id, condition):
release = self.d.release(release_id)
r = {
"M": release.price_suggestions.mint,
"NM": release.price_suggestions.near_mint,
"VG+": release.price_suggestions.very_good_plus,
"VG": release.price_suggestions.very_good,
"G+": release.price_suggestions.good_plus,
"G": release.price_suggestions.good,
"F": release.price_suggestions.fair,
if isinstance(release_id, Release):
r = release_id
else:
r = self.d.release(release_id)

c = {
"M": r.price_suggestions.mint,
"NM": r.price_suggestions.near_mint,
"VG+": r.price_suggestions.very_good_plus,
"VG": r.price_suggestions.very_good,
"G+": r.price_suggestions.good_plus,
"G": r.price_suggestions.good,
"F": r.price_suggestions.fair,
}
return r[condition.upper()] if r else None
return c[condition.upper()] if r else None

def fetch_relevant_price_suggestions(self, release_id):
release = self.d.release(release_id)
suggestions = {}
for cond in ["M", "NM", "VG+", "VG"]:
price = self.fetch_price_suggestion(release, cond)
suggestions[cond] = round(price.value, 2)
return suggestions

def list_for_sale( # pylint: disable=too-many-positional-arguments,too-many-arguments
self,
Expand Down
53 changes: 53 additions & 0 deletions discodos/view/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
from time import time
from tabulate import tabulate as tab
from rich import print # pylint: disable=redefined-builtin
from rich.table import Table as rich_table
from rich.markdown import Markdown

from discodos.utils import is_number, join_sep

Expand Down Expand Up @@ -680,6 +682,57 @@ def edit_ask_details(self, orig_data, edit_questions): # pylint: disable=R0912,
log.debug("CTRL: _edit_ask_details: answers dict: {}".format(answers))
return answers

def two_column_view(self, details_dict, translate_keys=None, as_is=False):
"""A Rich-formatted view of keys and values.
- by default simply capitalizes key names...
- ... or not (set as_is!)
- optionally alters key names via a passed translaton table
We use it for Marketplace stats and Marketplace listing details.
"""
# Create a rich Table with two columns.
table = rich_table(box=None)
table.add_column("Field", style="cyan", justify="right")
table.add_column("Value", style="white")
# Display an empty table instead of nothing.
if not details_dict:
return table

# Highlight/fix/replace some values first
values_replaced = {}
for key, value in details_dict.items():
if key in ["d_sales_release_url", "d_sales_url"]:
value = Markdown(f"[View in browser]({value})")
if key == "d_sales_allow_offers":
value = "Yes" if value in [1, True] else "No"
elif key == "status" and value == "Sold":
value = f"[magenta]{value}[/magenta]"
elif key == "d_sales_posted" and isinstance(value, datetime):
value = datetime.strftime(value, "%Y-%m-%d")
values_replaced[key] = value

# Prettify column captions
if as_is:
final_details = values_replaced
elif translate_keys:
final_details = {
translate_keys.get(k, k): v for k, v in values_replaced.items()
}
else: # Without a tranlation table, fall back to simply capitalizing
final_details = {
k.capitalize(): v for k, v in values_replaced.items()
}

# The final creation of the Rich table
for key, value in final_details.items():
if isinstance(value, Markdown):
table.add_row(f"[bold]{key}[/bold]", value)
continue
# Format key bold and value normal font (or as we manipulated it above)
table.add_row(f"[bold]{key}[/bold]", str(value))
return table

def view_tutorial(self):
tutorial_items = [
'\n\nFirst things first: Whenever DiscoDOS asks you a question, '
Expand Down

0 comments on commit fe3737f

Please sign in to comment.