Skip to content

Commit c163890

Browse files
Merge pull request #313 from RemainingDelta/201-Feature
201-Feature add transcript generation to redemption ticket close flow
2 parents 53f6ca2 + 450409a commit c163890

2 files changed

Lines changed: 113 additions & 4 deletions

File tree

features/config.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
REDEMPTION_TICKET_CATEGORY_ID = 1481456156080738346
3939
BOTS_CATEGORY_ID = 767612682357964810
4040
SUPPORT_TRANSCRIPT_LOG_CHANNEL_ID = 1481117793222004746
41+
REDEMPTION_TRANSCRIPT_CHANNEL_ID = 1515605936801316874
4142
SUPPORT_STAFF_APPS_INFO_CHANNEL_ID = 1261020578790248459
4243

4344
LOG_CHANNEL_ID = 1442374964144640090
@@ -217,6 +218,7 @@
217218
REDEMPTION_TICKET_CATEGORY_ID = 1481455542236086293
218219
BOTS_CATEGORY_ID = 1506812222704451677
219220
SUPPORT_TRANSCRIPT_LOG_CHANNEL_ID = 1480735066924781711
221+
REDEMPTION_TRANSCRIPT_CHANNEL_ID = 1515606218654220288
220222
SUPPORT_STAFF_APPS_INFO_CHANNEL_ID = 1481083131342618754
221223

222224
LOG_CHANNEL_ID = 1442227896302174298

features/economy.py

Lines changed: 111 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import io
12
import time
23
import discord
34
from discord import app_commands
@@ -33,6 +34,7 @@
3334
SHOP_DATA,
3435
MODERATOR_ROLE_ID,
3536
REDEMPTION_TICKET_CATEGORY_ID,
37+
REDEMPTION_TRANSCRIPT_CHANNEL_ID,
3638
TRIAL_MODERATOR_ROLE_ID,
3739
PASSIVE_REWARD_EXCLUDED_CHANNEL_IDS,
3840
)
@@ -247,6 +249,81 @@ async def handle_redemption_delete_attempt(ctx: commands.Context) -> None:
247249
)
248250

249251

252+
async def _build_redemption_transcript_text(
253+
channel: discord.TextChannel,
254+
item: str,
255+
token_cost: int,
256+
balance_before: int,
257+
balance_after: int,
258+
) -> str:
259+
opener_raw = _extract_topic_value(channel.topic, "redemption-opener")
260+
lines: list[str] = [
261+
f"Channel: {channel.name}",
262+
f"Opener ID: {opener_raw or 'Unknown'}",
263+
f"Item: {item}",
264+
f"Token Cost: {token_cost}",
265+
f"Balance Before: {balance_before}",
266+
f"Balance After: {balance_after}",
267+
"",
268+
]
269+
async for msg in channel.history(limit=None, oldest_first=True):
270+
ts = msg.created_at.strftime("%Y-%m-%d %H:%M")
271+
author = f"{msg.author} ({msg.author.id})"
272+
content = msg.content or ""
273+
if msg.attachments:
274+
attachment_list = ", ".join(a.url for a in msg.attachments)
275+
if content:
276+
content += " "
277+
content += f"[Attachments: {attachment_list}]"
278+
lines.append(f"[{ts}] {author}: {content}")
279+
if len(lines) <= 7:
280+
lines.append("No messages in this ticket.")
281+
return "\n".join(lines)
282+
283+
284+
async def _save_redemption_transcript(
285+
channel: discord.TextChannel,
286+
actor: discord.Member,
287+
item: str,
288+
token_cost: int,
289+
balance_before: int,
290+
balance_after: int,
291+
outcome: str,
292+
) -> None:
293+
transcript_text = await _build_redemption_transcript_text(
294+
channel, item, token_cost, balance_before, balance_after
295+
)
296+
transcript_bytes = transcript_text.encode("utf-8")
297+
filename = f"{channel.name}_transcript.txt"
298+
299+
opener_raw = _extract_topic_value(channel.topic, "redemption-opener")
300+
opener_display = f"<@{opener_raw}>" if opener_raw else "unknown"
301+
item_display = SHOP_DATA.get(item, {}).get("display", item).replace("**", "")
302+
303+
if outcome == "refunded":
304+
balance_original = balance_before + token_cost
305+
outcome_line = f"🔄 **Refunded** | **Balance:** {balance_original:,}{balance_before:,}{balance_after:,} R7 tokens"
306+
else:
307+
outcome_line = f"✅ **Fulfilled** | **Balance:** {balance_before:,}{balance_after:,} R7 tokens"
308+
309+
log_channel = (
310+
channel.guild.get_channel(REDEMPTION_TRANSCRIPT_CHANNEL_ID)
311+
if isinstance(REDEMPTION_TRANSCRIPT_CHANNEL_ID, int)
312+
else None
313+
)
314+
if isinstance(log_channel, discord.TextChannel):
315+
log_file = discord.File(io.BytesIO(transcript_bytes), filename=filename)
316+
await log_channel.send(
317+
content=(
318+
f"📝 Transcript for redemption ticket **#{channel.name}** "
319+
f"deleted by **{actor.name}** (opener: {opener_display}).\n"
320+
f"**Item:** {item_display} | **Cost:** {token_cost:,} R7 tokens\n"
321+
f"{outcome_line}"
322+
),
323+
file=log_file,
324+
)
325+
326+
250327
class RedemptionClosedOptionsView(discord.ui.View):
251328
def __init__(self):
252329
super().__init__(timeout=None)
@@ -314,13 +391,26 @@ async def refund_delete_button(
314391
opener_raw = _extract_topic_value(
315392
interaction.channel.topic, "redemption-opener"
316393
)
317-
item = _extract_topic_value(interaction.channel.topic, "item")
394+
item = _extract_topic_value(interaction.channel.topic, "item") or ""
395+
token_cost = _token_price_for_item(item) if item else 0
396+
balance_before = 0
397+
balance_after = 0
318398
if opener_raw and opener_raw.isdigit() and item:
319399
refund_amount = _token_price_for_item(item)
320400
if refund_amount > 0:
321-
current_balance = await get_user_balance(opener_raw)
322-
await update_user_balance(opener_raw, current_balance + refund_amount)
323-
401+
balance_before = await get_user_balance(opener_raw)
402+
balance_after = balance_before + refund_amount
403+
await update_user_balance(opener_raw, balance_after)
404+
405+
await _save_redemption_transcript(
406+
interaction.channel,
407+
interaction.user,
408+
item,
409+
token_cost,
410+
balance_before,
411+
balance_after,
412+
outcome="refunded",
413+
)
324414
await interaction.channel.delete(
325415
reason=f"Redemption ticket refunded and deleted by {interaction.user}"
326416
)
@@ -365,6 +455,23 @@ async def budget_delete_button(
365455
except ValueError:
366456
cost = _budget_cost_for_item(item)
367457

458+
opener_raw = _extract_topic_value(
459+
interaction.channel.topic, "redemption-opener"
460+
)
461+
token_cost = _token_price_for_item(item) if item else 0
462+
current_balance = 0
463+
if opener_raw and opener_raw.isdigit():
464+
current_balance = await get_user_balance(opener_raw)
465+
466+
await _save_redemption_transcript(
467+
interaction.channel,
468+
interaction.user,
469+
item,
470+
token_cost,
471+
current_balance + token_cost,
472+
current_balance,
473+
outcome="fulfilled",
474+
)
368475
await add_budget_spent(cost)
369476
await interaction.channel.delete(
370477
reason=f"Redemption fulfilled and deleted by {interaction.user}"

0 commit comments

Comments
 (0)