Skip to content

Reuse existing ledger load transactions in Compass Card mapper with date tolerance#153

Draft
Copilot wants to merge 5 commits into
mainfrom
copilot/swiftbean-count-map-load-transaction
Draft

Reuse existing ledger load transactions in Compass Card mapper with date tolerance#153
Copilot wants to merge 5 commits into
mainfrom
copilot/swiftbean-count-map-load-transaction

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented May 25, 2026

Compass Card load imports did not account for cases where the corresponding funding transaction was already present in the ledger, typically from importing the credit card first. In that case, the mapper created a new load using fallback metadata instead of aligning with the existing transaction.

  • Load account resolution

    • For Compass Card load rows, the mapper now first looks for an existing ledger transaction within a date tolerance window with the same Compass Card posting amount.
    • When a match is found, it reuses the existing counter-account for the imported load transaction.
    • If no match exists, the prior compass-card-load metadata lookup and default fallback behavior are unchanged.
  • Matching behavior

    • Matching is limited to transactions that:
      • fall within an inclusive 4-day date tolerance of the Compass Card load,
      • contain the same Compass Card posting amount,
      • have exactly one non-Compass-card counter-posting.
    • When multiple candidates exist, the mapper prefers the one closest in time.
  • Regression coverage

    • Adds focused mapper tests for the “credit card imported first” flow.
    • Covers matching both within the date tolerance window and outside the tolerance window to verify the fallback behavior still applies when no nearby existing transaction should be reused.
let amount = Amount(number: decimal, commoditySymbol: commodity, decimalDigits: 2)
let expenseAccount = ledgerLoadAccountName(
    cardNumber: cardNumber,
    transactionDate: transaction.date,
    account: account,
    amount: amount
)

Copilot AI changed the title [WIP] Map existing load transaction for SwiftBeanCountCompassCardMapper Reuse existing ledger load transactions in Compass Card mapper May 25, 2026
Copilot finished work on behalf of Nef10 May 25, 2026 05:52
Copilot AI requested a review from Nef10 May 25, 2026 05:52
@Nef10
Copy link
Copy Markdown
Owner

Nef10 commented May 25, 2026

@copilot add a date tolerance like in the SwiftBeanCountSheetSync LedgerSettings

Copy link
Copy Markdown
Contributor Author

Copilot AI commented May 25, 2026

@copilot add a date tolerance like in the SwiftBeanCountSheetSync LedgerSettings

Implemented in c2b47de. The Compass Card mapper now uses an inclusive 24-hour date tolerance when matching existing load transactions, with regression coverage for both inside and outside the tolerance window.

Copilot AI changed the title Reuse existing ledger load transactions in Compass Card mapper Reuse existing ledger load transactions in Compass Card mapper with date tolerance May 25, 2026
Copilot finished work on behalf of Nef10 May 25, 2026 06:28
@Nef10
Copy link
Copy Markdown
Owner

Nef10 commented May 25, 2026

@copilot change to 4 days

Copy link
Copy Markdown
Contributor Author

Copilot AI commented May 25, 2026

@copilot change to 4 days

Updated in b6ac0af. The existing Compass Card load match tolerance is now 4 days, and the focused boundary tests were adjusted to cover the new inclusive limit.

Copilot finished work on behalf of Nef10 May 25, 2026 06:37
@github-actions
Copy link
Copy Markdown

Minimum coverage required: 89%

Coverage after merging copilot/swiftbean-count-map-load-transaction into main will be

91.91%

Coverage Report
FileStmtsFuncsLinesUncovered Lines
Sources/SwiftBeanCountCLI
   ColorizedCommand.swift100%100%100%
   FormattableCommand.swift100%100%100%
   FormattableLedgerCommand.swift100%100%100%
   LedgerCommand.swift100%100%100%
   SwiftBeanCountCLI.swift100%100%100%
Sources/SwiftBeanCountCLI/SubCommands
   Accounts.swift100%100%100%
   Check.swift100%100%100%
   Stats.swift100%100%100%
   TaxSlips.swift100%100%100%
   TaxableSales.swift96.63%85.71%98.09%
Sources/SwiftBeanCountCompassCardMapper
   SwiftBeanCountCompassCardMapper.swift97.80%94%98.65%
   SwiftBeanCountCompassCardMapperError.swift100%100%100%
Sources/SwiftBeanCountImporter
   BaseImporter.swift97.96%96.67%98.29%46
   CSVBaseImporter.swift91.04%80%92.98%74–76
   CSVImporter.swift97.62%100%97.37%52
   DownloadImporter.swift100%100%100%
   FileImporter.swift100%100%100%
   Importer.swift98.33%100%98.04%274
   Settings.swift100%100%100%
   TextImporter.swift100%100%100%
Sources/SwiftBeanCountImporter/Importers
   CompassCardDownloadImporter.swift95.62%92.86%95.98%109–110, 126–127, 153–155, 207
   CompassCardImporter.swift100%100%100%
   EquatePlusImporter.swift98.38%100%98.14%178–181, 218, 285
   GoogleSheetDownloadImporter.swift9.18%24%7.02%100–107, 109–134, 136–141, 143–150, 17–19, 26–60, 62, 79–99
   LunchOnUsImporter.swift100%100%100%
   ManuLifeImporter.swift96.63%96.49%96.66%270, 276, 318, 364–371
   N26Importer.swift100%100%100%
   RBCImporter.swift100%100%100%
   RogersDownloadImporter.swift99.13%98.18%99.26%190, 243
   RogersImporter.swift100%100%100%
   SimpliiImporter.swift100%100%100%
   TangerineAccountImporter.swift100%100%100%
   TangerineCardImporter.swift100%100%100%
   TangerineDownloadImporter.swift99.45%100%99.36%162, 209
   WealthsimpleDownloadImporter.swift97.18%94.74%97.47%259–267
Sources/SwiftBeanCountModel
   Account.swift98.40%96.88%98.71%214
   AccountName.swift92.13%93.33%91.89%100–104, 99
   Amount.swift100%100%100%
   Balance.swift100%100%100%
   Commodity.swift100%100%100%
   Cost.swift100%100%100%
   Custom.swift100%100%100%
   Event.swift100%100%100%
   Flag.swift100%100%100%
   Inventory.swift97.77%96.77%97.97%76–77
   Ledger.swift100%100%100%
   MultiCurrencyAmount.swift100%100%100%
   Option.swift100%100%100%
   Price.swift89.55%91.67%89.09%100, 95–99
   Tag.swift77.78%80%76.92%59–61
   Transaction.swift99.29%100%99.15%143
   TransactionMetaData.swift100%100%100%
   TransactionPosting.swift95.79%94.12%95.95%161–162, 178, 197, 283, 285
Sources/SwiftBeanCountParser
   AccountParser.swift97.83%100%97.62%43
   BalanceParser.swift100%100%100%
   CommodityParser.swift100%100%100%
   CostParser.swift100%100%100%
   CustomsParser.swift100%100%100%
   DateParser.swift100%100%100%
   EventParser.swift100%100%100%
   MetaDataParser.swift100%100%100%
   OptionParser.swift100%100%100%
   Parser.swift98.79%97.14%98.99%104, 207
   PluginParser.swift100%100%100%
   PostingParser.swift100%100%100%
   PriceParser.swift100%100%100%
   TransactionMetaDataParser.swift100%100%100%
Sources/SwiftBeanCountParser/Extensions
   Collection.swift100%100%100%
Sources/SwiftBeanCountParserUtils
   String.swift100%100%100%
Sources/SwiftBeanCountRogersBankMapper
   RogersBankMappingError.swift100%100%100%
   SwiftBeanCountRogersBankMapper.swift99.19%100%99.07%71
Sources/SwiftBeanCountSheetSync
   Downloader.swift0%0%0%18–43, 45–59, 61–73
   LedgerReader.swift85.23%85.71%85.07%15–22
   LedgerSettings.swift100%100%100%
   SheetCellsFormatter.swift88.95%82.61%89.87%179, 192, 202, 210–214, 249–251, 76
   SheetDownloader.swift0%0%0%21–28, 31–35, 37–53
   SheetParser.swift97.72%100%97.49%106, 230, 239, 242, 335, 338, 406, 439
   Syncer.swift58.59%65.96%57.20%131–134, 155–172, 183–195, 220, 234–244, 284, 355–372, 39, 41
   TransactionMapper.swift100%100%100%
   Uploader.swift0%0%0%18–30, 36–65, 71–75
Sources/SwiftBeanCountStatements
   AccountStartEndDateValidator.swift100%100%100%
   LatestStatementValidator.swift96.49%83.33%98.04%
   StatementDatesValidator.swift81.11%100%79.76%151, 155–156, 161, 163–164, 166–173, 175–176, 197–198, 203, 205–206, 208–215, 217–218, 233, 237–238
   StatementFileValidator.swift89.02%81.82%90.14%41, 51–52, 82–83
   StatementValidator.swift93.75%87.50%95.83%14
   StatementValidatorError.swift100%100%100%
Sources/SwiftBeanCountTangerineMapper
   SwiftBeanCountTangerineMapper.swift98.04%94.74%98.80%
   SwiftBeanCountTangerineMapperError.swift100%100%100%
Sources/SwiftBeanCountTax
   Sale.swift100%100%100%
   TaxCalculator.swift99.21%98.99%99.26%191, 82
   TaxErrors.swift100%100%100%
   TaxSlip.swift98.76%98.25%98.92%27, 65
Sources/SwiftBeanCountWealthsimpleMapper
   LedgerLookup.swift98.33%95.65%98.97%
   WealthsimpleConversionError.swift100%100%100%
   WealthsimpleLedgerMapper+Helpers.swift95.38%96.97%95%116, 125, 47, 60, 72, 95
   WealthsimpleLedgerMapper+TransactionMapping.swift98.86%100%98.74%146–147
   WealthsimpleLedgerMapper.swift99.18%100%99.08%225, 230
Sources/SwiftBeanCountWealthsimpleMapper/Extensions
   Amount+init.swift100%100%100%
   String+KebabCase.swift100%100%100%
   Wealthsimple.Transaction+Helper.swift100%100%100%

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

SwiftBeanCountCompassCardMapper: Map to existing load transaction

2 participants