CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
sagemathinc

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: sagemathinc/cocalc
Path: blob/master/src/scripts/sales_tax.py
Views: 687
1
#!/usr/bin/env python
2
3
# Prints a CoffeeScript map from zip codes to tax rates based on
4
# http://dor.wa.gov/Content/FindTaxesAndRates/RetailSalesTax/DestinationBased/ClientInterface.aspx
5
# only for the State of Washington.
6
# Output is large. Pipe into a file.
7
8
import urllib2
9
import re
10
import csv
11
12
13
def parse_tax_rate(text):
14
match = re.search("Rate=([0-][\.1][0-9]*)", text)
15
if match is not None:
16
return match.group(1)
17
else:
18
return None
19
20
21
def parse_result_code(text):
22
match = re.search("ResultCode=([0-9])", text)
23
if match is not None:
24
return match.group(1)
25
else:
26
return None
27
28
29
def get_tax_rate_of_zip(zip_code):
30
"""
31
This function returns the tax rate of a given zipcode (no +4 extension) in WA
32
33
Uses the interface described here
34
http://dor.wa.gov/Content/FindTaxesAndRates/RetailSalesTax/DestinationBased/ClientInterface.aspx
35
36
A result code will be returned for both XML and text response formats. The codes are defined as:
37
38
0: The address was found.
39
1: The address was not found, but the ZIP+4 was located.
40
2: Neither the address or ZIP+4 was found, but the 5-digit ZIP was located.
41
3: The address, ZIP+4, and ZIP could not be found.
42
4: Invalid arguments.
43
5: Internal error.
44
45
A tax rate of 9.7% is reported as a float .097
46
"""
47
URL = "http://dor.wa.gov/AddressRates.aspx?output=text&addr=&city=&zip={}".format(
48
zip_code)
49
response = urllib2.urlopen(URL)
50
text = response.read()
51
# Example responses:
52
# LocationCode=4000 Rate=0.086 ResultCode=2
53
# LocationCode=-1 Rate=-1 ResultCode=3 debughint=
54
tax_rate = parse_tax_rate(text)
55
result_code = parse_result_code(text)
56
57
if int(result_code) != 2:
58
return None
59
elif tax_rate < 0:
60
raise ValueError(
61
"Result code was 0 but tax rate was negative for zip code {}".
62
format(zip_code))
63
else:
64
return float(tax_rate)
65
66
67
## list of WA_zips retriven this way:
68
# import pandas as pd
69
# import json
70
# import requests
71
# url = 'https://www.unitedstateszipcodes.org/wa/'
72
# data = pd.read_html(requests.get(url, headers={'User-agent': 'Mozilla/5.0'}).text, attrs={"class":"table-striped"})
73
# x = data[1]
74
# y = x['ZIP Code'].as_matrix().tolist()
75
# json.dumps(y)
76
77
WA_zips = [
78
98001, 98002, 98003, 98004, 98005, 98006, 98007, 98008, 98009, 98010,
79
98011, 98012, 98013, 98014, 98015, 98019, 98020, 98021, 98022, 98023,
80
98024, 98025, 98026, 98027, 98028, 98029, 98030, 98031, 98032, 98033,
81
98034, 98035, 98036, 98037, 98038, 98039, 98040, 98041, 98042, 98043,
82
98045, 98046, 98047, 98050, 98051, 98052, 98053, 98054, 98055, 98056,
83
98057, 98058, 98059, 98061, 98062, 98063, 98064, 98065, 98068, 98070,
84
98071, 98072, 98073, 98074, 98075, 98077, 98082, 98083, 98087, 98089,
85
98092, 98093, 98101, 98102, 98103, 98104, 98105, 98106, 98107, 98108,
86
98109, 98110, 98111, 98112, 98113, 98114, 98115, 98116, 98117, 98118,
87
98119, 98121, 98122, 98124, 98125, 98126, 98127, 98129, 98131, 98132,
88
98133, 98134, 98136, 98138, 98139, 98141, 98144, 98145, 98146, 98148,
89
98151, 98154, 98155, 98158, 98160, 98161, 98164, 98165, 98166, 98168,
90
98170, 98171, 98174, 98175, 98177, 98178, 98181, 98184, 98185, 98188,
91
98189, 98190, 98191, 98194, 98195, 98198, 98199, 98201, 98203, 98204,
92
98205, 98206, 98207, 98208, 98213, 98220, 98221, 98222, 98223, 98224,
93
98225, 98226, 98227, 98228, 98229, 98230, 98231, 98232, 98233, 98235,
94
98236, 98237, 98238, 98239, 98240, 98241, 98243, 98244, 98245, 98247,
95
98248, 98249, 98250, 98251, 98252, 98253, 98255, 98256, 98257, 98258,
96
98259, 98260, 98261, 98262, 98263, 98264, 98266, 98267, 98270, 98271,
97
98272, 98273, 98274, 98275, 98276, 98277, 98278, 98279, 98280, 98281,
98
98282, 98283, 98284, 98286, 98287, 98288, 98290, 98291, 98292, 98293,
99
98294, 98295, 98296, 98297, 98303, 98304, 98305, 98310, 98311, 98312,
100
98314, 98315, 98320, 98321, 98322, 98323, 98324, 98325, 98326, 98327,
101
98328, 98329, 98330, 98331, 98332, 98333, 98335, 98336, 98337, 98338,
102
98339, 98340, 98342, 98343, 98344, 98345, 98346, 98348, 98349, 98350,
103
98351, 98352, 98353, 98354, 98355, 98356, 98357, 98358, 98359, 98360,
104
98361, 98362, 98363, 98364, 98365, 98366, 98367, 98368, 98370, 98371,
105
98372, 98373, 98374, 98375, 98376, 98377, 98378, 98380, 98381, 98382,
106
98383, 98384, 98385, 98386, 98387, 98388, 98390, 98391, 98392, 98393,
107
98394, 98395, 98396, 98397, 98398, 98401, 98402, 98403, 98404, 98405,
108
98406, 98407, 98408, 98409, 98411, 98412, 98413, 98415, 98416, 98417,
109
98418, 98419, 98421, 98422, 98424, 98430, 98431, 98433, 98438, 98439,
110
98442, 98443, 98444, 98445, 98446, 98447, 98448, 98450, 98455, 98460,
111
98464, 98465, 98466, 98467, 98471, 98477, 98481, 98490, 98492, 98493,
112
98496, 98497, 98498, 98499, 98501, 98502, 98503, 98504, 98505, 98506,
113
98507, 98508, 98509, 98511, 98512, 98513, 98516, 98520, 98522, 98524,
114
98526, 98527, 98528, 98530, 98531, 98532, 98533, 98535, 98536, 98537,
115
98538, 98539, 98540, 98541, 98542, 98544, 98546, 98547, 98548, 98550,
116
98552, 98554, 98555, 98556, 98557, 98558, 98559, 98560, 98561, 98562,
117
98563, 98564, 98565, 98566, 98568, 98569, 98570, 98571, 98572, 98575,
118
98576, 98577, 98579, 98580, 98581, 98582, 98583, 98584, 98585, 98586,
119
98587, 98588, 98589, 98590, 98591, 98592, 98593, 98595, 98596, 98597,
120
98599, 98601, 98602, 98603, 98604, 98605, 98606, 98607, 98609, 98610,
121
98611, 98612, 98613, 98614, 98616, 98617, 98619, 98620, 98621, 98622,
122
98623, 98624, 98625, 98626, 98628, 98629, 98631, 98632, 98635, 98637,
123
98638, 98639, 98640, 98641, 98642, 98643, 98644, 98645, 98647, 98648,
124
98649, 98650, 98651, 98660, 98661, 98662, 98663, 98664, 98665, 98666,
125
98667, 98668, 98670, 98671, 98672, 98673, 98674, 98675, 98682, 98683,
126
98684, 98685, 98686, 98687, 98801, 98802, 98807, 98811, 98812, 98813,
127
98814, 98815, 98816, 98817, 98819, 98821, 98822, 98823, 98824, 98826,
128
98827, 98828, 98829, 98830, 98831, 98832, 98833, 98834, 98836, 98837,
129
98840, 98841, 98843, 98844, 98845, 98846, 98847, 98848, 98849, 98850,
130
98851, 98852, 98853, 98855, 98856, 98857, 98858, 98859, 98860, 98862,
131
98901, 98902, 98903, 98904, 98907, 98908, 98909, 98920, 98921, 98922,
132
98923, 98925, 98926, 98929, 98930, 98932, 98933, 98934, 98935, 98936,
133
98937, 98938, 98939, 98940, 98941, 98942, 98943, 98944, 98946, 98947,
134
98948, 98950, 98951, 98952, 98953, 99001, 99003, 99004, 99005, 99006,
135
99008, 99009, 99011, 99012, 99013, 99014, 99016, 99017, 99018, 99019,
136
99020, 99021, 99022, 99023, 99025, 99026, 99027, 99029, 99030, 99031,
137
99032, 99033, 99034, 99036, 99037, 99039, 99040, 99101, 99102, 99103,
138
99104, 99105, 99107, 99109, 99110, 99111, 99113, 99114, 99115, 99116,
139
99117, 99118, 99119, 99121, 99122, 99123, 99124, 99125, 99126, 99128,
140
99129, 99130, 99131, 99133, 99134, 99135, 99136, 99137, 99138, 99139,
141
99140, 99141, 99143, 99144, 99146, 99147, 99148, 99149, 99150, 99151,
142
99152, 99153, 99154, 99155, 99156, 99157, 99158, 99159, 99160, 99161,
143
99163, 99164, 99165, 99166, 99167, 99169, 99170, 99171, 99173, 99174,
144
99176, 99179, 99180, 99181, 99185, 99201, 99202, 99203, 99204, 99205,
145
99206, 99207, 99208, 99209, 99210, 99211, 99212, 99213, 99214, 99215,
146
99216, 99217, 99218, 99219, 99220, 99223, 99224, 99228, 99251, 99252,
147
99256, 99258, 99260, 99299, 99301, 99302, 99320, 99321, 99322, 99323,
148
99324, 99326, 99328, 99329, 99330, 99333, 99335, 99336, 99337, 99338,
149
99341, 99343, 99344, 99345, 99346, 99347, 99348, 99349, 99350, 99352,
150
99353, 99354, 99356, 99357, 99359, 99360, 99361, 99362, 99363, 99371,
151
99401, 99402, 99403
152
]
153
154
taxes_per_zip = []
155
closest_rate = 0.065
156
for zip_code in WA_zips:
157
tax_rate = get_tax_rate_of_zip(zip_code)
158
if tax_rate is None:
159
tax_rate = closest_rate
160
if tax_rate is not None:
161
taxes_per_zip.append("{}:{:.6f}".format(zip_code, tax_rate))
162
closest_rate = tax_rate
163
164
print("WA_sales_tax = {%s}" % (', '.join(taxes_per_zip[0:])))
165
166