๐ฆ Scalable Capital Importers
broker_scalable and broker_scalable_deposit import the two accounts of Scalable Capital,
each into a LibreFolio broker of its own: the broker account (Scalable Capital broker) and the
overnight account (Scalable Capital overnight account). They live in
backend/app/services/brim_providers/broker_scalable/plugin.py and broker_scalable_deposit/plugin.py
(plugin_version 1.0.0, .csv only, detection_priority 100), which hold only their properties
and calls to the shared reader, _scalable.py: recognition, refusals and parsing are written once,
for both accounts. The leading underscore keeps _scalable.py out of the registry's
auto-discovery.
This page covers what is specific to Scalable. The user's view is
Scalable Capital, where the docs_url of both
plugins points.
๐๏ธ Files and detection
Every file starts with the 14 columns of Scalable's own CSV export (PRIME_COLUMNS):
| File | Header | Read by |
|---|---|---|
| Scalable's own CSV โ PRIME and PRIME+ plans, broker account only | the 14 columns | broker_scalable |
| The LibreFolio exporter's broker file | the 14 columns, then lf_*; lf_account is broker |
broker_scalable |
| The exporter's overnight account file | the 14 columns, then lf_*; lf_account is deposit |
broker_scalable_deposit |
- Recognition (
read_file, behindcan_parse): a.csvwhose first line holds the 14 columns, in any case and any order, split on the delimiter the base class detects. Without anlf_accountcolumn the file is Scalable's own CSV, always the broker account; with it, thelf_accountvalues give the account โbroker,deposit, both (mixed), or none for an export without rows, which both plugins accept. The file name is never read: the user may rename the file. A file that cannot be read is simply not a Scalable export: recognition never raises. - Refusals (
refusal): each plugin refuses the other account's file, and both refuse a mixed one, with a code and โ except for the mixed file โ the plugin that reads it. The codes are listed in Saying why with a code. Any other file gets no refusal. - Values are read by column name. The 14 columns use the decimal comma (
to_decimal_it) anddateisYYYY-MM-DD. Of the exporter's own columns, described in its format, the reader useslf_account,lf_id,lf_subtype,lf_is_cancellation,lf_ordered_sharesandlf_account_index.
๐ What is imported
_Reader takes the data rows in file order. A reversal (lf_is_cancellation is true) and a row
whose status is not Executed or Settled are left out, and so is a row without a readable
date, amount or currency. Then type, compared lower-case, decides:
In the file (type) |
Imported as |
|---|---|
Buy, Savings plan |
BUY on the gross amount โ the value of the shares, as Scalable's CSV and exporter 1.0.1 or later write it โ with fee as a FEE and a positive tax as a TAX of the same asset. A negative tax, given back, becomes a DEPOSIT without asset |
Sell |
SELL, the same way |
a type containing Distribution |
DIVIDEND, gross โ amount plus the tax withheld in tax โ with that tax as a TAX of the same asset; net when tax is empty |
Interest |
INTEREST, gross, with the tax withheld as a TAX, both without asset; net when tax is empty |
Deposit, Withdrawal โ bank transfers, and transfers between the two accounts |
DEPOSIT, WITHDRAWAL |
Fee |
FEE, without asset |
Taxes, Tax |
TAX, without asset; a positive amount, a refund, becomes a DEPOSIT |
Any other row whose assetType is Cash, such as a bonus |
DEPOSIT or WITHDRAWAL, by the sign of amount |
Security transfer, Corporate action and any other type |
Not imported: the scalable_not_imported notice lists them |
- Signs: a cash row whose sign contradicts its type โ a negative
Deposit, a positiveWithdrawalorFeeโ is booked by its sign, and so is a negative dividend or interest (scalable_cash_by_sign). A cash row, a dividend or an interest of zero is not imported (scalable_not_imported). - Trades without their details: in an exporter file, an empty
feemeans the details were not read, and the trade is booked onamountas it is, without legs (scalable_fees_unknown). - Exporter 1.0.0 is not supported: its trades carry the fee and the tax inside
amount(added on a purchase, taken away on a sale), so both would be counted twice; the user exports again with 1.0.1 or later. - Only executed rows are imported. A
Pendingrow withlf_ordered_sharesand somesharesalready executed is an order filled in part (scalable_open_partial): it comes, executed, with a later export. The other statuses go toscalable_not_executed. - Assets: one fake asset id per ISIN โ per
descriptionwhen the row has no ISIN โ counting down fromFAKE_ASSET_ID_BASEin order of first use, withextracted_isinandextracted_name(description) and no symbol; only the assets of written transactions are returned. The user matches them to LibreFolio's assets in the wizard's Review step. A trade or a dividend with neither ISIN nor description is unreadable. - Descriptions (
_description): an optional leg prefix โOrder fee,Tax,Tax refundโ then the row'sdescription(itstypewhen empty,Scalable Capitalwhen both are) cut to 350 characters, thenid <lf_id>in exporter files andref <reference>when the row has one, joined byยท. The id keeps two identical movements of one day apart and lets a new export recognise the rows already imported: the deduplication makes a match on the key fieldsLIKELY, unticked, only when the descriptions match too. Only the exporter's descriptions carryid โฆ, so a row imported from one layout comes back from the other as aPOSSIBLEduplicate, ticked. - Transfers between the two accounts (
lf_subtypeCASH_TRANSFER_INorCASH_TRANSFER_OUT) are imported as plainDEPOSITandWITHDRAWALand listed byscalable_internal_transfers: aCASH_TRANSFERlinks two brokers, so the user merges the two halves in the bulk editor (Transfers). A merged half still matches when it is exported again (Merged transfers and exchanges). - Tags:
importandscalable(_TAGS), from both plugins, so the two halves of a merged transfer carry the same tags. Both plugins declarehistory_tagscalableto match:broker_scalableby default,broker_scalable_depositby override, since its default would bescalable_deposit. - Amounts are copied from the file, never recomputed or converted โ a gross dividend or
interest is the sum of
amountand the tax withheld โ and the currency comes from each row'scurrency: a value that is not an ISO 4217 code makes the row unreadable.
๐ Notices
_NOTICES holds the eleven notices in display order, each with its severity, an English message
and the comment of its evidence table. A notice comes only when it has rows, with context.count
and one BRIMEvidence: those rows under the file's header, with their line numbers and an empty
title, so the wizard captions the table itself. The wizard words the message as
importWizard.brimNotice.<code> and the comment as importWizard.brimEvidence.<code>, keys
present in the four catalogues; the English texts are the fallback
(Talking to the import wizard).
| Code | Severity | Rows |
|---|---|---|
scalable_unreadable_rows |
warning | A date, an amount, a currency, the shares or the security missing or unreadable: not imported |
scalable_fees_unknown |
warning | Exporter rows without their fee and tax details: imported on the amount shown, without legs |
scalable_open_partial |
warning | Orders filled in part and still open: not imported yet |
scalable_reversal |
warning | Reversals of a transaction already booked: not imported |
scalable_not_imported |
warning | Security transfers, corporate actions, other types and zero amounts |
scalable_several_overnight_accounts |
warning | The first row of each overnight account (lf_account_index), when the file holds more than one: they all go into one broker |
scalable_not_executed |
info | Pending, cancelled, expired or rejected rows |
scalable_internal_transfers |
info | Transfers between the two accounts: imported, to be merged |
scalable_dividends_net |
info | Dividends without tax: imported net |
scalable_tax_refund |
info | Tax refunds: imported as DEPOSIT |
scalable_cash_by_sign |
info | Cash rows of an unknown type, or with an unexpected sign: booked by the sign of amount |
๐งช Samples and tests
backend/app/services/brim_providers/sample_reports/holdsscalable-prime-export.csv(Scalable's own CSV),scalable-broker-export.csvandscalable-deposit-export.csv(exporter 1.0.1, one file per account, whose internal transfers mirror each other): invented values on the real layout, described in the folder'sREADME.md../dev.py test external brim-scalable(test_external/test_brim_scalable.py) pins recognition, refusals, the three samples row by row, the rules on synthetic files and the catalogue keys;./dev.py test api brim-scalable(test_api/test_brim_scalable_api.py) imports both accounts end to end, merges the transfers and imports them again as duplicates.