Skip to main content

total-fees-calculation

Skill for computing total payment processing fees for a merchant over a specific day, date range, or month in the dabstep dataset. Use this skill whenever the question asks for "total fees", "fees paid", or "fees charged" for a merchant over some time period. The computation requires matching each transaction to a fee rule from fees.json using multiple merchant and transaction properties, then summing fixed_amount + rate * eur_amount / 10000 for each matched transaction.

Source facts

Repository
zjunlp/DataMind
Last source activity
July 5, 2026 at 09:13
Detected SKILL.md language
English
Stars
149
Forks
13

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
Total_Fees_Calculation
description
Skill for computing total payment processing fees for a merchant over a specific day, date range, or month in the dabstep dataset. Use this skill whenever the question asks for "total fees", "fees paid", or "fees charged" for a merchant over some time period. The computation requires matching each transaction to a fee rule from fees.json using multiple merchant and transaction properties, then summing fixed_amount + rate * eur_amount / 10000 for each matched transaction.
# Total Fees Calculation — dabstep Dataset ## Problem Summary Compute total payment processing fees (in euros) for a given merchant over a specified period (a specific day of year, a month, or a full year). Round the final answer to 2 decimal places. ## Data Files Required - `payments.csv` — transactions (filter by `merchant`, `year`, `day_of_year`) - `fees.json` — 1000 fee rules with conditions and fee parameters - `merchant_data.json` — per-merchant properties: `account_type`, `capture_delay`, `merchant_category_code` - `manual.md` — read for domain definitions ## Fee Formula ``` fee = fixed_amount + rate * eur_amount / 10000 ``` Sum fees across all transactions that match a fee rule. Transactions with no matching rule contribute 0. --- ## CRITICAL: Output Immediately After computing `total_fees`, **print `round(total_fees, 2)` and use it as your final answer immediately**. Do NOT continue debugging why some transactions are unmatched. **It is completely normal and expected for 50–80% of transactions to have no matching fee rule.** This is a property of the fee rule system, not a bug. Common reasons: - ACI='G' (Card Not Present - Non-3-D Secure) appears in payments but is absent from all fee rule ACI lists — it can only match rules where `aci: []` - Specific combinations of card_scheme + capture_delay + fraud_level + volume + account_type have no corresponding rule - These transactions legitimately contribute 0 to the total Do not waste turns investigating individual unmatched transactions. Trust the algorithm and output the answer. --- ## Step-by-Step Algorithm ### Step 1: Load Merchant Properties From `merchant_data.json`, for the target merchant extract: - `account_type`: one of `R`, `D`, `H`, `F`, `S`, `O` - `capture_delay`: raw value (numeric like `"1"` or `"7"`, or categorical like `"immediate"`, `"manual"`) - `merchant_category_code` (MCC): integer **Map numeric `capture_delay` to fee rule category:** ```python def map_capture_delay(cd): try: n = int(cd) return '<3' if n < 3 else ('3-5' if n <= 5 else '>5') except (ValueError, TypeError): return cd # already a string category ``` ### Step 2: Determine the Query Period and Month Boundaries **2023 is NOT a leap year.** Day-of-year to month mapping: | Month | day_of_year range | |-------|-------------------| | Jan | 1 – 31 | | Feb | 32 – 59 | | Mar | 60 – 90 | | Apr | 91 – 120 | | May | 121 – 151| | Jun | 152 – 181| | Jul | 182 – 212| | Aug | 213 – 243| | Sep | 244 – 273| | Oct | 274 – 304| | Nov | 305 – 334| | Dec | 335 – 365| - "Nth day of the year" → `day_of_year == N`; its month is determined by the table above. - "Month X 2023" → use the full month range for TARGET_DAYS and for monthly stats. - "Full year 2023" → process each month separately (monthly stats differ per month). ### Step 3: Compute Monthly Statistics (Full Natural Month) Monthly stats must be computed from **ALL transactions in the full natural month** (not just the queried day). This is critical for fee rule matching. ```python MONTH_RANGES = { 1:(1,31), 2:(32,59), 3:(60,90), 4:(91,120), 5:(121,151), 6:(152,181), 7:(182,212), 8:(213,243), 9:(244,273), 10:(274,304), 11:(305,334), 12:(335,365) } month_txns = payments[ (payments['merchant'] == MERCHANT) & (payments['year'] == YEAR) & (payments['day_of_year'].between(MONTH_START, MONTH_END)) ] monthly_vol = month_txns['eur_amount'].sum() fraud_vol = month_txns[month_txns['has_fraudulent_dispute'] == True]['eur_amount'].sum() fraud_rate = fraud_vol / monthly_vol if monthly_vol > 0 else 0 ``` **Categorize into fee rule buckets:** ```python def categorize_volume(v): if v < 100_000: return '<100k' elif v < 1_000_000: return '100k-1m' elif v < 5_000_000: return '1m-5m' else: return '>5m' def categorize_fraud(f): if f < 0.072: return '<7.2%' elif f < 0.077: return '7.2%-7.7%' elif f < 0.083: return '7.7%-8.3%' else: return '>8.3%' ``` ### Step 4: Match Each Transaction to a Fee Rule **The single most important rule: empty list `[]` in any fee rule field means "applies to all" (same semantics as `null`).** In `fees.json`: `account_type: []`, `merchant_category_code: []`, `aci: []` all mean "no restriction on this field". ```python def rule_specificity(rule): return sum([ bool(rule['account_type']), rule['capture_delay'] is not None, rule['monthly_fraud_level'] is not None, rule['monthly_volume'] is not None, bool(rule['merchant_category_code']), rule['is_credit'] is not None, bool(rule['aci']), rule['intracountry'] is not None, ]) def find_best_rule(txn, acct_type, cap_delay, mcc, fraud_level, vol_category): intracountry = (txn['issuing_country'] == txn['acquirer_country']) matches = [] for rule in fees: if rule['card_scheme'] != txn['card_scheme']: continue if rule['account_type'] and acct_type not in rule['account_type']: continue if rule['capture_delay'] is not None and rule['capture_delay'] != cap_delay: continue if rule['monthly_fraud_level'] is not None and rule['monthly_fraud_level'] != fraud_level: continue if rule['monthly_volume'] is not None and rule['monthly_volume'] != vol_category: continue if rule['merchant_category_code'] and mcc not in rule['merchant_category_code']: continue if rule['is_credit'] is not None and rule['is_credit'] != bool(txn['is_credit']): continue if rule['aci'] and txn['aci'] not in rule['aci']: continue if rule['intracountry'] is not None and bool(rule['intracountry']) != intracountry: continue matches.append(rule) if not matches: return None return sorted(matches, key=lambda r: (-rule_specificity(r), r['ID']))[0] ``` ### Step 5: Sum All Transaction Fees and Output Answer ```python total_fees = 0.0 for _, txn in target_transactions.iterrows(): rule = find_best_rule(txn, acct_type, cap_delay, mcc, fraud_level, vol_category) if rule: total_fees += rule['fixed_amount'] + rule['rate'] * txn['eur_amount'] / 10000 print(round(total_fees, 2)) # Use the printed value as your final answer — do not investigate further ``` --- ## Complete Python Template (Single Day or Month) ```python import json import pandas as pd payments = pd.read_csv('<path>/payments.csv') with open('<path>/fees.json') as f: fees = json.load(f) with open('<path>/merchant_data.json') as f: merchant_data = json.load(f) MERCHANT = '<merchant_name>' YEAR = 2023 # Date range for the QUERY (e.g., single day: [10]; full month: list(range(60, 91)) for March) TARGET_DAYS = [<day_of_year>] # Date range of the full natural MONTH containing the target (for monthly stats): MONTH_START, MONTH_END = <start>, <end> # e.g., 1, 31 for January; 335, 365 for December MONTH_RANGES = { 1:(1,31), 2:(32,59), 3:(60,90), 4:(91,120), 5:(121,151), 6:(152,181), 7:(182,212), 8:(213,243), 9:(244,273), 10:(274,304), 11:(305,334), 12:(335,365) } def map_capture_delay(cd): try: n = int(cd) return '<3' if n < 3 else ('3-5' if n <= 5 else '>5') except (ValueError, TypeError): return cd def categorize_volume(v): if v < 100_000: return '<100k' elif v < 1_000_000: return '100k-1m' elif v < 5_000_000: return '1m-5m' else: return '>5m' def categorize_fraud(f): if f < 0.072: return '<7.2%' elif f < 0.077: return '7.2%-7.7%' elif f < 0.083: return '7.7%-8.3%' else: return '>8.3%' def rule_specificity(rule): return sum([bool(rule['account_type']), rule['capture_delay'] is not None, rule['monthly_fraud_level'] is not None, rule['monthly_volume'] is not None, bool(rule['merchant_category_code']), rule['is_credit'] is not None, bool(rule['aci']), rule['intracountry'] is not None]) def find_best_rule(txn, acct_type, cap_delay, mcc, fraud_level, vol_category): intracountry = (txn['issuing_country'] == txn['acquirer_country']) matches = [] for rule in fees: if rule['card_scheme'] != txn['card_scheme']: continue if rule['account_type'] and acct_type not in rule['account_type']: continue if rule['capture_delay'] is not None and rule['capture_delay'] != cap_delay: continue if rule['monthly_fraud_level'] is not None and rule['monthly_fraud_level'] != fraud_level: continue if rule['monthly_volume'] is not None and rule['monthly_volume'] != vol_category: continue if rule['merchant_category_code'] and mcc not in rule['merchant_category_code']: continue if rule['is_credit'] is not None and rule['is_credit'] != bool(txn['is_credit']): continue if rule['aci'] and txn['aci'] not in rule['aci']: continue if rule['intracountry'] is not None and bool(rule['intracountry']) != intracountry: continue matches.append(rule) if not matches: return None return sorted(matches, key=lambda r: (-rule_specificity(r), r['ID']))[0] # Merchant properties merchant = next(m for m in merchant_data if m['merchant'] == MERCHANT) acct_type = merchant['account_type'] cap_delay = map_capture_delay(merchant['capture_delay']) mcc = merchant['merchant_category_code'] # Monthly stats (full natural month) month_txns = payments[ (payments['merchant'] == MERCHANT) & (payments['year'] == YEAR) & (payments['day_of_year'].between(MONTH_START, MONTH_END)) ] monthly_vol = month_txns['eur_amount'].sum() fraud_vol = month_txns[month_txns['has_fraudulent_dispute'] == True]['eur_amount'].sum() fraud_rate = fraud_vol / monthly_vol if monthly_vol > 0 else 0 fraud_level = categorize_fraud(fraud_rate) vol_category = categorize_volume(monthly_vol) # Target transactions and fee computation target_txns = payments[ (payments['merchant'] == MERCHANT) & (payments['year'] == YEAR) & (payments['day_of_year'].isin(TARGET_DAYS)) ] total_fees = 0.0 for _, txn in target_txns.iterrows(): rule = find_best_rule(txn, acct_type, cap_delay, mcc, fraud_level, vol_category) if rule: total_fees += rule['fixed_amount'] + rule['rate'] * txn['eur_amount'] / 10000 print(round(total_fees, 2)) ``` ## Full Year Variation For a full year query, monthly stats differ per month. Precompute them and apply per-transaction: ```python # Precompute monthly stats for all 12 months monthly_stats = {} for month, (ms, me) in MONTH_RANGES.items(): mt = payments[(payments['merchant']==MERCHANT) & (payments['year']==YEAR) & (payments['day_of_year'].between(ms, me))] mv = mt['eur_amount'].sum()
View on GitHub
This SKILL.md is very large, so SkillsMP previews the first section here. View on GitHub