Skip to content
GitLab
Menu
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
Luc Didry
kresus
Commits
f299c6d6
Commit
f299c6d6
authored
Sep 20, 2018
by
Antoine
Browse files
Update balance computation and introduce outstanding balance computation
parent
0ba8c1d4
Changes
7
Hide whitespace changes
Inline
Side-by-side
client/helpers.js
View file @
f299c6d6
...
...
@@ -14,7 +14,9 @@ import {
UNKNOWN_OPERATION_TYPE
as
UNKNOWN_OPERATION_TYPE_
,
formatDate
as
formatDate_
,
MIN_WEBOOB_VERSION
as
MIN_WEBOOB_VERSION_
,
validatePassword
as
validatePassword_
validatePassword
as
validatePassword_
,
shouldIncludeInBalance
as
shouldIncludeInBalance_
,
shouldIncludeInOutstandingSum
as
shouldIncludeInOutstandingSum_
}
from
'
../shared/helpers.js
'
;
export
const
maybeHas
=
maybeHas_
;
...
...
@@ -27,6 +29,8 @@ export const UNKNOWN_OPERATION_TYPE = UNKNOWN_OPERATION_TYPE_;
export
const
formatDate
=
formatDate_
;
export
const
MIN_WEBOOB_VERSION
=
MIN_WEBOOB_VERSION_
;
export
const
validatePassword
=
validatePassword_
;
export
const
shouldIncludeInBalance
=
shouldIncludeInBalance_
;
export
const
shouldIncludeInOutstandingSum
=
shouldIncludeInOutstandingSum_
;
export
const
AlertTypes
=
[
'
balance
'
,
'
transaction
'
];
...
...
client/models.js
View file @
f299c6d6
...
...
@@ -87,6 +87,8 @@ export class Account {
// Make sure to update `updateFrom` if you add any fields here.
this
.
operationIds
=
[];
this
.
balance
=
this
.
initialBalance
;
// The sum of the amount of transactions not yet taken into account in the balance.
this
.
outstandingSum
=
0
;
}
static
updateFrom
(
arg
,
defaultCurrency
,
previousAccount
)
{
...
...
@@ -96,6 +98,7 @@ export class Account {
newAccount
.
operationIds
=
previousAccount
.
operationIds
;
newAccount
.
balance
=
previousAccount
.
balance
-
previousAccount
.
initialBalance
+
newAccount
.
initialBalance
;
newAccount
.
outstandingSum
=
previousAccount
.
outstandingSum
;
return
newAccount
;
}
...
...
client/store/banks.js
View file @
f299c6d6
import
u
from
'
updeep
'
;
import
moment
from
'
moment
'
;
import
{
assert
,
...
...
@@ -9,7 +10,9 @@ import {
NONE_CATEGORY_ID
,
translate
as
$t
,
UNKNOWN_ACCOUNT_TYPE
,
displayLabel
displayLabel
,
shouldIncludeInBalance
,
shouldIncludeInOutstandingSum
}
from
'
../helpers
'
;
import
{
Account
,
Access
,
Alert
,
Bank
,
Operation
}
from
'
../models
'
;
...
...
@@ -656,20 +659,29 @@ function addOperations(state, pOperations) {
let
accountsMapUpdate
=
{};
let
operationMapUpdate
=
{};
let
today
=
moment
();
for
(
let
op
of
operations
)
{
if
(
typeof
accountsMapUpdate
[
op
.
accountId
]
===
'
undefined
'
)
{
let
account
=
accountById
(
state
,
op
.
accountId
);
accountsMapUpdate
[
op
.
accountId
]
=
{
let
operation
=
new
Operation
(
op
);
if
(
typeof
accountsMapUpdate
[
operation
.
accountId
]
===
'
undefined
'
)
{
let
account
=
accountById
(
state
,
operation
.
accountId
);
accountsMapUpdate
[
operation
.
accountId
]
=
{
operationIds
:
account
.
operationIds
.
slice
(),
balance
:
account
.
balance
balance
:
account
.
balance
,
outstandingSum
:
account
.
outstandingSum
,
type
:
account
.
type
};
}
let
accountUpdate
=
accountsMapUpdate
[
op
.
accountId
];
accountUpdate
.
balance
+=
op
.
amount
;
accountUpdate
.
operationIds
.
push
(
op
.
id
);
let
accountUpdate
=
accountsMapUpdate
[
operation
.
accountId
];
operationMapUpdate
[
op
.
id
]
=
new
Operation
(
op
);
if
(
shouldIncludeInBalance
(
operation
,
today
,
accountUpdate
.
type
))
{
accountUpdate
.
balance
+=
operation
.
amount
;
}
else
if
(
shouldIncludeInOutstandingSum
(
operation
))
{
accountUpdate
.
outstandingSum
+=
operation
.
amount
;
}
accountUpdate
.
operationIds
.
push
(
operation
.
id
);
operationMapUpdate
[
operation
.
id
]
=
operation
;
}
let
newState
=
updateOperationsMap
(
state
,
operationMapUpdate
);
...
...
@@ -884,9 +896,19 @@ function removeOperation(state, operationId) {
let
op
=
operationById
(
state
,
operationId
);
let
account
=
accountById
(
state
,
op
.
accountId
);
let
{
balance
,
outstandingSum
}
=
account
;
let
today
=
moment
();
if
(
shouldIncludeInBalance
(
op
,
today
,
account
.
type
))
{
balance
-=
op
.
amount
;
}
else
if
(
shouldIncludeInOutstandingSum
(
op
))
{
outstandingSum
-=
op
.
amount
;
}
let
newState
=
updateAccountFields
(
state
,
account
.
id
,
{
operationIds
:
u
.
reject
(
id
=>
id
===
operationId
),
balance
:
account
.
balance
-
op
.
amount
balance
,
outstandingSum
});
return
updateOperationsMap
(
newState
,
u
.
omit
(
`
${
operationId
}
`
));
...
...
server/helpers.js
View file @
f299c6d6
...
...
@@ -8,7 +8,9 @@ import {
UNKNOWN_OPERATION_TYPE
as
UNKNOWN_OPERATION_TYPE_
,
UNKNOWN_ACCOUNT_TYPE
as
UNKNOWN_ACCOUNT_TYPE_
,
formatDate
as
formatDate_
,
MIN_WEBOOB_VERSION
as
MIN_WEBOOB_VERSION_
MIN_WEBOOB_VERSION
as
MIN_WEBOOB_VERSION_
,
shouldIncludeInBalance
as
shouldIncludeInBalance_
,
shouldIncludeInOutstandingSum
as
shouldIncludeInOutstandingSum_
}
from
'
./shared/helpers.js
'
;
import
errors
from
'
./shared/errors.json
'
;
...
...
@@ -22,6 +24,8 @@ export const UNKNOWN_ACCOUNT_TYPE = UNKNOWN_ACCOUNT_TYPE_;
export
const
setupTranslator
=
setupTranslator_
;
export
const
formatDate
=
formatDate_
;
export
const
MIN_WEBOOB_VERSION
=
MIN_WEBOOB_VERSION_
;
export
const
shouldIncludeInBalance
=
shouldIncludeInBalance_
;
export
const
shouldIncludeInOutstandingSum
=
shouldIncludeInOutstandingSum_
;
export
function
makeLogger
(
prefix
)
{
return
new
Logger
(
prefix
);
...
...
server/lib/accounts-manager.js
View file @
f299c6d6
...
...
@@ -19,7 +19,8 @@ import {
currency
,
assert
,
displayLabel
,
UNKNOWN_OPERATION_TYPE
UNKNOWN_OPERATION_TYPE
,
shouldIncludeInBalance
}
from
'
../helpers
'
;
import
AsyncQueue
from
'
./async-queue
'
;
...
...
@@ -389,7 +390,7 @@ merging as per request`);
// Resync balance only if we are sure that the operation is a new one.
let
accountImportDate
=
new
Date
(
account
.
importDate
);
accountInfo
.
balanceOffset
=
providerOrphans
.
filter
(
op
=>
+
op
.
debitDate
<
+
accountImportDate
)
.
filter
(
op
=>
shouldIncludeInBalance
(
op
,
accountImportDate
,
account
.
type
)
)
.
reduce
((
sum
,
op
)
=>
sum
+
op
.
amount
,
0
);
}
}
...
...
@@ -461,13 +462,12 @@ to be resynced, by an offset of ${balanceOffset}.`);
if
(
typeof
retrievedAccount
!==
'
undefined
'
)
{
let
realBalance
=
retrievedAccount
.
initialBalance
;
let
operations
=
await
Transactions
.
byAccount
(
userId
,
account
);
let
operationsSum
=
operations
.
reduce
((
amount
,
op
)
=>
amount
+
op
.
amount
,
0
);
let
kresusBalance
=
operationsSum
+
account
.
initialBalance
;
let
kresusBalance
=
await
account
.
computeBalance
();
let
balanceDelta
=
realBalance
-
kresusBalance
;
if
(
Math
.
abs
(
realB
alance
-
kresusBalance
)
>
0.01
)
{
log
.
info
(
`Updating balance for account
${
accountNumber
}
`
);
let
initialBalance
=
realBalance
-
operationsSum
;
if
(
Math
.
abs
(
b
alance
Delta
)
>
0.
0
01
)
{
log
.
info
(
`Updating balance for account
${
account
.
accountNumber
}
`
);
let
initialBalance
=
account
.
initialBalance
+
balanceDelta
;
return
await
Accounts
.
update
(
userId
,
account
.
id
,
{
initialBalance
});
}
}
else
{
...
...
server/models/accounts.js
View file @
f299c6d6
import
*
as
cozydb
from
'
cozydb
'
;
import
{
assert
,
makeLogger
,
promisify
,
promisifyModel
,
UNKNOWN_ACCOUNT_TYPE
}
from
'
../helpers
'
;
import
moment
from
'
moment
'
;
import
{
assert
,
makeLogger
,
promisify
,
promisifyModel
,
UNKNOWN_ACCOUNT_TYPE
,
shouldIncludeInBalance
,
shouldIncludeInOutstandingSum
}
from
'
../helpers
'
;
import
Transactions
from
'
./transactions
'
;
...
...
@@ -142,7 +152,19 @@ Account.updateAttributes = function() {
Account
.
prototype
.
computeBalance
=
async
function
computeBalance
()
{
let
userId
=
await
this
.
getUserId
();
let
ops
=
await
Transactions
.
byAccount
(
userId
,
this
);
let
s
=
ops
.
reduce
((
sum
,
op
)
=>
sum
+
op
.
amount
,
this
.
initialBalance
);
let
today
=
moment
();
let
s
=
ops
.
filter
(
op
=>
shouldIncludeInBalance
(
op
,
today
,
this
.
type
))
.
reduce
((
sum
,
op
)
=>
sum
+
op
.
amount
,
this
.
initialBalance
);
return
Math
.
round
(
s
*
100
)
/
100
;
};
Account
.
prototype
.
computeOutstandingSum
=
async
function
computeOutstandingSum
()
{
let
userId
=
await
this
.
getUserId
();
let
ops
=
await
Transactions
.
byAccount
(
userId
,
this
);
let
s
=
ops
.
filter
(
op
=>
shouldIncludeInOutstandingSum
(
op
))
.
reduce
((
sum
,
op
)
=>
sum
+
op
.
amount
,
0
);
return
Math
.
round
(
s
*
100
)
/
100
;
};
...
...
shared/helpers.js
View file @
f299c6d6
...
...
@@ -10,6 +10,9 @@ import Polyglot from 'node-polyglot';
import
{
format
as
currencyFormatter
,
findCurrency
}
from
'
currency-formatter
'
;
import
moment
from
'
moment
'
;
import
ACCOUNT_TYPES
from
'
./account-types.json
'
;
import
OPERATION_TYPES
from
'
./operation-types.json
'
;
export
function
maybeHas
(
obj
,
prop
)
{
return
obj
&&
obj
.
hasOwnProperty
(
prop
);
}
...
...
@@ -132,3 +135,21 @@ const PASSPHRASE_VALIDATION_REGEXP = /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,}$/;
export
function
validatePassword
(
password
)
{
return
PASSPHRASE_VALIDATION_REGEXP
.
test
(
password
);
}
const
DEFERRED_CARD_TYPE
=
OPERATION_TYPES
.
find
(
type
=>
type
.
name
===
'
type.deferred_card
'
);
const
SUMMARY_CARD_TYPE
=
OPERATION_TYPES
.
find
(
type
=>
type
.
name
===
'
type.card_summary
'
);
const
ACCOUNT_TYPE_CARD
=
ACCOUNT_TYPES
.
find
(
type
=>
type
.
name
===
'
account-type.card
'
);
export
const
shouldIncludeInBalance
=
(
op
,
balanceDate
,
accountType
)
=>
{
let
opDebitMoment
=
moment
(
op
.
debitDate
||
op
.
date
);
return
(
opDebitMoment
.
isSameOrBefore
(
balanceDate
,
'
day
'
)
&&
(
op
.
type
!==
DEFERRED_CARD_TYPE
.
name
||
accountType
===
ACCOUNT_TYPE_CARD
.
name
)
);
};
export
const
shouldIncludeInOutstandingSum
=
op
=>
{
let
opDebitMoment
=
moment
(
op
.
debitDate
||
op
.
date
);
let
today
=
moment
();
return
opDebitMoment
.
isAfter
(
today
,
'
day
'
)
&&
op
.
type
!==
SUMMARY_CARD_TYPE
.
name
;
};
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment