-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathprocess_year.go
162 lines (142 loc) · 5.28 KB
/
process_year.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
package main
import (
"fmt"
"time"
"github.com/leavengood/donation_tracker/other"
"github.com/leavengood/donation_tracker/paypal"
"github.com/leavengood/donation_tracker/util"
)
func AddTransactions(year int, m util.MonthlySummaries) {
transactions, err := other.TransactionsFromCsv(fmt.Sprintf("transactions-%d.csv", year))
if err != nil {
fmt.Printf("Transaction file could not be found for %d, will assume there are no other transactions.\n", year)
return
}
fmt.Printf("Adding %d transactions from CSV to the monthly summaries...\n", len(transactions))
otherSummary := util.NewSummary()
for _, t := range transactions {
_, month, _ := t.Date.Date()
fmt.Printf(" Merging in transaction [%s] to month %s\n", util.Colorize(util.Green, t.String()), month)
m.ForMonth(month).AddOneTime(t.Amt, t.FeeAmt, t.CurrencyCode)
otherSummary.AddOneTime(t.Amt, t.FeeAmt, t.CurrencyCode)
}
fmt.Printf("Total for other transactions: %s\n", otherSummary)
}
func SummarizeYear(year int, eurToUsdRate float32, fm *paypal.FileManager) *DonationSummary {
summaries := util.MonthlySummaries{}
// TODO: Extract this so it can be used for the one month process. Maybe put it into
// MonthlySummaries itself.
summarizeMonth := func(month time.Month, txns paypal.Transactions) {
donations, other := txns.FilterDonations()
monthStr := util.Colorize(util.Blue, fmt.Sprintf("%s %d", month, year))
fmt.Printf("%s: There are %d donations from %d transactions\n",
monthStr, len(donations), len(txns))
// TODO: Maybe this Summarize in PayPalTxns needs to be moved into
// MonthlySummaries, so this all becomes less awkward.
sums := donations.Summarize()
if len(sums) > 1 {
fmt.Printf(" WARNING: multiple months found in summary for %s\n", monthStr)
}
monthSummary := sums[month]
// At the beginning of the month in the current year, this could be empty
if monthSummary != nil {
fmt.Printf(" Donations: %s\n", monthSummary)
summaries[month] = monthSummary
}
if len(other) > 0 {
fmt.Println("\n Other transactions:")
for _, t := range other {
fmt.Printf(" %s\n", t)
}
}
fmt.Println("")
}
fmt.Printf("%s\n\n", util.Colorize(util.Green, "Monthly Totals"))
// Summarize each month
months := fm.GetExistingMonths()
for _, month := range months {
summarizeMonth(time.Month(month), fm.Months[month])
}
// Add in special transactions to each monthly summary
AddTransactions(year, summaries)
// Create totals and return the summary
total := summaries.Total()
fmt.Printf("\nTotal: %s\n", total)
grossTotal := total.GrossTotal()
fmt.Printf("Combined Total: %s\n", grossTotal)
grandTotal := grossTotal.GrandTotal(eurToUsdRate)
fmt.Println(util.Colorize(util.Yellow, fmt.Sprintf("Grand Total (at EUR to USD rate of %f): %.02f",
eurToUsdRate, grandTotal)))
return &DonationSummary{
UpdatedAt: time.Now().UTC(),
UsdDonations: grossTotal["USD"],
EurDonations: grossTotal["EUR"],
EurToUsdRate: eurToUsdRate,
TotalDonations: grandTotal,
}
}
// ProcessYear will take the provided year and EUR to USD conversion rate and
// perform the summary process which involves loading current data for the given
// year, getting any missing data, and then summarizing it all.
func ProcessYear(client *paypal.Client, year int, eurToUsdRate float32) (*DonationSummary, error) {
currentYear, currentMonth, _ := time.Now().UTC().Date()
// Load current files for the year
fm, err := paypal.NewFileManager(year)
if err != nil {
return nil, err
}
// First deal with the latest month we have saved. It could be several
// months ago depending on how long it has been between runs.
latest := fm.GetLatestMonth()
if latest != 0 {
// Assume this is a partial month
t := fm.GetLatestTransaction()
month := time.Month(latest)
var day int
// There may not be any transactions so far this month
if t == nil {
// Go to the beginning of the month
day = 1
} else {
day = t.Timestamp.Day()
}
// fmt.Printf("The latest transaction is: %#v, with timestamp: %s\n", t, t.Timestamp)
// Start from the beginning of this day so we don't miss anything
startDate := fmt.Sprintf("%d-%02d-%02dT00:00:00Z", year, month, day)
fmt.Printf("Fetching PayPal transactions newer than: %s\n", startDate)
newTxns := client.GetTransactions(startDate, paypal.GetEndDate(year, int(month)))
fmt.Printf("Found %d new transactions\n", len(newTxns))
previous := fm.Months[latest]
// Merge will remove any duplicates
txns := previous.Merge(newTxns)
// Only save if we got new transactions
if len(txns) > len(previous) {
if err := fm.SaveMonth(latest, txns); err != nil {
return nil, err
}
} else {
fmt.Printf("No new transactions found for latest month: %d\n", latest)
}
}
missing := fm.GetMissingMonths()
// If the current year is being processed, remove future months
if year == currentYear {
newMissing := []int{}
for _, month := range missing {
if month > int(currentMonth) {
break
}
newMissing = append(newMissing, month)
}
missing = newMissing
}
fmt.Printf("The missing months are: %v\n", missing)
// Get missing months from PayPal API and save them
for _, month := range missing {
if err := client.GetAndSaveMonth(year, month, fm); err != nil {
return nil, err
}
}
fmt.Println("")
return SummarizeYear(year, eurToUsdRate, fm), nil
}