Skip to content

Commit

Permalink
Introduce new subsidiary 'Apple Services Pte. Ltd.'
Browse files Browse the repository at this point in the history
  • Loading branch information
fedoco committed Sep 27, 2024
1 parent e9f469e commit 2bb696a
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 48 deletions.
57 changes: 33 additions & 24 deletions apple.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,30 @@
# VAT ID of Apple's EU subsidiary
vat_id_europe = 'IE9700053D'

# List of countries handled by Apple Inc. and each of Apple's (currently five) foreign subsidiaries.
# Information is taken from Schedule 2, Exhibit A of Apple's "iOS / macOS Paid Applications" contract as effective of August, 2023.
# List of countries handled by Apple Inc. and each of Apple's (currently six) foreign subsidiaries.
# Information is taken from Schedule 2, Exhibit A of Apple's "iOS / macOS Paid Applications" contract as effective of October 26, 2024.

apac = {
'BT': 'Bhutan',
'BN': 'Brunei',
'KH': 'Cambodia',
'FM': 'Federal States of Micronesia',
'FJ': 'Fiji',
'KR': 'Korea',
'LA': 'Laos',
'MO': 'Macao',
'MV': 'Maldives',
'MN': 'Mongolia',
'MM': 'Myanmar',
'NR': 'Nauru',
'NP': 'Nepal',
'PW': 'Palau',
'PG': 'Papua New Guinea',
'SB': 'Solomon Islands',
'LK': 'Sri Lanka',
'TO': 'Tonga',
'VU': 'Vanuatu'
}

australia = {
'AU': 'Australia',
Expand All @@ -49,13 +71,10 @@
'BY': 'Belarus',
'BE': 'Belgium',
'BJ': 'Benin',
'BT': 'Bhutan',
'BA': 'Bosnia and Herzegovina',
'BW': 'Botswana',
'BN': 'Brunei',
'BG': 'Bulgaria',
'BF': 'Burkina-Faso',
'KH': 'Cambodia',
'CM': 'Cameroon',
'CV': 'Cape Verde',
'TD': 'Chad',
Expand All @@ -69,7 +88,6 @@
'DK': 'Denmark',
'EG': 'Egypt',
'EE': 'Estonia',
'FJ': 'Fiji',
'FI': 'Finland',
'FR': 'France',
'GA': 'Gabon',
Expand All @@ -91,45 +109,34 @@
'JO': 'Jordan',
'KZ': 'Kazakhstan',
'KE': 'Kenya',
'KR': 'Korea',
'XK': 'Kosovo',
'KW': 'Kuwait',
'KG': 'Kyrgyzstan',
'LA': 'Laos',
'LV': 'Latvia',
'LB': 'Lebanon',
'LR': 'Liberia',
'LY': 'Libya',
'LT': 'Lithuania',
'LU': 'Luxembourg',
'MO': 'Macao',
'MK': 'Macedonia',
'MG': 'Madagascar',
'MW': 'Malawi',
'MY': 'Malaysia',
'MV': 'Maldives',
'ML': 'Mali',
'MT': 'Republic of Malta',
'MR': 'Mauritania',
'MU': 'Mauritius',
'FM': 'Federal States of Micronesia',
'MD': 'Moldova',
'MN': 'Mongolia',
'ME': 'Montenegro',
'MA': 'Morocco',
'MZ': 'Mozambique',
'MM': 'Myanmar',
'NA': 'Namibia',
'NR': 'Nauru',
'NP': 'Nepal',
'NL': 'Netherlands',
'NE': 'Niger',
'NG': 'Nigeria',
'NO': 'Norway',
'OM': 'Oman',
'PK': 'Pakistan',
'PW': 'Palau',
'PG': 'Papua New Guinea',
'PH': 'Philippines',
'PL': 'Poland',
'PT': 'Portugal',
Expand All @@ -146,18 +153,15 @@
'SG': 'Singapore',
'SK': 'Slovakia',
'SI': 'Slovenia',
'SB': 'Solomon Islands',
'ZA': 'South Africa',
'ES': 'Spain',
'LK': 'Sri Lanka',
'SZ': 'Swaziland',
'SE': 'Sweden',
'CH': 'Switzerland',
'TW': 'Taiwan',
'TJ': 'Tajikistan',
'TZ': 'Tanzania',
'TH': 'Thailand',
'TO': 'Tonga',
'TN': 'Tunisia',
'TR': 'Türkiye',
'TM': 'Turkmenistan',
Expand All @@ -166,7 +170,6 @@
'UA': 'Ukraine',
'GB': 'United Kingdom',
'UZ': 'Uzbekistan',
'VU': 'Vanuatu',
'VN': 'Vietnam',
'YE': 'Yemen',
'ZM': 'Zambia',
Expand Down Expand Up @@ -221,10 +224,11 @@
'US': 'United States'
}

corporations = [australia, canada, europe, japan, latam, us]
corporations = [apac, australia, canada, europe, japan, latam, us]

def corporation(cc):
"""Get Apple subsidiary handling sales of the given country"""
if cc in apac: return 'AP'
if cc in australia: return 'AU'
if cc in canada: return 'CA'
if cc in europe: return 'EU'
Expand All @@ -242,11 +246,16 @@ def countryname(cc):

def address(corporation):
"""Get billing address of Apple subsidiary with given handle"""
if corporation == 'AU':
if corporation == 'AP':
return """Apple Services Pte. Ltd.
7 Ang Mo Kio Street 64
Singapore 569086
Singapore"""
elif corporation == 'AU':
return """Apple Pty Limited
Level 3
20 Martin Place
Sydney South 2000
Sydney NSW 2000
Australia"""
elif corporation == 'CA':
return """Apple Canada Inc.
Expand Down
49 changes: 25 additions & 24 deletions slicer.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,17 @@

# -------------------------------------------------------------------------------------------------------------------------------------

# US dollars may occur multiple times in financial_report.csv due to different exchange rates for each world region they're
# used in: Care must be taken to distinguish between USD for purchases made in the region "Americas" (the default), or in
# regions "South Asia and Pacific", "Latin America and the Caribbean" and "Rest of World", as Apple calls it.
# Unfortunately, Apple decided to localize these strings, so they need to be looked up in the following spelling table.
# Luckily, localized report files currently seem to be generated only for French, German, Italian and Spanish locale settings.
usd_regions_localizations = {
'AP': ['Pacif', 'Pacíf', 'Pazif'], # South Asia and Pacific
'LL': ['Latin', 'Latein'], # Latin America and the Caribbean
'WW': ['of World', 'du monde', 'der Welt', 'del mondo', 'del mundo'] # Rest of World
}

def format_date(date_str):
"""Formats an US-style date string according to the default format of the current locale."""
return datetime.strptime(date_str,"%m/%d/%Y").strftime('%x')
Expand Down Expand Up @@ -131,21 +142,13 @@ def parse_currency_data(filename):
sys.exit(1)
currency = r.group(1)

# USD can occur thrice in the file: We must take special care to distinguish between USD (and their corresponding exchange
# rate) for purchases made in "Americas", "Latin America and the Caribbean" and in "Rest of World", as Apple calls it.
# Unfortunately, Apple decided to localize the aforementioned strings so they need to be looked up in a translation table.
# Luckily, localized report files currently seem to be generated only for French, German, Italian and Spanish locale settings.
localizations_LATAM = ["Latein", "Latin"]
localizations_RoW = ["of World", "du monde", "der Welt", "del mondo", "del mundo"]
# for any region of the world in which Apple bills in USD, a distinct exchange rate may have been used
if currency == 'USD':
for localization in localizations_LATAM:
if localization.lower() in fields[0].lower():
currency = 'USD - LATAM'

for localization in localizations_RoW:
if localization.lower() in fields[0].lower():
currency = 'USD - RoW'

for region, localized_region_spellings in usd_regions_localizations.items():
if any(spelling.lower() in fields[0].lower() for spelling in localized_region_spellings):
currency = 'USD' + region # should serve as a unique key for the current region's USD variety
break

amount_pre_tax = Decimal(fields[column_index_amount_pre_tax].replace(',', ''))
amount_after_tax = Decimal(fields[column_index_amount_after_tax].replace(',', ''))
earnings = Decimal(fields[column_index_earnings].replace(',', ''))
Expand Down Expand Up @@ -210,15 +213,13 @@ def parse_financial_reports(workingdir):
# remember currency of current line's country
currencies[countrycode] = currency

# special case affecting countries Apple put in the "Rest of World" group: currency for those is listed as "USD"
# in the sales reports but the corresponding exchange rate is keyed "USD - RoW" - a pragmatic way of identifying
# those "RoW" countries is to inspect the filename of the sales report
if "_WW." in filename and currency == "USD":
currencies[countrycode] = "USD - RoW"

# same for the "Latin America and the Caribbean" group
if "_LL." in filename and currency == "USD":
currencies[countrycode] = "USD - LATAM"
# if the current country uses USD, identify which world region's USD exchange rate
# applies – a pragmatic way to do this is to inspect the filename of its sales report
if currency == 'USD':
for region in usd_regions_localizations.keys():
if f'_{region}.' in filename:
currencies[countrycode] = 'USD' + region
break

f.close()

Expand Down Expand Up @@ -350,7 +351,7 @@ def steuerapp_esl_import(eu_sales_amount, date_range):
if __name__ == '__main__':
parser = argparse.ArgumentParser(description='Tool for splitting App Store Connect financial reports by Apple legal entities')

parser.add_argument('-l', choices=['AU', 'CA', 'EU', 'JP', 'LL', 'US'], nargs='+', dest='selected_corporations', help='limit output to sales of the specified Apple legal entities (Australia, Canada, Europe, Japan, Latin America, United States)')
parser.add_argument('-l', choices=['AP', 'AU', 'CA', 'EU', 'JP', 'LL', 'US'], nargs='+', dest='selected_corporations', help='limit output to sales of the specified Apple legal entities (South Asia and Pacific, Australia, Canada, Europe, Japan, Latin America, United States)')
subtotals_group = parser.add_mutually_exclusive_group(required=False)
subtotals_group.add_argument('--no-subtotals', action='store_true', help='omit printing of subtotal for each country')
subtotals_group.add_argument('--only-subtotals', action='store_true', help='only print subtotal for each country (i.e. skip per-product Euro conversion)')
Expand Down

0 comments on commit 2bb696a

Please sign in to comment.