splitkaro 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Kanhaiya Kumar
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,323 @@
1
+ Metadata-Version: 2.4
2
+ Name: splitkaro
3
+ Version: 0.1.0
4
+ Summary: Bill splitter for friends, flatmates and trips: split shared expenses, see who owes whom, and settle up with the fewest payments and UPI links.
5
+ Author: Kanhaiya Kumar
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/K70281095/splitkaro
8
+ Project-URL: Issues, https://github.com/K70281095/splitkaro/issues
9
+ Project-URL: Changelog, https://github.com/K70281095/splitkaro/blob/main/CHANGELOG.md
10
+ Keywords: bill-splitter,split-expenses,expense-splitter,group-expenses,settle-up,splitwise-alternative,upi,india,roommates,travel,personal-finance,cli
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Environment :: Console
13
+ Classifier: Intended Audience :: End Users/Desktop
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3 :: Only
18
+ Classifier: Programming Language :: Python :: 3.9
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Programming Language :: Python :: 3.13
23
+ Classifier: Topic :: Office/Business :: Financial
24
+ Classifier: Topic :: Utilities
25
+ Requires-Python: >=3.9
26
+ Description-Content-Type: text/markdown
27
+ License-File: LICENSE
28
+ Provides-Extra: dev
29
+ Requires-Dist: ruff>=0.6; extra == "dev"
30
+ Dynamic: license-file
31
+
32
+ # splitkaro: split expenses & settle up with UPI
33
+
34
+ **A bill splitter for friends, flatmates and trips: track shared expenses, see who owes whom, and settle up with the fewest payments and one-tap UPI links.**
35
+
36
+ [![CI](https://github.com/K70281095/splitkaro/actions/workflows/ci.yml/badge.svg)](https://github.com/K70281095/splitkaro/actions/workflows/ci.yml)
37
+ ![Python](https://img.shields.io/badge/python-3.9%20%E2%80%93%203.13-blue)
38
+ ![Dependencies](https://img.shields.io/badge/dependencies-0-brightgreen)
39
+ [![License: MIT](https://img.shields.io/badge/license-MIT-green)](LICENSE)
40
+
41
+ *Split karo* is Hinglish for "split it". It is the phrase every group says at the end of a trip,
42
+ right before the *hisaab* (the accounts) gets complicated.
43
+
44
+ Every trip, every shared flat and every office lunch ends with the same questions:
45
+
46
+ - Who paid for what, and who still owes whom?
47
+ - The hotel was ₹9,000, but a couple shared one room. How do we split that fairly?
48
+ - Five people owe each other money. Do we really need ten transfers?
49
+ - Somebody paid in dollars. What is that in rupees?
50
+
51
+ `splitkaro` answers all of them from your terminal. It keeps the group's records in one readable
52
+ JSON file, does every calculation with exact decimal arithmetic so the totals always add up to
53
+ the paisa, and works out the smallest set of payments that settles everyone, with UPI links you
54
+ can open in GPay, PhonePe, Paytm or BHIM.
55
+
56
+ ```console
57
+ $ splitkaro balances
58
+ Asha gets back ₹2,618.00
59
+ Ravi owes ₹682.00
60
+ Meera owes ₹1,936.00
61
+
62
+ $ splitkaro settle --upi
63
+ 2 payment(s) settle everything:
64
+ Meera pays Asha ₹1,936.00
65
+ upi://pay?pa=asha%40okbank&pn=Asha&am=1936.00&cu=INR&tn=splitkaro%3A+Goa+trip
66
+ Ravi pays Asha ₹682.00
67
+ upi://pay?pa=asha%40okbank&pn=Asha&am=682.00&cu=INR&tn=splitkaro%3A+Goa+trip
68
+ ```
69
+
70
+ ---
71
+
72
+ ## Contents
73
+
74
+ - [Features](#features)
75
+ - [Install](#install)
76
+ - [A full example: a Goa trip](#a-full-example-a-goa-trip)
77
+ - [Ways to split](#ways-to-split)
78
+ - [Command reference](#command-reference)
79
+ - [Your data](#your-data)
80
+ - [Using splitkaro from Python](#using-splitkaro-from-python)
81
+ - [How it works](#how-it-works)
82
+ - [Roadmap](#roadmap)
83
+ - [Contributing](#contributing)
84
+ - [License](#license)
85
+
86
+ ## Features
87
+
88
+ | | |
89
+ |---|---|
90
+ | **Four ways to split** | Equally, by exact amounts, by percentage, or by shares (a couple counts as 2). |
91
+ | **Several payers** | "I paid ₹1,000 and you paid ₹500" for the same bill works naturally. |
92
+ | **Fewest payments** | Suggests at most *n − 1* transfers for *n* people, and pairs up exact matches first. |
93
+ | **UPI links** | One `upi://pay` link per payment; the payer just confirms it in their app. |
94
+ | **Exact to the paisa** | Decimal arithmetic and fair rounding: ₹100 split three ways is 33.34 + 33.33 + 33.33. |
95
+ | **Foreign currency** | Record an expense in USD or EUR; it is converted with the rate you set. |
96
+ | **Reports** | Spending by category and month, and who paid vs. who consumed. |
97
+ | **Statements** | A running, line-by-line history of one person's balance. |
98
+ | **CSV import/export** | Move data to and from spreadsheets. Imports are all-or-nothing. |
99
+ | **Your data, your file** | Plain JSON you can read, back up, sync or put under git. No account, no server, no ads. |
100
+ | **Zero dependencies** | Pure Python standard library, Python 3.9+. |
101
+
102
+ ## Install
103
+
104
+ ```bash
105
+ pip install splitkaro
106
+ ```
107
+
108
+ Or straight from GitHub:
109
+
110
+ ```bash
111
+ pip install git+https://github.com/K70281095/splitkaro.git
112
+ ```
113
+
114
+ Check it works:
115
+
116
+ ```bash
117
+ splitkaro --version
118
+ ```
119
+
120
+ ## A full example: a Goa trip
121
+
122
+ Asha, Ravi and Meera go to Goa. Asha travels with her partner, so on the hotel she counts as two.
123
+
124
+ ```bash
125
+ splitkaro init "Goa trip"
126
+ splitkaro member add Asha Ravi Meera
127
+ splitkaro member upi Asha asha@okbank # so others can pay her with one tap
128
+
129
+ # Hotel: Asha paid, split by shares (Asha 2, Ravi 1, Meera 1)
130
+ splitkaro add "Hotel (2 nights)" 9000 --paid-by Asha --shares Asha=2,Ravi=1,Meera=1 --category stay
131
+
132
+ # Dinner: Ravi paid, split equally among everyone (the default)
133
+ splitkaro add "Dinner at the shack" 2400 --paid-by Ravi --category food
134
+
135
+ # Scooters: two people paid, and only they used them
136
+ splitkaro add "Scooter rental" 1500 --paid-by Asha=1000 --paid-by Meera=500 --among Asha,Meera --category travel
137
+
138
+ # Parasailing was paid in dollars
139
+ splitkaro rate USD 83.20
140
+ splitkaro add "Parasailing" 30 --currency USD --paid-by Meera --category fun
141
+
142
+ # Groceries: everyone took different things
143
+ splitkaro add "Groceries" 1260 --paid-by Ravi --exact Asha=500,Ravi=460,Meera=300 --category food
144
+ ```
145
+
146
+ Where does everyone stand, and how do they square up?
147
+
148
+ ```console
149
+ $ splitkaro settle
150
+ 2 payment(s) settle everything:
151
+ Meera pays Asha ₹1,936.00
152
+ Ravi pays Asha ₹682.00
153
+ ```
154
+
155
+ Where did the money go?
156
+
157
+ ```console
158
+ $ splitkaro report
159
+ Goa trip: 5 expense(s), ₹16,656.00 in total
160
+
161
+ By category
162
+ stay ₹9,000.00 54%
163
+ food ₹3,660.00 22%
164
+ fun ₹2,496.00 15%
165
+ travel ₹1,500.00 9%
166
+
167
+ By month
168
+ 2026-11 ₹16,656.00
169
+
170
+ member paid share
171
+ Asha ₹10,000.00 ₹7,382.00
172
+ Ravi ₹3,660.00 ₹4,342.00
173
+ Meera ₹2,996.00 ₹4,932.00
174
+ ```
175
+
176
+ Meera wants to see exactly how she ended up owing ₹1,936:
177
+
178
+ ```console
179
+ $ splitkaro statement meera
180
+ 2026-11-01 -₹2,250.00 -₹2,250.00 #1 Hotel (2 nights)
181
+ 2026-11-01 -₹800.00 -₹3,050.00 #2 Dinner at the shack
182
+ 2026-11-02 -₹250.00 -₹3,300.00 #3 Scooter rental
183
+ 2026-11-02 ₹1,664.00 -₹1,636.00 #4 Parasailing
184
+ 2026-11-03 -₹300.00 -₹1,936.00 #5 Groceries
185
+
186
+ Meera owes ₹1,936.00
187
+ ```
188
+
189
+ Once the money has moved, record it, and everyone is back to zero:
190
+
191
+ ```bash
192
+ splitkaro pay Meera Asha 1936
193
+ splitkaro pay Ravi Asha 682
194
+ splitkaro settle # Everyone is settled up. 🎉
195
+ ```
196
+
197
+ The same trip is available as [`examples/goa-trip.csv`](examples/goa-trip.csv), which you can
198
+ load with `splitkaro import examples/goa-trip.csv`.
199
+
200
+ ## Ways to split
201
+
202
+ | Option | Example | Meaning |
203
+ |---|---|---|
204
+ | *(none)* | `--paid-by Ravi` | Equally among **all** members. |
205
+ | `--among` | `--among Asha,Meera` | Equally among the listed members. |
206
+ | `--exact` | `--exact Asha=500,Ravi=460,Meera=300` | Fixed amounts; must add up to the total. |
207
+ | `--percent` | `--percent Asha=50,Ravi=25,Meera=25` | Percentages; must add up to 100. |
208
+ | `--shares` | `--shares Asha=2,Ravi=1,Meera=1` | Proportional weights, e.g. couples, or nights stayed. |
209
+
210
+ Whoever paid is given with `--paid-by NAME`, or `--paid-by NAME=AMOUNT` repeated when several
211
+ people paid the same bill. Names are case-insensitive.
212
+
213
+ ## Command reference
214
+
215
+ | Command | What it does |
216
+ |---|---|
217
+ | `splitkaro init NAME [--currency INR]` | Start a group (creates `splitkaro.json`). |
218
+ | `splitkaro member add NAME... [--upi ID]` | Add members. |
219
+ | `splitkaro member upi NAME ID` | Set a member's UPI ID. |
220
+ | `splitkaro member list` / `remove NAME` | List members, or remove one who has no history. |
221
+ | `splitkaro add DESC AMOUNT --paid-by ...` | Record an expense (`--category`, `--date`, `--currency`, `--note`). |
222
+ | `splitkaro list [--month YYYY-MM] [--category C] [--member M]` | List expenses. |
223
+ | `splitkaro delete ID` | Delete an expense. |
224
+ | `splitkaro balances [--json]` | Who gets money back, who owes. |
225
+ | `splitkaro settle [--upi] [--json]` | Fewest payments to settle everything. |
226
+ | `splitkaro pay FROM TO AMOUNT` | Record a payment between members. |
227
+ | `splitkaro statement NAME` | Running history of one member's balance. |
228
+ | `splitkaro report [filters] [--json]` | Totals by category, month and member. |
229
+ | `splitkaro rate CUR VALUE` | Exchange rate: 1 CUR = VALUE in the group currency. |
230
+ | `splitkaro export FILE` / `import FILE` | CSV out and in (`-` for stdout/stdin). |
231
+
232
+ Every command accepts `--file PATH` (or the `SPLITKARO_FILE` environment variable) to work with
233
+ more than one group, for example `splitkaro -f flat.json balances`.
234
+
235
+ Errors are printed as `splitkaro: <message>` with exit code `1`, and nothing is saved when a command
236
+ fails.
237
+
238
+ ## Your data
239
+
240
+ A group lives in a single JSON file, `splitkaro.json` by default (shortened here):
241
+
242
+ ```json
243
+ {
244
+ "version": 1,
245
+ "name": "Goa trip",
246
+ "currency": "INR",
247
+ "members": [{ "name": "Asha", "upi": "asha@okbank" }, { "name": "Ravi", "upi": null }],
248
+ "expenses": [
249
+ {
250
+ "id": 2,
251
+ "date": "2026-11-01",
252
+ "description": "Dinner at the shack",
253
+ "amount": "2400.00",
254
+ "paid_by": { "Ravi": "2400.00" },
255
+ "split": { "kind": "equal", "among": ["Asha", "Ravi", "Meera"], "values": {} }
256
+ }
257
+ ]
258
+ }
259
+ ```
260
+
261
+ - Amounts are stored as strings, never floats, so nothing is ever rounded away.
262
+ - Files are written atomically: a crash or a full disk cannot leave a half-written file.
263
+ - There is no account, server or tracking. Share the file however your group likes.
264
+
265
+ The CSV format is documented in [docs/csv-format.md](docs/csv-format.md).
266
+
267
+ ## Using splitkaro from Python
268
+
269
+ ```python
270
+ import datetime as dt
271
+ from decimal import Decimal
272
+
273
+ from splitkaro import Expense, Group, Split, balances, settle
274
+
275
+ group = Group("Flat 302")
276
+ for name in ("Asha", "Ravi", "Meera"):
277
+ group.add_member(name)
278
+
279
+ group.add_expense(Expense(
280
+ id=0, description="Electricity", amount=Decimal("3120"),
281
+ paid_by={"Ravi": Decimal("3120")}, split=Split.equal(["Asha", "Ravi", "Meera"]),
282
+ date=dt.date(2026, 11, 5), currency="INR", category="bills",
283
+ ))
284
+
285
+ for t in settle(balances(group)):
286
+ print(f"{t.sender} pays {t.receiver} {t.amount}")
287
+ ```
288
+
289
+ ## How it works
290
+
291
+ - **Rounding:** amounts are split with the largest-remainder method on whole paise, so the parts
292
+ always add up to the exact total and nobody is ever short-changed by more than one paisa.
293
+ - **Balances:** each member's balance is what they paid minus their share, plus payments made
294
+ minus payments received. Balances always add up to exactly zero.
295
+ - **Settling:** exact matches (someone owes exactly what someone else is owed) are paired first;
296
+ the rest is settled greedily between the largest debtor and the largest creditor. This never
297
+ needs more than *n − 1* payments.
298
+
299
+ The details, with worked examples, are in [docs/how-it-works.md](docs/how-it-works.md).
300
+
301
+ ## Roadmap
302
+
303
+ - [ ] Recurring expenses (rent, Wi-Fi, maid) added automatically each month
304
+ - [ ] UPI QR codes in the terminal
305
+ - [ ] Simplify across groups (one payment per pair of people for several trips)
306
+ - [ ] Budgets per category with warnings
307
+ - [ ] Hindi and other Indian language output
308
+ - [ ] A small web or mobile front end on top of the same file format
309
+
310
+ Ideas and pull requests are welcome, see the [issues](https://github.com/K70281095/splitkaro/issues).
311
+
312
+ ## Contributing
313
+
314
+ Bug reports, ideas, translations and code are all welcome. Please read
315
+ [CONTRIBUTING.md](CONTRIBUTING.md) and the [Code of Conduct](CODE_OF_CONDUCT.md). To report a
316
+ security problem, see [SECURITY.md](SECURITY.md).
317
+
318
+ ## License
319
+
320
+ [MIT](LICENSE) © 2026 Kanhaiya Kumar
321
+
322
+ *UPI is a system of the National Payments Corporation of India. splitkaro only creates standard
323
+ `upi://pay` links and never handles money, bank details or PINs.*
@@ -0,0 +1,292 @@
1
+ # splitkaro: split expenses & settle up with UPI
2
+
3
+ **A bill splitter for friends, flatmates and trips: track shared expenses, see who owes whom, and settle up with the fewest payments and one-tap UPI links.**
4
+
5
+ [![CI](https://github.com/K70281095/splitkaro/actions/workflows/ci.yml/badge.svg)](https://github.com/K70281095/splitkaro/actions/workflows/ci.yml)
6
+ ![Python](https://img.shields.io/badge/python-3.9%20%E2%80%93%203.13-blue)
7
+ ![Dependencies](https://img.shields.io/badge/dependencies-0-brightgreen)
8
+ [![License: MIT](https://img.shields.io/badge/license-MIT-green)](LICENSE)
9
+
10
+ *Split karo* is Hinglish for "split it". It is the phrase every group says at the end of a trip,
11
+ right before the *hisaab* (the accounts) gets complicated.
12
+
13
+ Every trip, every shared flat and every office lunch ends with the same questions:
14
+
15
+ - Who paid for what, and who still owes whom?
16
+ - The hotel was ₹9,000, but a couple shared one room. How do we split that fairly?
17
+ - Five people owe each other money. Do we really need ten transfers?
18
+ - Somebody paid in dollars. What is that in rupees?
19
+
20
+ `splitkaro` answers all of them from your terminal. It keeps the group's records in one readable
21
+ JSON file, does every calculation with exact decimal arithmetic so the totals always add up to
22
+ the paisa, and works out the smallest set of payments that settles everyone, with UPI links you
23
+ can open in GPay, PhonePe, Paytm or BHIM.
24
+
25
+ ```console
26
+ $ splitkaro balances
27
+ Asha gets back ₹2,618.00
28
+ Ravi owes ₹682.00
29
+ Meera owes ₹1,936.00
30
+
31
+ $ splitkaro settle --upi
32
+ 2 payment(s) settle everything:
33
+ Meera pays Asha ₹1,936.00
34
+ upi://pay?pa=asha%40okbank&pn=Asha&am=1936.00&cu=INR&tn=splitkaro%3A+Goa+trip
35
+ Ravi pays Asha ₹682.00
36
+ upi://pay?pa=asha%40okbank&pn=Asha&am=682.00&cu=INR&tn=splitkaro%3A+Goa+trip
37
+ ```
38
+
39
+ ---
40
+
41
+ ## Contents
42
+
43
+ - [Features](#features)
44
+ - [Install](#install)
45
+ - [A full example: a Goa trip](#a-full-example-a-goa-trip)
46
+ - [Ways to split](#ways-to-split)
47
+ - [Command reference](#command-reference)
48
+ - [Your data](#your-data)
49
+ - [Using splitkaro from Python](#using-splitkaro-from-python)
50
+ - [How it works](#how-it-works)
51
+ - [Roadmap](#roadmap)
52
+ - [Contributing](#contributing)
53
+ - [License](#license)
54
+
55
+ ## Features
56
+
57
+ | | |
58
+ |---|---|
59
+ | **Four ways to split** | Equally, by exact amounts, by percentage, or by shares (a couple counts as 2). |
60
+ | **Several payers** | "I paid ₹1,000 and you paid ₹500" for the same bill works naturally. |
61
+ | **Fewest payments** | Suggests at most *n − 1* transfers for *n* people, and pairs up exact matches first. |
62
+ | **UPI links** | One `upi://pay` link per payment; the payer just confirms it in their app. |
63
+ | **Exact to the paisa** | Decimal arithmetic and fair rounding: ₹100 split three ways is 33.34 + 33.33 + 33.33. |
64
+ | **Foreign currency** | Record an expense in USD or EUR; it is converted with the rate you set. |
65
+ | **Reports** | Spending by category and month, and who paid vs. who consumed. |
66
+ | **Statements** | A running, line-by-line history of one person's balance. |
67
+ | **CSV import/export** | Move data to and from spreadsheets. Imports are all-or-nothing. |
68
+ | **Your data, your file** | Plain JSON you can read, back up, sync or put under git. No account, no server, no ads. |
69
+ | **Zero dependencies** | Pure Python standard library, Python 3.9+. |
70
+
71
+ ## Install
72
+
73
+ ```bash
74
+ pip install splitkaro
75
+ ```
76
+
77
+ Or straight from GitHub:
78
+
79
+ ```bash
80
+ pip install git+https://github.com/K70281095/splitkaro.git
81
+ ```
82
+
83
+ Check it works:
84
+
85
+ ```bash
86
+ splitkaro --version
87
+ ```
88
+
89
+ ## A full example: a Goa trip
90
+
91
+ Asha, Ravi and Meera go to Goa. Asha travels with her partner, so on the hotel she counts as two.
92
+
93
+ ```bash
94
+ splitkaro init "Goa trip"
95
+ splitkaro member add Asha Ravi Meera
96
+ splitkaro member upi Asha asha@okbank # so others can pay her with one tap
97
+
98
+ # Hotel: Asha paid, split by shares (Asha 2, Ravi 1, Meera 1)
99
+ splitkaro add "Hotel (2 nights)" 9000 --paid-by Asha --shares Asha=2,Ravi=1,Meera=1 --category stay
100
+
101
+ # Dinner: Ravi paid, split equally among everyone (the default)
102
+ splitkaro add "Dinner at the shack" 2400 --paid-by Ravi --category food
103
+
104
+ # Scooters: two people paid, and only they used them
105
+ splitkaro add "Scooter rental" 1500 --paid-by Asha=1000 --paid-by Meera=500 --among Asha,Meera --category travel
106
+
107
+ # Parasailing was paid in dollars
108
+ splitkaro rate USD 83.20
109
+ splitkaro add "Parasailing" 30 --currency USD --paid-by Meera --category fun
110
+
111
+ # Groceries: everyone took different things
112
+ splitkaro add "Groceries" 1260 --paid-by Ravi --exact Asha=500,Ravi=460,Meera=300 --category food
113
+ ```
114
+
115
+ Where does everyone stand, and how do they square up?
116
+
117
+ ```console
118
+ $ splitkaro settle
119
+ 2 payment(s) settle everything:
120
+ Meera pays Asha ₹1,936.00
121
+ Ravi pays Asha ₹682.00
122
+ ```
123
+
124
+ Where did the money go?
125
+
126
+ ```console
127
+ $ splitkaro report
128
+ Goa trip: 5 expense(s), ₹16,656.00 in total
129
+
130
+ By category
131
+ stay ₹9,000.00 54%
132
+ food ₹3,660.00 22%
133
+ fun ₹2,496.00 15%
134
+ travel ₹1,500.00 9%
135
+
136
+ By month
137
+ 2026-11 ₹16,656.00
138
+
139
+ member paid share
140
+ Asha ₹10,000.00 ₹7,382.00
141
+ Ravi ₹3,660.00 ₹4,342.00
142
+ Meera ₹2,996.00 ₹4,932.00
143
+ ```
144
+
145
+ Meera wants to see exactly how she ended up owing ₹1,936:
146
+
147
+ ```console
148
+ $ splitkaro statement meera
149
+ 2026-11-01 -₹2,250.00 -₹2,250.00 #1 Hotel (2 nights)
150
+ 2026-11-01 -₹800.00 -₹3,050.00 #2 Dinner at the shack
151
+ 2026-11-02 -₹250.00 -₹3,300.00 #3 Scooter rental
152
+ 2026-11-02 ₹1,664.00 -₹1,636.00 #4 Parasailing
153
+ 2026-11-03 -₹300.00 -₹1,936.00 #5 Groceries
154
+
155
+ Meera owes ₹1,936.00
156
+ ```
157
+
158
+ Once the money has moved, record it, and everyone is back to zero:
159
+
160
+ ```bash
161
+ splitkaro pay Meera Asha 1936
162
+ splitkaro pay Ravi Asha 682
163
+ splitkaro settle # Everyone is settled up. 🎉
164
+ ```
165
+
166
+ The same trip is available as [`examples/goa-trip.csv`](examples/goa-trip.csv), which you can
167
+ load with `splitkaro import examples/goa-trip.csv`.
168
+
169
+ ## Ways to split
170
+
171
+ | Option | Example | Meaning |
172
+ |---|---|---|
173
+ | *(none)* | `--paid-by Ravi` | Equally among **all** members. |
174
+ | `--among` | `--among Asha,Meera` | Equally among the listed members. |
175
+ | `--exact` | `--exact Asha=500,Ravi=460,Meera=300` | Fixed amounts; must add up to the total. |
176
+ | `--percent` | `--percent Asha=50,Ravi=25,Meera=25` | Percentages; must add up to 100. |
177
+ | `--shares` | `--shares Asha=2,Ravi=1,Meera=1` | Proportional weights, e.g. couples, or nights stayed. |
178
+
179
+ Whoever paid is given with `--paid-by NAME`, or `--paid-by NAME=AMOUNT` repeated when several
180
+ people paid the same bill. Names are case-insensitive.
181
+
182
+ ## Command reference
183
+
184
+ | Command | What it does |
185
+ |---|---|
186
+ | `splitkaro init NAME [--currency INR]` | Start a group (creates `splitkaro.json`). |
187
+ | `splitkaro member add NAME... [--upi ID]` | Add members. |
188
+ | `splitkaro member upi NAME ID` | Set a member's UPI ID. |
189
+ | `splitkaro member list` / `remove NAME` | List members, or remove one who has no history. |
190
+ | `splitkaro add DESC AMOUNT --paid-by ...` | Record an expense (`--category`, `--date`, `--currency`, `--note`). |
191
+ | `splitkaro list [--month YYYY-MM] [--category C] [--member M]` | List expenses. |
192
+ | `splitkaro delete ID` | Delete an expense. |
193
+ | `splitkaro balances [--json]` | Who gets money back, who owes. |
194
+ | `splitkaro settle [--upi] [--json]` | Fewest payments to settle everything. |
195
+ | `splitkaro pay FROM TO AMOUNT` | Record a payment between members. |
196
+ | `splitkaro statement NAME` | Running history of one member's balance. |
197
+ | `splitkaro report [filters] [--json]` | Totals by category, month and member. |
198
+ | `splitkaro rate CUR VALUE` | Exchange rate: 1 CUR = VALUE in the group currency. |
199
+ | `splitkaro export FILE` / `import FILE` | CSV out and in (`-` for stdout/stdin). |
200
+
201
+ Every command accepts `--file PATH` (or the `SPLITKARO_FILE` environment variable) to work with
202
+ more than one group, for example `splitkaro -f flat.json balances`.
203
+
204
+ Errors are printed as `splitkaro: <message>` with exit code `1`, and nothing is saved when a command
205
+ fails.
206
+
207
+ ## Your data
208
+
209
+ A group lives in a single JSON file, `splitkaro.json` by default (shortened here):
210
+
211
+ ```json
212
+ {
213
+ "version": 1,
214
+ "name": "Goa trip",
215
+ "currency": "INR",
216
+ "members": [{ "name": "Asha", "upi": "asha@okbank" }, { "name": "Ravi", "upi": null }],
217
+ "expenses": [
218
+ {
219
+ "id": 2,
220
+ "date": "2026-11-01",
221
+ "description": "Dinner at the shack",
222
+ "amount": "2400.00",
223
+ "paid_by": { "Ravi": "2400.00" },
224
+ "split": { "kind": "equal", "among": ["Asha", "Ravi", "Meera"], "values": {} }
225
+ }
226
+ ]
227
+ }
228
+ ```
229
+
230
+ - Amounts are stored as strings, never floats, so nothing is ever rounded away.
231
+ - Files are written atomically: a crash or a full disk cannot leave a half-written file.
232
+ - There is no account, server or tracking. Share the file however your group likes.
233
+
234
+ The CSV format is documented in [docs/csv-format.md](docs/csv-format.md).
235
+
236
+ ## Using splitkaro from Python
237
+
238
+ ```python
239
+ import datetime as dt
240
+ from decimal import Decimal
241
+
242
+ from splitkaro import Expense, Group, Split, balances, settle
243
+
244
+ group = Group("Flat 302")
245
+ for name in ("Asha", "Ravi", "Meera"):
246
+ group.add_member(name)
247
+
248
+ group.add_expense(Expense(
249
+ id=0, description="Electricity", amount=Decimal("3120"),
250
+ paid_by={"Ravi": Decimal("3120")}, split=Split.equal(["Asha", "Ravi", "Meera"]),
251
+ date=dt.date(2026, 11, 5), currency="INR", category="bills",
252
+ ))
253
+
254
+ for t in settle(balances(group)):
255
+ print(f"{t.sender} pays {t.receiver} {t.amount}")
256
+ ```
257
+
258
+ ## How it works
259
+
260
+ - **Rounding:** amounts are split with the largest-remainder method on whole paise, so the parts
261
+ always add up to the exact total and nobody is ever short-changed by more than one paisa.
262
+ - **Balances:** each member's balance is what they paid minus their share, plus payments made
263
+ minus payments received. Balances always add up to exactly zero.
264
+ - **Settling:** exact matches (someone owes exactly what someone else is owed) are paired first;
265
+ the rest is settled greedily between the largest debtor and the largest creditor. This never
266
+ needs more than *n − 1* payments.
267
+
268
+ The details, with worked examples, are in [docs/how-it-works.md](docs/how-it-works.md).
269
+
270
+ ## Roadmap
271
+
272
+ - [ ] Recurring expenses (rent, Wi-Fi, maid) added automatically each month
273
+ - [ ] UPI QR codes in the terminal
274
+ - [ ] Simplify across groups (one payment per pair of people for several trips)
275
+ - [ ] Budgets per category with warnings
276
+ - [ ] Hindi and other Indian language output
277
+ - [ ] A small web or mobile front end on top of the same file format
278
+
279
+ Ideas and pull requests are welcome, see the [issues](https://github.com/K70281095/splitkaro/issues).
280
+
281
+ ## Contributing
282
+
283
+ Bug reports, ideas, translations and code are all welcome. Please read
284
+ [CONTRIBUTING.md](CONTRIBUTING.md) and the [Code of Conduct](CODE_OF_CONDUCT.md). To report a
285
+ security problem, see [SECURITY.md](SECURITY.md).
286
+
287
+ ## License
288
+
289
+ [MIT](LICENSE) © 2026 Kanhaiya Kumar
290
+
291
+ *UPI is a system of the National Payments Corporation of India. splitkaro only creates standard
292
+ `upi://pay` links and never handles money, bank details or PINs.*
@@ -0,0 +1,60 @@
1
+ [build-system]
2
+ requires = ["setuptools>=77"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "splitkaro"
7
+ version = "0.1.0"
8
+ description = "Bill splitter for friends, flatmates and trips: split shared expenses, see who owes whom, and settle up with the fewest payments and UPI links."
9
+ readme = "README.md"
10
+ requires-python = ">=3.9"
11
+ license = "MIT"
12
+ license-files = ["LICENSE"]
13
+ authors = [{ name = "Kanhaiya Kumar" }]
14
+ keywords = ["bill-splitter", "split-expenses", "expense-splitter", "group-expenses", "settle-up", "splitwise-alternative", "upi", "india", "roommates", "travel", "personal-finance", "cli"]
15
+ classifiers = [
16
+ "Development Status :: 3 - Alpha",
17
+ "Environment :: Console",
18
+ "Intended Audience :: End Users/Desktop",
19
+ "Intended Audience :: Developers",
20
+ "Operating System :: OS Independent",
21
+ "Programming Language :: Python :: 3",
22
+ "Programming Language :: Python :: 3 :: Only",
23
+ "Programming Language :: Python :: 3.9",
24
+ "Programming Language :: Python :: 3.10",
25
+ "Programming Language :: Python :: 3.11",
26
+ "Programming Language :: Python :: 3.12",
27
+ "Programming Language :: Python :: 3.13",
28
+ "Topic :: Office/Business :: Financial",
29
+ "Topic :: Utilities",
30
+ ]
31
+ dependencies = []
32
+
33
+ [project.optional-dependencies]
34
+ dev = ["ruff>=0.6"]
35
+
36
+ [project.scripts]
37
+ splitkaro = "splitkaro.cli:main"
38
+
39
+ [project.urls]
40
+ Homepage = "https://github.com/K70281095/splitkaro"
41
+ Issues = "https://github.com/K70281095/splitkaro/issues"
42
+ Changelog = "https://github.com/K70281095/splitkaro/blob/main/CHANGELOG.md"
43
+
44
+ [tool.setuptools.packages.find]
45
+ where = ["src"]
46
+
47
+ [tool.ruff]
48
+ line-length = 110
49
+ target-version = "py39"
50
+ src = ["src", "tests"]
51
+
52
+ [tool.ruff.format]
53
+ # Code samples in the docs are laid out for reading, not by the formatter.
54
+ exclude = ["*.md"]
55
+
56
+ [tool.ruff.lint]
57
+ select = ["E", "F", "W", "I", "B", "UP"]
58
+
59
+ [tool.ruff.lint.isort]
60
+ known-first-party = ["splitkaro", "helpers"]