-
Notifications
You must be signed in to change notification settings - Fork 44
/
api.js
164 lines (146 loc) · 4.9 KB
/
api.js
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
163
164
/**
* TODO Handle pagination
*
* As of now, paginations for recurrence bundles and for transactions inside
* recurrence has not been dealt with, both in the API and on the UI side
* of things. Since having more than 100 hundred recurrences is infrequent,
* we do not think it is a major hurdle if users only see their 100 most recent
* recurrences, or only the most recent 100 transactions inside this recurrence
* bundle.
*/
import set from 'lodash/set'
import flatten from 'lodash/flatten'
import omit from 'lodash/omit'
import { dehydrate } from 'cozy-client'
import maxBy from 'lodash/maxBy'
import get from 'lodash/get'
import groupBy from 'lodash/groupBy'
import { getAutomaticLabelFromBundle } from './utils'
import {
queryRecurrenceTransactions,
queryRecurrencesTransactions
} from './queries'
import { TRANSACTION_DOCTYPE, RECURRENCE_DOCTYPE } from 'doctypes'
const addRelationship = (doc, relationshipName, definition) => {
return set(doc, ['relationships', relationshipName], { data: definition })
}
const getRecurrenceIdFromRawTransaction = tr =>
get(tr, 'relationships.recurrence.data._id', null)
/**
* Fetch bundles and associated transactions from CouchDB
* Returns "hydrated" bundles with an `ops` field containing all its transactions
*
* @param {CozyClient} client
* @return {Promise<HydratedRecurrences>}
*/
export const fetchHydratedBundles = async client => {
const recurrenceCol = client.collection(RECURRENCE_DOCTYPE)
const { data: recurrences } = await recurrenceCol.all()
const { data: transactions } = await client.query(
queryRecurrencesTransactions(recurrences)
)
const byRecurrence = groupBy(transactions, getRecurrenceIdFromRawTransaction)
return recurrences.map(rec => ({
...rec,
ops: byRecurrence[rec._id] || []
}))
}
/**
* Saves recurrence bundles and update related transactions
*
* Recurrence bundles here are "hydrated" with an `ops` attribute with
* all its operations. In CouchDB, the `ops` field is not present, the
* transactions have a HasOne relationship to the bundle.
*
* @param {CozyClient} client
* @param {HydratedRecurrence} recurrences - Bundles with `ops` attributes
* @return {Promise}
*/
export const saveHydratedBundles = async (client, recurrenceClientBundles) => {
const recurrenceCol = client.collection(RECURRENCE_DOCTYPE)
const saveBundlesResp = await recurrenceCol.updateAll(
recurrenceClientBundles.map(bundle => {
const withoutOps = omit(bundle, 'ops')
withoutOps.automaticLabel = getAutomaticLabelFromBundle(bundle)
const latestOperation = maxBy(bundle.ops, x => x.date)
withoutOps.latestDate = latestOperation.date
return withoutOps
})
)
const bundlesWithIds = recurrenceClientBundles.map((recurrenceBundle, i) => ({
...recurrenceBundle,
_id: saveBundlesResp[i].id
}))
const ops = flatten(
bundlesWithIds.map(recurrenceBundle =>
recurrenceBundle.ops.map(op =>
addRelationship(dehydrate(op), 'recurrence', {
_id: recurrenceBundle._id,
_type: RECURRENCE_DOCTYPE
})
)
)
)
const opCollection = client.collection('io.cozy.bank.operations')
await opCollection.updateAll(ops.map(op => omit(op, '_type')))
}
export const resetBundles = async client => {
const recurrenceCol = client.collection(RECURRENCE_DOCTYPE)
const { data: serverBundles } = await recurrenceCol.all()
await recurrenceCol.destroyAll(serverBundles)
}
const setTransactionAsUnrecurrent = transaction =>
addRelationship(transaction, 'recurrence', {
_id: NOT_RECURRENT_ID,
_type: RECURRENCE_DOCTYPE
})
export const NOT_RECURRENT_ID = 'not-recurrent'
export const deleteRecurrence = async (client, recurrence) => {
const opCollection = client.collection(TRANSACTION_DOCTYPE)
const { data: ops } = await client.query(
queryRecurrenceTransactions(recurrence)
)
await opCollection.updateAll(
ops.map(op => setTransactionAsUnrecurrent(omit(op, '_type')))
)
await client.destroy(recurrence)
}
export const renameRecurrenceManually = async (
client,
recurrence,
newLabel
) => {
return client.save({
...recurrence,
manualLabel: newLabel
})
}
const STATUS_ONGOING = 'ongoing'
const STATUS_FINISHED = 'finished'
export const getStatus = recurrence => {
if (recurrence.status) {
return recurrence.status
} else {
return STATUS_ONGOING
}
}
export const isOngoing = recurrence => {
const status = getStatus(recurrence)
return status === STATUS_ONGOING
}
export const isFinished = recurrence => {
const status = getStatus(recurrence)
return status === STATUS_FINISHED
}
export const setStatusOngoing = async (client, recurrence) => {
return setStatus(client, recurrence, STATUS_ONGOING)
}
export const setStatusFinished = async (client, recurrence) => {
return setStatus(client, recurrence, STATUS_FINISHED)
}
export const setStatus = async (client, recurrence, status) => {
client.save({
...recurrence,
status
})
}