Skip to content

Commit d112ad6

Browse files
committed
Merge branch 'dev'
2 parents d02ae11 + e319d9b commit d112ad6

35 files changed

+2797
-541
lines changed

notebooks/demo/demo-invoicing.ipynb

Lines changed: 275 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,275 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "markdown",
5+
"id": "34b777b3-2f88-4b67-ab04-eb8dc126975e",
6+
"metadata": {
7+
"tags": []
8+
},
9+
"source": [
10+
"# Invoicing"
11+
]
12+
},
13+
{
14+
"cell_type": "markdown",
15+
"id": "3335c617-d50d-4e33-a5dc-b56f388081d2",
16+
"metadata": {},
17+
"source": [
18+
"Now that we have set up our user info, clients, contracts and projects, as well as a source for time tracking data, we are ready to automatically generate invoices."
19+
]
20+
},
21+
{
22+
"cell_type": "markdown",
23+
"id": "1d98382c-6c1f-446f-97de-f5b19b97f582",
24+
"metadata": {},
25+
"source": [
26+
"## Preamble"
27+
]
28+
},
29+
{
30+
"cell_type": "code",
31+
"execution_count": 1,
32+
"id": "aa4ef82b-a4b1-4c07-a2fe-087be2c45bc4",
33+
"metadata": {},
34+
"outputs": [],
35+
"source": [
36+
"from pathlib import Path\n",
37+
"import datetime\n",
38+
"from IPython import display"
39+
]
40+
},
41+
{
42+
"cell_type": "code",
43+
"execution_count": 2,
44+
"id": "50ec9b6a-ce3d-477c-a4d9-9b1c5db3b4ee",
45+
"metadata": {},
46+
"outputs": [],
47+
"source": [
48+
"import tuttle"
49+
]
50+
},
51+
{
52+
"cell_type": "code",
53+
"execution_count": 3,
54+
"id": "d515270c-5a23-49ef-b8cf-dd3c34bdbc00",
55+
"metadata": {},
56+
"outputs": [],
57+
"source": [
58+
"app = tuttle.app.App(verbose=False)"
59+
]
60+
},
61+
{
62+
"cell_type": "markdown",
63+
"id": "8918a540-ef25-417a-9eae-310d9a63f578",
64+
"metadata": {
65+
"tags": []
66+
},
67+
"source": [
68+
"## Workflow"
69+
]
70+
},
71+
{
72+
"cell_type": "markdown",
73+
"id": "0857141e-106f-4197-ac03-b985f218c20a",
74+
"metadata": {},
75+
"source": [
76+
"_1. Select a project_"
77+
]
78+
},
79+
{
80+
"cell_type": "code",
81+
"execution_count": 4,
82+
"id": "55f0bf60-d0ec-4b5d-a475-4b541d8799cd",
83+
"metadata": {},
84+
"outputs": [
85+
{
86+
"name": "stderr",
87+
"output_type": "stream",
88+
"text": [
89+
"/Users/cls/miniforge3/envs/tuttle/lib/python3.9/site-packages/sqlmodel/orm/session.py:60: SAWarning: Class SelectOfScalar will not make use of SQL compilation caching as it does not set the 'inherit_cache' attribute to ``True``. This can have significant performance implications including some performance degradations in comparison to prior SQLAlchemy versions. Set this attribute to True if this object can make use of the cache key generated by the superclass. Alternatively, this attribute may be set to False which will disable this warning. (Background on this error at: https://sqlalche.me/e/14/cprf)\n",
90+
" results = super().execute(\n"
91+
]
92+
}
93+
],
94+
"source": [
95+
"my_project = app.get_project(title=\"Heating Repair\")"
96+
]
97+
},
98+
{
99+
"cell_type": "markdown",
100+
"id": "c0b2e5f5-7890-46ca-a52f-c6d00197563d",
101+
"metadata": {},
102+
"source": [
103+
"2. Select a time tracking data source."
104+
]
105+
},
106+
{
107+
"cell_type": "code",
108+
"execution_count": 5,
109+
"id": "b5194e28-e05f-41f0-9f37-066e5c4a4d12",
110+
"metadata": {},
111+
"outputs": [],
112+
"source": [
113+
"from tuttle.calendar import FileCalendar\n",
114+
"\n",
115+
"timetracking_calendar_path = Path(\"../../tests/data/TuttleDemo-TimeTracking.ics\")\n",
116+
"my_calendar = FileCalendar(\n",
117+
" path=timetracking_calendar_path, \n",
118+
" name=\"TimeTracking\"\n",
119+
")"
120+
]
121+
},
122+
{
123+
"cell_type": "markdown",
124+
"id": "0142e10a-ebd8-4f7e-84d2-2b8a5f9cd6e4",
125+
"metadata": {},
126+
"source": [
127+
"3. Generate one or more timesheets"
128+
]
129+
},
130+
{
131+
"cell_type": "code",
132+
"execution_count": 6,
133+
"id": "ecb0e9e5-63a0-4b48-a99d-2d6e2c0905d1",
134+
"metadata": {},
135+
"outputs": [
136+
{
137+
"name": "stderr",
138+
"output_type": "stream",
139+
"text": [
140+
"/Users/cls/miniforge3/envs/tuttle/lib/python3.9/site-packages/sqlmodel/orm/session.py:101: SAWarning: Dialect sqlite+pysqlite does *not* support Decimal objects natively, and SQLAlchemy must convert from floating point - rounding errors and other issues may occur. Please consider storing Decimal numbers as strings or integers on this platform for lossless storage.\n",
141+
" return super().execute( # type: ignore\n"
142+
]
143+
}
144+
],
145+
"source": [
146+
"my_timesheet = tuttle.timetracking.generate_timesheet(\n",
147+
" source=my_calendar,\n",
148+
" project=my_project,\n",
149+
" period=\"February 2022\",\n",
150+
" item_description=my_project.title,\n",
151+
")"
152+
]
153+
},
154+
{
155+
"cell_type": "markdown",
156+
"id": "d9a64c75-554b-4e84-92a4-48c6783a1a5d",
157+
"metadata": {},
158+
"source": [
159+
"4. Generate an invoice for the timesheet(s)."
160+
]
161+
},
162+
{
163+
"cell_type": "code",
164+
"execution_count": 7,
165+
"id": "8a097cc3-5aec-448d-9725-d8f588a02cd4",
166+
"metadata": {},
167+
"outputs": [],
168+
"source": [
169+
"my_invoice = tuttle.invoicing.generate_invoice(\n",
170+
" timesheets=[\n",
171+
" my_timesheet,\n",
172+
" ],\n",
173+
" contract=my_project.contract,\n",
174+
" date=datetime.date.today(),\n",
175+
")"
176+
]
177+
},
178+
{
179+
"cell_type": "markdown",
180+
"id": "8f6b4806-a372-48f2-8b9b-0ddae21ce1db",
181+
"metadata": {},
182+
"source": [
183+
"5. Render the invoice to a document template:"
184+
]
185+
},
186+
{
187+
"cell_type": "code",
188+
"execution_count": 8,
189+
"id": "3da4513d-6523-4268-ab41-647049591267",
190+
"metadata": {},
191+
"outputs": [],
192+
"source": [
193+
"invoice_dir = Path.home() / \"Downloads\""
194+
]
195+
},
196+
{
197+
"cell_type": "code",
198+
"execution_count": 9,
199+
"id": "2a918ca1-9c15-4c56-82e2-396c88116b2d",
200+
"metadata": {},
201+
"outputs": [],
202+
"source": [
203+
"tuttle.rendering.render_invoice(\n",
204+
" user=app.user, \n",
205+
" invoice=my_invoice,\n",
206+
" style=\"anvil\",\n",
207+
" out_dir=invoice_dir,\n",
208+
")"
209+
]
210+
},
211+
{
212+
"cell_type": "code",
213+
"execution_count": 10,
214+
"id": "15041ce5-c6b9-4597-86b7-0a5cc5d51fc6",
215+
"metadata": {},
216+
"outputs": [],
217+
"source": [
218+
"invoice_path = str(invoice_dir / f\"Invoice-{my_invoice.number}\" / f\"Invoice-{my_invoice.number}.html\")"
219+
]
220+
},
221+
{
222+
"cell_type": "code",
223+
"execution_count": 11,
224+
"id": "8793081f-1f50-4943-8449-cebad19689af",
225+
"metadata": {},
226+
"outputs": [
227+
{
228+
"name": "stdout",
229+
"output_type": "stream",
230+
"text": [
231+
"Testing Quick Look preview with files:\n",
232+
"\t/Users/cls/Downloads/Invoice-2022-02-21-01/Invoice-2022-02-21-01.html\n",
233+
"2022-02-21 21:55:53.852 qlmanage[11525:332330] *** CFMessagePort: bootstrap_register(): failed 1100 (0x44c) 'Permission denied', port = 0x14003, name = 'com.apple.coredrag'\n",
234+
"See /usr/include/servers/bootstrap_defs.h for the error codes.\n",
235+
"2022-02-21 21:55:53.883 qlmanage[11525:332330] *** CFMessagePort: bootstrap_register(): failed 1100 (0x44c) 'Permission denied', port = 0xca03, name = 'com.apple.tsm.portname'\n",
236+
"See /usr/include/servers/bootstrap_defs.h for the error codes.\n",
237+
"2022-02-21 21:55:59.974 qlmanage[11525:332343] Persistent UI failed to open file file:///Users/cls/Library/Saved%20Application%20State/com.apple.quicklook.qlmanage.savedState/window_1.data: No such file or directory (2)\n"
238+
]
239+
}
240+
],
241+
"source": [
242+
"!qlmanage -p {invoice_path}"
243+
]
244+
},
245+
{
246+
"cell_type": "code",
247+
"execution_count": null,
248+
"id": "40c8f4b4-2ddb-4d66-b6fa-eccd9ef7d70c",
249+
"metadata": {},
250+
"outputs": [],
251+
"source": []
252+
}
253+
],
254+
"metadata": {
255+
"kernelspec": {
256+
"display_name": "tuttle",
257+
"language": "python",
258+
"name": "ex"
259+
},
260+
"language_info": {
261+
"codemirror_mode": {
262+
"name": "ipython",
263+
"version": 3
264+
},
265+
"file_extension": ".py",
266+
"mimetype": "text/x-python",
267+
"name": "python",
268+
"nbconvert_exporter": "python",
269+
"pygments_lexer": "ipython3",
270+
"version": "3.9.7"
271+
}
272+
},
273+
"nbformat": 4,
274+
"nbformat_minor": 5
275+
}

0 commit comments

Comments
 (0)