Skip to content

Commit 9f6dc86

Browse files
committed
filing progress
1 parent 7cd70c9 commit 9f6dc86

File tree

25 files changed

+368
-269
lines changed

25 files changed

+368
-269
lines changed

backend/routers/filing.py

Lines changed: 52 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -39,68 +39,73 @@ class HTTPError(BaseModel):
3939
@router.get(
4040
"/query",
4141
tags=["filing"],
42-
status_code=201,
42+
status_code=200,
4343
)
44-
async def query_filer(
44+
async def query_filing(
4545
cik: str, access_number: str, background: BackgroundTasks = BackgroundTasks
4646
):
4747
filing = database.find_filing(cik, access_number, {"_id": 1})
48+
4849
if not filing:
49-
try:
50-
sec_data = sec_filer_search(cik)
51-
except Exception as e:
52-
logging.error(e)
53-
raise HTTPException(404, detail="CIK not found.")
50+
51+
update, last_report = web.check_new(cik)
52+
company = database.find_filer(cik)
53+
54+
if not update:
55+
return update_filing(company, last_report, background)
56+
57+
if not company:
58+
raise HTTPException(404, detail="Filer not found.")
59+
60+
filings = database.find_filings(cik, {"access_number": 1})
61+
access_numbers = [filing["access_number"] for filing in filings]
62+
63+
if access_number not in access_numbers:
64+
raise HTTPException(404, detail="Filing not found. Invalid access number.")
5465

5566
if production_environment:
56-
worker.create_filer.delay(cik, sec_data)
67+
worker.repair_filer.delay(cik)
5768
else:
58-
background.add_task(filer.create_filer, cik, sec_data)
69+
background.add_task(filer.repair_filer, cik)
5970

60-
return {"status": "Filing creation started."}
61-
else:
71+
raise HTTPException(201, detail="Filing found but not queried. Repair started.")
6272

63-
if filing["form"] not in database.holding_forms:
64-
raise HTTPException(404, detail="Filing type not supported.")
73+
else:
6574

66-
return update_filing({"cik": cik})
75+
return {"description": "Filing already queried."}
6776

6877

6978
# Exact functionality as `update_filer`, so changes need to be synced
7079

7180

72-
def update_filing(filing, background: BackgroundTasks = BackgroundTasks):
73-
cik = filing["cik"]
81+
def update_filing(
82+
company, last_report: str, background: BackgroundTasks = BackgroundTasks
83+
):
84+
cik = company["cik"]
7485
time = datetime.now().timestamp()
7586

7687
operation = database.find_log(cik)
7788
if operation is None:
78-
raise HTTPException(404, detail="Filing log not found.")
89+
raise HTTPException(404, detail="Filer log not found.")
7990
elif (
8091
production_environment and operation["status"] == 2 or operation["status"] == 1
8192
):
8293
raise HTTPException( # @IgnoreException
83-
302, detail="Filing is partially building."
94+
302, detail="Filer is partially building."
8495
)
8596
elif operation["status"] >= 2:
86-
raise HTTPException(409, detail="Filing still building.")
87-
88-
update, last_report = web.check_new(cik)
89-
if not update:
90-
raise HTTPException(
91-
200, detail="Filing is already up to date."
92-
) # @IgnoreException
97+
raise HTTPException(409, detail="Filer still building.")
9398

9499
database.edit_status(cik, 1)
95100
database.edit_filer({"cik": cik}, {"$set": {"last_report": last_report}})
96101

97102
stamp = {"name": company["name"], "start": time}
98103
if production_environment:
99-
worker.create_historical.delay(cik, company, stamp)
104+
worker.create_recent.delay(cik, company, stamp)
100105
else:
101-
background.add_task(create_historical, cik, company, stamp)
106+
background.add_task(filer.create_recent, cik, company, stamp)
102107

103-
return {"description": "Filer update started."}
108+
return {"description": "Filing update started."}
104109

105110

106111
@cache(24)
@@ -148,6 +153,9 @@ async def record_filing_csv(cik: str, access_number: str, headers: str = None):
148153
file_name = f"wallstreetlocal-{cik}-{access_number}.csv"
149154

150155
filing = database.find_filing(cik, access_number)
156+
if filing is None:
157+
raise HTTPException(404, detail="Filing not found.")
158+
151159
stock_dict = filing["stocks"]
152160
stock_list = [stock_dict[cusip] for cusip in stock_dict]
153161

@@ -157,15 +165,27 @@ async def record_filing_csv(cik: str, access_number: str, headers: str = None):
157165
)
158166

159167

160-
@router.get("/info", status_code=200)
161-
async def query_filings(cik: str):
168+
@router.get("/filer", status_code=200)
169+
async def filings_info(cik: str):
162170
pipeline = [
163-
{"$match": {"cik": cik, "form": "13F-HR"}},
164-
{"$project": {"stocks": 0, "_id": 0}},
171+
{"$match": {"cik": cik, "form": {"$in": database.holding_forms}}},
172+
{"$project": {"cik": 0, "stocks": 0, "_id": 0}},
165173
]
166174
cursor = database.search_filings(pipeline)
167175
if not cursor:
168176
raise HTTPException(detail="Filer not found.", status_code=404)
169177
filings = [result for result in cursor]
170178

171179
return {"filings": filings}
180+
181+
182+
@router.get("/info", status_code=200)
183+
async def filing_info(cik: str, access_number: str):
184+
filing = database.find_filing(cik, access_number, {"_id": 0, "cik": 0, "stocks": 0})
185+
if filing is None:
186+
raise HTTPException(detail="Filing not found.", status_code=404)
187+
188+
status = database.find_log(cik, {"status": 1, "_id": 0})
189+
filing["status"] = status["status"]
190+
191+
return {"description": "Filing found.", "filing": filing}

backend/routers/general.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,13 @@
3131
@cache(24)
3232
@router.get("/", status_code=200)
3333
async def info():
34-
return {"message": "Hello World!"}
34+
return {"description": "Hello World!"}
3535

3636

3737
@cache
3838
@router.get("/undefined", status_code=200)
3939
async def info_undefined():
40-
return {"message": "Hello World!"}
40+
return {"description": "Hello World!"}
4141

4242

4343
@cache(4)
@@ -69,13 +69,13 @@ async def health():
6969
if health_passed < 0.8:
7070
raise HTTPException(status_code=500, detail="The server doesn't seem healthy.")
7171

72-
return {"message": "The server is healthy."}
72+
return {"description": "The server is healthy."}
7373

7474

7575
# @router.get("/error", include_in_schema=False)
7676
# async def trigger_error():
7777
# 1 / 0
78-
# return {"message": "This will never be reached."}
78+
# return {"description": "This will never be reached."}
7979

8080

8181
@router.get("/task-error", include_in_schema=False)
@@ -86,7 +86,7 @@ async def task_error(password: str):
8686

8787
worker.delay_error.delay()
8888

89-
return {"message": "Task error triggered."}
89+
return {"description": "Task error triggered."}
9090

9191

9292
# Terrible code

backend/routers/lib/analysis.py

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -699,8 +699,7 @@ def create_json(content, file_name):
699699
filer_json = json.load(f)
700700
if (datetime.now().timestamp() - filer_json["updated"]) > 60 * 60 * 3:
701701
raise ValueError
702-
except Exception as e:
703-
errors.report_error(file_name, e)
702+
except FileNotFoundError:
704703
with open(file_path, "w") as r:
705704
json.dump(content, r, indent=6)
706705

@@ -765,8 +764,7 @@ def create_csv(content, file_name, headers=None):
765764
expire_time = 60 * 60 * 24 * 3
766765
cache.set_key(file_path, "bababooey", expire_time)
767766
raise ValueError
768-
except Exception as e:
769-
errors.report_error(file_name, e)
767+
except FileNotFoundError:
770768
stock_list = create_dataframe(content, headers)
771769
with open(file_path, "w") as f:
772770
writer = csv.writer(f)
@@ -938,11 +936,7 @@ def analyze_allocation(cik):
938936
allocation_statistic = {
939937
"filings": allocation_access,
940938
}
941-
database.add_statistic(
942-
cik,
943-
"allocation",
944-
allocation_statistic,
945-
)
939+
database.add_statistic(cik, "allocation", allocation_statistic, completion)
946940

947941
return allocation_list
948942

backend/routers/lib/database.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ def find_filing(cik, access_number, project={"_id": 0}, form_type="13F-HR"):
183183

184184

185185
@retry_on_rate_limit()
186-
def find_filings(cik, project={"_id": 0}, form_type="13F-HR"):
186+
def find_filings(cik, project={"_id": 0}, form_type={"$in": holding_forms}):
187187
cursor = filings.find({"cik": cik, "form": form_type}, project)
188188
results = [result for result in cursor]
189189
return results

backend/routers/stocks.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@ async def stock_info(
5959
cik, limit, offset, sort, sold, reverse, unavailable
6060
)
6161
cursor = database.search_filers(pipeline)
62+
except LookupError as e:
63+
errors.report_error(cik, e)
64+
raise HTTPException(detail="No results found.", status_code=422)
6265
except Exception as e:
6366
errors.report_error(cik, e)
6467
cursor = []

backend/static/statistics.json

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
{
22
"latest": {
3-
"count": 1690,
4-
"total": 1255375.0261363983,
5-
"average": 742.8254592523067
3+
"count": 1699,
4+
"total": 1271220.7323975563,
5+
"average": 748.2170290744887
66
},
77
"historical": {
8-
"count": 1675,
9-
"total": 5818102.588788748,
10-
"average": 3473.494082858954
8+
"count": 1684,
9+
"total": 5897062.192974329,
10+
"average": 3501.818404379055
1111
}
1212
}

frontend/components/Explorer/Explorer.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ const Explorer = () => {
7575
})
7676
.catch((e) => console.error(e));
7777
const { isLoading: loading, error } = useSWR(
78-
cik ? [server + "/filing/info", cik] : null,
78+
cik ? [server + "/filing/filer", cik] : null,
7979
([url, cik]) => filingFetcher(url, cik),
8080
{
8181
revalidateOnFocus: false,

frontend/components/Filer/Info.jsx

Lines changed: 16 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -11,25 +11,22 @@ import Explorer from "components/Explorer/Explorer";
1111
import Header from "components/Header/Header";
1212

1313
const convertTitle = (d) => {
14-
if (d) {
15-
d = d.replace(
16-
/(^\w|\s\w)(\S*)/g,
17-
(_, m1, m2) => {
18-
if (/[a-z][A-Z]|[A-Z][a-z]/.test(m1 + m2)) {
19-
return m1 + m2; // Return the original word
20-
} else {
21-
return m1.toUpperCase() + m2.toLowerCase(); // Convert to title case
22-
}
23-
}
24-
);
25-
["LLC", "LP", "L.P.", "LLP", "N.A."].forEach((word) => {
26-
d = d.replace(
27-
word.at(0).toUpperCase() + word.toLowerCase().slice(1),
28-
word
29-
);
30-
});
31-
}
32-
return d;
14+
if (d) {
15+
d = d.replace(/(^\w|\s\w)(\S*)/g, (_, m1, m2) => {
16+
if (/[a-z][A-Z]|[A-Z][a-z]/.test(m1 + m2)) {
17+
return m1 + m2; // Return the original word
18+
} else {
19+
return m1.toUpperCase() + m2.toLowerCase(); // Convert to title case
20+
}
21+
});
22+
["LLC", "LP", "L.P.", "LLP", "N.A."].forEach((word) => {
23+
d = d.replace(
24+
word.at(0).toUpperCase() + word.toLowerCase().slice(1),
25+
word
26+
);
27+
});
28+
}
29+
return d;
3330
};
3431

3532
const Info = (props) => {

frontend/components/Filer/Redirect.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ const Redirect = (props) => {
1414
const { ellipsis } = useEllipsis();
1515
useEffect(() => {
1616
setTimeout(() => {
17-
router.replace("/filers/" + cik + "?continuous=true");
17+
router.replace("/filers/" + cik + "/overview?continuous=true");
1818
}, props.delay || wait);
1919
}, [cik]);
2020

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
"use server";
2+
3+
import styles from "@/styles/Filer.module.css";
4+
5+
import Head from "next/head";
6+
7+
import Tabs from "components/Tabs/Tabs";
8+
import Index from "components/Index/Index";
9+
import Charts from "components/Charts/Charts";
10+
import Explorer from "components/Explorer/Explorer";
11+
import Header from "components/Header/Header";
12+
import { convertTitle } from "components/Filer/Info";
13+
14+
const Info = (props) => {
15+
const cik = props.cik || null;
16+
const tab = props.tab || "recent";
17+
const title = `Filers - ${cik}`; // Fallback for header title
18+
19+
return (
20+
<>
21+
<Head>
22+
<title>{title}</title>
23+
</Head>
24+
<Header cik={cik} tab={tab} />
25+
<Tabs />
26+
<div className={styles.data}>
27+
{tab === "filings" ? <Explorer /> : null}
28+
{/* {tab === "charts" ? <Charts /> : null} */}
29+
{tab === "stocks" ? <Index /> : null}
30+
</div>
31+
</>
32+
);
33+
};
34+
35+
export default Info;

0 commit comments

Comments
 (0)